#define LIST_ALL_INTERFACES 0
#define AAAA_OVER_V4 1
#include "mDNSClientAPI.h" // Defines the interface provided to the client layer above
#include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
#include <stdio.h>
#include <unistd.h> // For select() and close()
#include <stdarg.h> // For va_list support
#include <net/if.h>
#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>
#define RUN_ON_PUMA_WITHOUT_IFADDRS 0
#if RUN_ON_PUMA_WITHOUT_IFADDRS
#include "CFSocketPuma.c"
#else
#include <ifaddrs.h>
#endif
#include <IOKit/IOKitLib.h>
#include <IOKit/IOMessage.h>
#include <mach/mach_time.h>
typedef struct AuthRecordListElem
{
struct AuthRecordListElem *next;
AuthRecord ar;
} AuthRecordListElem;
typedef struct SearchListElem
{
struct SearchListElem *next;
domainname domain;
int flag;
DNSQuestion browseQ;
DNSQuestion registerQ;
AuthRecordListElem *AuthRecs;
} SearchListElem;
static mDNSu32 clockdivisor = 0;
static mDNSBool DNSConfigInitialized = mDNSfalse;
#define MAX_SEARCH_DOMAINS 32
static SearchListElem *SearchList = NULL; static DNSQuestion DefBrowseDomainQ; static DNameListElem *DefBrowseList = NULL;
#define CONFIG_FILE "/etc/mDNSResponder.conf"
#define LH_KEYCHAIN_DESC "Lighthouse Shared Secret"
#define LH_KEYCHAIN_SERVICE "Lighthouse"
#define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain"
#define LH_SUFFIX "members.mac.com."
#define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
#define mDNSSameIPv6Address(A,B) ((A).l[0] == (B).l[0] && (A).l[1] == (B).l[1] && (A).l[2] == (B).l[2] && (A).l[3] == (B).l[3])
#define mDNSAddressIsAllDNSLinkGroup(X) ( \
((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup )) || \
((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6)) )
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 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 == (uint32_t)~0) 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((mDNSu32)~0);
if (id)
for (i = m->p->InterfaceList; i; i = i->next)
if ((mDNSInterfaceID)i == id) return(i->scope_id);
return 0;
}
mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *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 (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!\n");
return mStatus_BadParamErr;
}
if (s >= 0)
verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %X %s/%d to %#a:%d skt %d",
InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
else
verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %X %s/%d (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 (errno == EHOSTDOWN && !mDNSAddressIsAllDNSLinkGroup(dst)) return(err);
if (errno == EHOSTUNREACH && (mDNSu32)(m->timenow) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(err);
LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %s/%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(err);
}
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("CFSocket.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("CFSocket.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("CFSocket.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;
const mDNSInterfaceID InterfaceID = ss->info ? ss->info->ifinfo.InterfaceID : mDNSNULL;
DNSMessage packet;
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, &packet, sizeof(packet), (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 (!ss->info)
verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on unicast socket", &senderAddr, &destAddr);
else if (!strcmp(ss->info->ifa_name, packetifname))
verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s",
&senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
else
{
verbosedebugf("myCFSocketCallBack got a 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;
}
if (err < (int)sizeof(DNSMessageHeader)) { debugf("myCFSocketCallBack packet length (%d) too short", err); return; }
mDNSCoreReceive(m, &packet, (unsigned char*)&packet + err, &senderAddr, senderPort, &destAddr, destPort, InterfaceID, ttl);
}
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);
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;
CFOptionFlags srFlags;
(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;
}
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0)
{
LogMsg("ERROR: socket; %s", 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;
}
srFlags = CFSocketGetSocketFlags(sr);
CFSocketSetSocketFlags(sr, srFlags & (~kCFSocketCloseOnInvalidate));
rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sr, 0);
if (!rls)
{
LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketCreateRunLoopSource failed");
freeL("mDNSPlatformTCPConnect", info);
return mStatus_UnknownErr;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = dstport.NotAnInteger;
memcpy(&saddr.sin_addr, &dst->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
if (connect(sd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
if (errno == EINPROGRESS)
{
info->connected = 0;
*descriptor= sd;
return mStatus_ConnectionPending;
}
LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno));
freeL("mDNSPlatformTCPConnect", info);
CFSocketInvalidate(sr);
return mStatus_ConnectionFailed;
}
info->connected = 1;
*descriptor = sd;
return mStatus_ConnectionEstablished;
}
mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
{
CFSocketContext cfContext;
tcpInfo_t *info;
CFSocketRef sr;
sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, NULL, NULL, NULL);
if (!sr)
{
LogMsg("ERROR: mDNSPlatformTCPCloseConnection - attempt to close a socket that was not properly created");
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);
close(sd);
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 GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
{
CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
if (cfs)
{
CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
CFRelease(cfs);
}
}
mDNSlocal mStatus SetupSocket(CFSocketSet *cp, mDNSIPPort port, 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;
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 < 0) { LogMsg("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 (port.NotAnInteger)
{
struct in_addr addr = { ifaddr->ip.v4.NotAnInteger };
struct ip_mreq imr;
imr.imr_multiaddr.s_addr = AllDNSLinkGroup.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 (port.NotAnInteger)
{
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));
close(skt);
return(err);
}
mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
{
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(0);
}
else 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(0);
}
else
{
LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
return(-1);
}
}
mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa)
{
mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
mDNSAddr ip;
SetupAddr(&ip, ifa->ifa_addr);
NetworkInterfaceInfoOSX **p;
for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
if (scope_id == (*p)->scope_id && mDNSSameAddress(&ip, &(*p)->ifinfo.ip))
{
debugf("AddInterfaceToList: Found existing interface %u with address %#a", scope_id, &ip);
(*p)->Exists = mDNStrue;
return(*p);
}
debugf("AddInterfaceToList: Making new interface %u with address %#a", scope_id, &ip);
NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
if (!i) return(mDNSNULL);
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);
bzero(&i->ifinfo.uDNS_info, sizeof(uDNS_NetworkInterfaceInfo));
i->ifinfo.InterfaceID = mDNSNULL;
i->ifinfo.ip = ip;
i->ifinfo.Advertise = m->AdvertiseLocalAddresses;
i->ifinfo.McastTxRx = mDNSfalse;
i->next = mDNSNULL;
i->Exists = mDNStrue;
i->scope_id = scope_id;
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)
{
mDNSBool foundav4 = mDNSfalse;
struct ifaddrs *ifa = myGetIfAddrs(1);
struct ifaddrs *theLoopback = NULL;
int err = (ifa != NULL) ? 0 : (errno != 0 ? errno : -1);
int InfoSocket = err ? -1 : socket(AF_INET6, SOCK_DGRAM, 0);
if (err) return(err);
m->nicelabel.c[0] = 0;
GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Macintosh");
domainlabel hostlabel;
hostlabel.c[0] = 0;
GetUserSpecifiedRFC1034ComputerName(&hostlabel);
if (hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&hostlabel, "Macintosh");
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_GenerateFQDN(m);
if (mDNS_DNSRegistered(m)) mDNS_GenerateGlobalFQDN(m);
}
while (ifa)
{
#if LIST_ALL_INTERFACES
if (ifa->ifa_addr->sa_family == AF_APPLETALK)
debugf("UpdateInterfaceList: %4s(%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)
debugf("UpdateInterfaceList: %4s(%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)
debugf("UpdateInterfaceList: %4s(%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))
debugf("UpdateInterfaceList: %4s(%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))
debugf("UpdateInterfaceList: %4s(%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)
debugf("UpdateInterfaceList: %4s(%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)
debugf("UpdateInterfaceList: %4s(%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_flags & IFF_UP)
if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
{
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)
theLoopback = ifa;
else
{
AddInterfaceToList(m, ifa);
if (ifa->ifa_addr->sa_family == AF_INET)
foundav4 = mDNStrue;
}
}
}
ifa = ifa->ifa_next;
}
if (!foundav4 && theLoopback)
AddInterfaceToList(m, theLoopback);
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);
return(err);
}
mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, 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 void SetupActiveInterfaces(mDNS *const m)
{
NetworkInterfaceInfoOSX *i;
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;
mDNS_RegisterInterface(m, n);
LogOperation("SetupActiveInterfaces: Registered %s(%lu) InterfaceID %p %#a%s",
i->ifa_name, i->scope_id, primary, &n->ip, n->InterfaceActive ? " (Primary)" : "");
}
if (!n->McastTxRx)
debugf("SetupActiveInterfaces: No Tx/Rx on %s(%lu) InterfaceID %p %#a", i->ifa_name, i->scope_id, primary, &n->ip);
else
{
if (i->sa_family == AF_INET && primary->ss.sktv4 == -1)
{
mStatus err = SetupSocket(&primary->ss, MulticastDNSPort, &i->ifinfo.ip, AF_INET);
if (err == 0) debugf("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a", primary->ss.sktv4, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
else LogMsg("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a FAILED", primary->ss.sktv4, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
}
if (i->sa_family == AF_INET6 && primary->ss.sktv6 == -1)
{
mStatus err = SetupSocket(&primary->ss, MulticastDNSPort, &i->ifinfo.ip, AF_INET6);
if (err == 0) debugf("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a", primary->ss.sktv6, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
else LogMsg("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a FAILED", primary->ss.sktv6, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
}
}
}
}
mDNSlocal void MarkAllInterfacesInactive(mDNS *const m)
{
NetworkInterfaceInfoOSX *i;
for (i = m->p->InterfaceList; i; i = i->next)
i->Exists = mDNSfalse;
}
mDNSlocal void CloseSocketSet(CFSocketSet *ss)
{
if (ss->cfsv4) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), ss->rlsv4, kCFRunLoopDefaultMode); CFRelease(ss->rlsv4); CFSocketInvalidate(ss->cfsv4); CFRelease(ss->cfsv4); }
if (ss->cfsv6) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), ss->rlsv6, kCFRunLoopDefaultMode); CFRelease(ss->rlsv6); CFSocketInvalidate(ss->cfsv6); CFRelease(ss->cfsv6); }
ss->sktv4 = ss->sktv6 = -1;
ss->cfsv4 = ss->cfsv6 = NULL;
ss->rlsv4 = ss->rlsv6 = NULL;
}
mDNSlocal void ClearInactiveInterfaces(mDNS *const m)
{
NetworkInterfaceInfoOSX *i;
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 %s(%lu) InterfaceID %p %#a%s",
i->ifa_name, i->scope_id, i->ifinfo.InterfaceID, &i->ifinfo.ip, i->ifinfo.InterfaceActive ? " (Primary)" : "");
mDNS_DeregisterInterface(m, &i->ifinfo);
i->ifinfo.InterfaceID = mDNSNULL;
}
}
NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
while (*p)
{
i = *p;
CloseSocketSet(&i->ss);
if (!i->Exists && NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0)
{
debugf("ClearInactiveInterfaces: Deleting %#a", &i->ifinfo.ip);
*p = i->next;
if (i->ifa_name) freeL("NetworkInterfaceInfoOSX name", i->ifa_name);
freeL("NetworkInterfaceInfoOSX", i);
}
else
p = &i->next;
}
}
mDNSlocal mStatus RegisterNameServers(mDNS *const m, CFDictionaryRef dict)
{
int i, count;
CFArrayRef values;
char buf[256];
mDNSv4Addr saddr;
CFStringRef s;
mDNS_DeregisterDNSList(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, kCFStringEncodingASCII))
{
LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
continue;
}
if (!inet_aton(buf, (struct in_addr *)saddr.b))
{
LogMsg("ERROR: RegisterNameServers - invalid address string %s", buf);
continue;
}
mDNS_RegisterDNS(m, &saddr);
}
return mStatus_NoError;
}
mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
{
(void)m; AuthRecordListElem *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;
AuthRecordListElem *arElem, *ptr, *prev;
AuthRecord *dereg;
char *name;
mStatus err;
if (AddRecord)
{
arElem = mallocL("FoundDomain - arElem", sizeof(AuthRecordListElem));
if (!arElem) { LogMsg("ERROR: malloc"); return; }
mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem);
if (question == &slElem->browseQ) name = "_browse._dns-sd._udp.local.";
else name = "_register._dns-sd._udp.local.";
MakeDomainNameFromDNSNameString(&arElem->ar.resrec.name, name);
strcpy(arElem->ar.resrec.rdata->u.name.c, answer->rdata->u.name.c);
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.name, &answer->name) && 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 mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
{
int i, count;
CFArrayRef values;
domainname domain;
char buf[MAX_ESCAPED_DOMAIN_NAME];
CFStringRef s;
SearchListElem *new, *ptr, *prev, *freeSLPtr;
AuthRecordListElem *arList;
mStatus err;
for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = -1;
values = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
if (values)
{
count = CFArrayGetCount(values);
for (i = 0; i < count; i++)
{
s = CFArrayGetValueAtIndex(values, i);
if (!s) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
if (!CFStringGetCString(s, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingASCII))
{
LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
continue;
}
if (!MakeDomainNameFromDNSNameString(&domain, buf))
{
LogMsg("ERROR: RegisterNameServers - invalid search domain %s", buf);
continue;
}
for (ptr = SearchList; ptr; ptr = ptr->next)
if (SameDomainName(&ptr->domain, &domain)) { ptr->flag = 0; break; }
if (!ptr)
{
new = mallocL("RegisterSearchDomains - SearchListElem", sizeof(SearchListElem));
if (!new) { LogMsg("ERROR: RegisterSearchDomains - malloc"); return mStatus_UnknownErr; }
bzero(new, sizeof(SearchListElem));
strcpy(new->domain.c, domain.c);
new->flag = 1; new->next = SearchList;
SearchList = new;
}
}
}
prev = NULL;
ptr = SearchList;
while (ptr)
{
if (ptr->flag == -1) {
mDNS_StopQuery(m, &ptr->browseQ);
mDNS_StopQuery(m, &ptr->registerQ);
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("RegisterNameServers - freeSLPtr", freeSLPtr);
continue;
}
if (ptr->flag == 1) {
err = mDNS_GetDomains(m, &ptr->browseQ, mDNS_DomainTypeBrowse, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
if (err) LogMsg("ERROR: RegisterNameServers - mDNS_DomainTypeBrowse, %d", err);
err = mDNS_GetDomains(m, &ptr->registerQ, mDNS_DomainTypeRegistration, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
if (err) LogMsg("ERROR: RegisterNameServers - mDNS_DomainTypeRegistration, %d", err);
ptr->flag = 0;
}
if (ptr->flag) { LogMsg("RegisterNameServers - unknown flag %d. Skipping.", ptr->flag); }
prev = ptr;
ptr = ptr->next;
}
return mStatus_NoError;
}
mDNSlocal mStatus RegisterDNSConfig(mDNS *const m, CFDictionaryRef dict, const CFStringRef key)
{
if (key == kSCPropNetDNSSearchDomains) return RegisterSearchDomains(m, dict);
if (key == kSCPropNetDNSServerAddresses) return RegisterNameServers(m, dict);
LogMsg("ERROR: RegisterDNSConfig - bad key"); return mStatus_UnknownErr;
}
mDNSlocal void DNSConfigChanged(SCDynamicStoreRef session, CFArrayRef changes, void *context)
{
mDNS *m = context;
CFDictionaryRef dict;
CFStringRef key;
if (DNSConfigInitialized && (!changes || CFArrayGetCount(changes) == 0)) return;
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
if (!key) { LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); return; }
dict = SCDynamicStoreCopyValue(session, key);
CFRelease(key);
if (dict)
{
RegisterDNSConfig(m, dict, kSCPropNetDNSServerAddresses);
RegisterDNSConfig(m, dict, kSCPropNetDNSSearchDomains);
CFRelease(dict);
}
if (mDNS_DNSRegistered(m)) mDNS_GenerateGlobalFQDN(m);
}
mDNSlocal mStatus WatchForDNSChanges(mDNS *const m)
{
CFStringRef key;
CFMutableArrayRef keyList;
CFRunLoopSourceRef rls;
SCDynamicStoreRef session;
SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
session = SCDynamicStoreCreate(NULL, CFSTR("trackDNS"), DNSConfigChanged, &context);
if (!session) { LogMsg("ERROR: WatchForDNSChanges - SCDynamicStoreCreate"); return mStatus_UnknownErr; }
keyList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (!keyList) { LogMsg("ERROR: WatchForDNSChanges - CFArrayCreateMutable"); return mStatus_UnknownErr; }
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
if (!key) { LogMsg("ERROR: WatchForDNSChanges - SCDynamicStoreKeyCreateNetworkGlobalEntity"); return mStatus_UnknownErr; }
CFArrayAppendValue(keyList, key);
CFRelease(key);
SCDynamicStoreSetNotificationKeys(session, keyList, NULL);
CFRelease(keyList);
rls = SCDynamicStoreCreateRunLoopSource(NULL, session, 0);
if (!rls) { LogMsg("ERROR: WatchForDNSChanges - SCDynamicStoreCreateRunLoopSource"); return mStatus_UnknownErr; }
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
DNSConfigChanged(session, NULL, m);
return mStatus_NoError;
}
mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
{
(void)store; (void)changedKeys; debugf("*** Network Configuration Change ***");
mDNS *const m = (mDNS *const)context;
MarkAllInterfacesInactive(m);
UpdateInterfaceList(m);
ClearInactiveInterfaces(m);
SetupActiveInterfaces(m);
if (m->MainCallback)
m->MainCallback(m, mStatus_ConfigChanged);
}
mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
{
mStatus err = -1;
SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder"), NetworkChanged, &context);
CFStringRef key1 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
CFStringRef key2 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
CFStringRef key3 = SCDynamicStoreKeyCreateComputerName(NULL);
CFStringRef key4 = SCDynamicStoreKeyCreateHostNames(NULL);
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\n", 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(patterns, pattern1);
CFArrayAppendValue(patterns, pattern2);
if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
{ LogMsg("SCDynamicStoreSetNotificationKeys failed: %s\n", SCErrorString(SCError())); goto error; }
m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s\n", 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 (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: debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreMachineSleep(m, true); break; case kIOMessageSystemWillNotPowerOff: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; case kIOMessageCanSystemSleep: debugf("PowerChanged kIOMessageCanSystemSleep (no action)"); break; case kIOMessageSystemWillSleep: debugf("PowerChanged kIOMessageSystemWillSleep"); mDNSCoreMachineSleep(m, true); break; case kIOMessageSystemWillNotSleep: debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; case kIOMessageSystemHasPoweredOn: debugf("PowerChanged kIOMessageSystemHasPoweredOn"); mDNSCoreMachineSleep(m, false); break; default: debugf("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);
}
mDNSexport mDNSBool haveSecInfo = mDNSfalse; mDNSlocal void GetAuthInfoFromKeychainItem(mDNS *m, SecKeychainItemRef item)
{
OSStatus err;
mDNSu32 infoTag = kSecAccountItemAttr;
mDNSu32 infoFmt = 0; SecKeychainAttributeInfo info;
SecKeychainAttributeList *authAttrList = NULL;
void *data;
mDNSu32 dataLen;
mStatus regErr;
char accountName[MAX_ESCAPED_DOMAIN_NAME];
domainname zone;
AuthRecord *rrReg, *rrBrowse;
info.count = 1;
info.tag = &infoTag;
info.format = &infoFmt;
err = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &authAttrList, &dataLen, &data);
if (err) { LogMsg("SecKeychainItemCopyAttributesAndData returned error %d", err); return; }
if (!authAttrList->count || authAttrList->attr->tag != kSecAccountItemAttr)
{ LogMsg("Received bad authAttrList"); return; }
if (authAttrList->attr->length + strlen(LH_SUFFIX) > MAX_ESCAPED_DOMAIN_NAME)
{ LogMsg("Account name too long (%d bytes)", authAttrList->attr->length); return; }
memcpy(accountName, authAttrList->attr->data, authAttrList->attr->length);
accountName[authAttrList->attr->length] = '\0';
zone.c[0] = '\0';
if (!AppendLiteralLabelString(&zone, accountName) ||
!AppendDNSNameString(&zone, LH_SUFFIX))
{ LogMsg("InitAuthInfo - bad account name"); return; }
mDNS_UpdateDomainRequiresAuthentication(m, &zone, &zone, data, dataLen, mDNStrue);
if(m->uDNS_info.NameRegDomain) { debugf("Overwriting config file options with KeyChain values"); }
if (!ConvertDomainNameToCString(&zone, m->uDNS_info.NameRegDomain) ||
!ConvertDomainNameToCString(&zone, m->uDNS_info.ServiceRegDomain))
{ LogMsg("Couldn't set keychain username in uDNS global info"); }
mDNS_GenerateGlobalFQDN(m);
haveSecInfo = mDNStrue;
rrReg = mallocL("AuthRecord", sizeof(AuthRecord));
rrBrowse = mallocL("AuthRecord", sizeof(AuthRecord));
if (!rrReg || !rrBrowse) { LogMsg("ERROR: Malloc"); return; }
mDNS_SetupResourceRecord(rrBrowse, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
MakeDomainNameFromDNSNameString(&rrBrowse->resrec.name, "_browse._dns-sd._udp.local.");
strcpy(rrBrowse->resrec.rdata->u.name.c, zone.c);
mDNS_SetupResourceRecord(rrReg, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
MakeDomainNameFromDNSNameString(&rrReg->resrec.name, "_register._dns-sd._udp.local.");
strcpy(rrReg->resrec.rdata->u.name.c, zone.c);
regErr = mDNS_Register(m, rrReg);
if (regErr) LogMsg("Registration of local-only reg domain %s failed", zone.c);
regErr = mDNS_Register(m, rrBrowse);
if (regErr) LogMsg("Registration of local-only browse domain %s failed", zone.c);
SecKeychainItemFreeContent(authAttrList, data);
}
mDNSlocal void InitAuthInfo(mDNS *m);
mDNSlocal OSStatus KeychainCallback(SecKeychainEvent event, SecKeychainCallbackInfo *info, void *context)
{
(void)event;
(void)info;
debugf("SecKeychainAddCallback received event %d", event);
InitAuthInfo((mDNS *)context); return 0;
}
mDNSexport void InitAuthInfo(mDNS *m)
{
OSStatus err;
SecKeychainSearchRef searchRef = NULL;
SecKeychainRef sysKeychain = NULL;
SecKeychainAttribute searchAttrs[] = { { kSecDescriptionItemAttr, strlen(LH_KEYCHAIN_DESC), LH_KEYCHAIN_DESC },
{ kSecServiceItemAttr, strlen(LH_KEYCHAIN_SERVICE), LH_KEYCHAIN_SERVICE } };
SecKeychainAttributeList searchList = { sizeof(searchAttrs) / sizeof(*searchAttrs), searchAttrs };
SecKeychainItemRef item;
mDNS_ClearAuthenticationList(m);
err = SecKeychainOpen(SYS_KEYCHAIN_PATH, &sysKeychain);
if (err) { LogMsg("ERROR: InitAuthInfo - couldn't open system keychain - %d", err); goto release_refs; }
err = SecKeychainSetDomainDefault(kSecPreferencesDomainSystem, sysKeychain);
if (err) { LogMsg("ERROR: InitAuthInfo - couldn't set domain default for system keychain - %d", err); goto release_refs; }
err = SecKeychainSearchCreateFromAttributes(sysKeychain, kSecGenericPasswordItemClass, &searchList, &searchRef);
if (err) { LogMsg("ERROR: InitAuthInfo - SecKeychainSearchCreateFromAttributes %d", err); goto release_refs; }
while (!SecKeychainSearchCopyNext(searchRef, &item))
{
GetAuthInfoFromKeychainItem(m, item);
CFRelease(item);
}
err = SecKeychainAddCallback(KeychainCallback, kSecAddEventMask | kSecDeleteEventMask | kSecUpdateEventMask | kSecPasswordChangedEventMask, m);
if (err && err != errSecDuplicateCallback) { LogMsg("SecKeychainAddCallback returned error %d", err); }
release_refs:
if (searchRef) CFRelease(searchRef);
if (sysKeychain) CFRelease(sysKeychain);
}
CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
mDNSexport mDNSBool 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_ReceiveUnicast(void)
{
int err;
int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
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) debugf("No unicast UDP responses");
else debugf("Unicast UDP responses okay");
return(err == 0);
}
mDNSlocal mDNSBool GetConfigOption(char *dst, const char *option, FILE *f)
{
char buf[1024];
int len;
if (!fgets(buf, 1024, f)) { LogMsg("Option %s not set", option); return mDNSfalse; }
len = strlen(option);
if (!strncmp(buf, option, len))
{
strcpy(dst, buf + len + 1);
len = strlen(dst);
if ( len && dst[len-1] == '\n') dst[len-1] = '\0'; return mDNStrue;
}
LogMsg("Malformatted config file - %s not set", option);
return mDNSfalse;
}
mDNSlocal void ReadRegDomainFromConfig(mDNS *const m)
{
FILE *f;
uDNS_GlobalInfo *u = &m->uDNS_info;;
char key[MAX_ESCAPED_DOMAIN_NAME];
domainname key_d, name_d, service_d;
char secret[1024];
int slen;
mStatus err;
if (m->uDNS_info.NameRegDomain[0] || m->uDNS_info.ServiceRegDomain[0])
{ debugf("Options from config already set via keychain. Ignoring config file."); return; }
f = fopen(CONFIG_FILE, "r");
if (!f)
{
if (errno != ENOENT) LogMsg("ERROR: Config file exists, but cannot be opened.");
return;
}
if (!GetConfigOption(u->NameRegDomain, "name-reg", f)) goto end;
if (!GetConfigOption(u->ServiceRegDomain, "service-reg", f)) goto end;
if (!GetConfigOption(key, "key-name", f)) goto end;
if (!GetConfigOption(secret, "secret-64", f)) { LogMsg("ERROR: config file contains key without secret"); goto end; }
if (!MakeDomainNameFromDNSNameString(&service_d, u->ServiceRegDomain))
{ LogMsg("ERROR: config file contains bad service reg domain %s", u->ServiceRegDomain); u->ServiceRegDomain[0] = '\0'; }
if (!MakeDomainNameFromDNSNameString(&name_d, u->NameRegDomain))
{ LogMsg("ERROR: config file contains bad name reg domain %s", u->NameRegDomain); u->NameRegDomain[0] = '\0'; }
if (!MakeDomainNameFromDNSNameString(&key_d, key))
{ LogMsg("ERROR: config file contains bad key %s", key); key[0] = '\0'; }
if (key[0])
{
slen = strlen(secret);
if (u->ServiceRegDomain[0])
{
err = mDNS_UpdateDomainRequiresAuthentication(m, &service_d, &key_d, secret, slen, mDNStrue);
if (err) LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication returned %d for domain ", err, u->ServiceRegDomain);
}
if (u->NameRegDomain[0])
{
err = mDNS_UpdateDomainRequiresAuthentication(m, &name_d, &key_d, secret, slen, mDNStrue);
if (err) LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication returned %d for domain ", err, u->NameRegDomain);
}
}
end:
fclose(f);
}
mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
{
return mDNS_CopyDNameList(DefBrowseList);
}
mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
{
static DNameListElem tmp;
static mDNSBool init = mDNSfalse;
if (!init)
{
MakeDomainNameFromDNSNameString(&tmp.name, "local.");
tmp.next = NULL;
init = mDNStrue;
}
return mDNS_CopyDNameList(&tmp);
}
mDNSlocal void FoundDefBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
DNameListElem *ptr, *prev, *new;
(void)m; (void)question;
if (AddRecord)
{
new = mallocL("FoundDefBrowseDomain", sizeof(DNameListElem));
if (!new) { LogMsg("ERROR: malloc"); return; }
strcpy(new->name.c, answer->rdata->u.name.c);
new->next = DefBrowseList;
DefBrowseList = new;
return;
}
else
{
ptr = DefBrowseList;
prev = NULL;
while (ptr)
{
if (SameDomainName(&ptr->name, &answer->rdata->u.name))
{
if (prev) prev->next = ptr->next;
else DefBrowseList = ptr->next;
freeL("FoundDefBrowseDomain", ptr);
return;
}
prev = ptr;
ptr = ptr->next;
}
LogMsg("FoundDefBrowseDomain: Got remove event for domain %s not in list", answer->rdata->u.name.c);
}
}
mDNSlocal mStatus InitDNSConfig(mDNS *const m)
{
mStatus err;
AuthRecord local;
DNSConfigInitialized = mDNStrue;
err = mDNS_GetDomains(m, &DefBrowseDomainQ, mDNS_DomainTypeBrowse, NULL, mDNSInterface_LocalOnly, FoundDefBrowseDomain, NULL);
mDNS_SetupResourceRecord(&local, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
MakeDomainNameFromDNSNameString(&local.resrec.name, "_browse._dns-sd._udp.local.");
MakeDomainNameFromDNSNameString(&local.resrec.rdata->u.name, "local.");
FoundDefBrowseDomain(m, &DefBrowseDomainQ, &local.resrec, 1);
return mStatus_NoError;
}
mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
{
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_ReceiveUnicast()) m->CanReceiveUnicast = 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->p->unicastsockets, zeroIPPort, &zeroAddr, AF_INET);
err = SetupSocket(&m->p->unicastsockets, zeroIPPort, &zeroAddr, AF_INET6);
m->p->InterfaceList = mDNSNULL;
m->p->userhostlabel.c[0] = 0;
UpdateInterfaceList(m);
SetupActiveInterfaces(m);
err = WatchForNetworkChanges(m);
if (err) return(err);
err = WatchForPowerChanges(m);
if (err) return err;
err = WatchForDNSChanges(m);
InitDNSConfig(m);
m->uDNS_info.ServiceRegDomain[0] = '\0';
m->uDNS_info.NameRegDomain[0] = '\0';
InitAuthInfo(m);
ReadRegDomainFromConfig(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 = NULL;
m->p->PowerNotifier = NULL;
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;
}
MarkAllInterfacesInactive(m);
ClearInactiveInterfaces(m);
CloseSocketSet(&m->p->unicastsockets);
}
mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
mDNSexport mStatus mDNSPlatformTimeInit(mDNSs32 *timenow)
{
struct mach_timebase_info tbi;
kern_return_t result = mach_timebase_info(&tbi);
if (result != KERN_SUCCESS) return(result);
clockdivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
*timenow = mDNSPlatformTimeNow();
return(mStatus_NoError);
}
mDNSexport mDNSs32 mDNSPlatformTimeNow(void)
{
if (clockdivisor == 0) { LogMsg("mDNSPlatformTimeNow called before mDNSPlatformTimeInit"); return(0); }
return((mDNSs32)(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); }