| /* -*- Mode: C; tab-width: 4 -*- |
| * |
| * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <stdio.h> // Needed for fopen() etc. |
| #include <unistd.h> // Needed for close() |
| #include <string.h> // Needed for strlen() etc. |
| #include <errno.h> // Needed for errno etc. |
| #include <sys/socket.h> // Needed for socket() etc. |
| #include <netinet/in.h> // Needed for sockaddr_in |
| #include <syslog.h> |
| |
| #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above |
| #include "DNSCommon.h" |
| #include "PlatformCommon.h" |
| |
| #ifdef __ANDROID__ |
| #include <android/log.h> |
| #endif |
| |
| #ifdef NOT_HAVE_SOCKLEN_T |
| typedef unsigned int socklen_t; |
| #endif |
| |
| // Bind a UDP socket to find the source address to a destination |
| mDNSexport void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst) |
| { |
| union { struct sockaddr s; struct sockaddr_in a4; struct sockaddr_in6 a6; } addr; |
| socklen_t len = sizeof(addr); |
| socklen_t inner_len = 0; |
| int sock = socket(AF_INET, SOCK_DGRAM, 0); |
| src->type = mDNSAddrType_None; |
| if (sock == -1) return; |
| if (dst->type == mDNSAddrType_IPv4) |
| { |
| inner_len = sizeof(addr.a4); |
| #ifndef NOT_HAVE_SA_LEN |
| addr.a4.sin_len = inner_len; |
| #endif |
| addr.a4.sin_family = AF_INET; |
| addr.a4.sin_port = 1; // Not important, any port will do |
| addr.a4.sin_addr.s_addr = dst->ip.v4.NotAnInteger; |
| } |
| else if (dst->type == mDNSAddrType_IPv6) |
| { |
| inner_len = sizeof(addr.a6); |
| #ifndef NOT_HAVE_SA_LEN |
| addr.a6.sin6_len = inner_len; |
| #endif |
| addr.a6.sin6_family = AF_INET6; |
| addr.a6.sin6_flowinfo = 0; |
| addr.a6.sin6_port = 1; // Not important, any port will do |
| addr.a6.sin6_addr = *(struct in6_addr*)&dst->ip.v6; |
| addr.a6.sin6_scope_id = 0; |
| } |
| else return; |
| |
| if ((connect(sock, &addr.s, inner_len)) < 0) |
| { LogMsg("mDNSPlatformSourceAddrForDest: connect %#a failed errno %d (%s)", dst, errno, strerror(errno)); goto exit; } |
| |
| if ((getsockname(sock, &addr.s, &len)) < 0) |
| { LogMsg("mDNSPlatformSourceAddrForDest: getsockname failed errno %d (%s)", errno, strerror(errno)); goto exit; } |
| |
| src->type = dst->type; |
| if (dst->type == mDNSAddrType_IPv4) src->ip.v4.NotAnInteger = addr.a4.sin_addr.s_addr; |
| else src->ip.v6 = *(mDNSv6Addr*)&addr.a6.sin6_addr; |
| exit: |
| close(sock); |
| } |
| |
| // dst must be at least MAX_ESCAPED_DOMAIN_NAME bytes, and option must be less than 32 bytes in length |
| mDNSlocal mDNSBool GetConfigOption(char *dst, const char *option, FILE *f) |
| { |
| char buf[32+1+MAX_ESCAPED_DOMAIN_NAME]; // Option name, one space, option value |
| unsigned int len = strlen(option); |
| if (len + 1 + MAX_ESCAPED_DOMAIN_NAME > sizeof(buf)-1) { LogMsg("GetConfigOption: option %s too long", option); return mDNSfalse; } |
| fseek(f, 0, SEEK_SET); // set position to beginning of stream |
| while (fgets(buf, sizeof(buf), f)) // Read at most sizeof(buf)-1 bytes from file, and append '\0' C-string terminator |
| { |
| if (!strncmp(buf, option, len)) |
| { |
| strncpy(dst, buf + len + 1, MAX_ESCAPED_DOMAIN_NAME-1); |
| if (dst[MAX_ESCAPED_DOMAIN_NAME-1]) dst[MAX_ESCAPED_DOMAIN_NAME-1] = '\0'; |
| len = strlen(dst); |
| if (len && dst[len-1] == '\n') dst[len-1] = '\0'; // chop newline |
| return mDNStrue; |
| } |
| } |
| debugf("Option %s not set", option); |
| return mDNSfalse; |
| } |
| |
| mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled) |
| { |
| char buf[MAX_ESCAPED_DOMAIN_NAME] = ""; |
| mStatus err; |
| FILE *f = fopen(filename, "r"); |
| |
| if (hostname) hostname->c[0] = 0; |
| if (domain) domain->c[0] = 0; |
| if (DomainDiscoveryDisabled) *DomainDiscoveryDisabled = mDNSfalse; |
| |
| if (f) |
| { |
| if (DomainDiscoveryDisabled && GetConfigOption(buf, "DomainDiscoveryDisabled", f) && !strcasecmp(buf, "true")) *DomainDiscoveryDisabled = mDNStrue; |
| if (hostname && GetConfigOption(buf, "hostname", f) && !MakeDomainNameFromDNSNameString(hostname, buf)) goto badf; |
| if (domain && GetConfigOption(buf, "zone", f) && !MakeDomainNameFromDNSNameString(domain, buf)) goto badf; |
| buf[0] = 0; |
| GetConfigOption(buf, "secret-64", f); // failure means no authentication |
| fclose(f); |
| f = NULL; |
| } |
| else |
| { |
| if (errno != ENOENT) LogMsg("ERROR: Config file exists, but cannot be opened."); |
| return; |
| } |
| |
| if (domain && domain->c[0] && buf[0]) |
| { |
| DomainAuthInfo *info = (DomainAuthInfo*)mDNSPlatformMemAllocate(sizeof(*info)); |
| // for now we assume keyname = service reg domain and we use same key for service and hostname registration |
| err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0, NULL); |
| if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c); |
| } |
| |
| return; |
| |
| badf: |
| LogMsg("ERROR: malformatted config file"); |
| if (f) fclose(f); |
| } |
| |
| #if MDNS_DEBUGMSGS |
| mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg) |
| { |
| #ifdef __ANDROID__ |
| __android_log_print(ANDROID_LOG_DEBUG, "mdns", "%s", msg); |
| #else |
| fprintf(stderr,"%s\n", msg); |
| fflush(stderr); |
| #endif |
| } |
| #endif |
| |
| mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, mDNSLogLevel_t loglevel) |
| { |
| #if APPLE_OSX_mDNSResponder && LogTimeStamps |
| extern mDNS mDNSStorage; |
| extern mDNSu32 mDNSPlatformClockDivisor; |
| mDNSs32 t = mDNSStorage.timenow ? mDNSStorage.timenow : mDNSPlatformClockDivisor ? mDNS_TimeNow_NoLock(&mDNSStorage) : 0; |
| int ms = ((t < 0) ? -t : t) % 1000; |
| #endif |
| |
| if (mDNS_DebugMode) // In debug mode we write to stderr |
| { |
| #if APPLE_OSX_mDNSResponder && LogTimeStamps |
| if (ident && ident[0] && mDNSPlatformClockDivisor) |
| fprintf(stderr,"%8d.%03d: %s\n", (int)(t/1000), ms, buffer); |
| else |
| #endif |
| fprintf(stderr,"%s\n", buffer); |
| fflush(stderr); |
| } |
| else // else, in production mode, we write to syslog |
| { |
| static int log_inited = 0; |
| |
| int syslog_level = LOG_ERR; |
| switch (loglevel) |
| { |
| case MDNS_LOG_MSG: syslog_level = LOG_ERR; break; |
| case MDNS_LOG_OPERATION: syslog_level = LOG_WARNING; break; |
| case MDNS_LOG_SPS: syslog_level = LOG_NOTICE; break; |
| case MDNS_LOG_INFO: syslog_level = LOG_INFO; break; |
| case MDNS_LOG_DEBUG: syslog_level = LOG_DEBUG; break; |
| default: |
| fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel); |
| fflush(stderr); |
| } |
| |
| if (!log_inited) { openlog(ident, LOG_CONS, LOG_DAEMON); log_inited++; } |
| |
| #if APPLE_OSX_mDNSResponder && LogTimeStamps |
| if (ident && ident[0] && mDNSPlatformClockDivisor) |
| syslog(syslog_level, "%8d.%03d: %s", (int)(t/1000), ms, buffer); |
| else |
| #endif |
| #ifdef __ANDROID__ |
| switch (loglevel) |
| { |
| case MDNS_LOG_DEBUG: syslog_level = ANDROID_LOG_DEBUG; break; |
| #if MDNS_DEBUGMSGS > 0 |
| case MDNS_LOG_OPERATION: syslog_level = ANDROID_LOG_WARN; break; |
| case MDNS_LOG_SPS: syslog_level = ANDROID_LOG_DEBUG; break; |
| case MDNS_LOG_INFO: syslog_level = ANDROID_LOG_INFO; break; |
| default: syslog_level = ANDROID_LOG_ERROR; break; |
| #else |
| default: return; |
| #endif |
| } |
| __android_log_print(syslog_level, "mdns", "%s", buffer); |
| #else |
| syslog(syslog_level, "%s", buffer); |
| #endif |
| } |
| } |