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
mDNSPlatformAddListValidator(mDNSListValidator * lv,mDNSListValidationFunction * lvf,const char * lvfName,void * context)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
validateLists(void)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
mallocL(const char * msg,mDNSu32 size)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
callocL(const char * msg,mDNSu32 size)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
freeL(const char * msg,void * x)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
mDNSPlatformSourceAddrForDest(mDNSAddr * const src,const mDNSAddr * const dst)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
GetConfigOption(char * dst,const char * option,FILE * f)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
ReadDDNSSettingsFromConfFile(mDNS * const m,const char * const filename,domainname * const hostname,domainname * const domain,mDNSBool * DomainDiscoveryDisabled)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
mDNSPlatformWriteDebugMsg(const char * msg)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)
mDNSPlatformWriteLogMsg(const char * ident,const char * buffer,mDNSLogLevel_t loglevel)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
mDNSPosixTCPSocketSetup(int * fd,mDNSAddr_Type addrType,mDNSIPPort * port,mDNSIPPort * outTcpPort)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
mDNSPosixDoTCPListenCallback(int fd,mDNSAddr_Type addressType,TCPSocketFlags socketFlags,TCPAcceptedCallback callback,void * context)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
mDNSPosixTCPListen(int * fd,mDNSAddr_Type addrtype,mDNSIPPort * port,mDNSAddr * addr,mDNSBool reuseAddr,int queueLength)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
mDNSPosixReadTCP(int fd,void * buf,unsigned long buflen,mDNSBool * closed)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
mDNSPosixWriteTCP(int fd,const char * msg,unsigned long len)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