Home | History | Annotate | Download | only in mDNSShared
      1 /* -*- Mode: C; tab-width: 4 -*-
      2  *
      3  * Copyright (c) 2004 Apple Computer, 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 
     18 #include <stdio.h>				// Needed for fopen() etc.
     19 #include <unistd.h>				// Needed for close()
     20 #include <string.h>				// Needed for strlen() etc.
     21 #include <errno.h>				// Needed for errno etc.
     22 #include <sys/socket.h>			// Needed for socket() etc.
     23 #include <netinet/in.h>			// Needed for sockaddr_in
     24 #include <syslog.h>
     25 
     26 #include "mDNSEmbeddedAPI.h"	// Defines the interface provided to the client layer above
     27 #include "DNSCommon.h"
     28 #include "PlatformCommon.h"
     29 
     30 #ifdef __ANDROID__
     31 #include <android/log.h>
     32 #endif
     33 
     34 #ifdef NOT_HAVE_SOCKLEN_T
     35     typedef unsigned int socklen_t;
     36 #endif
     37 
     38 // Bind a UDP socket to find the source address to a destination
     39 mDNSexport void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
     40 	{
     41 	union { struct sockaddr s; struct sockaddr_in a4; struct sockaddr_in6 a6; } addr;
     42 	socklen_t len = sizeof(addr);
     43 	socklen_t inner_len = 0;
     44 	int sock = socket(AF_INET, SOCK_DGRAM, 0);
     45 	src->type = mDNSAddrType_None;
     46 	if (sock == -1) return;
     47 	if (dst->type == mDNSAddrType_IPv4)
     48 		{
     49 		inner_len = sizeof(addr.a4);
     50 		#ifndef NOT_HAVE_SA_LEN
     51 		addr.a4.sin_len         = inner_len;
     52 		#endif
     53 		addr.a4.sin_family      = AF_INET;
     54 		addr.a4.sin_port        = 1;	// Not important, any port will do
     55 		addr.a4.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
     56 		}
     57 	else if (dst->type == mDNSAddrType_IPv6)
     58 		{
     59 		inner_len = sizeof(addr.a6);
     60 		#ifndef NOT_HAVE_SA_LEN
     61 		addr.a6.sin6_len      = inner_len;
     62 		#endif
     63 		addr.a6.sin6_family   = AF_INET6;
     64 		addr.a6.sin6_flowinfo = 0;
     65 		addr.a6.sin6_port     = 1;	// Not important, any port will do
     66 		addr.a6.sin6_addr     = *(struct in6_addr*)&dst->ip.v6;
     67 		addr.a6.sin6_scope_id = 0;
     68 		}
     69 	else return;
     70 
     71 	if ((connect(sock, &addr.s, inner_len)) < 0)
     72 		{ LogMsg("mDNSPlatformSourceAddrForDest: connect %#a failed errno %d (%s)", dst, errno, strerror(errno)); goto exit; }
     73 
     74 	if ((getsockname(sock, &addr.s, &len)) < 0)
     75 		{ LogMsg("mDNSPlatformSourceAddrForDest: getsockname failed errno %d (%s)", errno, strerror(errno)); goto exit; }
     76 
     77 	src->type = dst->type;
     78 	if (dst->type == mDNSAddrType_IPv4) src->ip.v4.NotAnInteger = addr.a4.sin_addr.s_addr;
     79 	else                                src->ip.v6 = *(mDNSv6Addr*)&addr.a6.sin6_addr;
     80 exit:
     81 	close(sock);
     82 	}
     83 
     84 // dst must be at least MAX_ESCAPED_DOMAIN_NAME bytes, and option must be less than 32 bytes in length
     85 mDNSlocal mDNSBool GetConfigOption(char *dst, const char *option, FILE *f)
     86 	{
     87 	char buf[32+1+MAX_ESCAPED_DOMAIN_NAME];	// Option name, one space, option value
     88 	unsigned int len = strlen(option);
     89 	if (len + 1 + MAX_ESCAPED_DOMAIN_NAME > sizeof(buf)-1) { LogMsg("GetConfigOption: option %s too long", option); return mDNSfalse; }
     90 	fseek(f, 0, SEEK_SET);  // set position to beginning of stream
     91 	while (fgets(buf, sizeof(buf), f))		// Read at most sizeof(buf)-1 bytes from file, and append '\0' C-string terminator
     92 		{
     93 		if (!strncmp(buf, option, len))
     94 			{
     95 			strncpy(dst, buf + len + 1, MAX_ESCAPED_DOMAIN_NAME-1);
     96 			if (dst[MAX_ESCAPED_DOMAIN_NAME-1]) dst[MAX_ESCAPED_DOMAIN_NAME-1] = '\0';
     97 			len = strlen(dst);
     98 			if (len && dst[len-1] == '\n') dst[len-1] = '\0';  // chop newline
     99 			return mDNStrue;
    100 			}
    101 		}
    102 	debugf("Option %s not set", option);
    103 	return mDNSfalse;
    104 	}
    105 
    106 mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled)
    107 	{
    108 	char buf[MAX_ESCAPED_DOMAIN_NAME] = "";
    109 	mStatus err;
    110 	FILE *f = fopen(filename, "r");
    111 
    112     if (hostname)                 hostname->c[0] = 0;
    113     if (domain)                   domain->c[0] = 0;
    114 	if (DomainDiscoveryDisabled) *DomainDiscoveryDisabled = mDNSfalse;
    115 
    116 	if (f)
    117 		{
    118 		if (DomainDiscoveryDisabled && GetConfigOption(buf, "DomainDiscoveryDisabled", f) && !strcasecmp(buf, "true")) *DomainDiscoveryDisabled = mDNStrue;
    119 		if (hostname && GetConfigOption(buf, "hostname", f) && !MakeDomainNameFromDNSNameString(hostname, buf)) goto badf;
    120 		if (domain && GetConfigOption(buf, "zone", f) && !MakeDomainNameFromDNSNameString(domain, buf)) goto badf;
    121 		buf[0] = 0;
    122 		GetConfigOption(buf, "secret-64", f);  // failure means no authentication
    123 		fclose(f);
    124 		f = NULL;
    125 		}
    126 	else
    127 		{
    128 		if (errno != ENOENT) LogMsg("ERROR: Config file exists, but cannot be opened.");
    129 		return;
    130 		}
    131 
    132 	if (domain && domain->c[0] && buf[0])
    133 		{
    134 		DomainAuthInfo *info = (DomainAuthInfo*)mDNSPlatformMemAllocate(sizeof(*info));
    135 		// for now we assume keyname = service reg domain and we use same key for service and hostname registration
    136 		err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0, NULL);
    137 		if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c);
    138 		}
    139 
    140 	return;
    141 
    142 	badf:
    143 	LogMsg("ERROR: malformatted config file");
    144 	if (f) fclose(f);
    145 	}
    146 
    147 #if MDNS_DEBUGMSGS
    148 mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
    149 	{
    150 #ifdef __ANDROID__
    151 	__android_log_print(ANDROID_LOG_DEBUG, "mdns", "%s", msg);
    152 #else
    153 	fprintf(stderr,"%s\n", msg);
    154 	fflush(stderr);
    155 #endif
    156 	}
    157 #endif
    158 
    159 mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, mDNSLogLevel_t loglevel)
    160 	{
    161 #if APPLE_OSX_mDNSResponder && LogTimeStamps
    162 	extern mDNS mDNSStorage;
    163 	extern mDNSu32 mDNSPlatformClockDivisor;
    164 	mDNSs32 t = mDNSStorage.timenow ? mDNSStorage.timenow : mDNSPlatformClockDivisor ? mDNS_TimeNow_NoLock(&mDNSStorage) : 0;
    165 	int ms = ((t < 0) ? -t : t) % 1000;
    166 #endif
    167 
    168 	if (mDNS_DebugMode)	// In debug mode we write to stderr
    169 		{
    170 #if APPLE_OSX_mDNSResponder && LogTimeStamps
    171 		if (ident && ident[0] && mDNSPlatformClockDivisor)
    172 			fprintf(stderr,"%8d.%03d: %s\n", (int)(t/1000), ms, buffer);
    173 		else
    174 #endif
    175 			fprintf(stderr,"%s\n", buffer);
    176 		fflush(stderr);
    177 		}
    178 	else				// else, in production mode, we write to syslog
    179 		{
    180 		static int log_inited = 0;
    181 
    182 		int syslog_level = LOG_ERR;
    183 		switch (loglevel)
    184 			{
    185 			case MDNS_LOG_MSG:       syslog_level = LOG_ERR;     break;
    186 			case MDNS_LOG_OPERATION: syslog_level = LOG_WARNING; break;
    187 			case MDNS_LOG_SPS:       syslog_level = LOG_NOTICE;  break;
    188 			case MDNS_LOG_INFO:      syslog_level = LOG_INFO;    break;
    189 			case MDNS_LOG_DEBUG:     syslog_level = LOG_DEBUG;   break;
    190 			default:
    191 			fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
    192 			fflush(stderr);
    193 			}
    194 
    195 		if (!log_inited) { openlog(ident, LOG_CONS, LOG_DAEMON); log_inited++; }
    196 
    197 #if APPLE_OSX_mDNSResponder && LogTimeStamps
    198 		if (ident && ident[0] && mDNSPlatformClockDivisor)
    199 			syslog(syslog_level, "%8d.%03d: %s", (int)(t/1000), ms, buffer);
    200 		else
    201 #endif
    202 #ifdef __ANDROID__
    203 		switch (loglevel)
    204 			{
    205 			case MDNS_LOG_DEBUG:     syslog_level = ANDROID_LOG_DEBUG;  break;
    206 #if MDNS_DEBUGMSGS > 0
    207 			case MDNS_LOG_OPERATION: syslog_level = ANDROID_LOG_WARN;   break;
    208 			case MDNS_LOG_SPS:       syslog_level = ANDROID_LOG_DEBUG;  break;
    209 			case MDNS_LOG_INFO:      syslog_level = ANDROID_LOG_INFO;   break;
    210 			default:                 syslog_level = ANDROID_LOG_ERROR;  break;
    211 #else
    212 			default:		return;
    213 #endif
    214 			}
    215 		__android_log_print(syslog_level, "mdns", "%s", buffer);
    216 #else
    217 			syslog(syslog_level, "%s", buffer);
    218 #endif
    219 		}
    220 	}
    221