14b22b933Srs /* -*- Mode: C; tab-width: 4 -*-
24b22b933Srs  *
3cda73f64SToomas Soome  * Copyright (c) 2004-2015 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.
164b22b933Srs  */
174b22b933Srs 
185ffb0c9bSToomas Soome #include <stdio.h>              // Needed for fopen() etc.
195ffb0c9bSToomas Soome #include <unistd.h>             // Needed for close()
205ffb0c9bSToomas Soome #include <string.h>             // Needed for strlen() etc.
215ffb0c9bSToomas Soome #include <errno.h>              // Needed for errno etc.
225ffb0c9bSToomas Soome #include <sys/socket.h>         // Needed for socket() etc.
235ffb0c9bSToomas Soome #include <netinet/in.h>         // Needed for sockaddr_in
245ffb0c9bSToomas Soome #include <syslog.h>
254b22b933Srs 
26c65ebfc7SToomas Soome #if APPLE_OSX_mDNSResponder
27c65ebfc7SToomas Soome #include <os/log.h>
28c65ebfc7SToomas Soome #endif
29c65ebfc7SToomas Soome 
305ffb0c9bSToomas Soome #include "mDNSEmbeddedAPI.h"    // Defines the interface provided to the client layer above
315ffb0c9bSToomas Soome #include "DNSCommon.h"
324b22b933Srs #include "PlatformCommon.h"
334b22b933Srs 
344b22b933Srs #ifdef NOT_HAVE_SOCKLEN_T
355ffb0c9bSToomas Soome typedef unsigned int socklen_t;
364b22b933Srs #endif
374b22b933Srs 
385ffb0c9bSToomas Soome // Bind a UDP socket to find the source address to a destination
395ffb0c9bSToomas Soome mDNSexport void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
405ffb0c9bSToomas Soome {
415ffb0c9bSToomas Soome     union { struct sockaddr s; struct sockaddr_in a4; struct sockaddr_in6 a6; } addr;
425ffb0c9bSToomas Soome     socklen_t len = sizeof(addr);
435ffb0c9bSToomas Soome     socklen_t inner_len = 0;
445ffb0c9bSToomas Soome     int sock = socket(AF_INET, SOCK_DGRAM, 0);
455ffb0c9bSToomas Soome     src->type = mDNSAddrType_None;
465ffb0c9bSToomas Soome     if (sock == -1) return;
475ffb0c9bSToomas Soome     if (dst->type == mDNSAddrType_IPv4)
485ffb0c9bSToomas Soome     {
495ffb0c9bSToomas Soome         inner_len = sizeof(addr.a4);
505ffb0c9bSToomas Soome         #ifndef NOT_HAVE_SA_LEN
515ffb0c9bSToomas Soome         addr.a4.sin_len         = inner_len;
525ffb0c9bSToomas Soome         #endif
535ffb0c9bSToomas Soome         addr.a4.sin_family      = AF_INET;
545ffb0c9bSToomas Soome         addr.a4.sin_port        = 1;    // Not important, any port will do
555ffb0c9bSToomas Soome         addr.a4.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
565ffb0c9bSToomas Soome     }
575ffb0c9bSToomas Soome     else if (dst->type == mDNSAddrType_IPv6)
585ffb0c9bSToomas Soome     {
595ffb0c9bSToomas Soome         inner_len = sizeof(addr.a6);
605ffb0c9bSToomas Soome         #ifndef NOT_HAVE_SA_LEN
615ffb0c9bSToomas Soome         addr.a6.sin6_len      = inner_len;
625ffb0c9bSToomas Soome         #endif
635ffb0c9bSToomas Soome         addr.a6.sin6_family   = AF_INET6;
645ffb0c9bSToomas Soome         addr.a6.sin6_flowinfo = 0;
655ffb0c9bSToomas Soome         addr.a6.sin6_port     = 1;  // Not important, any port will do
665ffb0c9bSToomas Soome         addr.a6.sin6_addr     = *(struct in6_addr*)&dst->ip.v6;
675ffb0c9bSToomas Soome         addr.a6.sin6_scope_id = 0;
685ffb0c9bSToomas Soome     }
695ffb0c9bSToomas Soome     else return;
705ffb0c9bSToomas Soome 
71cda73f64SToomas Soome     if ((connect(sock, &addr.s, inner_len)) < 0) {
72*3b436d06SToomas Soome 	if (errno != ENETUNREACH)
73*3b436d06SToomas Soome 		LogMsg("mDNSPlatformSourceAddrForDest: connect %#a failed errno %d (%s)", dst, errno,
74*3b436d06SToomas Soome 		    strerror(errno));
75cda73f64SToomas Soome 	goto exit;
76cda73f64SToomas Soome     }
775ffb0c9bSToomas Soome 
785ffb0c9bSToomas Soome     if ((getsockname(sock, &addr.s, &len)) < 0)
795ffb0c9bSToomas Soome     { LogMsg("mDNSPlatformSourceAddrForDest: getsockname failed errno %d (%s)", errno, strerror(errno)); goto exit; }
805ffb0c9bSToomas Soome 
815ffb0c9bSToomas Soome     src->type = dst->type;
825ffb0c9bSToomas Soome     if (dst->type == mDNSAddrType_IPv4) src->ip.v4.NotAnInteger = addr.a4.sin_addr.s_addr;
835ffb0c9bSToomas Soome     else src->ip.v6 = *(mDNSv6Addr*)&addr.a6.sin6_addr;
845ffb0c9bSToomas Soome exit:
855ffb0c9bSToomas Soome     close(sock);
865ffb0c9bSToomas Soome }
874b22b933Srs 
884b22b933Srs // dst must be at least MAX_ESCAPED_DOMAIN_NAME bytes, and option must be less than 32 bytes in length
894b22b933Srs mDNSlocal mDNSBool GetConfigOption(char *dst, const char *option, FILE *f)
905ffb0c9bSToomas Soome {
915ffb0c9bSToomas Soome     char buf[32+1+MAX_ESCAPED_DOMAIN_NAME]; // Option name, one space, option value
925ffb0c9bSToomas Soome     unsigned int len = strlen(option);
935ffb0c9bSToomas Soome     if (len + 1 + MAX_ESCAPED_DOMAIN_NAME > sizeof(buf)-1) { LogMsg("GetConfigOption: option %s too long", option); return mDNSfalse; }
945ffb0c9bSToomas Soome     fseek(f, 0, SEEK_SET);  // set position to beginning of stream
955ffb0c9bSToomas Soome     while (fgets(buf, sizeof(buf), f))      // Read at most sizeof(buf)-1 bytes from file, and append '\0' C-string terminator
965ffb0c9bSToomas Soome     {
975ffb0c9bSToomas Soome         if (!strncmp(buf, option, len))
985ffb0c9bSToomas Soome         {
995ffb0c9bSToomas Soome             strncpy(dst, buf + len + 1, MAX_ESCAPED_DOMAIN_NAME-1);
1005ffb0c9bSToomas Soome             if (dst[MAX_ESCAPED_DOMAIN_NAME-1]) dst[MAX_ESCAPED_DOMAIN_NAME-1] = '\0';
1015ffb0c9bSToomas Soome             len = strlen(dst);
1025ffb0c9bSToomas Soome             if (len && dst[len-1] == '\n') dst[len-1] = '\0';  // chop newline
1035ffb0c9bSToomas Soome             return mDNStrue;
1045ffb0c9bSToomas Soome         }
1055ffb0c9bSToomas Soome     }
1065ffb0c9bSToomas Soome     debugf("Option %s not set", option);
1075ffb0c9bSToomas Soome     return mDNSfalse;
1085ffb0c9bSToomas Soome }
1094b22b933Srs 
1104b22b933Srs mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled)
1115ffb0c9bSToomas Soome {
1125ffb0c9bSToomas Soome     char buf[MAX_ESCAPED_DOMAIN_NAME] = "";
1135ffb0c9bSToomas Soome     mStatus err;
1145ffb0c9bSToomas Soome     FILE *f = fopen(filename, "r");
1155ffb0c9bSToomas Soome 
1165ffb0c9bSToomas Soome     if (hostname) hostname->c[0] = 0;
1175ffb0c9bSToomas Soome     if (domain) domain->c[0] = 0;
1185ffb0c9bSToomas Soome     if (DomainDiscoveryDisabled) *DomainDiscoveryDisabled = mDNSfalse;
1195ffb0c9bSToomas Soome 
1205ffb0c9bSToomas Soome     if (f)
1215ffb0c9bSToomas Soome     {
1225ffb0c9bSToomas Soome         if (DomainDiscoveryDisabled && GetConfigOption(buf, "DomainDiscoveryDisabled", f) && !strcasecmp(buf, "true")) *DomainDiscoveryDisabled = mDNStrue;
1235ffb0c9bSToomas Soome         if (hostname && GetConfigOption(buf, "hostname", f) && !MakeDomainNameFromDNSNameString(hostname, buf)) goto badf;
1245ffb0c9bSToomas Soome         if (domain && GetConfigOption(buf, "zone", f) && !MakeDomainNameFromDNSNameString(domain, buf)) goto badf;
1255ffb0c9bSToomas Soome         buf[0] = 0;
1265ffb0c9bSToomas Soome         GetConfigOption(buf, "secret-64", f);  // failure means no authentication
1275ffb0c9bSToomas Soome         fclose(f);
1285ffb0c9bSToomas Soome         f = NULL;
1295ffb0c9bSToomas Soome     }
1305ffb0c9bSToomas Soome     else
1315ffb0c9bSToomas Soome     {
1325ffb0c9bSToomas Soome         if (errno != ENOENT) LogMsg("ERROR: Config file exists, but cannot be opened.");
1335ffb0c9bSToomas Soome         return;
1345ffb0c9bSToomas Soome     }
1355ffb0c9bSToomas Soome 
1365ffb0c9bSToomas Soome     if (domain && domain->c[0] && buf[0])
1375ffb0c9bSToomas Soome     {
1385ffb0c9bSToomas Soome         DomainAuthInfo *info = (DomainAuthInfo*)mDNSPlatformMemAllocate(sizeof(*info));
1395ffb0c9bSToomas Soome         // for now we assume keyname = service reg domain and we use same key for service and hostname registration
1405ffb0c9bSToomas Soome         err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0, mDNSfalse);
1415ffb0c9bSToomas Soome         if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c);
1425ffb0c9bSToomas Soome     }
1435ffb0c9bSToomas Soome 
1445ffb0c9bSToomas Soome     return;
1455ffb0c9bSToomas Soome 
1465ffb0c9bSToomas Soome badf:
1475ffb0c9bSToomas Soome     LogMsg("ERROR: malformatted config file");
1485ffb0c9bSToomas Soome     if (f) fclose(f);
1495ffb0c9bSToomas Soome }
1505ffb0c9bSToomas Soome 
1515ffb0c9bSToomas Soome #if MDNS_DEBUGMSGS
1525ffb0c9bSToomas Soome mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
1535ffb0c9bSToomas Soome {
1545ffb0c9bSToomas Soome     fprintf(stderr,"%s\n", msg);
1555ffb0c9bSToomas Soome     fflush(stderr);
1565ffb0c9bSToomas Soome }
1575ffb0c9bSToomas Soome #endif
1585ffb0c9bSToomas Soome 
1595ffb0c9bSToomas Soome mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, mDNSLogLevel_t loglevel)
1605ffb0c9bSToomas Soome {
1615ffb0c9bSToomas Soome #if APPLE_OSX_mDNSResponder && LogTimeStamps
1625ffb0c9bSToomas Soome     extern mDNS mDNSStorage;
1635ffb0c9bSToomas Soome     extern mDNSu32 mDNSPlatformClockDivisor;
1645ffb0c9bSToomas Soome     mDNSs32 t = mDNSStorage.timenow ? mDNSStorage.timenow : mDNSPlatformClockDivisor ? mDNS_TimeNow_NoLock(&mDNSStorage) : 0;
1655ffb0c9bSToomas Soome     int ms = ((t < 0) ? -t : t) % 1000;
1665ffb0c9bSToomas Soome #endif
1675ffb0c9bSToomas Soome 
1685ffb0c9bSToomas Soome     if (mDNS_DebugMode) // In debug mode we write to stderr
1695ffb0c9bSToomas Soome     {
1705ffb0c9bSToomas Soome #if APPLE_OSX_mDNSResponder && LogTimeStamps
1715ffb0c9bSToomas Soome         if (ident && ident[0] && mDNSPlatformClockDivisor)
1725ffb0c9bSToomas Soome             fprintf(stderr,"%8d.%03d: %s\n", (int)(t/1000), ms, buffer);
1735ffb0c9bSToomas Soome         else
1745ffb0c9bSToomas Soome #endif
1755ffb0c9bSToomas Soome         fprintf(stderr,"%s\n", buffer);
1765ffb0c9bSToomas Soome         fflush(stderr);
1775ffb0c9bSToomas Soome     }
1785ffb0c9bSToomas Soome     else                // else, in production mode, we write to syslog
1795ffb0c9bSToomas Soome     {
1805ffb0c9bSToomas Soome         static int log_inited = 0;
1815ffb0c9bSToomas Soome 
1825ffb0c9bSToomas Soome         int syslog_level = LOG_ERR;
1835ffb0c9bSToomas Soome         switch (loglevel)
1845ffb0c9bSToomas Soome         {
185c65ebfc7SToomas Soome #if APPLE_OSX_mDNSResponder
186c65ebfc7SToomas Soome         case MDNS_LOG_MSG:       syslog_level = OS_LOG_TYPE_DEFAULT;     break;
187c65ebfc7SToomas Soome         case MDNS_LOG_OPERATION: syslog_level = OS_LOG_TYPE_INFO;        break;
188c65ebfc7SToomas Soome         case MDNS_LOG_SPS:       syslog_level = OS_LOG_TYPE_INFO;        break;
189c65ebfc7SToomas Soome         case MDNS_LOG_INFO:      syslog_level = OS_LOG_TYPE_INFO;        break;
190c65ebfc7SToomas Soome         case MDNS_LOG_DEBUG:     syslog_level = OS_LOG_TYPE_DEBUG;       break;
191c65ebfc7SToomas Soome         default:                 syslog_level = OS_LOG_TYPE_DEFAULT;     break;
192c65ebfc7SToomas Soome #else
1935ffb0c9bSToomas Soome         case MDNS_LOG_MSG:       syslog_level = LOG_ERR;     break;
1945ffb0c9bSToomas Soome         case MDNS_LOG_OPERATION: syslog_level = LOG_WARNING; break;
1955ffb0c9bSToomas Soome         case MDNS_LOG_SPS:       syslog_level = LOG_NOTICE;  break;
1965ffb0c9bSToomas Soome         case MDNS_LOG_INFO:      syslog_level = LOG_INFO;    break;
1975ffb0c9bSToomas Soome         case MDNS_LOG_DEBUG:     syslog_level = LOG_DEBUG;   break;
1985ffb0c9bSToomas Soome         default:
1995ffb0c9bSToomas Soome             fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
2005ffb0c9bSToomas Soome             fflush(stderr);
201c65ebfc7SToomas Soome #endif
2025ffb0c9bSToomas Soome         }
2035ffb0c9bSToomas Soome 
2045ffb0c9bSToomas Soome         if (!log_inited) { openlog(ident, LOG_CONS, LOG_DAEMON); log_inited++; }
2055ffb0c9bSToomas Soome 
2065ffb0c9bSToomas Soome #if APPLE_OSX_mDNSResponder && LogTimeStamps
2075ffb0c9bSToomas Soome         if (ident && ident[0] && mDNSPlatformClockDivisor)
2085ffb0c9bSToomas Soome             syslog(syslog_level, "%8d.%03d: %s", (int)(t/1000), ms, buffer);
2095ffb0c9bSToomas Soome         else
210cda73f64SToomas Soome #endif
211cda73f64SToomas Soome         {
212cda73f64SToomas Soome #if APPLE_OSX_mDNSResponder
213cda73f64SToomas Soome             mDNSPlatformLogToFile(syslog_level, buffer);
2145ffb0c9bSToomas Soome #else
215cda73f64SToomas Soome             syslog(syslog_level, "%s", buffer);
2165ffb0c9bSToomas Soome #endif
217cda73f64SToomas Soome         }
2185ffb0c9bSToomas Soome     }
2195ffb0c9bSToomas Soome }
220