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 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 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 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 278 DNSServiceErrorType DNSSD_API DNSServiceSendQueuedRequests 279 ( 280 DNSServiceRef sdr 281 ) 282 { 283 return DNSServiceSendQueuedRequestsInternal(sdr); 284 } 285 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 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 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 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 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 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 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 380 get_required_length_for_attribute_tlvs(const DNSServiceAttribute * const attr) 381 { 382 return put_attribute_tlvs(attr, NULL, NULL, NULL); 383 } 384 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) 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 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 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 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. 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 */ 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 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 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) 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 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 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 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. 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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() 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 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 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 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 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 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 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 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 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 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 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 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 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