1*472cd20dSToomas Soome /* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
24b22b933Srs  *
3*472cd20dSToomas Soome  * Copyright (c) 2004-2019 Apple Inc. All rights reserved.
44b22b933Srs  *
54b22b933Srs  * Licensed under the Apache License, Version 2.0 (the "License");
64b22b933Srs  * you may not use this file except in compliance with the License.
74b22b933Srs  * You may obtain a copy of the License at
85ffb0c9bSToomas Soome  *
94b22b933Srs  *     http://www.apache.org/licenses/LICENSE-2.0
105ffb0c9bSToomas Soome  *
114b22b933Srs  * Unless required by applicable law or agreed to in writing, software
124b22b933Srs  * distributed under the License is distributed on an "AS IS" BASIS,
134b22b933Srs  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144b22b933Srs  * See the License for the specific language governing permissions and
154b22b933Srs  * limitations under the License.
16*472cd20dSToomas Soome  *
17*472cd20dSToomas Soome  * This file defines functions that are common to platforms with Posix APIs.
18*472cd20dSToomas Soome  * Current examples are mDNSMacOSX and mDNSPosix.
194b22b933Srs  */
204b22b933Srs 
215ffb0c9bSToomas Soome #include <stdio.h>              // Needed for fopen() etc.
225ffb0c9bSToomas Soome #include <unistd.h>             // Needed for close()
23*472cd20dSToomas Soome #include <stdlib.h>             // Needed for malloc()
245ffb0c9bSToomas Soome #include <string.h>             // Needed for strlen() etc.
255ffb0c9bSToomas Soome #include <errno.h>              // Needed for errno etc.
265ffb0c9bSToomas Soome #include <sys/socket.h>         // Needed for socket() etc.
275ffb0c9bSToomas Soome #include <netinet/in.h>         // Needed for sockaddr_in
285ffb0c9bSToomas Soome #include <syslog.h>
29*472cd20dSToomas Soome #include <sys/fcntl.h>
30*472cd20dSToomas Soome #include <netinet/tcp.h>
31*472cd20dSToomas Soome #include <arpa/inet.h>
32*472cd20dSToomas Soome #include <assert.h>
334b22b933Srs 
34c65ebfc7SToomas Soome #if APPLE_OSX_mDNSResponder
35c65ebfc7SToomas Soome #include <os/log.h>
36c65ebfc7SToomas Soome #endif
37c65ebfc7SToomas Soome 
385ffb0c9bSToomas Soome #include "mDNSEmbeddedAPI.h"    // Defines the interface provided to the client layer above
395ffb0c9bSToomas Soome #include "DNSCommon.h"
404b22b933Srs #include "PlatformCommon.h"
414b22b933Srs 
424b22b933Srs #ifdef NOT_HAVE_SOCKLEN_T
435ffb0c9bSToomas Soome typedef unsigned int socklen_t;
444b22b933Srs #endif
454b22b933Srs 
46*472cd20dSToomas Soome #if MDNS_MALLOC_DEBUGGING
47*472cd20dSToomas Soome // We ONLY want this for malloc debugging--on a running production system we want to deal with
48*472cd20dSToomas Soome // malloc failures, not just die.   There is a small performance penalty for enabling these options
49*472cd20dSToomas Soome // as well, so they are all only appropriate for debugging.   The flags mean:
50*472cd20dSToomas Soome //
51*472cd20dSToomas Soome // A = warnings are errors
52*472cd20dSToomas Soome // X = abort on failure
53*472cd20dSToomas Soome // Z = sets J & R
54*472cd20dSToomas Soome // J = allocated memory is initialized to a pattern
55*472cd20dSToomas Soome // R causes realloc to always reallocate even if not needed
56*472cd20dSToomas Soome 
57*472cd20dSToomas Soome char _malloc_options[] = "AXZ";
58*472cd20dSToomas Soome 
59*472cd20dSToomas Soome mDNSlocal mDNSListValidator *listValidators;
60*472cd20dSToomas Soome 
mDNSPlatformAddListValidator(mDNSListValidator * lv,mDNSListValidationFunction * lvf,const char * lvfName,void * context)61*472cd20dSToomas Soome mDNSexport void mDNSPlatformAddListValidator(mDNSListValidator *lv, mDNSListValidationFunction *lvf,
62*472cd20dSToomas Soome                                              const char *lvfName, void *context)
63*472cd20dSToomas Soome {
64*472cd20dSToomas Soome     mDNSPlatformMemZero(lv, sizeof *lv);
65*472cd20dSToomas Soome     lv->validator = lvf;
66*472cd20dSToomas Soome     lv->validationFunctionName = lvfName;
67*472cd20dSToomas Soome     lv->context = context;
68*472cd20dSToomas Soome     lv->next = listValidators;
69*472cd20dSToomas Soome     listValidators = lv;
70*472cd20dSToomas Soome }
71*472cd20dSToomas Soome 
validateLists(void)72*472cd20dSToomas Soome mDNSlocal void validateLists(void)
73*472cd20dSToomas Soome {
74*472cd20dSToomas Soome     mDNSListValidator *vfp;
75*472cd20dSToomas Soome     // Check Unix Domain Socket client lists (uds_daemon.c)
76*472cd20dSToomas Soome     for (vfp = listValidators; vfp; vfp = vfp->next)
77*472cd20dSToomas Soome     {
78*472cd20dSToomas Soome         vfp->validator(vfp->context);
79*472cd20dSToomas Soome     }
80*472cd20dSToomas Soome 
81*472cd20dSToomas Soome     mDNSPlatformValidateLists();
82*472cd20dSToomas Soome }
83*472cd20dSToomas Soome 
84*472cd20dSToomas Soome #define kAllocMagic     0xDEAD1234
85*472cd20dSToomas Soome #define kGuardMagic     0xDEAD1234
86*472cd20dSToomas Soome #define kFreeMagic      0xDEADDEAD
87*472cd20dSToomas Soome #define kAllocLargeSize 32768
88*472cd20dSToomas Soome 
mallocL(const char * msg,mDNSu32 size)89*472cd20dSToomas Soome mDNSexport void *mallocL(const char *msg, mDNSu32 size)
90*472cd20dSToomas Soome {
91*472cd20dSToomas Soome     // Allocate space for two words of sanity checking data before the requested block and two words after.
92*472cd20dSToomas Soome     // Adjust the length for alignment.
93*472cd20dSToomas Soome     mDNSu32 *mem = malloc(sizeof(mDNSu32) * 4 + size);
94*472cd20dSToomas Soome     mDNSu32 guard[2];
95*472cd20dSToomas Soome     if (!mem)
96*472cd20dSToomas Soome     { LogMsg("malloc( %s : %u ) failed", msg, size); return(NULL); }
97*472cd20dSToomas Soome     else
98*472cd20dSToomas Soome     {
99*472cd20dSToomas Soome         mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)(mem + 2) + size);
100*472cd20dSToomas Soome         if      (size > kAllocLargeSize)      LogMsg("malloc( %s : %lu ) @ %p suspiciously large", msg, size, &mem[2]);
101*472cd20dSToomas Soome         else if (MDNS_MALLOC_DEBUGGING >= 2)  LogMsg("malloc( %s : %lu ) @ %p",                    msg, size, &mem[2]);
102*472cd20dSToomas Soome         mem[  0] = kAllocMagic;
103*472cd20dSToomas Soome         guard[0] = kGuardMagic;
104*472cd20dSToomas Soome         mem[  1] = size;
105*472cd20dSToomas Soome         guard[1] = size;
106*472cd20dSToomas Soome         memcpy(after, &guard, sizeof guard);
107*472cd20dSToomas Soome         memset(&mem[2], 0xFF, size);
108*472cd20dSToomas Soome         validateLists();
109*472cd20dSToomas Soome         return(&mem[2]);
110*472cd20dSToomas Soome     }
111*472cd20dSToomas Soome }
112*472cd20dSToomas Soome 
callocL(const char * msg,mDNSu32 size)113*472cd20dSToomas Soome mDNSexport void *callocL(const char *msg, mDNSu32 size)
114*472cd20dSToomas Soome {
115*472cd20dSToomas Soome     mDNSu32 guard[2];
116*472cd20dSToomas Soome     const mDNSu32 headerSize = 4 * sizeof(mDNSu32);
117*472cd20dSToomas Soome 
118*472cd20dSToomas Soome     // Allocate space for two words of sanity checking data before the requested block and two words after.
119*472cd20dSToomas Soome     // Adjust the length for alignment.
120*472cd20dSToomas Soome     mDNSu32 *mem = (mDNSu32 *)calloc(1, headerSize + size);
121*472cd20dSToomas Soome     if (!mem)
122*472cd20dSToomas Soome     { LogMsg("calloc( %s : %u ) failed", msg, size); return(NULL); }
123*472cd20dSToomas Soome     else
124*472cd20dSToomas Soome     {
125*472cd20dSToomas Soome         mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)(mem + 2) + size);
126*472cd20dSToomas Soome         if      (size > kAllocLargeSize)     LogMsg("calloc( %s : %lu ) @ %p suspiciously large", msg, size, &mem[2]);
127*472cd20dSToomas Soome         else if (MDNS_MALLOC_DEBUGGING >= 2) LogMsg("calloc( %s : %lu ) @ %p",                    msg, size, &mem[2]);
128*472cd20dSToomas Soome         mem[  0] = kAllocMagic;
129*472cd20dSToomas Soome         guard[0] = kGuardMagic;
130*472cd20dSToomas Soome         mem[  1] = size;
131*472cd20dSToomas Soome         guard[1] = size;
132*472cd20dSToomas Soome         memcpy(after, guard, sizeof guard);
133*472cd20dSToomas Soome         validateLists();
134*472cd20dSToomas Soome         return(&mem[2]);
135*472cd20dSToomas Soome     }
136*472cd20dSToomas Soome }
137*472cd20dSToomas Soome 
freeL(const char * msg,void * x)138*472cd20dSToomas Soome mDNSexport void freeL(const char *msg, void *x)
139*472cd20dSToomas Soome {
140*472cd20dSToomas Soome     if (!x)
141*472cd20dSToomas Soome         LogMsg("free( %s @ NULL )!", msg);
142*472cd20dSToomas Soome     else
143*472cd20dSToomas Soome     {
144*472cd20dSToomas Soome         mDNSu32 *mem = ((mDNSu32 *)x) - 2;
145*472cd20dSToomas Soome         if      (mem[0] == kFreeMagic)  { LogMemCorruption("free( %s : %lu @ %p ) !!!! ALREADY DISPOSED !!!!", msg, mem[1], &mem[2]); return; }
146*472cd20dSToomas Soome         if      (mem[0] != kAllocMagic) { LogMemCorruption("free( %s : %lu @ %p ) !!!! NEVER ALLOCATED !!!!",  msg, mem[1], &mem[2]); return; }
147*472cd20dSToomas Soome         if      (mem[1] > kAllocLargeSize)          LogMsg("free( %s : %lu @ %p) suspiciously large",          msg, mem[1], &mem[2]);
148*472cd20dSToomas Soome         else if (MDNS_MALLOC_DEBUGGING >= 2)        LogMsg("free( %s : %ld @ %p)",                             msg, mem[1], &mem[2]);
149*472cd20dSToomas Soome         mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)x + mem[1]);
150*472cd20dSToomas Soome         mDNSu32 guard[2];
151*472cd20dSToomas Soome 
152*472cd20dSToomas Soome         memcpy(guard, after, sizeof guard);
153*472cd20dSToomas Soome         if (guard[0] != kGuardMagic)    { LogMemCorruption("free( %s : %lu @ %p ) !!!! END GUARD OVERWRITE !!!!",
154*472cd20dSToomas Soome                                                            msg, mem[1], &mem[2]); return; }
155*472cd20dSToomas Soome         if (guard[1] != mem[1])         { LogMemCorruption("free( %s : %lu @ %p ) !!!! LENGTH MISMATCH !!!!",
156*472cd20dSToomas Soome                                                            msg, mem[1], &mem[2]); return; }
157*472cd20dSToomas Soome         mem[0] = kFreeMagic;
158*472cd20dSToomas Soome         memset(mem + 2, 0xFF, mem[1] + 2 * sizeof(mDNSu32));
159*472cd20dSToomas Soome         validateLists();
160*472cd20dSToomas Soome         free(mem);
161*472cd20dSToomas Soome     }
162*472cd20dSToomas Soome }
163*472cd20dSToomas Soome 
164*472cd20dSToomas Soome #endif
165*472cd20dSToomas Soome 
1665ffb0c9bSToomas Soome // Bind a UDP socket to find the source address to a destination
mDNSPlatformSourceAddrForDest(mDNSAddr * const src,const mDNSAddr * const dst)1675ffb0c9bSToomas Soome mDNSexport void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
1685ffb0c9bSToomas Soome {
1695ffb0c9bSToomas Soome     union { struct sockaddr s; struct sockaddr_in a4; struct sockaddr_in6 a6; } addr;
1705ffb0c9bSToomas Soome     socklen_t len = sizeof(addr);
1715ffb0c9bSToomas Soome     socklen_t inner_len = 0;
1725ffb0c9bSToomas Soome     int sock = socket(AF_INET, SOCK_DGRAM, 0);
1735ffb0c9bSToomas Soome     src->type = mDNSAddrType_None;
1745ffb0c9bSToomas Soome     if (sock == -1) return;
1755ffb0c9bSToomas Soome     if (dst->type == mDNSAddrType_IPv4)
1765ffb0c9bSToomas Soome     {
1775ffb0c9bSToomas Soome         inner_len = sizeof(addr.a4);
1785ffb0c9bSToomas Soome         #ifndef NOT_HAVE_SA_LEN
1795ffb0c9bSToomas Soome         addr.a4.sin_len         = inner_len;
1805ffb0c9bSToomas Soome         #endif
1815ffb0c9bSToomas Soome         addr.a4.sin_family      = AF_INET;
1825ffb0c9bSToomas Soome         addr.a4.sin_port        = 1;    // Not important, any port will do
1835ffb0c9bSToomas Soome         addr.a4.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1845ffb0c9bSToomas Soome     }
1855ffb0c9bSToomas Soome     else if (dst->type == mDNSAddrType_IPv6)
1865ffb0c9bSToomas Soome     {
1875ffb0c9bSToomas Soome         inner_len = sizeof(addr.a6);
1885ffb0c9bSToomas Soome         #ifndef NOT_HAVE_SA_LEN
1895ffb0c9bSToomas Soome         addr.a6.sin6_len      = inner_len;
1905ffb0c9bSToomas Soome         #endif
1915ffb0c9bSToomas Soome         addr.a6.sin6_family   = AF_INET6;
1925ffb0c9bSToomas Soome         addr.a6.sin6_flowinfo = 0;
1935ffb0c9bSToomas Soome         addr.a6.sin6_port     = 1;  // Not important, any port will do
1945ffb0c9bSToomas Soome         addr.a6.sin6_addr     = *(struct in6_addr*)&dst->ip.v6;
1955ffb0c9bSToomas Soome         addr.a6.sin6_scope_id = 0;
1965ffb0c9bSToomas Soome     }
1975ffb0c9bSToomas Soome     else return;
1985ffb0c9bSToomas Soome 
199cda73f64SToomas Soome     if ((connect(sock, &addr.s, inner_len)) < 0) {
2003b436d06SToomas Soome 	if (errno != ENETUNREACH)
2013b436d06SToomas Soome 		LogMsg("mDNSPlatformSourceAddrForDest: connect %#a failed errno %d (%s)", dst, errno,
2023b436d06SToomas Soome 		    strerror(errno));
203cda73f64SToomas Soome 	goto exit;
204cda73f64SToomas Soome     }
2055ffb0c9bSToomas Soome 
2065ffb0c9bSToomas Soome     if ((getsockname(sock, &addr.s, &len)) < 0)
2075ffb0c9bSToomas Soome     { LogMsg("mDNSPlatformSourceAddrForDest: getsockname failed errno %d (%s)", errno, strerror(errno)); goto exit; }
2085ffb0c9bSToomas Soome 
2095ffb0c9bSToomas Soome     src->type = dst->type;
2105ffb0c9bSToomas Soome     if (dst->type == mDNSAddrType_IPv4) src->ip.v4.NotAnInteger = addr.a4.sin_addr.s_addr;
2115ffb0c9bSToomas Soome     else src->ip.v6 = *(mDNSv6Addr*)&addr.a6.sin6_addr;
2125ffb0c9bSToomas Soome exit:
2135ffb0c9bSToomas Soome     close(sock);
2145ffb0c9bSToomas Soome }
2154b22b933Srs 
2164b22b933Srs // 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)2174b22b933Srs mDNSlocal mDNSBool GetConfigOption(char *dst, const char *option, FILE *f)
2185ffb0c9bSToomas Soome {
2195ffb0c9bSToomas Soome     char buf[32+1+MAX_ESCAPED_DOMAIN_NAME]; // Option name, one space, option value
220*472cd20dSToomas Soome     size_t len = strlen(option);
2215ffb0c9bSToomas Soome     if (len + 1 + MAX_ESCAPED_DOMAIN_NAME > sizeof(buf)-1) { LogMsg("GetConfigOption: option %s too long", option); return mDNSfalse; }
2225ffb0c9bSToomas Soome     fseek(f, 0, SEEK_SET);  // set position to beginning of stream
2235ffb0c9bSToomas Soome     while (fgets(buf, sizeof(buf), f))      // Read at most sizeof(buf)-1 bytes from file, and append '\0' C-string terminator
2245ffb0c9bSToomas Soome     {
2255ffb0c9bSToomas Soome         if (!strncmp(buf, option, len))
2265ffb0c9bSToomas Soome         {
2275ffb0c9bSToomas Soome             strncpy(dst, buf + len + 1, MAX_ESCAPED_DOMAIN_NAME-1);
2285ffb0c9bSToomas Soome             if (dst[MAX_ESCAPED_DOMAIN_NAME-1]) dst[MAX_ESCAPED_DOMAIN_NAME-1] = '\0';
2295ffb0c9bSToomas Soome             len = strlen(dst);
2305ffb0c9bSToomas Soome             if (len && dst[len-1] == '\n') dst[len-1] = '\0';  // chop newline
2315ffb0c9bSToomas Soome             return mDNStrue;
2325ffb0c9bSToomas Soome         }
2335ffb0c9bSToomas Soome     }
2345ffb0c9bSToomas Soome     debugf("Option %s not set", option);
2355ffb0c9bSToomas Soome     return mDNSfalse;
2365ffb0c9bSToomas Soome }
2374b22b933Srs 
ReadDDNSSettingsFromConfFile(mDNS * const m,const char * const filename,domainname * const hostname,domainname * const domain,mDNSBool * DomainDiscoveryDisabled)2384b22b933Srs mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled)
2395ffb0c9bSToomas Soome {
2405ffb0c9bSToomas Soome     char buf[MAX_ESCAPED_DOMAIN_NAME] = "";
2415ffb0c9bSToomas Soome     mStatus err;
2425ffb0c9bSToomas Soome     FILE *f = fopen(filename, "r");
2435ffb0c9bSToomas Soome 
2445ffb0c9bSToomas Soome     if (hostname) hostname->c[0] = 0;
2455ffb0c9bSToomas Soome     if (domain) domain->c[0] = 0;
2465ffb0c9bSToomas Soome     if (DomainDiscoveryDisabled) *DomainDiscoveryDisabled = mDNSfalse;
2475ffb0c9bSToomas Soome 
2485ffb0c9bSToomas Soome     if (f)
2495ffb0c9bSToomas Soome     {
2505ffb0c9bSToomas Soome         if (DomainDiscoveryDisabled && GetConfigOption(buf, "DomainDiscoveryDisabled", f) && !strcasecmp(buf, "true")) *DomainDiscoveryDisabled = mDNStrue;
2515ffb0c9bSToomas Soome         if (hostname && GetConfigOption(buf, "hostname", f) && !MakeDomainNameFromDNSNameString(hostname, buf)) goto badf;
2525ffb0c9bSToomas Soome         if (domain && GetConfigOption(buf, "zone", f) && !MakeDomainNameFromDNSNameString(domain, buf)) goto badf;
2535ffb0c9bSToomas Soome         buf[0] = 0;
2545ffb0c9bSToomas Soome         GetConfigOption(buf, "secret-64", f);  // failure means no authentication
2555ffb0c9bSToomas Soome         fclose(f);
2565ffb0c9bSToomas Soome         f = NULL;
2575ffb0c9bSToomas Soome     }
2585ffb0c9bSToomas Soome     else
2595ffb0c9bSToomas Soome     {
2605ffb0c9bSToomas Soome         if (errno != ENOENT) LogMsg("ERROR: Config file exists, but cannot be opened.");
2615ffb0c9bSToomas Soome         return;
2625ffb0c9bSToomas Soome     }
2635ffb0c9bSToomas Soome 
2645ffb0c9bSToomas Soome     if (domain && domain->c[0] && buf[0])
2655ffb0c9bSToomas Soome     {
266*472cd20dSToomas Soome         DomainAuthInfo *info = (DomainAuthInfo*) mDNSPlatformMemAllocateClear(sizeof(*info));
2675ffb0c9bSToomas Soome         // for now we assume keyname = service reg domain and we use same key for service and hostname registration
268*472cd20dSToomas Soome         err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0);
2695ffb0c9bSToomas Soome         if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c);
2705ffb0c9bSToomas Soome     }
2715ffb0c9bSToomas Soome 
2725ffb0c9bSToomas Soome     return;
2735ffb0c9bSToomas Soome 
2745ffb0c9bSToomas Soome badf:
2755ffb0c9bSToomas Soome     LogMsg("ERROR: malformatted config file");
2765ffb0c9bSToomas Soome     if (f) fclose(f);
2775ffb0c9bSToomas Soome }
2785ffb0c9bSToomas Soome 
2795ffb0c9bSToomas Soome #if MDNS_DEBUGMSGS
mDNSPlatformWriteDebugMsg(const char * msg)2805ffb0c9bSToomas Soome mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
2815ffb0c9bSToomas Soome {
2825ffb0c9bSToomas Soome     fprintf(stderr,"%s\n", msg);
2835ffb0c9bSToomas Soome     fflush(stderr);
2845ffb0c9bSToomas Soome }
2855ffb0c9bSToomas Soome #endif
2865ffb0c9bSToomas Soome 
287*472cd20dSToomas Soome #if !MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
mDNSPlatformWriteLogMsg(const char * ident,const char * buffer,mDNSLogLevel_t loglevel)2885ffb0c9bSToomas Soome mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, mDNSLogLevel_t loglevel)
2895ffb0c9bSToomas Soome {
2905ffb0c9bSToomas Soome #if APPLE_OSX_mDNSResponder && LogTimeStamps
2915ffb0c9bSToomas Soome     extern mDNS mDNSStorage;
2925ffb0c9bSToomas Soome     extern mDNSu32 mDNSPlatformClockDivisor;
2935ffb0c9bSToomas Soome     mDNSs32 t = mDNSStorage.timenow ? mDNSStorage.timenow : mDNSPlatformClockDivisor ? mDNS_TimeNow_NoLock(&mDNSStorage) : 0;
2945ffb0c9bSToomas Soome     int ms = ((t < 0) ? -t : t) % 1000;
2955ffb0c9bSToomas Soome #endif
2965ffb0c9bSToomas Soome 
2975ffb0c9bSToomas Soome     if (mDNS_DebugMode) // In debug mode we write to stderr
2985ffb0c9bSToomas Soome     {
2995ffb0c9bSToomas Soome #if APPLE_OSX_mDNSResponder && LogTimeStamps
3005ffb0c9bSToomas Soome         if (ident && ident[0] && mDNSPlatformClockDivisor)
3015ffb0c9bSToomas Soome             fprintf(stderr,"%8d.%03d: %s\n", (int)(t/1000), ms, buffer);
3025ffb0c9bSToomas Soome         else
3035ffb0c9bSToomas Soome #endif
3045ffb0c9bSToomas Soome         fprintf(stderr,"%s\n", buffer);
3055ffb0c9bSToomas Soome         fflush(stderr);
3065ffb0c9bSToomas Soome     }
3075ffb0c9bSToomas Soome     else                // else, in production mode, we write to syslog
3085ffb0c9bSToomas Soome     {
3095ffb0c9bSToomas Soome         static int log_inited = 0;
3105ffb0c9bSToomas Soome 
311*472cd20dSToomas Soome         int syslog_level;
3125ffb0c9bSToomas Soome         switch (loglevel)
3135ffb0c9bSToomas Soome         {
314*472cd20dSToomas Soome             case MDNS_LOG_FAULT:     syslog_level = LOG_ERR;     break;
315*472cd20dSToomas Soome             case MDNS_LOG_ERROR:     syslog_level = LOG_ERR;     break;
316*472cd20dSToomas Soome             case MDNS_LOG_WARNING:   syslog_level = LOG_WARNING; break;
317*472cd20dSToomas Soome             case MDNS_LOG_DEFAULT:   syslog_level = LOG_NOTICE;  break;
318*472cd20dSToomas Soome             case MDNS_LOG_INFO:      syslog_level = LOG_INFO;    break;
319*472cd20dSToomas Soome             case MDNS_LOG_DEBUG:     syslog_level = LOG_DEBUG;   break;
320*472cd20dSToomas Soome             default:                 syslog_level = LOG_NOTICE;  break;
3215ffb0c9bSToomas Soome         }
3225ffb0c9bSToomas Soome 
3235ffb0c9bSToomas Soome         if (!log_inited) { openlog(ident, LOG_CONS, LOG_DAEMON); log_inited++; }
3245ffb0c9bSToomas Soome 
3255ffb0c9bSToomas Soome #if APPLE_OSX_mDNSResponder && LogTimeStamps
3265ffb0c9bSToomas Soome         if (ident && ident[0] && mDNSPlatformClockDivisor)
3275ffb0c9bSToomas Soome             syslog(syslog_level, "%8d.%03d: %s", (int)(t/1000), ms, buffer);
3285ffb0c9bSToomas Soome         else
329cda73f64SToomas Soome #endif
330cda73f64SToomas Soome         {
331cda73f64SToomas Soome             syslog(syslog_level, "%s", buffer);
332*472cd20dSToomas Soome         }
333*472cd20dSToomas Soome     }
334*472cd20dSToomas Soome }
335*472cd20dSToomas Soome #endif // !MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
336*472cd20dSToomas Soome 
mDNSPosixTCPSocketSetup(int * fd,mDNSAddr_Type addrType,mDNSIPPort * port,mDNSIPPort * outTcpPort)337*472cd20dSToomas Soome mDNSexport mDNSBool mDNSPosixTCPSocketSetup(int *fd, mDNSAddr_Type addrType, mDNSIPPort *port, mDNSIPPort *outTcpPort)
338*472cd20dSToomas Soome {
339*472cd20dSToomas Soome     int sa_family = (addrType == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
340*472cd20dSToomas Soome     int err;
341*472cd20dSToomas Soome     int sock;
342*472cd20dSToomas Soome     mDNSu32 lowWater = 15384;
343*472cd20dSToomas Soome 
344*472cd20dSToomas Soome     sock = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
345*472cd20dSToomas Soome     if (sock < 3)
346*472cd20dSToomas Soome     {
347*472cd20dSToomas Soome         if (errno != EAFNOSUPPORT)
348*472cd20dSToomas Soome         {
349*472cd20dSToomas Soome             LogMsg("mDNSPosixTCPSocketSetup: socket error %d errno %d (%s)", sock, errno, strerror(errno));
350*472cd20dSToomas Soome         }
351*472cd20dSToomas Soome         return mDNStrue;
352*472cd20dSToomas Soome     }
353*472cd20dSToomas Soome     *fd = sock;
354*472cd20dSToomas Soome 
355*472cd20dSToomas Soome     union
356*472cd20dSToomas Soome     {
357*472cd20dSToomas Soome         struct sockaddr sa;
358*472cd20dSToomas Soome         struct sockaddr_in sin;
359*472cd20dSToomas Soome         struct sockaddr_in6 sin6;
360*472cd20dSToomas Soome     } addr;
361*472cd20dSToomas Soome     // If port is not NULL, bind to it.
362*472cd20dSToomas Soome     if (port != NULL)
363*472cd20dSToomas Soome     {
364*472cd20dSToomas Soome         socklen_t len = (sa_family == AF_INET) ? sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6);
365*472cd20dSToomas Soome         mDNSPlatformMemZero(&addr, sizeof addr);
366*472cd20dSToomas Soome 
367*472cd20dSToomas Soome         addr.sa.sa_family = sa_family;
368*472cd20dSToomas Soome #ifndef NOT_HAVE_SA_LEN
369*472cd20dSToomas Soome 	addr.sa.sa_len = len;
3705ffb0c9bSToomas Soome #endif
371*472cd20dSToomas Soome         if (sa_family == AF_INET6)
372*472cd20dSToomas Soome         {
373*472cd20dSToomas Soome             addr.sin6.sin6_port = port->NotAnInteger;
374cda73f64SToomas Soome         }
375*472cd20dSToomas Soome         else
376*472cd20dSToomas Soome         {
377*472cd20dSToomas Soome             addr.sin.sin_port = port->NotAnInteger;
378*472cd20dSToomas Soome         }
379*472cd20dSToomas Soome         err = bind(sock, &addr.sa, len);
380*472cd20dSToomas Soome         if (err < 0)
381*472cd20dSToomas Soome         {
382*472cd20dSToomas Soome             LogMsg("mDNSPosixTCPSocketSetup getsockname: %s", strerror(errno));
383*472cd20dSToomas Soome             return mDNSfalse;
384*472cd20dSToomas Soome         }
385*472cd20dSToomas Soome     }
386*472cd20dSToomas Soome 
387*472cd20dSToomas Soome     socklen_t addrlen = sizeof addr;
388*472cd20dSToomas Soome     err = getsockname(sock, (struct sockaddr *)&addr, &addrlen);
389*472cd20dSToomas Soome     if (err < 0)
390*472cd20dSToomas Soome     {
391*472cd20dSToomas Soome         LogMsg("mDNSPosixTCPSocketSetup getsockname: %s", strerror(errno));
392*472cd20dSToomas Soome         return mDNSfalse;
393*472cd20dSToomas Soome     }
394*472cd20dSToomas Soome     if (sa_family == AF_INET6)
395*472cd20dSToomas Soome     {
396*472cd20dSToomas Soome         outTcpPort->NotAnInteger = addr.sin6.sin6_port;
397*472cd20dSToomas Soome 
398*472cd20dSToomas Soome     } else
399*472cd20dSToomas Soome     {
400*472cd20dSToomas Soome         outTcpPort->NotAnInteger = addr.sin.sin_port;
401*472cd20dSToomas Soome     }
402*472cd20dSToomas Soome     if (port)
403*472cd20dSToomas Soome         port->NotAnInteger = outTcpPort->NotAnInteger;
404*472cd20dSToomas Soome 
405*472cd20dSToomas Soome #ifdef TCP_NOTSENT_LOWAT
406*472cd20dSToomas Soome     err = setsockopt(sock, IPPROTO_TCP, TCP_NOTSENT_LOWAT, &lowWater, sizeof lowWater);
407*472cd20dSToomas Soome     if (err < 0)
408*472cd20dSToomas Soome     {
409*472cd20dSToomas Soome         LogMsg("mDNSPosixTCPSocketSetup: TCP_NOTSENT_LOWAT failed: %s", strerror(errno));
410*472cd20dSToomas Soome         return mDNSfalse;
411*472cd20dSToomas Soome     }
412*472cd20dSToomas Soome #endif
413*472cd20dSToomas Soome 
414*472cd20dSToomas Soome     return mDNStrue;
415*472cd20dSToomas Soome }
416*472cd20dSToomas Soome 
mDNSPosixDoTCPListenCallback(int fd,mDNSAddr_Type addressType,TCPSocketFlags socketFlags,TCPAcceptedCallback callback,void * context)417*472cd20dSToomas Soome mDNSexport TCPSocket *mDNSPosixDoTCPListenCallback(int fd, mDNSAddr_Type addressType, TCPSocketFlags socketFlags,
418*472cd20dSToomas Soome                                              TCPAcceptedCallback callback, void *context)
419*472cd20dSToomas Soome {
420*472cd20dSToomas Soome     union
421*472cd20dSToomas Soome     {
422*472cd20dSToomas Soome         struct sockaddr_in6 sin6;
423*472cd20dSToomas Soome         struct sockaddr_in sin;
424*472cd20dSToomas Soome         struct sockaddr sa;
425*472cd20dSToomas Soome     } address;
426*472cd20dSToomas Soome 
427*472cd20dSToomas Soome     socklen_t slen = sizeof address;
428*472cd20dSToomas Soome     int remoteSock;
429*472cd20dSToomas Soome     mDNSAddr addr;
430*472cd20dSToomas Soome     mDNSIPPort port;
431*472cd20dSToomas Soome     TCPSocket *sock = mDNSNULL;
432*472cd20dSToomas Soome     int failed;
433*472cd20dSToomas Soome     char *nbp;
434*472cd20dSToomas Soome     int i;
435*472cd20dSToomas Soome     mDNSu32 lowWater = 16384;
436*472cd20dSToomas Soome     // When we remember our connection, we remember a name that we can print for logging.   But
437*472cd20dSToomas Soome     // since we are the listener in this case, we don't /have/ a name for it.   This buffer
438*472cd20dSToomas Soome     // is used to print the IP address into a human readable string which will serve that purpose
439*472cd20dSToomas Soome     // for this case.
440*472cd20dSToomas Soome     char namebuf[INET6_ADDRSTRLEN + 1 + 5 + 1];
441*472cd20dSToomas Soome 
442*472cd20dSToomas Soome     remoteSock = accept(fd, &address.sa, &slen);
443*472cd20dSToomas Soome     if (remoteSock < 0)
444*472cd20dSToomas Soome     {
445*472cd20dSToomas Soome         LogMsg("mDNSPosixDoTCPListenCallback: accept returned %d", remoteSock);
446*472cd20dSToomas Soome         goto out;
447*472cd20dSToomas Soome     }
448*472cd20dSToomas Soome 
449*472cd20dSToomas Soome     failed = fcntl(remoteSock, F_SETFL, O_NONBLOCK);
450*472cd20dSToomas Soome     if (failed < 0)
451*472cd20dSToomas Soome     {
452*472cd20dSToomas Soome         close(remoteSock);
453*472cd20dSToomas Soome         LogMsg("mDNSPosixDoTCPListenCallback: fcntl returned %d", errno);
454*472cd20dSToomas Soome         goto out;
455*472cd20dSToomas Soome     }
456*472cd20dSToomas Soome 
457*472cd20dSToomas Soome #ifdef TCP_NOTSENT_LOWAT
458*472cd20dSToomas Soome     failed = setsockopt(remoteSock, IPPROTO_TCP, TCP_NOTSENT_LOWAT,
459*472cd20dSToomas Soome                         &lowWater, sizeof lowWater);
460*472cd20dSToomas Soome     if (failed < 0)
461*472cd20dSToomas Soome     {
462*472cd20dSToomas Soome         close(remoteSock);
463*472cd20dSToomas Soome         LogMsg("mDNSPosixDoTCPListenCallback: TCP_NOTSENT_LOWAT returned %d", errno);
464*472cd20dSToomas Soome         goto out;
465*472cd20dSToomas Soome     }
466*472cd20dSToomas Soome #endif
467*472cd20dSToomas Soome 
468*472cd20dSToomas Soome     if (address.sa.sa_family == AF_INET6)
469*472cd20dSToomas Soome     {
470*472cd20dSToomas Soome         // If we are listening on an IPv4/IPv6 socket, the incoming address might be an IPv4-in-IPv6 address
471*472cd20dSToomas Soome         for (i = 0; i < 10; i++)
472*472cd20dSToomas Soome         {
473*472cd20dSToomas Soome             if (address.sin6.sin6_addr.s6_addr[i] != 0)
474*472cd20dSToomas Soome             {
475*472cd20dSToomas Soome                 addr.type = mDNSAddrType_IPv6;
476*472cd20dSToomas Soome                 goto nope;
477*472cd20dSToomas Soome             }
478*472cd20dSToomas Soome         }
479*472cd20dSToomas Soome 
480*472cd20dSToomas Soome         // a legit IPv4 address would be ::ffff:a.b.c.d; if there's no ::ffff bit, then it's an IPv6
481*472cd20dSToomas Soome         // address with a really weird prefix.
482*472cd20dSToomas Soome         if (address.sin6.sin6_addr.s6_addr[10] != 0xFF || address.sin6.sin6_addr.s6_addr[11] != 0xFF)
483*472cd20dSToomas Soome         {
484*472cd20dSToomas Soome             addr.type = mDNSAddrType_IPv6;
485*472cd20dSToomas Soome         } else if (addressType != mDNSAddrType_None)
486*472cd20dSToomas Soome         {
487*472cd20dSToomas Soome             if (inet_ntop(AF_INET, &address.sin6.sin6_addr.s6_addr[12], namebuf, INET6_ADDRSTRLEN + 1) == NULL)
488*472cd20dSToomas Soome             {
489*472cd20dSToomas Soome                 strcpy(namebuf, ":unknown:");
490*472cd20dSToomas Soome             }
491*472cd20dSToomas Soome             LogMsg("mDNSPosixDoTCPListenCallback received an IPv4 connection from %s on an IPv6-only socket.",
492*472cd20dSToomas Soome                    namebuf);
493*472cd20dSToomas Soome             close(remoteSock);
494*472cd20dSToomas Soome             goto out;
495*472cd20dSToomas Soome         }
496*472cd20dSToomas Soome         else
497*472cd20dSToomas Soome         {
498*472cd20dSToomas Soome             addr.type = mDNSAddrType_IPv4;
499*472cd20dSToomas Soome         }
500*472cd20dSToomas Soome     nope:
501*472cd20dSToomas Soome         if (addr.type == mDNSAddrType_IPv6)
502*472cd20dSToomas Soome         {
503*472cd20dSToomas Soome             if (inet_ntop(address.sin6.sin6_family, &address.sin6.sin6_addr, namebuf, INET6_ADDRSTRLEN + 1) == NULL)
504*472cd20dSToomas Soome             {
505*472cd20dSToomas Soome                 strcpy(namebuf, ":unknown:");
506*472cd20dSToomas Soome             }
507*472cd20dSToomas Soome             memcpy(&addr.ip.v6, &address.sin6.sin6_addr, sizeof addr.ip.v6);
508*472cd20dSToomas Soome         }
509*472cd20dSToomas Soome         else
510*472cd20dSToomas Soome         {
511*472cd20dSToomas Soome             if (inet_ntop(AF_INET, &address.sin6.sin6_addr.s6_addr[12], namebuf, INET6_ADDRSTRLEN + 1) == NULL)
512*472cd20dSToomas Soome             {
513*472cd20dSToomas Soome                 strcpy(namebuf, ":unknown:");
514*472cd20dSToomas Soome             }
515*472cd20dSToomas Soome             memcpy(&addr.ip.v4, &address.sin6.sin6_addr.s6_addr[12], sizeof addr.ip.v4);
516*472cd20dSToomas Soome         }
517*472cd20dSToomas Soome         port.NotAnInteger = address.sin6.sin6_port;
518*472cd20dSToomas Soome     }
519*472cd20dSToomas Soome     else if (address.sa.sa_family == AF_INET)
520*472cd20dSToomas Soome     {
521*472cd20dSToomas Soome         addr.type = mDNSAddrType_IPv4;
522*472cd20dSToomas Soome         memcpy(&addr.ip.v4, &address.sin.sin_addr, sizeof addr.ip.v4);
523*472cd20dSToomas Soome         port.NotAnInteger = address.sin.sin_port;
524*472cd20dSToomas Soome         if (inet_ntop(AF_INET, &address.sin.sin_addr, namebuf, INET6_ADDRSTRLEN + 1) == NULL)
525*472cd20dSToomas Soome         {
526*472cd20dSToomas Soome             strcpy(namebuf, ":unknown:");
527*472cd20dSToomas Soome         }
528*472cd20dSToomas Soome     } else {
529*472cd20dSToomas Soome         LogMsg("mDNSPosixDoTCPListenCallback: connection from unknown address family %d", address.sa.sa_family);
530*472cd20dSToomas Soome         close(remoteSock);
531*472cd20dSToomas Soome         goto out;
532*472cd20dSToomas Soome     }
533*472cd20dSToomas Soome     nbp = namebuf + strlen(namebuf);
534*472cd20dSToomas Soome     *nbp++ = '%';
535*472cd20dSToomas Soome     snprintf(nbp, 6, "%u", ntohs(port.NotAnInteger));
536*472cd20dSToomas Soome 
537*472cd20dSToomas Soome     sock = mDNSPlatformTCPAccept(socketFlags, remoteSock);
538*472cd20dSToomas Soome     if (sock == NULL)
539*472cd20dSToomas Soome     {
540*472cd20dSToomas Soome         LogMsg("mDNSPosixDoTCPListenCallback: mDNSPlatformTCPAccept returned NULL; dropping connection from %s",
541*472cd20dSToomas Soome                namebuf);
542*472cd20dSToomas Soome         close(remoteSock);
543*472cd20dSToomas Soome         goto out;
544*472cd20dSToomas Soome     }
545*472cd20dSToomas Soome     callback(sock, &addr, &port, namebuf, context);
546*472cd20dSToomas Soome out:
547*472cd20dSToomas Soome     return sock;
548*472cd20dSToomas Soome }
549*472cd20dSToomas Soome 
mDNSPosixTCPListen(int * fd,mDNSAddr_Type addrtype,mDNSIPPort * port,mDNSAddr * addr,mDNSBool reuseAddr,int queueLength)550*472cd20dSToomas Soome mDNSexport mDNSBool mDNSPosixTCPListen(int *fd, mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr,
551*472cd20dSToomas Soome                                        mDNSBool reuseAddr, int queueLength)
552*472cd20dSToomas Soome 
553*472cd20dSToomas Soome {
554*472cd20dSToomas Soome     union
555*472cd20dSToomas Soome     {
556*472cd20dSToomas Soome         struct sockaddr_in6 sin6;
557*472cd20dSToomas Soome         struct sockaddr_in sin;
558*472cd20dSToomas Soome         struct sockaddr sa;
559*472cd20dSToomas Soome     } address;
560*472cd20dSToomas Soome 
561*472cd20dSToomas Soome     int failed;
562*472cd20dSToomas Soome     int sock;
563*472cd20dSToomas Soome     int one = 1;
564*472cd20dSToomas Soome     socklen_t sock_len;
565*472cd20dSToomas Soome 
566*472cd20dSToomas Soome     // We require an addrtype parameter because addr is allowed to be null, but they have to agree.
567*472cd20dSToomas Soome     if (addr != mDNSNULL && addr->type != addrtype)
568*472cd20dSToomas Soome     {
569*472cd20dSToomas Soome         LogMsg("mDNSPlatformTCPListen: address type conflict: %d:%d", addr->type, addrtype);
570*472cd20dSToomas Soome         return mDNSfalse;
571*472cd20dSToomas Soome     }
572*472cd20dSToomas Soome     if (port == mDNSNULL)
573*472cd20dSToomas Soome     {
574*472cd20dSToomas Soome         LogMsg("mDNSPlatformTCPListen: port must not be NULL");
575*472cd20dSToomas Soome         return mDNSfalse;
576*472cd20dSToomas Soome     }
577*472cd20dSToomas Soome 
578*472cd20dSToomas Soome     mDNSPlatformMemZero(&address, sizeof address);
579*472cd20dSToomas Soome     if (addrtype == mDNSAddrType_None || addrtype == mDNSAddrType_IPv6)
580*472cd20dSToomas Soome     {
581*472cd20dSToomas Soome         // Set up DNS listener socket
582*472cd20dSToomas Soome         if (addr != mDNSNULL)
583*472cd20dSToomas Soome         {
584*472cd20dSToomas Soome             memcpy(&address.sin6.sin6_addr.s6_addr, &addr->ip, sizeof address.sin6.sin6_addr.s6_addr);
585*472cd20dSToomas Soome         }
586*472cd20dSToomas Soome         address.sin6.sin6_port = port->NotAnInteger;
587*472cd20dSToomas Soome 
588*472cd20dSToomas Soome         sock_len = sizeof address.sin6;
589*472cd20dSToomas Soome         address.sin6.sin6_family = AF_INET6;
590*472cd20dSToomas Soome     }
591*472cd20dSToomas Soome     else if (addrtype == mDNSAddrType_IPv4)
592*472cd20dSToomas Soome     {
593*472cd20dSToomas Soome         if (addr != mDNSNULL)
594*472cd20dSToomas Soome         {
595*472cd20dSToomas Soome             memcpy(&address.sin.sin_addr.s_addr, &addr->ip, sizeof address.sin.sin_addr.s_addr);
596*472cd20dSToomas Soome         }
597*472cd20dSToomas Soome         address.sin.sin_port = port->NotAnInteger;
598*472cd20dSToomas Soome         sock_len = sizeof address.sin;
599*472cd20dSToomas Soome         address.sin.sin_family = AF_INET;
600*472cd20dSToomas Soome     }
601*472cd20dSToomas Soome     else
602*472cd20dSToomas Soome     {
603*472cd20dSToomas Soome         LogMsg("mDNSPlatformTCPListen: invalid address type: %d", addrtype);
604*472cd20dSToomas Soome         return mDNSfalse;
605*472cd20dSToomas Soome     }
606*472cd20dSToomas Soome #ifndef NOT_HAVE_SA_LEN
607*472cd20dSToomas Soome     address.sa.sa_len = sock_len;
608*472cd20dSToomas Soome #endif
609*472cd20dSToomas Soome     sock = socket(address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
610*472cd20dSToomas Soome 
611*472cd20dSToomas Soome     if (sock < 0)
612*472cd20dSToomas Soome     {
613*472cd20dSToomas Soome         LogMsg("mDNSPlatformTCPListen: socket call failed: %s", strerror(errno));
614*472cd20dSToomas Soome         return mDNSfalse;
615*472cd20dSToomas Soome     }
616*472cd20dSToomas Soome     *fd = sock;
617*472cd20dSToomas Soome 
618*472cd20dSToomas Soome     // The reuseAddr flag is used to indicate that we want to listen on this port even if
619*472cd20dSToomas Soome     // there are still lingering sockets.   We will still fail if there is another listener.
620*472cd20dSToomas Soome     // Note that this requires SO_REUSEADDR, not SO_REUSEPORT, which does not have special
621*472cd20dSToomas Soome     // handling for lingering sockets.
622*472cd20dSToomas Soome     if (reuseAddr)
623*472cd20dSToomas Soome     {
624*472cd20dSToomas Soome         failed = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
625*472cd20dSToomas Soome         if (failed < 0)
626*472cd20dSToomas Soome         {
627*472cd20dSToomas Soome             LogMsg("mDNSPlatformTCPListen: SO_REUSEADDR failed %s", strerror(errno));
628*472cd20dSToomas Soome             return mDNSfalse;
629*472cd20dSToomas Soome         }
630*472cd20dSToomas Soome     }
631*472cd20dSToomas Soome 
632*472cd20dSToomas Soome     // Bind to the port and (if provided) address
633*472cd20dSToomas Soome     failed = bind(sock, &address.sa, sock_len);
634*472cd20dSToomas Soome     if (failed < 0)
635*472cd20dSToomas Soome     {
636*472cd20dSToomas Soome         LogMsg("mDNSPlatformTCPListen: bind failed %s", strerror(errno));
637*472cd20dSToomas Soome         return mDNSfalse;
638*472cd20dSToomas Soome     }
639*472cd20dSToomas Soome 
640*472cd20dSToomas Soome     // If there was no specified listen port, we need to know what port we got.
641*472cd20dSToomas Soome     if (port->NotAnInteger == 0)
642*472cd20dSToomas Soome     {
643*472cd20dSToomas Soome         mDNSPlatformMemZero(&address, sizeof address);
644*472cd20dSToomas Soome         failed = getsockname(sock, &address.sa, &sock_len);
645*472cd20dSToomas Soome         if (failed < 0)
646*472cd20dSToomas Soome         {
647*472cd20dSToomas Soome             LogMsg("mDNSRelay: getsockname failed: %s", strerror(errno));
648*472cd20dSToomas Soome             return mDNSfalse;
649*472cd20dSToomas Soome         }
650*472cd20dSToomas Soome         if (address.sa.sa_family == AF_INET)
651*472cd20dSToomas Soome         {
652*472cd20dSToomas Soome             port->NotAnInteger = address.sin.sin_port;
653*472cd20dSToomas Soome         }
654*472cd20dSToomas Soome         else
655*472cd20dSToomas Soome         {
656*472cd20dSToomas Soome             port->NotAnInteger = address.sin6.sin6_port;
657*472cd20dSToomas Soome         }
658*472cd20dSToomas Soome     }
659*472cd20dSToomas Soome 
660*472cd20dSToomas Soome     failed = listen(sock, queueLength);
661*472cd20dSToomas Soome     if (failed < 0)
662*472cd20dSToomas Soome     {
663*472cd20dSToomas Soome         LogMsg("mDNSPlatformTCPListen: listen failed: %s", strerror(errno));
664*472cd20dSToomas Soome         return mDNSfalse;
665*472cd20dSToomas Soome     }
666*472cd20dSToomas Soome     return mDNStrue;
667*472cd20dSToomas Soome }
668*472cd20dSToomas Soome 
mDNSPosixReadTCP(int fd,void * buf,unsigned long buflen,mDNSBool * closed)669*472cd20dSToomas Soome mDNSexport long mDNSPosixReadTCP(int fd, void *buf, unsigned long buflen, mDNSBool *closed)
670*472cd20dSToomas Soome {
671*472cd20dSToomas Soome     static int CLOSEDcount = 0;
672*472cd20dSToomas Soome     static int EAGAINcount = 0;
673*472cd20dSToomas Soome     ssize_t nread = recv(fd, buf, buflen, 0);
674*472cd20dSToomas Soome 
675*472cd20dSToomas Soome     if (nread > 0)
676*472cd20dSToomas Soome     {
677*472cd20dSToomas Soome         CLOSEDcount = 0;
678*472cd20dSToomas Soome         EAGAINcount = 0;
679*472cd20dSToomas Soome     } // On success, clear our error counters
680*472cd20dSToomas Soome     else if (nread == 0)
681*472cd20dSToomas Soome     {
682*472cd20dSToomas Soome         *closed = mDNStrue;
683*472cd20dSToomas Soome         if ((++CLOSEDcount % 20) == 0)
684*472cd20dSToomas Soome         {
685*472cd20dSToomas Soome             LogMsg("ERROR: mDNSPosixReadFromSocket - recv %d got CLOSED %d times", fd, CLOSEDcount);
686*472cd20dSToomas Soome             assert(CLOSEDcount < 1000);
687*472cd20dSToomas Soome             // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error
688*472cd20dSToomas Soome             // msg multiple times, crash mDNSResponder using assert() and restart fresh. See advantages
689*472cd20dSToomas Soome             // below:
690*472cd20dSToomas Soome             // 1.Better User Experience
691*472cd20dSToomas Soome             // 2.CrashLogs frequency can be monitored
692*472cd20dSToomas Soome             // 3.StackTrace can be used for more info
693*472cd20dSToomas Soome         }
694*472cd20dSToomas Soome     }
695*472cd20dSToomas Soome     // else nread is negative -- see what kind of error we got
696*472cd20dSToomas Soome     else if (errno == ECONNRESET)
697*472cd20dSToomas Soome     {
698*472cd20dSToomas Soome         nread = 0; *closed = mDNStrue;
699*472cd20dSToomas Soome     }
700*472cd20dSToomas Soome     else if (errno != EAGAIN)
701*472cd20dSToomas Soome     {
702*472cd20dSToomas Soome         LogMsg("ERROR: mDNSPosixReadFromSocket - recv: %d (%s)", errno, strerror(errno));
703*472cd20dSToomas Soome         nread = -1;
704*472cd20dSToomas Soome     }
705*472cd20dSToomas Soome     else
706*472cd20dSToomas Soome     { // errno is EAGAIN (EWOULDBLOCK) -- no data available
707*472cd20dSToomas Soome         nread = 0;
708*472cd20dSToomas Soome         if ((++EAGAINcount % 1000) == 0)
709*472cd20dSToomas Soome         {
710*472cd20dSToomas Soome             LogMsg("ERROR: mDNSPosixReadFromSocket - recv %d got EAGAIN %d times", fd, EAGAINcount);
711*472cd20dSToomas Soome             sleep(1);
712*472cd20dSToomas Soome         }
713*472cd20dSToomas Soome     }
714*472cd20dSToomas Soome     return nread;
715*472cd20dSToomas Soome }
716*472cd20dSToomas Soome 
mDNSPosixWriteTCP(int fd,const char * msg,unsigned long len)717*472cd20dSToomas Soome mDNSexport long mDNSPosixWriteTCP(int fd, const char *msg, unsigned long len)
718*472cd20dSToomas Soome {
719*472cd20dSToomas Soome     ssize_t result;
720*472cd20dSToomas Soome     long nsent;
721*472cd20dSToomas Soome 
722*472cd20dSToomas Soome     result = write(fd, msg, len);
723*472cd20dSToomas Soome     if (result < 0)
724*472cd20dSToomas Soome     {
725*472cd20dSToomas Soome         if (errno == EAGAIN)
726*472cd20dSToomas Soome         {
727*472cd20dSToomas Soome             nsent = 0;
728*472cd20dSToomas Soome         }
729*472cd20dSToomas Soome         else
730*472cd20dSToomas Soome         {
731*472cd20dSToomas Soome             LogMsg("ERROR: mDNSPosixWriteTCP - send %s", strerror(errno)); nsent = -1;
732*472cd20dSToomas Soome         }
733*472cd20dSToomas Soome     }
734*472cd20dSToomas Soome     else
735*472cd20dSToomas Soome     {
736*472cd20dSToomas Soome         nsent = (long)result;
7375ffb0c9bSToomas Soome     }
738*472cd20dSToomas Soome     return nsent;
7395ffb0c9bSToomas Soome }
740