#define LIST_ALL_INTERFACES 0
#define AAAA_OVER_V4 1
#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
#include "DNSCommon.h"
#include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
#include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
#include "PlatformCommon.h"
#include <stdio.h>
#include <stdarg.h> // For va_list support
#include <net/if.h>
#include <net/if_types.h> // For IFT_ETHER
#include <net/if_dl.h>
#include <sys/uio.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <time.h> // platform support for UTC time
#include <arpa/inet.h> // for inet_aton
#include <netinet/in.h> // For IP_RECVTTL
#ifndef IP_RECVTTL
#define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
#endif
#include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
#include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
#include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
#include <Security/Security.h>
#include "dnsinfo.h"
#define RUN_ON_PUMA_WITHOUT_IFADDRS 0
#if RUN_ON_PUMA_WITHOUT_IFADDRS
#include "mDNSMacOSXPuma.c"
#else
#include <ifaddrs.h>
#endif
#include <IOKit/IOKitLib.h>
#include <IOKit/IOMessage.h>
#include <mach/mach_time.h>
typedef struct SearchListElem
{
struct SearchListElem *next;
domainname domain;
int flag;
DNSQuestion BrowseQ;
DNSQuestion DefBrowseQ;
DNSQuestion LegacyBrowseQ;
DNSQuestion RegisterQ;
DNSQuestion DefRegisterQ;
ARListElem *AuthRecs;
} SearchListElem;
static mDNSu32 clockdivisor = 0;
static SearchListElem *SearchList = NULL; static DNSQuestion LegacyBrowseDomainQ; static DNameListElem *DefBrowseList = NULL; static DNameListElem *DefRegList = NULL; static ARListElem *SCPrefBrowseDomains = NULL;
static domainname DynDNSRegDomain; static CFArrayRef DynDNSBrowseDomains = NULL; static domainname DynDNSHostname;
static mDNSBool DomainDiscoveryDisabled = mDNSfalse;
#define CONFIG_FILE "/etc/mDNSResponder.conf"
#define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
#define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain"
mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add);
mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
{
return mDNS_CopyDNameList(DefBrowseList);
}
mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
{
return mDNS_CopyDNameList(DefRegList);
}
mDNSlocal void AddDefRegDomain(domainname *d)
{
DNameListElem *newelem = NULL, *ptr;
for (ptr = DefRegList; ptr; ptr = ptr->next)
{
if (SameDomainName(&ptr->name, d))
{ debugf("duplicate addition of default reg domain %##s", d->c); return; }
}
newelem = mallocL("DNameListElem", sizeof(*newelem));
if (!newelem) { LogMsg("Error - malloc"); return; }
AssignDomainName(&newelem->name, d);
newelem->next = DefRegList;
DefRegList = newelem;
DefaultRegDomainChanged(d, mDNStrue);
udsserver_default_reg_domain_changed(d, mDNStrue);
}
mDNSlocal void RemoveDefRegDomain(domainname *d)
{
DNameListElem *ptr = DefRegList, *prev = NULL;
while (ptr)
{
if (SameDomainName(&ptr->name, d))
{
if (prev) prev->next = ptr->next;
else DefRegList = ptr->next;
freeL("DNameListElem", ptr);
DefaultRegDomainChanged(d, mDNSfalse);
udsserver_default_reg_domain_changed(d, mDNSfalse);
return;
}
prev = ptr;
ptr = ptr->next;
}
debugf("Requested removal of default registration domain %##s not in contained in list", d->c);
}
mDNSlocal void NotifyOfElusiveBug(const char *title, mDNSu32 radarid, const char *msg)
{
extern mDNS mDNSStorage;
NetworkInterfaceInfoOSX *i;
static int notifyCount = 0;
if (notifyCount) return;
if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
break;
if (!i) return;
notifyCount++;
CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
CFStringRef alertFormat = CFSTR("Congratulations, you've reproduced an elusive bug. Please contact the owner of <rdar://problem/%d>. %s");
CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, alertFormat, radarid, msg);
CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL);
}
mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh)
{
static struct ifaddrs *ifa = NULL;
if (refresh && ifa)
{
freeifaddrs(ifa);
ifa = NULL;
}
if (ifa == NULL) getifaddrs(&ifa);
return ifa;
}
mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
{
NetworkInterfaceInfoOSX *i;
for (i = m->p->InterfaceList; i; i = i->next)
if (i->Exists && !strcmp(i->ifa_name, ifname) &&
((AAAA_OVER_V4 ) ||
(type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
(type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6) )) return(i);
return(NULL);
}
mDNSlocal int myIfIndexToName(u_short index, char* name)
{
struct ifaddrs *ifa;
for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
if (ifa->ifa_addr->sa_family == AF_LINK)
if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == index)
{ strncpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
return -1;
}
mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index)
{
NetworkInterfaceInfoOSX *i;
if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
if (index)
for (i = m->p->InterfaceList; i; i = i->next)
if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID);
return(mDNSNULL);
}
mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id)
{
NetworkInterfaceInfoOSX *i;
if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
if (id)
for (i = m->p->InterfaceList; i; i = i->next)
if ((mDNSInterfaceID)i == id) return(i->scope_id);
return 0;
}
mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
{
mDNSBool result = mDNSfalse;
SCNetworkConnectionFlags flags;
SCNetworkReachabilityRef ReachRef = NULL;
ReachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, addr);
if (!ReachRef) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end; }
if (!SCNetworkReachabilityGetFlags(ReachRef, &flags)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end; }
result = flags & kSCNetworkFlagsConnectionRequired;
end:
if (ReachRef) CFRelease(ReachRef);
return result;
}
mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
{
#pragma unused(m)
NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
char *ifa_name = info ? info->ifa_name : "unicast";
struct sockaddr_storage to;
int s = -1, err;
if (info && !mDNSAddrIsDNSMulticast(dst))
{
const DNSMessage *const m = (DNSMessage *)msg;
if ((m->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Query)
LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst, mDNSVal16(dstPort));
}
if (dst->type == mDNSAddrType_IPv4)
{
struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
sin_to->sin_len = sizeof(*sin_to);
sin_to->sin_family = AF_INET;
sin_to->sin_port = dstPort.NotAnInteger;
sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
s = info ? info->ss.sktv4 : m->p->unicastsockets.sktv4;
}
else if (dst->type == mDNSAddrType_IPv6)
{
struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
sin6_to->sin6_len = sizeof(*sin6_to);
sin6_to->sin6_family = AF_INET6;
sin6_to->sin6_port = dstPort.NotAnInteger;
sin6_to->sin6_flowinfo = 0;
sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
sin6_to->sin6_scope_id = info ? info->scope_id : 0;
s = info ? info->ss.sktv6 : m->p->unicastsockets.sktv6;
}
else
{
LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
return mStatus_BadParamErr;
}
if (!mDNSAddrIsDNSMulticast(dst) && AddrRequiresPPPConnection((struct sockaddr *)&to))
{
debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
return mStatus_NoError;
}
if (s >= 0)
verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
else
verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
if (s < 0) return(mStatus_Invalid);
err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
if (err < 0)
{
if (!mDNSAddressIsAllDNSLinkGroup(dst))
if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr);
LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
return(mStatus_UnknownErr);
}
return(mStatus_NoError);
}
mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
{
static unsigned int numLogMessages = 0;
struct iovec databuffers = { (char *)buffer, max };
struct msghdr msg;
ssize_t n;
struct cmsghdr *cmPtr;
char ancillary[1024];
*ttl = 255;
msg.msg_name = (caddr_t)from;
msg.msg_namelen = *fromlen;
msg.msg_iov = &databuffers;
msg.msg_iovlen = 1;
msg.msg_control = (caddr_t)&ancillary;
msg.msg_controllen = sizeof(ancillary);
msg.msg_flags = 0;
n = recvmsg(s, &msg, 0);
if (n<0)
{
if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
return(-1);
}
if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
{
if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
s, msg.msg_controllen, sizeof(struct cmsghdr));
return(-1);
}
if (msg.msg_flags & MSG_CTRUNC)
{
if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
return(-1);
}
*fromlen = msg.msg_namelen;
for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
{
if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
{
dstaddr->type = mDNSAddrType_IPv4;
dstaddr->ip.v4.NotAnInteger = *(u_int32_t*)CMSG_DATA(cmPtr);
}
if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
if (sdl->sdl_nlen < IF_NAMESIZE)
{
mDNSPlatformMemCopy(sdl->sdl_data, ifname, sdl->sdl_nlen);
ifname[sdl->sdl_nlen] = 0;
}
}
if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
{
*ttl = *(u_char*)CMSG_DATA(cmPtr);
}
if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
{
struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
dstaddr->type = mDNSAddrType_IPv6;
dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
}
if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
{
*ttl = *(int*)CMSG_DATA(cmPtr);
}
}
return(n);
}
mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBackType, CFDataRef address, const void *data, void *context)
{
mDNSAddr senderAddr, destAddr;
mDNSIPPort senderPort, destPort = MulticastDNSPort;
const CFSocketSet *ss = (const CFSocketSet *)context;
mDNS *const m = ss->m;
mDNSInterfaceID InterfaceID = ss->info ? ss->info->ifinfo.InterfaceID : mDNSNULL;
struct sockaddr_storage from;
size_t fromlen = sizeof(from);
char packetifname[IF_NAMESIZE] = "";
int err, s1 = -1, skt = CFSocketGetNative(cfs);
int count = 0;
(void)address; (void)data;
if (CallBackType != kCFSocketReadCallBack)
LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType);
if (cfs == ss->cfsv4) s1 = ss->sktv4;
else if (cfs == ss->cfsv6) s1 = ss->sktv6;
if (s1 < 0 || s1 != skt)
{
LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1, skt, cfs);
LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", ss->cfsv4, ss->sktv4);
LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", ss->cfsv6, ss->sktv6);
}
mDNSu8 ttl;
while ((err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl)) >= 0)
{
count++;
if (from.ss_family == AF_INET)
{
struct sockaddr_in *sin = (struct sockaddr_in*)&from;
senderAddr.type = mDNSAddrType_IPv4;
senderAddr.ip.v4.NotAnInteger = sin->sin_addr.s_addr;
senderPort.NotAnInteger = sin->sin_port;
}
else if (from.ss_family == AF_INET6)
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
senderAddr.type = mDNSAddrType_IPv6;
senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
senderPort.NotAnInteger = sin6->sin6_port;
}
else
{
LogMsg("myCFSocketCallBack from is unknown address family %d", from.ss_family);
return;
}
if (mDNSAddrIsDNSMulticast(&destAddr))
{
if (!ss->info || !ss->info->Exists)
{
verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on unicast socket (Ignored)", &senderAddr, &destAddr);
return;
}
else if (!strcmp(ss->info->ifa_name, packetifname))
verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s",
&senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
else
{
verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
&senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name, packetifname);
return;
}
}
else
{
NetworkInterfaceInfo *intf = m->HostInterfaces;
while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
if (intf) InterfaceID = intf->InterfaceID;
}
mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, destPort, InterfaceID);
}
if (err < 0 && (errno != EWOULDBLOCK || count == 0))
{
int save_errno = errno;
int so_error = -1;
int so_nread = -1;
int fionread = -1;
int solen = sizeof(int);
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(s1, &readfds);
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
int selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno);
if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno);
if (ioctl(s1, FIONREAD, &fionread) == -1)
LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno);
static unsigned int numLogMessages = 0;
if (numLogMessages++ < 100)
LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
if (numLogMessages > 5)
NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)", 3375328,
"Alternatively, you can send email to radar-3387020@group.apple.com. "
"If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
sleep(1); }
}
typedef struct
{
TCPConnectionCallback callback;
void *context;
int connected;
} tcpInfo_t;
mDNSlocal void tcpCFSocketCallback(CFSocketRef cfs, CFSocketCallBackType CallbackType, CFDataRef address,
const void *data, void *context)
{
#pragma unused(CallbackType, address, data)
mDNSBool connect = mDNSfalse;
tcpInfo_t *info = context;
if (!info->connected)
{
connect = mDNStrue;
info->connected = mDNStrue; }
info->callback(CFSocketGetNative(cfs), info->context, connect);
}
mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
TCPConnectionCallback callback, void *context, int *descriptor)
{
int sd, on = 1; struct sockaddr_in saddr;
CFSocketContext cfContext = { 0, NULL, 0, 0, 0 };
tcpInfo_t *info;
CFSocketRef sr;
CFRunLoopSourceRef rls;
(void)InterfaceID;
*descriptor = 0;
if (dst->type != mDNSAddrType_IPv4)
{
LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
return mStatus_UnknownErr;
}
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = dstport.NotAnInteger;
saddr.sin_len = sizeof(saddr);
memcpy(&saddr.sin_addr, &dst->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
if (AddrRequiresPPPConnection((struct sockaddr *)&saddr))
{
debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
return mStatus_UnknownErr;
}
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd < 3) { LogMsg("mDNSPlatformTCPConnect: socket error %d errno %d (%s)", sd, errno, strerror(errno)); return mStatus_UnknownErr; }
if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
{
LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
return mStatus_UnknownErr;
}
if (setsockopt(sd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
{
LogMsg("setsockopt IP_RECVIF - %s", strerror(errno));
return mStatus_UnknownErr;
}
info = mallocL("mDNSPlatformTCPConnect", sizeof(tcpInfo_t));
info->callback = callback;
info->context = context;
cfContext.info = info;
sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketReadCallBack | kCFSocketConnectCallBack,
tcpCFSocketCallback, &cfContext);
if (!sr)
{
LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketRefCreateWithNative failed");
freeL("mDNSPlatformTCPConnect", info);
return mStatus_UnknownErr;
}
rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sr, 0);
if (!rls)
{
LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketCreateRunLoopSource failed");
freeL("mDNSPlatformTCPConnect", info);
return mStatus_UnknownErr;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
if (connect(sd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
if (errno == EINPROGRESS)
{
info->connected = 0;
*descriptor= sd;
return mStatus_ConnPending;
}
LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno));
freeL("mDNSPlatformTCPConnect", info);
CFSocketInvalidate(sr); return mStatus_ConnFailed;
}
info->connected = 1;
*descriptor = sd;
return mStatus_ConnEstablished;
}
mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
{
CFSocketContext cfContext;
tcpInfo_t *info;
CFSocketRef sr;
if (sd < 3) LogMsg("mDNSPlatformTCPCloseConnection: ERROR sd %d < 3", sd);
sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketNoCallBack, NULL, NULL);
if (!sr) { LogMsg("ERROR: mDNSPlatformTCPCloseConnection - CFSocketCreateWithNative returned NULL"); return; }
CFSocketGetContext(sr, &cfContext);
if (!cfContext.info)
{
LogMsg("ERROR: mDNSPlatformTCPCloseConnection - could not retreive tcpInfo from socket context");
CFRelease(sr);
return;
}
CFRelease(sr);
info = cfContext.info;
CFSocketInvalidate(sr);
CFRelease(sr);
freeL("mDNSPlatformTCPCloseConnection", info);
}
mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
{
int nread = recv(sd, buf, buflen, 0);
if (nread < 0)
{
if (errno == EAGAIN) return 0; LogMsg("ERROR: mDNSPlatformReadTCP - recv: %s", strerror(errno));
return -1;
}
return nread;
}
mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
{
int nsent = send(sd, msg, len, 0);
if (nsent < 0)
{
if (errno == EAGAIN) return 0; LogMsg("ERROR: mDNSPlatformWriteTCP - sendL %s", strerror(errno));
return -1;
}
return nsent;
}
mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
{
CFStringEncoding encoding = kCFStringEncodingUTF8;
CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
if (cfs)
{
CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
CFRelease(cfs);
}
}
mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
{
CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
if (cfs)
{
CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
CFRelease(cfs);
}
}
mDNSlocal mDNSBool DDNSSettingEnabled(CFDictionaryRef dict)
{
mDNSs32 val;
CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled"));
if (!state) return mDNSfalse;
if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse; }
return val ? mDNStrue : mDNSfalse;
}
mDNSlocal void GetUserSpecifiedDDNSConfig(domainname *const fqdn, domainname *const regDomain, CFArrayRef *const browseDomains)
{
char buf[MAX_ESCAPED_DOMAIN_NAME];
fqdn->c[0] = 0;
regDomain->c[0] = 0;
buf[0] = 0;
*browseDomains = NULL;
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetUserSpecifiedDDNSConfig"), NULL, NULL);
if (store)
{
CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("Setup:/Network/DynamicDNS"));
if (dict)
{
CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("HostNames"));
if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
{
CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0); if (fqdnDict && DDNSSettingEnabled(fqdnDict))
{
CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
if (name)
{
if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
!MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
}
}
}
CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("RegistrationDomains"));
if (regArray && CFArrayGetCount(regArray) > 0)
{
CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
if (regDict && DDNSSettingEnabled(regDict))
{
CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
if (name)
{
if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
!MakeDomainNameFromDNSNameString(regDomain, buf) || !regDomain->c[0])
LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration zone: %s", buf);
}
}
}
CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("BrowseDomains"));
if (browseArray && CFArrayGetCount(browseArray) > 0)
{
CFRetain(browseArray);
*browseDomains = browseArray;
}
CFRelease(dict);
}
CFRelease(store);
}
}
mDNSlocal void SetDDNSNameStatus(domainname *const dname, mStatus status)
{
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SetDDNSNameStatus"), NULL, NULL);
if (store)
{
char uname[MAX_ESCAPED_DOMAIN_NAME];
ConvertDomainNameToCString(dname, uname);
char *p = uname;
while (*p)
{
*p = tolower(*p);
if (!(*(p+1)) && *p == '.') *p = 0; p++;
}
const void *StatusKey = CFSTR("Status");
const void *StatusVal = CFNumberCreate(NULL, kCFNumberSInt32Type, &status); const void *StatusDict = CFDictionaryCreate(NULL, &StatusKey, &StatusVal, 1, NULL, NULL);
const void *HostKey = CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8);
const void *HostDict = CFDictionaryCreate(NULL, &HostKey, &StatusDict, 1, NULL, NULL);
const void *StateKey = CFSTR("HostNames"); CFDictionaryRef StateDict = CFDictionaryCreate(NULL, &StateKey, &HostDict, 1, NULL, NULL);
SCDynamicStoreSetValue(store, CFSTR("State:/Network/DynamicDNS"), StateDict);
CFRelease(StateDict);
CFRelease(StateKey);
CFRelease(HostDict);
CFRelease(HostKey);
CFRelease(StatusDict);
CFRelease(StatusVal);
CFRelease(StatusKey);
CFRelease(store);
}
}
mDNSlocal mStatus SetupSocket(mDNS *const m, CFSocketSet *cp, mDNSBool mcast, const mDNSAddr *ifaddr, u_short sa_family)
{
int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
CFSocketRef *c = (sa_family == AF_INET) ? &cp->cfsv4 : &cp->cfsv6;
CFRunLoopSourceRef *r = (sa_family == AF_INET) ? &cp->rlsv4 : &cp->rlsv6;
const int on = 1;
const int twofivefive = 255;
mStatus err = mStatus_NoError;
char *errstr = mDNSNULL;
mDNSIPPort port = (mcast | m->CanReceiveUnicastOn5353) ? MulticastDNSPort : zeroIPPort;
if (*s >= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s); return(-1); }
if (*c) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c); return(-1); }
int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
if (skt < 3) { LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
if (port.NotAnInteger) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
if (sa_family == AF_INET)
{
err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
if (mcast)
{
struct in_addr addr = { ifaddr->ip.v4.NotAnInteger };
struct ip_mreq imr;
imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
imr.imr_interface = addr;
err = setsockopt(skt, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
if (err < 0) { errstr = "setsockopt - IP_ADD_MEMBERSHIP"; goto fail; }
err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));
if (err < 0) { errstr = "setsockopt - IP_MULTICAST_IF"; goto fail; }
}
err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
err = setsockopt(skt, IPPROTO_IP, IP_TOS, &ip_tosbits, sizeof(ip_tosbits));
if (err < 0) { errstr = "setsockopt - IP_TOS"; goto fail; }
struct sockaddr_in listening_sockaddr;
listening_sockaddr.sin_family = AF_INET;
listening_sockaddr.sin_port = port.NotAnInteger;
listening_sockaddr.sin_addr.s_addr = 0; err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
if (err) { errstr = "bind"; goto fail; }
}
else if (sa_family == AF_INET6)
{
err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; }
err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - IPV6_HOPLIMIT"; goto fail; }
err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
if (mcast)
{
int interface_id = if_nametoindex(cp->info->ifa_name);
struct ipv6_mreq i6mr;
i6mr.ipv6mr_interface = interface_id;
i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroupv6;
err = setsockopt(skt, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
if (err < 0) { errstr = "setsockopt - IPV6_JOIN_GROUP"; goto fail; }
err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interface_id, sizeof(interface_id));
if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_IF"; goto fail; }
}
err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
#ifdef IPV6_TCLASS
int tclass = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; err = setsockopt(skt, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass));
if (err < 0) { errstr = "setsockopt - IPV6_TCLASS"; goto fail; }
#endif
err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
struct sockaddr_in6 listening_sockaddr6;
bzero(&listening_sockaddr6, sizeof(listening_sockaddr6));
listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
listening_sockaddr6.sin6_family = AF_INET6;
listening_sockaddr6.sin6_port = port.NotAnInteger;
listening_sockaddr6.sin6_flowinfo = 0;
listening_sockaddr6.sin6_scope_id = 0;
err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
if (err) { errstr = "bind"; goto fail; }
}
fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); *s = skt;
CFSocketContext myCFSocketContext = { 0, cp, NULL, NULL, NULL };
*c = CFSocketCreateWithNative(kCFAllocatorDefault, *s, kCFSocketReadCallBack, myCFSocketCallBack, &myCFSocketContext);
*r = CFSocketCreateRunLoopSource(kCFAllocatorDefault, *c, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), *r, kCFRunLoopDefaultMode);
return(err);
fail:
LogMsg("%s error %ld errno %d (%s)", errstr, err, errno, strerror(errno));
if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed", 3814904,
"Alternatively, you can send email to radar-3387020@group.apple.com. "
"If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
close(skt);
return(err);
}
mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
{
if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
if (sa->sa_family == AF_INET)
{
struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
ip->type = mDNSAddrType_IPv4;
ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
return(mStatus_NoError);
}
if (sa->sa_family == AF_INET6)
{
struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
ip->type = mDNSAddrType_IPv6;
if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
return(mStatus_NoError);
}
LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
return(mStatus_Invalid);
}
mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
{
mDNSEthAddr eth = zeroEthAddr;
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
if (store)
{
CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
if (entityname)
{
CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
if (dict)
{
CFRange range = { 0, 6 }; CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
CFRelease(dict);
}
CFRelease(entityname);
}
CFRelease(store);
}
return(eth);
}
mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
{
mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
mDNSAddr ip, mask;
if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
NetworkInterfaceInfoOSX **p;
for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
if (scope_id == (*p)->scope_id && mDNSSameAddress(&ip, &(*p)->ifinfo.ip) && mDNSSameEthAddress(&bssid, &(*p)->BSSID))
{
debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, *p);
(*p)->Exists = mDNStrue;
return(*p);
}
NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
if (!i) return(mDNSNULL);
bzero(i, sizeof(NetworkInterfaceInfoOSX));
i->ifa_name = (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa->ifa_name) + 1);
if (!i->ifa_name) { freeL("NetworkInterfaceInfoOSX", i); return(mDNSNULL); }
strcpy(i->ifa_name, ifa->ifa_name);
i->ifinfo.InterfaceID = mDNSNULL;
i->ifinfo.ip = ip;
i->ifinfo.mask = mask;
strncpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
i->ifinfo.Advertise = m->AdvertiseLocalAddresses;
i->ifinfo.McastTxRx = mDNSfalse;
i->next = mDNSNULL;
i->Exists = mDNStrue;
i->LastSeen = utc;
i->scope_id = scope_id;
i->BSSID = bssid;
i->sa_family = ifa->ifa_addr->sa_family;
i->Multicast = (ifa->ifa_flags & IFF_MULTICAST) && !(ifa->ifa_flags & IFF_POINTOPOINT);
i->ss.m = m;
i->ss.info = i;
i->ss.sktv4 = i->ss.sktv6 = -1;
i->ss.cfsv4 = i->ss.cfsv6 = NULL;
i->ss.rlsv4 = i->ss.rlsv6 = NULL;
*p = i;
return(i);
}
mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
{
NetworkInterfaceInfoOSX *i;
for (i = m->p->InterfaceList; i; i = i->next)
if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
if (!(i->ifinfo.ip.ip.v4.b[0] == 169 && i->ifinfo.ip.ip.v4.b[1] == 254))
return(i);
return(mDNSNULL);
}
mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
{
mDNSBool foundav4 = mDNSfalse;
mDNSBool foundav6 = mDNSfalse;
struct ifaddrs *ifa = myGetIfAddrs(1);
struct ifaddrs *v4Loopback = NULL;
struct ifaddrs *v6Loopback = NULL;
mDNSEthAddr PrimaryMAC = zeroEthAddr;
char defaultname[32];
int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
if (InfoSocket < 3) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
if (m->SleepState) ifa = NULL;
while (ifa)
{
#if LIST_ALL_INTERFACES
if (ifa->ifa_addr->sa_family == AF_APPLETALK)
LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
else if (ifa->ifa_addr->sa_family == AF_LINK)
LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
if (!(ifa->ifa_flags & IFF_UP))
LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
if (!(ifa->ifa_flags & IFF_MULTICAST))
LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
if (ifa->ifa_flags & IFF_POINTOPOINT)
LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
if (ifa->ifa_flags & IFF_LOOPBACK)
LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
#endif
if (ifa->ifa_addr->sa_family == AF_LINK)
{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(PrimaryMAC) && mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr))
mDNSPlatformMemCopy(sdl->sdl_data + sdl->sdl_nlen, PrimaryMAC.b, 6);
}
if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
{
if (!ifa->ifa_netmask)
{
mDNSAddr ip;
SetupAddr(&ip, ifa->ifa_addr);
LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
}
else if (ifa->ifa_addr->sa_family != ifa->ifa_netmask->sa_family)
{
mDNSAddr ip;
SetupAddr(&ip, ifa->ifa_addr);
LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
}
else
{
int ifru_flags6 = 0;
if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
struct in6_ifreq ifr6;
bzero((char *)&ifr6, sizeof(ifr6));
strncpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr = *sin6;
if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
}
if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
{
if (ifa->ifa_flags & IFF_LOOPBACK)
if (ifa->ifa_addr->sa_family == AF_INET) v4Loopback = ifa;
else v6Loopback = ifa;
else
{
NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
if (i && i->Multicast)
{
if (ifa->ifa_addr->sa_family == AF_INET) foundav4 = mDNStrue;
else foundav6 = mDNStrue;
}
}
}
}
}
ifa = ifa->ifa_next;
}
if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
NetworkInterfaceInfoOSX *i;
for (i = m->p->InterfaceList; i; i = i->next)
if (i->Exists)
{
mDNSBool txrx = i->Multicast && ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
if (i->ifinfo.McastTxRx != txrx)
{
i->ifinfo.McastTxRx = txrx;
i->Exists = 2; }
}
if (InfoSocket >= 0) close(InfoSocket);
mDNS_snprintf(defaultname, sizeof(defaultname), "Macintosh-%02X%02X%02X%02X%02X%02X",
PrimaryMAC.b[0], PrimaryMAC.b[1], PrimaryMAC.b[2], PrimaryMAC.b[3], PrimaryMAC.b[4], PrimaryMAC.b[5]);
domainlabel nicelabel;
nicelabel.c[0] = 0;
GetUserSpecifiedFriendlyComputerName(&nicelabel);
if (nicelabel.c[0] == 0)
{
LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname);
MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
}
domainlabel hostlabel;
hostlabel.c[0] = 0;
GetUserSpecifiedLocalHostName(&hostlabel);
if (hostlabel.c[0] == 0)
{
LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname);
MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
}
if (SameDomainLabel(m->p->usernicelabel.c, nicelabel.c))
debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
else
{
debugf("Updating m->nicelabel to %#s", nicelabel.c);
m->p->usernicelabel = m->nicelabel = nicelabel;
}
if (SameDomainLabel(m->p->userhostlabel.c, hostlabel.c))
debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
else
{
debugf("Updating m->hostlabel to %#s", hostlabel.c);
m->p->userhostlabel = m->hostlabel = hostlabel;
mDNS_SetFQDN(m);
}
return(mStatus_NoError);
}
mDNSlocal int CountMaskBits(mDNSAddr *mask)
{
int i = 0, bits = 0;
int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
while (i < bytes)
{
mDNSu8 b = mask->ip.v6.b[i++];
while (b & 0x80) { bits++; b <<= 1; }
if (b) return(-1);
}
while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
return(bits);
}
mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
{
NetworkInterfaceInfoOSX *i;
int count = 0;
for (i = m->p->InterfaceList; i; i = i->next)
if (i->Exists)
{
NetworkInterfaceInfo *n = &i->ifinfo;
NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifa_name);
if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary) {
LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n->InterfaceID, primary);
n->InterfaceID = mDNSNULL;
}
if (!n->InterfaceID)
{
n->InterfaceID = (mDNSInterfaceID)primary;
mDNSBool flapping = (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
mDNS_RegisterInterface(m, n, flapping ? mDNSPlatformOneSecond * 5 : 0);
if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++;
LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s",
i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip, CountMaskBits(&n->mask),
flapping ? " (Flapping)" : "", n->InterfaceActive ? " (Primary)" : "");
}
if (!n->McastTxRx)
debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip);
else
{
if (i->sa_family == AF_INET && primary->ss.sktv4 == -1)
{
mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET);
if (err == 0) debugf("SetupActiveInterfaces: v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d", primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
else LogMsg("SetupActiveInterfaces: v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED", primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
}
if (i->sa_family == AF_INET6 && primary->ss.sktv6 == -1)
{
mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET6);
if (err == 0) debugf("SetupActiveInterfaces: v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d", primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
else LogMsg("SetupActiveInterfaces: v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED", primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
}
}
}
return count;
}
mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
{
NetworkInterfaceInfoOSX *i;
for (i = m->p->InterfaceList; i; i = i->next)
{
if (i->Exists) i->LastSeen = utc;
i->Exists = mDNSfalse;
}
}
mDNSlocal void CloseRunLoopSourceSocket(CFRunLoopSourceRef rls, CFSocketRef cfs)
{
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); CFRelease(rls); CFSocketInvalidate(cfs); CFRelease(cfs); }
mDNSlocal void CloseSocketSet(CFSocketSet *ss)
{
if (ss->cfsv4) CloseRunLoopSourceSocket(ss->rlsv4, ss->cfsv4);
if (ss->cfsv6) CloseRunLoopSourceSocket(ss->rlsv6, ss->cfsv6);
ss->sktv4 = ss->sktv6 = -1;
ss->cfsv4 = ss->cfsv6 = NULL;
ss->rlsv4 = ss->rlsv6 = NULL;
}
mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
{
NetworkInterfaceInfoOSX *i;
int count = 0;
for (i = m->p->InterfaceList; i; i = i->next)
{
NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
if (i->ifinfo.InterfaceID)
if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary)
{
LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s",
i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
&i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), i->ifinfo.InterfaceActive ? " (Primary)" : "");
mDNS_DeregisterInterface(m, &i->ifinfo);
if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++;
i->ifinfo.InterfaceID = mDNSNULL;
}
}
NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
while (*p)
{
i = *p;
CloseSocketSet(&i->ss);
if (!i->Exists)
{
if (i->LastSeen == utc) i->LastSeen = utc - 1;
mDNSBool delete = (NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0) && (utc - i->LastSeen >= 60);
LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
&i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
i->ifinfo.InterfaceActive ? " (Primary)" : "");
if (delete)
{
*p = i->next;
if (i->ifa_name) freeL("NetworkInterfaceInfoOSX name", i->ifa_name);
freeL("NetworkInterfaceInfoOSX", i);
continue; }
}
p = &i->next;
}
return count;
}
mDNSlocal mStatus GetDNSConfig(void **result)
{
#if MDNS_NO_DNSINFO
static int MessageShown = 0;
if (!MessageShown) { MessageShown = 1; LogMsg("Note: Compiled without Apple-specific Split-DNS support"); }
*result = NULL;
return mStatus_UnsupportedErr;
#else
*result = dns_configuration_copy();
if (!*result)
{
if (mDNSMacOSXSystemBuildNumber(NULL) < 8) return mStatus_UnsupportedErr;
if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return mStatus_NoError;
LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
return mStatus_UnknownErr;
}
return mStatus_NoError;
#endif // MDNS_NO_DNSINFO
}
mDNSlocal mStatus RegisterSplitDNS(mDNS *m, int *nAdditions, int *nDeletions)
{
(void)m; void *v;
*nAdditions = *nDeletions = 0;
mStatus err = GetDNSConfig(&v);
#if !MDNS_NO_DNSINFO
if (!err && v)
{
int i;
DNSServer *p;
dns_config_t *config = v; mDNS_Lock(m);
p = m->uDNS_info.Servers;
while (p) { p->flag = -1; p = p->next; }
LogOperation("RegisterSplitDNS: Registering %d resolvers", config->n_resolver);
for (i = 0; i < config->n_resolver; i++)
{
int j, n;
domainname d;
dns_resolver_t *r = config->resolver[i];
if (r->port == MulticastDNSPort.NotAnInteger) continue; if (r->search_order == DEFAULT_SEARCH_ORDER || !r->domain || !*r->domain) d.c[0] = 0; else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", r->domain); continue; }
for (j = 0; j < config->n_resolver; j++)
{
dns_resolver_t *p = config->resolver[j];
if (p->port == MulticastDNSPort.NotAnInteger) continue;
if (p->search_order <= r->search_order)
{
domainname tmp;
if (p->search_order == DEFAULT_SEARCH_ORDER || !p->domain || !*p->domain) tmp.c[0] = '\0';
else if (!MakeDomainNameFromDNSNameString(&tmp, p->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", p->domain); continue; }
if (SameDomainName(&d, &tmp))
if (p->search_order < r->search_order || j < i) break; }
}
if (j < config->n_resolver) { debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i, d.c, j); continue; }
for (n = 0; n < r->n_nameserver; n++)
{
if (r->nameserver[n]->sa_family == AF_INET && !AddrRequiresPPPConnection(r->nameserver[n]))
{
mDNSAddr saddr;
if (SetupAddr(&saddr, r->nameserver[n])) { LogMsg("RegisterSplitDNS: bad IP address"); continue; }
debugf("Adding dns server from slot %d %d.%d.%d.%d for domain %##s", i, saddr.ip.v4.b[0], saddr.ip.v4.b[1], saddr.ip.v4.b[2], saddr.ip.v4.b[3], d.c);
p = m->uDNS_info.Servers;
while (p)
{
if (mDNSSameAddress(&p->addr, &saddr) && SameDomainName(&p->domain, &d)) { p->flag = 0; break; }
else p = p->next;
}
if (!p)
{
p = mallocL("DNSServer", sizeof(*p));
if (!p) { LogMsg("Error: malloc"); mDNS_Unlock(m); return mStatus_UnknownErr; }
p->addr = saddr;
AssignDomainName(&p->domain, &d);
p->flag = 0;
p->next = m->uDNS_info.Servers;
m->uDNS_info.Servers = p;
(*nAdditions)++;
}
break; }
}
}
DNSServer **s = &m->uDNS_info.Servers;
while (*s)
{
if ((*s)->flag < 0)
{
p = *s;
*s = (*s)->next;
freeL("DNSServer", p);
(*nDeletions)--;
}
else s = &(*s)->next;
}
mDNS_Unlock(m);
dns_configuration_free(config);
}
#endif
return err;
}
mDNSlocal mStatus RegisterNameServers(mDNS *const m, CFDictionaryRef dict)
{
int i, count;
CFArrayRef values;
char buf[256];
mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 0 } } } };
CFStringRef s;
mDNS_DeleteDNSServers(m); values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
if (!values) return mStatus_NoError;
count = CFArrayGetCount(values);
for (i = 0; i < count; i++)
{
s = CFArrayGetValueAtIndex(values, i);
if (!s) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
if (!CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8))
{
LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
continue;
}
if (!inet_aton(buf, (struct in_addr *)saddr.ip.v4.b))
{
LogMsg("ERROR: RegisterNameServers - invalid address string %s", buf);
continue;
}
LogOperation("RegisterNameServers: Adding %#a", &saddr);
mDNS_AddDNSServer(m, &saddr, NULL);
}
return mStatus_NoError;
}
mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
{
(void)m; ARListElem *elem = rr->RecordContext;
if (result == mStatus_MemFree) freeL("FreeARElemCallback", elem);
}
mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
SearchListElem *slElem = question->QuestionContext;
ARListElem *arElem, *ptr, *prev;
AuthRecord *dereg;
const char *name;
mStatus err;
if (AddRecord)
{
arElem = mallocL("FoundDomain - arElem", sizeof(ARListElem));
if (!arElem) { LogMsg("ERROR: malloc"); return; }
mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem);
if (question == &slElem->BrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
else if (question == &slElem->DefBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
else if (question == &slElem->LegacyBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseLegacy];
else if (question == &slElem->RegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
else if (question == &slElem->DefRegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
else { LogMsg("FoundDomain - unknown question"); return; }
MakeDomainNameFromDNSNameString(arElem->ar.resrec.name, name);
AppendDNSNameString (arElem->ar.resrec.name, "local");
AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
err = mDNS_Register(m, &arElem->ar);
if (err)
{
LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err);
freeL("FoundDomain - arElem", arElem);
return;
}
arElem->next = slElem->AuthRecs;
slElem->AuthRecs = arElem;
}
else
{
ptr = slElem->AuthRecs;
prev = NULL;
while (ptr)
{
if (SameDomainName(&ptr->ar.resrec.rdata->u.name, &answer->rdata->u.name))
{
debugf("Deregistering PTR %##s -> %##s", ptr->ar.resrec.name->c, ptr->ar.resrec.rdata->u.name.c);
dereg = &ptr->ar;
if (prev) prev->next = ptr->next;
else slElem->AuthRecs = ptr->next;
ptr = ptr->next;
err = mDNS_Deregister(m, dereg);
if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
}
else
{
prev = ptr;
ptr = ptr->next;
}
}
}
}
mDNSlocal void MarkSearchListElem(const char *d)
{
SearchListElem *new, *ptr;
domainname domain;
if (!MakeDomainNameFromDNSNameString(&domain, d))
{ LogMsg("ERROR: MarkSearchListElem - bad domain %##s", d); return; }
if (SameDomainName(&domain, &localdomain) || SameDomainName(&domain, &LocalReverseMapomain))
{ debugf("MarkSearchListElem - ignoring local domain %##s", domain.c); return; }
for (ptr = SearchList; ptr; ptr = ptr->next)
if (SameDomainName(&ptr->domain, &domain))
{
if (ptr->flag != 1) ptr->flag = 0; break;
}
if (!ptr)
{
new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem));
if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
bzero(new, sizeof(SearchListElem));
AssignDomainName(&new->domain, &domain);
new->flag = 1; new->next = SearchList;
SearchList = new;
}
}
mDNSlocal mStatus GetSearchDomains(void)
{
void *v;
mStatus err = GetDNSConfig(&v);
#if !MDNS_NO_DNSINFO
if (!err && v)
{
int i;
dns_config_t *config = v;
if (!config->n_resolver) return err;
dns_resolver_t *resolv = config->resolver[0];
for (i = 0; i < resolv->n_search; i++) MarkSearchListElem(resolv->search[i]);
if (resolv->domain) MarkSearchListElem(resolv->domain);
dns_configuration_free(config);
}
#endif
return err;
}
mDNSlocal void GetDSSearchDomains(CFDictionaryRef dict)
{
char buf[MAX_ESCAPED_DOMAIN_NAME];
int i, count;
CFStringRef s;
if (dict)
{
CFArrayRef searchdomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
if (searchdomains)
{
count = CFArrayGetCount(searchdomains);
for (i = 0; i < count; i++)
{
s = CFArrayGetValueAtIndex(searchdomains, i);
if (!s) { LogMsg("ERROR: GetDSSearchDomains - CFArrayGetValueAtIndex"); break; }
if (!CFStringGetCString(s, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8))
{
LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
continue;
}
MarkSearchListElem(buf);
}
}
CFStringRef dname = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
if (dname)
{
if (CFStringGetCString(dname, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8))
MarkSearchListElem(buf);
else LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
}
}
}
mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
{
struct ifaddrs *ifa = NULL;
SearchListElem *ptr, *prev, *freeSLPtr;
ARListElem *arList;
mStatus err;
if (DomainDiscoveryDisabled) return mStatus_NoError;
for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = dict ? -1 : 0;
if (GetSearchDomains() == mStatus_UnsupportedErr) GetDSSearchDomains(dict);
ifa = myGetIfAddrs(1);
while (ifa)
{
mDNSAddr addr;
if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !IsPrivateV4Addr(&addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
{
mDNSAddr netmask;
char buffer[256];
if (!SetupAddr(&netmask, ifa->ifa_netmask))
{
sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
addr.ip.v4.b[2] & netmask.ip.v4.b[2],
addr.ip.v4.b[1] & netmask.ip.v4.b[1],
addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
MarkSearchListElem(buffer);
}
}
ifa = ifa->ifa_next;
}
prev = NULL;
ptr = SearchList;
while (ptr)
{
if (ptr->flag == -1) {
mDNS_StopQuery(m, &ptr->BrowseQ);
mDNS_StopQuery(m, &ptr->RegisterQ);
mDNS_StopQuery(m, &ptr->DefBrowseQ);
mDNS_StopQuery(m, &ptr->DefRegisterQ);
mDNS_StopQuery(m, &ptr->LegacyBrowseQ);
arList = ptr->AuthRecs;
ptr->AuthRecs = NULL;
while (arList)
{
AuthRecord *dereg = &arList->ar;
arList = arList->next;
debugf("Deregistering PTR %##s -> %##s", dereg->resrec.name->c, dereg->resrec.rdata->u.name.c);
err = mDNS_Deregister(m, dereg);
if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
}
if (prev) prev->next = ptr->next;
else SearchList = ptr->next;
freeSLPtr = ptr;
ptr = ptr->next;
freeL("RegisterSearchDomains - freeSLPtr", freeSLPtr);
continue;
}
if (ptr->flag == 1) {
mStatus err1, err2, err3, err4, err5;
err1 = mDNS_GetDomains(m, &ptr->BrowseQ, mDNS_DomainTypeBrowse, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ, mDNS_DomainTypeBrowseDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
err3 = mDNS_GetDomains(m, &ptr->RegisterQ, mDNS_DomainTypeRegistration, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ, mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
err5 = mDNS_GetDomains(m, &ptr->LegacyBrowseQ, mDNS_DomainTypeBrowseLegacy, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
if (err1 || err2 || err3 || err4 || err5)
LogMsg("GetDomains for domain %##s returned error(s):\n"
"%d (mDNS_DomainTypeBrowse)\n"
"%d (mDNS_DomainTypeBrowseDefault)\n"
"%d (mDNS_DomainTypeRegistration)\n"
"%d (mDNS_DomainTypeRegistrationDefault)"
"%d (mDNS_DomainTypeBrowseLegacy)\n",
ptr->domain.c, err1, err2, err3, err4, err5);
ptr->flag = 0;
}
if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); }
prev = ptr;
ptr = ptr->next;
}
return mStatus_NoError;
}
mDNSlocal void SCPrefsDynDNSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
{
(void)m; debugf("SCPrefsDynDNSCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
SetDDNSNameStatus(rr->resrec.name, result);
}
mDNSlocal void SetSecretForDomain(mDNS *m, const domainname *domain)
{
OSStatus err = 0;
char dstring[MAX_ESCAPED_DOMAIN_NAME];
mDNSu32 secretlen;
void *secret = NULL;
domainname *d, canon;
int i, dlen;
mDNSu32 type = 'ddns';
mDNSu32 typelen = sizeof(type);
char *failedfn = "(none)";
SecKeychainAttributeList *attrList = NULL;
SecKeychainItemRef itemRef = NULL;
err = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
if (err) { failedfn = "SecKeychainSetPreferenceDomain"; goto cleanup; }
ConvertDomainNameToCString(domain, dstring);
dlen = strlen(dstring);
for (i = 0; i < dlen; i++) dstring[i] = tolower(dstring[i]); MakeDomainNameFromDNSNameString(&canon, dstring);
d = &canon;
while (d->c[0] && *(d->c + d->c[0] + 1))
{
if (!ConvertDomainNameToCString(d, dstring)) { LogMsg("SetSecretForDomain: bad domain %##s", d->c); return; }
dlen = strlen(dstring);
if (dstring[dlen-1] == '.') { dstring[dlen-1] = '\0'; dlen--; } SecKeychainAttribute attrs[] = { { kSecServiceItemAttr, strlen(dstring), dstring },
{ kSecTypeItemAttr, typelen, (UInt32 *)&type } };
SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
SecKeychainSearchRef searchRef;
err = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributes, &searchRef);
if (err) { failedfn = "SecKeychainSearchCreateFromAttributes"; goto cleanup; }
err = SecKeychainSearchCopyNext(searchRef, &itemRef);
if (!err)
{
mDNSu32 tags[1];
SecKeychainAttributeInfo attrInfo;
mDNSu32 i;
char keybuf[MAX_ESCAPED_DOMAIN_NAME+1];
domainname keyname;
tags[0] = kSecAccountItemAttr;
attrInfo.count = 1;
attrInfo.tag = tags;
attrInfo.format = NULL;
err = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, &attrList, &secretlen, &secret);
if (err || !attrList) { failedfn = "SecKeychainItemCopyAttributesAndData"; goto cleanup; }
if (!secretlen || !secret) { LogMsg("SetSecretForDomain - bad shared secret"); return; }
if (((char *)secret)[secretlen-1]) { LogMsg("SetSecretForDomain - Shared secret not NULL-terminated"); goto cleanup; }
for (i = 0; i < attrList->count; i++)
{
SecKeychainAttribute attr = attrList->attr[i];
if (attr.tag == kSecAccountItemAttr)
{
if (!attr.length || attr.length > MAX_ESCAPED_DOMAIN_NAME) { LogMsg("SetSecretForDomain - Bad key length %d", attr.length); goto cleanup; }
strncpy(keybuf, attr.data, attr.length);
if (!MakeDomainNameFromDNSNameString(&keyname, keybuf)) { LogMsg("SetSecretForDomain - bad key %s", keybuf); goto cleanup; }
debugf("Setting shared secret for zone %s with key %##s", dstring, keyname.c);
mDNS_SetSecretForZone(m, d, &keyname, secret);
break;
}
}
if (i == attrList->count) LogMsg("SetSecretForDomain - no key name set");
goto cleanup;
}
else if (err == errSecItemNotFound) d = (domainname *)(d->c + d->c[0] + 1);
else { failedfn = "SecKeychainSearchCopyNext"; goto cleanup; }
}
cleanup:
if (err && err != errSecItemNotFound) LogMsg("Error: SetSecretForDomain - %s failed with error code %d", failedfn, err);
if (attrList) SecKeychainItemFreeAttributesAndData(attrList, secret);
if (itemRef) CFRelease(itemRef);
}
mDNSlocal void SetSCPrefsBrowseDomainsFromCFArray(mDNS *m, CFArrayRef browseDomains, mDNSBool add)
{
if (browseDomains)
{
CFIndex count = CFArrayGetCount(browseDomains);
CFDictionaryRef browseDict;
char buf[MAX_ESCAPED_DOMAIN_NAME];
int i;
for (i = 0; i < count; i++)
{
browseDict = (CFDictionaryRef)CFArrayGetValueAtIndex(browseDomains, i);
if (browseDict && DDNSSettingEnabled(browseDict))
{
CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
if (name)
{
domainname BrowseDomain;
if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || !MakeDomainNameFromDNSNameString(&BrowseDomain, buf) || !BrowseDomain.c[0])
LogMsg("SetSCPrefsBrowseDomainsFromCFArray SCDynamicStore bad DDNS browse domain: %s", buf[0] ? buf : "(unknown)");
else SetSCPrefsBrowseDomain(m, &BrowseDomain, add);
}
}
}
}
}
mDNSlocal void DynDNSConfigChanged(mDNS *const m)
{
static mDNSBool LegacyNATInitialized = mDNSfalse;
uDNS_GlobalInfo *u = &m->uDNS_info;
CFDictionaryRef dict;
CFStringRef key;
domainname RegDomain, fqdn;
CFArrayRef NewBrowseDomains = NULL;
int nAdditions = 0, nDeletions = 0;
GetUserSpecifiedDDNSConfig(&fqdn, &RegDomain, &NewBrowseDomains);
ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, fqdn.c[0] ? NULL : &fqdn, RegDomain.c[0] ? NULL : &RegDomain, &DomainDiscoveryDisabled);
if (!SameDomainName(&RegDomain, &DynDNSRegDomain))
{
if (DynDNSRegDomain.c[0])
{
RemoveDefRegDomain(&DynDNSRegDomain);
SetSCPrefsBrowseDomain(m, &DynDNSRegDomain, mDNSfalse); }
AssignDomainName(&DynDNSRegDomain, &RegDomain);
if (DynDNSRegDomain.c[0])
{
SetSecretForDomain(m, &DynDNSRegDomain);
AddDefRegDomain(&DynDNSRegDomain);
SetSCPrefsBrowseDomain(m, &DynDNSRegDomain, mDNStrue);
}
}
if (NewBrowseDomains) SetSCPrefsBrowseDomainsFromCFArray(m, NewBrowseDomains, mDNStrue);
if (DynDNSBrowseDomains)
{
SetSCPrefsBrowseDomainsFromCFArray(m, DynDNSBrowseDomains, mDNSfalse);
CFRelease(DynDNSBrowseDomains);
}
DynDNSBrowseDomains = NewBrowseDomains;
if (!SameDomainName(&fqdn, &DynDNSHostname))
{
if (DynDNSHostname.c[0]) mDNS_RemoveDynDNSHostName(m, &DynDNSHostname);
AssignDomainName(&DynDNSHostname, &fqdn);
if (DynDNSHostname.c[0])
{
SetSecretForDomain(m, &fqdn); SetDDNSNameStatus(&DynDNSHostname, 1); mDNS_AddDynDNSHostName(m, &DynDNSHostname, SCPrefsDynDNSCallback, NULL);
}
}
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:DynDNSConfigChanged"), NULL, NULL);
if (!store) return;
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
if (!key) { LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return; }
dict = SCDynamicStoreCopyValue(store, key);
CFRelease(key);
if (RegisterSplitDNS(m, &nAdditions, &nDeletions) != mStatus_NoError)
if (dict) RegisterNameServers(m, dict); RegisterSearchDomains(m, dict); if (dict) CFRelease(dict);
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,kSCDynamicStoreDomainState, kSCEntNetIPv4);
if (!key) { LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return; }
dict = SCDynamicStoreCopyValue(store, key);
CFRelease(key);
CFRelease(store);
if (!dict) {
mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL);
if (DynDNSHostname.c[0]) SetDDNSNameStatus(&DynDNSHostname, 1); return;
}
mDNSAddr r;
char buf[256];
r.type = mDNSAddrType_IPv4;
r.ip.v4.NotAnInteger = 0;
CFStringRef router = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
if (router)
{
struct sockaddr_in saddr;
if (!CFStringGetCString(router, buf, 256, kCFStringEncodingUTF8))
LogMsg("Could not convert router to CString");
else
{
saddr.sin_len = sizeof(saddr);
saddr.sin_family = AF_INET;
saddr.sin_port = 0;
inet_aton(buf, &saddr.sin_addr);
if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) { debugf("Ignoring router %s (requires PPP connection)", buf); }
else *(in_addr_t *)&r.ip.v4 = saddr.sin_addr.s_addr;
}
}
if (nAdditions || nDeletions) mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL);
CFStringRef primary = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
if (primary)
{
struct ifaddrs *ifa = myGetIfAddrs(1);
if (!CFStringGetCString(primary, buf, 256, kCFStringEncodingUTF8))
{ LogMsg("Could not convert router to CString"); goto error; }
while (ifa)
{
if (ifa->ifa_addr->sa_family == AF_INET && !strcmp(buf, ifa->ifa_name))
{
mDNSAddr ip;
SetupAddr(&ip, ifa->ifa_addr);
if (ip.ip.v4.b[0] == 169 && ip.ip.v4.b[1] == 254)
{ mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL); break; } if (ip.ip.v4.NotAnInteger != u->PrimaryIP.ip.v4.NotAnInteger ||
r.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger)
{
if (LegacyNATInitialized) { LegacyNATDestroy(); LegacyNATInitialized = mDNSfalse; }
if (r.ip.v4.NotAnInteger && IsPrivateV4Addr(&ip))
{
mStatus err = LegacyNATInit();
if (err) LogMsg("ERROR: LegacyNATInit");
else LegacyNATInitialized = mDNStrue;
}
mDNS_SetPrimaryInterfaceInfo(m, &ip, r.ip.v4.NotAnInteger ? &r : NULL);
break;
}
}
ifa = ifa->ifa_next;
}
}
error:
CFRelease(dict);
}
mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
{
LogOperation("*** Network Configuration Change ***");
m->p->NetworkChanged = 0; mDNSs32 utc = mDNSPlatformUTC();
MarkAllInterfacesInactive(m, utc);
UpdateInterfaceList(m, utc);
int nDeletions = ClearInactiveInterfaces(m, utc);
int nAdditions = SetupActiveInterfaces(m, utc);
DynDNSConfigChanged(m); if (nDeletions || nAdditions) mDNS_UpdateLLQs(m);
if (m->MainCallback)
m->MainCallback(m, mStatus_ConfigChanged);
}
mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
{
(void)store; (void)changedKeys; mDNS *const m = (mDNS *const)context;
mDNS_Lock(m);
mDNSs32 delay = mDNSPlatformOneSecond * 2;
int c = CFArrayGetCount(changedKeys); CFRange range = { 0, c };
CFStringRef k1 = SCDynamicStoreKeyCreateComputerName(NULL);
CFStringRef k2 = SCDynamicStoreKeyCreateHostNames(NULL);
if (k1 && k2)
{
int c1 = (CFArrayContainsValue(changedKeys, range, k1) != 0); int c2 = (CFArrayContainsValue(changedKeys, range, k2) != 0); int c3 = (CFArrayContainsValue(changedKeys, range, CFSTR("Setup:/Network/DynamicDNS")) != 0);
if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/10; }
if (k1) CFRelease(k1);
if (k2) CFRelease(k2);
LogOperation("*** NetworkChanged *** %d change%s, delay %d", c, c>1?"s":"", delay);
if (!m->p->NetworkChanged ||
m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
if (!m->SuppressSending ||
m->SuppressSending - m->p->NetworkChanged < 0)
m->SuppressSending = m->p->NetworkChanged;
mDNS_Unlock(m);
}
mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
{
mStatus err = -1;
SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
CFStringRef key1 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
CFStringRef key2 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
CFStringRef key3 = SCDynamicStoreKeyCreateComputerName(NULL);
CFStringRef key4 = SCDynamicStoreKeyCreateHostNames(NULL);
CFStringRef key5 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
if (!key1 || !key2 || !key3 || !key4 || !keys || !pattern1 || !pattern2 || !patterns) goto error;
CFArrayAppendValue(keys, key1);
CFArrayAppendValue(keys, key2);
CFArrayAppendValue(keys, key3);
CFArrayAppendValue(keys, key4);
CFArrayAppendValue(keys, key5);
CFArrayAppendValue(keys, CFSTR("Setup:/Network/DynamicDNS"));
CFArrayAppendValue(patterns, pattern1);
CFArrayAppendValue(patterns, pattern2);
CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
{ LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
m->p->Store = store;
err = 0;
goto exit;
error:
if (store) CFRelease(store);
exit:
if (key1) CFRelease(key1);
if (key2) CFRelease(key2);
if (key3) CFRelease(key3);
if (key4) CFRelease(key4);
if (key5) CFRelease(key5);
if (pattern1) CFRelease(pattern1);
if (pattern2) CFRelease(pattern2);
if (keys) CFRelease(keys);
if (patterns) CFRelease(patterns);
return(err);
}
mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
{
mDNS *const m = (mDNS *const)refcon;
(void)service; switch(messageType)
{
case kIOMessageCanSystemPowerOff: debugf ("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; case kIOMessageSystemWillPowerOff: LogOperation("PowerChanged kIOMessageSystemWillPowerOff");
mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m); break; case kIOMessageSystemWillNotPowerOff: debugf ("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; case kIOMessageCanSystemSleep: debugf ("PowerChanged kIOMessageCanSystemSleep (no action)"); break; case kIOMessageSystemWillSleep: LogOperation("PowerChanged kIOMessageSystemWillSleep");
mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m); break; case kIOMessageSystemWillNotSleep: debugf ("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; case kIOMessageSystemHasPoweredOn: LogOperation("PowerChanged kIOMessageSystemHasPoweredOn");
if (m->SleepState) mDNSCoreMachineSleep(m, false);
mDNSMacOSXNetworkChanged(m); break; case kIOMessageSystemWillRestart: debugf ("PowerChanged kIOMessageSystemWillRestart (no action)"); break; case kIOMessageSystemWillPowerOn: LogOperation("PowerChanged kIOMessageSystemWillPowerOn");
mDNSMacOSXNetworkChanged(m); mDNSCoreMachineSleep(m, false); break; default: LogOperation("PowerChanged unknown message %X", messageType); break;
}
IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
}
mDNSlocal mStatus WatchForPowerChanges(mDNS *const m)
{
IONotificationPortRef thePortRef;
m->p->PowerConnection = IORegisterForSystemPower(m, &thePortRef, PowerChanged, &m->p->PowerNotifier);
if (m->p->PowerConnection)
{
m->p->PowerRLS = IONotificationPortGetRunLoopSource(thePortRef);
CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
return(mStatus_NoError);
}
return(-1);
}
CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
{
int major = 0, minor = 0;
char letter = 0, prodname[256]="Mac OS X", prodvers[256]="", buildver[256]="?";
CFDictionaryRef vers = _CFCopySystemVersionDictionary();
if (vers)
{
CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
if (cfprodname) CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
if (cfprodvers) CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
sscanf(buildver, "%d%c%d", &major, &letter, &minor);
CFRelease(vers);
}
if (HINFO_SWstring) mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, mDNSResponderVersionString);
return(major);
}
mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
{
int err = -1;
int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s < 3)
LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
else
{
struct sockaddr_in s5353;
s5353.sin_family = AF_INET;
s5353.sin_port = MulticastDNSPort.NotAnInteger;
s5353.sin_addr.s_addr = 0;
err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
close(s);
}
if (err) LogMsg("No unicast UDP responses");
else debugf("Unicast UDP responses okay");
return(err == 0);
}
mDNSlocal void FoundLegacyBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
DNameListElem *ptr, *prev, *new;
(void)m; (void)question;
LogMsg("%s browse domain %##s", AddRecord ? "Adding" : "Removing", answer->rdata->u.name.c);
if (AddRecord)
{
new = mallocL("FoundLegacyBrowseDomain", sizeof(DNameListElem));
if (!new) { LogMsg("ERROR: malloc"); return; }
AssignDomainName(&new->name, &answer->rdata->u.name);
new->next = DefBrowseList;
DefBrowseList = new;
DefaultBrowseDomainChanged(&new->name, mDNStrue);
udsserver_default_browse_domain_changed(&new->name, mDNStrue);
return;
}
else
{
ptr = DefBrowseList;
prev = NULL;
while (ptr)
{
if (SameDomainName(&ptr->name, &answer->rdata->u.name))
{
DefaultBrowseDomainChanged(&ptr->name, mDNSfalse);
udsserver_default_browse_domain_changed(&ptr->name, mDNSfalse);
if (prev) prev->next = ptr->next;
else DefBrowseList = ptr->next;
freeL("FoundLegacyBrowseDomain", ptr);
return;
}
prev = ptr;
ptr = ptr->next;
}
LogMsg("FoundLegacyBrowseDomain: Got remove event for domain %##s not in list", answer->rdata->u.name.c);
}
}
mDNSlocal void RegisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
{
ARListElem *browse = mallocL("ARListElem", sizeof(*browse));
mDNS_SetupResourceRecord(&browse->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, browse);
MakeDomainNameFromDNSNameString(browse->ar.resrec.name, mDNS_DomainTypeNames[type]);
AppendDNSNameString (browse->ar.resrec.name, "local");
AssignDomainName(&browse->ar.resrec.rdata->u.name, d);
mStatus err = mDNS_Register(m, &browse->ar);
if (err)
{
LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
freeL("ARListElem", browse);
}
else
{
browse->next = SCPrefBrowseDomains;
SCPrefBrowseDomains = browse;
}
}
mDNSlocal void DeregisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
{
ARListElem *remove, **ptr = &SCPrefBrowseDomains;
domainname lhs;
MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]);
AppendDNSNameString (&lhs, "local");
while (*ptr)
{
if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
{
remove = *ptr;
*ptr = (*ptr)->next;
mDNS_Deregister(m, &remove->ar);
return;
}
else ptr = &(*ptr)->next;
}
}
mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add)
{
debugf("SetSCPrefsBrowseDomain: %s default browse domain %##s", add ? "Adding" : "Removing", d->c);
if (add)
{
RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
}
else
{
DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
}
}
mDNSlocal mStatus InitDNSConfig(mDNS *const m)
{
mStatus err;
static AuthRecord LocalRegPTR;
err = mDNS_GetDomains(m, &LegacyBrowseDomainQ, mDNS_DomainTypeBrowseLegacy, NULL, mDNSInterface_LocalOnly, FoundLegacyBrowseDomain, NULL);
SetSCPrefsBrowseDomain(m, &localdomain, mDNStrue);
mDNS_SetupResourceRecord(&LocalRegPTR, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, NULL, NULL);
MakeDomainNameFromDNSNameString(LocalRegPTR.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeRegistration]);
AppendDNSNameString (LocalRegPTR.resrec.name, "local");
AssignDomainName(&LocalRegPTR.resrec.rdata->u.name, &localdomain);
err = mDNS_Register(m, &LocalRegPTR);
if (err) LogMsg("ERROR: InitDNSConfig - mDNS_Register returned error %d", err);
return mStatus_NoError;
}
mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
{
int i;
for (i=0; i<100; i++)
{
domainlabel testlabel;
testlabel.c[0] = 0;
GetUserSpecifiedLocalHostName(&testlabel);
if (testlabel.c[0]) break;
usleep(50000);
}
mStatus err;
m->hostlabel.c[0] = 0;
char *HINFO_HWstring = "Macintosh";
char HINFO_HWstring_buffer[256];
int get_model[2] = { CTL_HW, HW_MODEL };
size_t len_model = sizeof(HINFO_HWstring_buffer);
if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
HINFO_HWstring = HINFO_HWstring_buffer;
char HINFO_SWstring[256] = "";
if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
if (hlen + slen < 254)
{
m->HIHardware.c[0] = hlen;
m->HISoftware.c[0] = slen;
mDNSPlatformMemCopy(HINFO_HWstring, &m->HIHardware.c[1], hlen);
mDNSPlatformMemCopy(HINFO_SWstring, &m->HISoftware.c[1], slen);
}
m->p->unicastsockets.m = m;
m->p->unicastsockets.info = NULL;
m->p->unicastsockets.sktv4 = m->p->unicastsockets.sktv6 = -1;
m->p->unicastsockets.cfsv4 = m->p->unicastsockets.cfsv6 = NULL;
m->p->unicastsockets.rlsv4 = m->p->unicastsockets.rlsv6 = NULL;
err = SetupSocket(m, &m->p->unicastsockets, mDNSfalse, &zeroAddr, AF_INET);
err = SetupSocket(m, &m->p->unicastsockets, mDNSfalse, &zeroAddr, AF_INET6);
struct sockaddr_in s4;
struct sockaddr_in6 s6;
int n4 = sizeof(s4);
int n6 = sizeof(s6);
if (getsockname(m->p->unicastsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
else m->UnicastPort4.NotAnInteger = s4.sin_port;
if (getsockname(m->p->unicastsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
else m->UnicastPort6.NotAnInteger = s6.sin6_port;
m->p->InterfaceList = mDNSNULL;
m->p->userhostlabel.c[0] = 0;
m->p->usernicelabel.c[0] = 0;
m->p->NotifyUser = 0;
mDNSs32 utc = mDNSPlatformUTC();
UpdateInterfaceList(m, utc);
SetupActiveInterfaces(m, utc);
err = WatchForNetworkChanges(m);
if (err) return(err);
err = WatchForPowerChanges(m);
if (err) return err;
DynDNSRegDomain.c[0] = '\0';
DynDNSConfigChanged(m);
InitDNSConfig(m);
return(err);
}
mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
{
mStatus result = mDNSPlatformInit_setup(m);
if (result == mStatus_NoError) mDNSCoreInitComplete(m, mStatus_NoError);
return(result);
}
mDNSexport void mDNSPlatformClose(mDNS *const m)
{
if (m->p->PowerConnection)
{
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
CFRunLoopSourceInvalidate(m->p->PowerRLS);
CFRelease(m->p->PowerRLS);
IODeregisterForSystemPower(&m->p->PowerNotifier);
m->p->PowerConnection = 0;
m->p->PowerNotifier = 0;
m->p->PowerRLS = NULL;
}
if (m->p->Store)
{
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
CFRunLoopSourceInvalidate(m->p->StoreRLS);
CFRelease(m->p->StoreRLS);
CFRelease(m->p->Store);
m->p->Store = NULL;
m->p->StoreRLS = NULL;
}
mDNSs32 utc = mDNSPlatformUTC();
MarkAllInterfacesInactive(m, utc);
ClearInactiveInterfaces(m, utc);
CloseSocketSet(&m->p->unicastsockets);
}
mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
{
return(mach_absolute_time());
}
mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
mDNSexport mStatus mDNSPlatformTimeInit(void)
{
struct mach_timebase_info tbi;
kern_return_t result = mach_timebase_info(&tbi);
if (result == KERN_SUCCESS) clockdivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
return(result);
}
mDNSexport mDNSs32 mDNSPlatformRawTime(void)
{
if (clockdivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
static uint64_t last_mach_absolute_time = 0;
uint64_t this_mach_absolute_time = mach_absolute_time();
if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
{
LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
last_mach_absolute_time = this_mach_absolute_time;
if (mDNSMacOSXSystemBuildNumber(NULL) >= 8)
NotifyOfElusiveBug("mach_absolute_time went backwards!", 3438376, "");
}
last_mach_absolute_time = this_mach_absolute_time;
return((mDNSs32)(this_mach_absolute_time / clockdivisor));
}
mDNSexport mDNSs32 mDNSPlatformUTC(void)
{
return time(NULL);
}
mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst) { strcpy((char *)dst, (char *)src); }
mDNSexport mDNSu32 mDNSPlatformStrLen (const void *src) { return(strlen((char*)src)); }
mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, mDNSu32 len) { memcpy(dst, src, len); }
mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { bzero(dst, len); }
mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }