1 /* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*- 2 * 3 * Copyright (c) 2004-2019 Apple Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 * This file defines functions that are common to platforms with Posix APIs. 18 * Current examples are mDNSMacOSX and mDNSPosix. 19 */ 20 21 #include <stdio.h> // Needed for fopen() etc. 22 #include <unistd.h> // Needed for close() 23 #include <stdlib.h> // Needed for malloc() 24 #include <string.h> // Needed for strlen() etc. 25 #include <errno.h> // Needed for errno etc. 26 #include <sys/socket.h> // Needed for socket() etc. 27 #include <netinet/in.h> // Needed for sockaddr_in 28 #include <syslog.h> 29 #include <sys/fcntl.h> 30 #include <netinet/tcp.h> 31 #include <arpa/inet.h> 32 #include <assert.h> 33 34 #if APPLE_OSX_mDNSResponder 35 #include <os/log.h> 36 #endif 37 38 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above 39 #include "DNSCommon.h" 40 #include "PlatformCommon.h" 41 42 #ifdef NOT_HAVE_SOCKLEN_T 43 typedef unsigned int socklen_t; 44 #endif 45 46 #if MDNS_MALLOC_DEBUGGING 47 // We ONLY want this for malloc debugging--on a running production system we want to deal with 48 // malloc failures, not just die. There is a small performance penalty for enabling these options 49 // as well, so they are all only appropriate for debugging. The flags mean: 50 // 51 // A = warnings are errors 52 // X = abort on failure 53 // Z = sets J & R 54 // J = allocated memory is initialized to a pattern 55 // R causes realloc to always reallocate even if not needed 56 57 char _malloc_options[] = "AXZ"; 58 59 mDNSlocal mDNSListValidator *listValidators; 60 61 mDNSexport void mDNSPlatformAddListValidator(mDNSListValidator *lv, mDNSListValidationFunction *lvf, 62 const char *lvfName, void *context) 63 { 64 mDNSPlatformMemZero(lv, sizeof *lv); 65 lv->validator = lvf; 66 lv->validationFunctionName = lvfName; 67 lv->context = context; 68 lv->next = listValidators; 69 listValidators = lv; 70 } 71 72 mDNSlocal void validateLists(void) 73 { 74 mDNSListValidator *vfp; 75 // Check Unix Domain Socket client lists (uds_daemon.c) 76 for (vfp = listValidators; vfp; vfp = vfp->next) 77 { 78 vfp->validator(vfp->context); 79 } 80 81 mDNSPlatformValidateLists(); 82 } 83 84 #define kAllocMagic 0xDEAD1234 85 #define kGuardMagic 0xDEAD1234 86 #define kFreeMagic 0xDEADDEAD 87 #define kAllocLargeSize 32768 88 89 mDNSexport void *mallocL(const char *msg, mDNSu32 size) 90 { 91 // Allocate space for two words of sanity checking data before the requested block and two words after. 92 // Adjust the length for alignment. 93 mDNSu32 *mem = malloc(sizeof(mDNSu32) * 4 + size); 94 mDNSu32 guard[2]; 95 if (!mem) 96 { LogMsg("malloc( %s : %u ) failed", msg, size); return(NULL); } 97 else 98 { 99 mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)(mem + 2) + size); 100 if (size > kAllocLargeSize) LogMsg("malloc( %s : %lu ) @ %p suspiciously large", msg, size, &mem[2]); 101 else if (MDNS_MALLOC_DEBUGGING >= 2) LogMsg("malloc( %s : %lu ) @ %p", msg, size, &mem[2]); 102 mem[ 0] = kAllocMagic; 103 guard[0] = kGuardMagic; 104 mem[ 1] = size; 105 guard[1] = size; 106 memcpy(after, &guard, sizeof guard); 107 memset(&mem[2], 0xFF, size); 108 validateLists(); 109 return(&mem[2]); 110 } 111 } 112 113 mDNSexport void *callocL(const char *msg, mDNSu32 size) 114 { 115 mDNSu32 guard[2]; 116 const mDNSu32 headerSize = 4 * sizeof(mDNSu32); 117 118 // Allocate space for two words of sanity checking data before the requested block and two words after. 119 // Adjust the length for alignment. 120 mDNSu32 *mem = (mDNSu32 *)calloc(1, headerSize + size); 121 if (!mem) 122 { LogMsg("calloc( %s : %u ) failed", msg, size); return(NULL); } 123 else 124 { 125 mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)(mem + 2) + size); 126 if (size > kAllocLargeSize) LogMsg("calloc( %s : %lu ) @ %p suspiciously large", msg, size, &mem[2]); 127 else if (MDNS_MALLOC_DEBUGGING >= 2) LogMsg("calloc( %s : %lu ) @ %p", msg, size, &mem[2]); 128 mem[ 0] = kAllocMagic; 129 guard[0] = kGuardMagic; 130 mem[ 1] = size; 131 guard[1] = size; 132 memcpy(after, guard, sizeof guard); 133 validateLists(); 134 return(&mem[2]); 135 } 136 } 137 138 mDNSexport void freeL(const char *msg, void *x) 139 { 140 if (!x) 141 LogMsg("free( %s @ NULL )!", msg); 142 else 143 { 144 mDNSu32 *mem = ((mDNSu32 *)x) - 2; 145 if (mem[0] == kFreeMagic) { LogMemCorruption("free( %s : %lu @ %p ) !!!! ALREADY DISPOSED !!!!", msg, mem[1], &mem[2]); return; } 146 if (mem[0] != kAllocMagic) { LogMemCorruption("free( %s : %lu @ %p ) !!!! NEVER ALLOCATED !!!!", msg, mem[1], &mem[2]); return; } 147 if (mem[1] > kAllocLargeSize) LogMsg("free( %s : %lu @ %p) suspiciously large", msg, mem[1], &mem[2]); 148 else if (MDNS_MALLOC_DEBUGGING >= 2) LogMsg("free( %s : %ld @ %p)", msg, mem[1], &mem[2]); 149 mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)x + mem[1]); 150 mDNSu32 guard[2]; 151 152 memcpy(guard, after, sizeof guard); 153 if (guard[0] != kGuardMagic) { LogMemCorruption("free( %s : %lu @ %p ) !!!! END GUARD OVERWRITE !!!!", 154 msg, mem[1], &mem[2]); return; } 155 if (guard[1] != mem[1]) { LogMemCorruption("free( %s : %lu @ %p ) !!!! LENGTH MISMATCH !!!!", 156 msg, mem[1], &mem[2]); return; } 157 mem[0] = kFreeMagic; 158 memset(mem + 2, 0xFF, mem[1] + 2 * sizeof(mDNSu32)); 159 validateLists(); 160 free(mem); 161 } 162 } 163 164 #endif 165 166 // Bind a UDP socket to find the source address to a destination 167 mDNSexport void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst) 168 { 169 union { struct sockaddr s; struct sockaddr_in a4; struct sockaddr_in6 a6; } addr; 170 socklen_t len = sizeof(addr); 171 socklen_t inner_len = 0; 172 int sock = socket(AF_INET, SOCK_DGRAM, 0); 173 src->type = mDNSAddrType_None; 174 if (sock == -1) return; 175 if (dst->type == mDNSAddrType_IPv4) 176 { 177 inner_len = sizeof(addr.a4); 178 #ifndef NOT_HAVE_SA_LEN 179 addr.a4.sin_len = inner_len; 180 #endif 181 addr.a4.sin_family = AF_INET; 182 addr.a4.sin_port = 1; // Not important, any port will do 183 addr.a4.sin_addr.s_addr = dst->ip.v4.NotAnInteger; 184 } 185 else if (dst->type == mDNSAddrType_IPv6) 186 { 187 inner_len = sizeof(addr.a6); 188 #ifndef NOT_HAVE_SA_LEN 189 addr.a6.sin6_len = inner_len; 190 #endif 191 addr.a6.sin6_family = AF_INET6; 192 addr.a6.sin6_flowinfo = 0; 193 addr.a6.sin6_port = 1; // Not important, any port will do 194 addr.a6.sin6_addr = *(struct in6_addr*)&dst->ip.v6; 195 addr.a6.sin6_scope_id = 0; 196 } 197 else return; 198 199 if ((connect(sock, &addr.s, inner_len)) < 0) { 200 if (errno != ENETUNREACH) 201 LogMsg("mDNSPlatformSourceAddrForDest: connect %#a failed errno %d (%s)", dst, errno, 202 strerror(errno)); 203 goto exit; 204 } 205 206 if ((getsockname(sock, &addr.s, &len)) < 0) 207 { LogMsg("mDNSPlatformSourceAddrForDest: getsockname failed errno %d (%s)", errno, strerror(errno)); goto exit; } 208 209 src->type = dst->type; 210 if (dst->type == mDNSAddrType_IPv4) src->ip.v4.NotAnInteger = addr.a4.sin_addr.s_addr; 211 else src->ip.v6 = *(mDNSv6Addr*)&addr.a6.sin6_addr; 212 exit: 213 close(sock); 214 } 215 216 // dst must be at least MAX_ESCAPED_DOMAIN_NAME bytes, and option must be less than 32 bytes in length 217 mDNSlocal mDNSBool GetConfigOption(char *dst, const char *option, FILE *f) 218 { 219 char buf[32+1+MAX_ESCAPED_DOMAIN_NAME]; // Option name, one space, option value 220 size_t len = strlen(option); 221 if (len + 1 + MAX_ESCAPED_DOMAIN_NAME > sizeof(buf)-1) { LogMsg("GetConfigOption: option %s too long", option); return mDNSfalse; } 222 fseek(f, 0, SEEK_SET); // set position to beginning of stream 223 while (fgets(buf, sizeof(buf), f)) // Read at most sizeof(buf)-1 bytes from file, and append '\0' C-string terminator 224 { 225 if (!strncmp(buf, option, len)) 226 { 227 strncpy(dst, buf + len + 1, MAX_ESCAPED_DOMAIN_NAME-1); 228 if (dst[MAX_ESCAPED_DOMAIN_NAME-1]) dst[MAX_ESCAPED_DOMAIN_NAME-1] = '\0'; 229 len = strlen(dst); 230 if (len && dst[len-1] == '\n') dst[len-1] = '\0'; // chop newline 231 return mDNStrue; 232 } 233 } 234 debugf("Option %s not set", option); 235 return mDNSfalse; 236 } 237 238 mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled) 239 { 240 char buf[MAX_ESCAPED_DOMAIN_NAME] = ""; 241 mStatus err; 242 FILE *f = fopen(filename, "r"); 243 244 if (hostname) hostname->c[0] = 0; 245 if (domain) domain->c[0] = 0; 246 if (DomainDiscoveryDisabled) *DomainDiscoveryDisabled = mDNSfalse; 247 248 if (f) 249 { 250 if (DomainDiscoveryDisabled && GetConfigOption(buf, "DomainDiscoveryDisabled", f) && !strcasecmp(buf, "true")) *DomainDiscoveryDisabled = mDNStrue; 251 if (hostname && GetConfigOption(buf, "hostname", f) && !MakeDomainNameFromDNSNameString(hostname, buf)) goto badf; 252 if (domain && GetConfigOption(buf, "zone", f) && !MakeDomainNameFromDNSNameString(domain, buf)) goto badf; 253 buf[0] = 0; 254 GetConfigOption(buf, "secret-64", f); // failure means no authentication 255 fclose(f); 256 f = NULL; 257 } 258 else 259 { 260 if (errno != ENOENT) LogMsg("ERROR: Config file exists, but cannot be opened."); 261 return; 262 } 263 264 if (domain && domain->c[0] && buf[0]) 265 { 266 DomainAuthInfo *info = (DomainAuthInfo*) mDNSPlatformMemAllocateClear(sizeof(*info)); 267 // for now we assume keyname = service reg domain and we use same key for service and hostname registration 268 err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0); 269 if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c); 270 } 271 272 return; 273 274 badf: 275 LogMsg("ERROR: malformatted config file"); 276 if (f) fclose(f); 277 } 278 279 #if MDNS_DEBUGMSGS 280 mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg) 281 { 282 fprintf(stderr,"%s\n", msg); 283 fflush(stderr); 284 } 285 #endif 286 287 #if !MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG) 288 mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, mDNSLogLevel_t loglevel) 289 { 290 #if APPLE_OSX_mDNSResponder && LogTimeStamps 291 extern mDNS mDNSStorage; 292 extern mDNSu32 mDNSPlatformClockDivisor; 293 mDNSs32 t = mDNSStorage.timenow ? mDNSStorage.timenow : mDNSPlatformClockDivisor ? mDNS_TimeNow_NoLock(&mDNSStorage) : 0; 294 int ms = ((t < 0) ? -t : t) % 1000; 295 #endif 296 297 if (mDNS_DebugMode) // In debug mode we write to stderr 298 { 299 #if APPLE_OSX_mDNSResponder && LogTimeStamps 300 if (ident && ident[0] && mDNSPlatformClockDivisor) 301 fprintf(stderr,"%8d.%03d: %s\n", (int)(t/1000), ms, buffer); 302 else 303 #endif 304 fprintf(stderr,"%s\n", buffer); 305 fflush(stderr); 306 } 307 else // else, in production mode, we write to syslog 308 { 309 static int log_inited = 0; 310 311 int syslog_level; 312 switch (loglevel) 313 { 314 case MDNS_LOG_FAULT: syslog_level = LOG_ERR; break; 315 case MDNS_LOG_ERROR: syslog_level = LOG_ERR; break; 316 case MDNS_LOG_WARNING: syslog_level = LOG_WARNING; break; 317 case MDNS_LOG_DEFAULT: syslog_level = LOG_NOTICE; break; 318 case MDNS_LOG_INFO: syslog_level = LOG_INFO; break; 319 case MDNS_LOG_DEBUG: syslog_level = LOG_DEBUG; break; 320 default: syslog_level = LOG_NOTICE; break; 321 } 322 323 if (!log_inited) { openlog(ident, LOG_CONS, LOG_DAEMON); log_inited++; } 324 325 #if APPLE_OSX_mDNSResponder && LogTimeStamps 326 if (ident && ident[0] && mDNSPlatformClockDivisor) 327 syslog(syslog_level, "%8d.%03d: %s", (int)(t/1000), ms, buffer); 328 else 329 #endif 330 { 331 syslog(syslog_level, "%s", buffer); 332 } 333 } 334 } 335 #endif // !MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG) 336 337 mDNSexport mDNSBool mDNSPosixTCPSocketSetup(int *fd, mDNSAddr_Type addrType, mDNSIPPort *port, mDNSIPPort *outTcpPort) 338 { 339 int sa_family = (addrType == mDNSAddrType_IPv4) ? AF_INET : AF_INET6; 340 int err; 341 int sock; 342 mDNSu32 lowWater = 15384; 343 344 sock = socket(sa_family, SOCK_STREAM, IPPROTO_TCP); 345 if (sock < 3) 346 { 347 if (errno != EAFNOSUPPORT) 348 { 349 LogMsg("mDNSPosixTCPSocketSetup: socket error %d errno %d (%s)", sock, errno, strerror(errno)); 350 } 351 return mDNStrue; 352 } 353 *fd = sock; 354 355 union 356 { 357 struct sockaddr sa; 358 struct sockaddr_in sin; 359 struct sockaddr_in6 sin6; 360 } addr; 361 // If port is not NULL, bind to it. 362 if (port != NULL) 363 { 364 socklen_t len = (sa_family == AF_INET) ? sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6); 365 mDNSPlatformMemZero(&addr, sizeof addr); 366 367 addr.sa.sa_family = sa_family; 368 #ifndef NOT_HAVE_SA_LEN 369 addr.sa.sa_len = len; 370 #endif 371 if (sa_family == AF_INET6) 372 { 373 addr.sin6.sin6_port = port->NotAnInteger; 374 } 375 else 376 { 377 addr.sin.sin_port = port->NotAnInteger; 378 } 379 err = bind(sock, &addr.sa, len); 380 if (err < 0) 381 { 382 LogMsg("mDNSPosixTCPSocketSetup getsockname: %s", strerror(errno)); 383 return mDNSfalse; 384 } 385 } 386 387 socklen_t addrlen = sizeof addr; 388 err = getsockname(sock, (struct sockaddr *)&addr, &addrlen); 389 if (err < 0) 390 { 391 LogMsg("mDNSPosixTCPSocketSetup getsockname: %s", strerror(errno)); 392 return mDNSfalse; 393 } 394 if (sa_family == AF_INET6) 395 { 396 outTcpPort->NotAnInteger = addr.sin6.sin6_port; 397 398 } else 399 { 400 outTcpPort->NotAnInteger = addr.sin.sin_port; 401 } 402 if (port) 403 port->NotAnInteger = outTcpPort->NotAnInteger; 404 405 #ifdef TCP_NOTSENT_LOWAT 406 err = setsockopt(sock, IPPROTO_TCP, TCP_NOTSENT_LOWAT, &lowWater, sizeof lowWater); 407 if (err < 0) 408 { 409 LogMsg("mDNSPosixTCPSocketSetup: TCP_NOTSENT_LOWAT failed: %s", strerror(errno)); 410 return mDNSfalse; 411 } 412 #endif 413 414 return mDNStrue; 415 } 416 417 mDNSexport TCPSocket *mDNSPosixDoTCPListenCallback(int fd, mDNSAddr_Type addressType, TCPSocketFlags socketFlags, 418 TCPAcceptedCallback callback, void *context) 419 { 420 union 421 { 422 struct sockaddr_in6 sin6; 423 struct sockaddr_in sin; 424 struct sockaddr sa; 425 } address; 426 427 socklen_t slen = sizeof address; 428 int remoteSock; 429 mDNSAddr addr; 430 mDNSIPPort port; 431 TCPSocket *sock = mDNSNULL; 432 int failed; 433 char *nbp; 434 int i; 435 mDNSu32 lowWater = 16384; 436 // When we remember our connection, we remember a name that we can print for logging. But 437 // since we are the listener in this case, we don't /have/ a name for it. This buffer 438 // is used to print the IP address into a human readable string which will serve that purpose 439 // for this case. 440 char namebuf[INET6_ADDRSTRLEN + 1 + 5 + 1]; 441 442 remoteSock = accept(fd, &address.sa, &slen); 443 if (remoteSock < 0) 444 { 445 LogMsg("mDNSPosixDoTCPListenCallback: accept returned %d", remoteSock); 446 goto out; 447 } 448 449 failed = fcntl(remoteSock, F_SETFL, O_NONBLOCK); 450 if (failed < 0) 451 { 452 close(remoteSock); 453 LogMsg("mDNSPosixDoTCPListenCallback: fcntl returned %d", errno); 454 goto out; 455 } 456 457 #ifdef TCP_NOTSENT_LOWAT 458 failed = setsockopt(remoteSock, IPPROTO_TCP, TCP_NOTSENT_LOWAT, 459 &lowWater, sizeof lowWater); 460 if (failed < 0) 461 { 462 close(remoteSock); 463 LogMsg("mDNSPosixDoTCPListenCallback: TCP_NOTSENT_LOWAT returned %d", errno); 464 goto out; 465 } 466 #endif 467 468 if (address.sa.sa_family == AF_INET6) 469 { 470 // If we are listening on an IPv4/IPv6 socket, the incoming address might be an IPv4-in-IPv6 address 471 for (i = 0; i < 10; i++) 472 { 473 if (address.sin6.sin6_addr.s6_addr[i] != 0) 474 { 475 addr.type = mDNSAddrType_IPv6; 476 goto nope; 477 } 478 } 479 480 // a legit IPv4 address would be ::ffff:a.b.c.d; if there's no ::ffff bit, then it's an IPv6 481 // address with a really weird prefix. 482 if (address.sin6.sin6_addr.s6_addr[10] != 0xFF || address.sin6.sin6_addr.s6_addr[11] != 0xFF) 483 { 484 addr.type = mDNSAddrType_IPv6; 485 } else if (addressType != mDNSAddrType_None) 486 { 487 if (inet_ntop(AF_INET, &address.sin6.sin6_addr.s6_addr[12], namebuf, INET6_ADDRSTRLEN + 1) == NULL) 488 { 489 strcpy(namebuf, ":unknown:"); 490 } 491 LogMsg("mDNSPosixDoTCPListenCallback received an IPv4 connection from %s on an IPv6-only socket.", 492 namebuf); 493 close(remoteSock); 494 goto out; 495 } 496 else 497 { 498 addr.type = mDNSAddrType_IPv4; 499 } 500 nope: 501 if (addr.type == mDNSAddrType_IPv6) 502 { 503 if (inet_ntop(address.sin6.sin6_family, &address.sin6.sin6_addr, namebuf, INET6_ADDRSTRLEN + 1) == NULL) 504 { 505 strcpy(namebuf, ":unknown:"); 506 } 507 memcpy(&addr.ip.v6, &address.sin6.sin6_addr, sizeof addr.ip.v6); 508 } 509 else 510 { 511 if (inet_ntop(AF_INET, &address.sin6.sin6_addr.s6_addr[12], namebuf, INET6_ADDRSTRLEN + 1) == NULL) 512 { 513 strcpy(namebuf, ":unknown:"); 514 } 515 memcpy(&addr.ip.v4, &address.sin6.sin6_addr.s6_addr[12], sizeof addr.ip.v4); 516 } 517 port.NotAnInteger = address.sin6.sin6_port; 518 } 519 else if (address.sa.sa_family == AF_INET) 520 { 521 addr.type = mDNSAddrType_IPv4; 522 memcpy(&addr.ip.v4, &address.sin.sin_addr, sizeof addr.ip.v4); 523 port.NotAnInteger = address.sin.sin_port; 524 if (inet_ntop(AF_INET, &address.sin.sin_addr, namebuf, INET6_ADDRSTRLEN + 1) == NULL) 525 { 526 strcpy(namebuf, ":unknown:"); 527 } 528 } else { 529 LogMsg("mDNSPosixDoTCPListenCallback: connection from unknown address family %d", address.sa.sa_family); 530 close(remoteSock); 531 goto out; 532 } 533 nbp = namebuf + strlen(namebuf); 534 *nbp++ = '%'; 535 snprintf(nbp, 6, "%u", ntohs(port.NotAnInteger)); 536 537 sock = mDNSPlatformTCPAccept(socketFlags, remoteSock); 538 if (sock == NULL) 539 { 540 LogMsg("mDNSPosixDoTCPListenCallback: mDNSPlatformTCPAccept returned NULL; dropping connection from %s", 541 namebuf); 542 close(remoteSock); 543 goto out; 544 } 545 callback(sock, &addr, &port, namebuf, context); 546 out: 547 return sock; 548 } 549 550 mDNSexport mDNSBool mDNSPosixTCPListen(int *fd, mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr, 551 mDNSBool reuseAddr, int queueLength) 552 553 { 554 union 555 { 556 struct sockaddr_in6 sin6; 557 struct sockaddr_in sin; 558 struct sockaddr sa; 559 } address; 560 561 int failed; 562 int sock; 563 int one = 1; 564 socklen_t sock_len; 565 566 // We require an addrtype parameter because addr is allowed to be null, but they have to agree. 567 if (addr != mDNSNULL && addr->type != addrtype) 568 { 569 LogMsg("mDNSPlatformTCPListen: address type conflict: %d:%d", addr->type, addrtype); 570 return mDNSfalse; 571 } 572 if (port == mDNSNULL) 573 { 574 LogMsg("mDNSPlatformTCPListen: port must not be NULL"); 575 return mDNSfalse; 576 } 577 578 mDNSPlatformMemZero(&address, sizeof address); 579 if (addrtype == mDNSAddrType_None || addrtype == mDNSAddrType_IPv6) 580 { 581 // Set up DNS listener socket 582 if (addr != mDNSNULL) 583 { 584 memcpy(&address.sin6.sin6_addr.s6_addr, &addr->ip, sizeof address.sin6.sin6_addr.s6_addr); 585 } 586 address.sin6.sin6_port = port->NotAnInteger; 587 588 sock_len = sizeof address.sin6; 589 address.sin6.sin6_family = AF_INET6; 590 } 591 else if (addrtype == mDNSAddrType_IPv4) 592 { 593 if (addr != mDNSNULL) 594 { 595 memcpy(&address.sin.sin_addr.s_addr, &addr->ip, sizeof address.sin.sin_addr.s_addr); 596 } 597 address.sin.sin_port = port->NotAnInteger; 598 sock_len = sizeof address.sin; 599 address.sin.sin_family = AF_INET; 600 } 601 else 602 { 603 LogMsg("mDNSPlatformTCPListen: invalid address type: %d", addrtype); 604 return mDNSfalse; 605 } 606 #ifndef NOT_HAVE_SA_LEN 607 address.sa.sa_len = sock_len; 608 #endif 609 sock = socket(address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); 610 611 if (sock < 0) 612 { 613 LogMsg("mDNSPlatformTCPListen: socket call failed: %s", strerror(errno)); 614 return mDNSfalse; 615 } 616 *fd = sock; 617 618 // The reuseAddr flag is used to indicate that we want to listen on this port even if 619 // there are still lingering sockets. We will still fail if there is another listener. 620 // Note that this requires SO_REUSEADDR, not SO_REUSEPORT, which does not have special 621 // handling for lingering sockets. 622 if (reuseAddr) 623 { 624 failed = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one); 625 if (failed < 0) 626 { 627 LogMsg("mDNSPlatformTCPListen: SO_REUSEADDR failed %s", strerror(errno)); 628 return mDNSfalse; 629 } 630 } 631 632 // Bind to the port and (if provided) address 633 failed = bind(sock, &address.sa, sock_len); 634 if (failed < 0) 635 { 636 LogMsg("mDNSPlatformTCPListen: bind failed %s", strerror(errno)); 637 return mDNSfalse; 638 } 639 640 // If there was no specified listen port, we need to know what port we got. 641 if (port->NotAnInteger == 0) 642 { 643 mDNSPlatformMemZero(&address, sizeof address); 644 failed = getsockname(sock, &address.sa, &sock_len); 645 if (failed < 0) 646 { 647 LogMsg("mDNSRelay: getsockname failed: %s", strerror(errno)); 648 return mDNSfalse; 649 } 650 if (address.sa.sa_family == AF_INET) 651 { 652 port->NotAnInteger = address.sin.sin_port; 653 } 654 else 655 { 656 port->NotAnInteger = address.sin6.sin6_port; 657 } 658 } 659 660 failed = listen(sock, queueLength); 661 if (failed < 0) 662 { 663 LogMsg("mDNSPlatformTCPListen: listen failed: %s", strerror(errno)); 664 return mDNSfalse; 665 } 666 return mDNStrue; 667 } 668 669 mDNSexport long mDNSPosixReadTCP(int fd, void *buf, unsigned long buflen, mDNSBool *closed) 670 { 671 static int CLOSEDcount = 0; 672 static int EAGAINcount = 0; 673 ssize_t nread = recv(fd, buf, buflen, 0); 674 675 if (nread > 0) 676 { 677 CLOSEDcount = 0; 678 EAGAINcount = 0; 679 } // On success, clear our error counters 680 else if (nread == 0) 681 { 682 *closed = mDNStrue; 683 if ((++CLOSEDcount % 20) == 0) 684 { 685 LogMsg("ERROR: mDNSPosixReadFromSocket - recv %d got CLOSED %d times", fd, CLOSEDcount); 686 assert(CLOSEDcount < 1000); 687 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error 688 // msg multiple times, crash mDNSResponder using assert() and restart fresh. See advantages 689 // below: 690 // 1.Better User Experience 691 // 2.CrashLogs frequency can be monitored 692 // 3.StackTrace can be used for more info 693 } 694 } 695 // else nread is negative -- see what kind of error we got 696 else if (errno == ECONNRESET) 697 { 698 nread = 0; *closed = mDNStrue; 699 } 700 else if (errno != EAGAIN) 701 { 702 LogMsg("ERROR: mDNSPosixReadFromSocket - recv: %d (%s)", errno, strerror(errno)); 703 nread = -1; 704 } 705 else 706 { // errno is EAGAIN (EWOULDBLOCK) -- no data available 707 nread = 0; 708 if ((++EAGAINcount % 1000) == 0) 709 { 710 LogMsg("ERROR: mDNSPosixReadFromSocket - recv %d got EAGAIN %d times", fd, EAGAINcount); 711 sleep(1); 712 } 713 } 714 return nread; 715 } 716 717 mDNSexport long mDNSPosixWriteTCP(int fd, const char *msg, unsigned long len) 718 { 719 ssize_t result; 720 long nsent; 721 722 result = write(fd, msg, len); 723 if (result < 0) 724 { 725 if (errno == EAGAIN) 726 { 727 nsent = 0; 728 } 729 else 730 { 731 LogMsg("ERROR: mDNSPosixWriteTCP - send %s", strerror(errno)); nsent = -1; 732 } 733 } 734 else 735 { 736 nsent = (long)result; 737 } 738 return nsent; 739 } 740