#include <mach/mach.h>
#include <mach/mach_error.h>
#include <servers/bootstrap.h>
#include <sys/types.h>
#include <unistd.h>
#include <paths.h>
#include <fcntl.h>
#include <pwd.h>
#include "DNSServiceDiscoveryRequestServer.h"
#include "DNSServiceDiscoveryReply.h"
#include "mDNSClientAPI.h" // Defines the interface to the client layer above
#include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
#include <DNSServiceDiscovery/DNSServiceDiscovery.h>
#define ENABLE_UDS 1
#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
mDNSexport mDNS mDNSStorage;
static mDNS_PlatformSupport PlatformStorage;
#define RR_CACHE_SIZE 64
static CacheRecord rrcachestorage[RR_CACHE_SIZE];
static const char PID_FILE[] = "/var/run/mDNSResponder.pid";
static const char kmDNSBootstrapName[] = "com.apple.mDNSResponderRestart";
static mach_port_t client_death_port = MACH_PORT_NULL;
static mach_port_t exit_m_port = MACH_PORT_NULL;
static mach_port_t info_m_port = MACH_PORT_NULL;
static mach_port_t server_priv_port = MACH_PORT_NULL;
#define MDNS_MM_TIMEOUT 250
static int restarting_via_mach_init = 0;
#if MDNS_DEBUGMSGS
int debug_mode = 1;
#else
int debug_mode = 0;
#endif
typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration;
struct DNSServiceDomainEnumeration_struct
{
DNSServiceDomainEnumeration *next;
mach_port_t ClientMachPort;
DNSQuestion dom; DNSQuestion def; };
typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult;
struct DNSServiceBrowserResult_struct
{
DNSServiceBrowserResult *next;
int resultType;
domainname result;
};
typedef struct DNSServiceBrowser_struct DNSServiceBrowser;
struct DNSServiceBrowser_struct
{
DNSServiceBrowser *next;
mach_port_t ClientMachPort;
DNSQuestion q;
DNSServiceBrowserResult *results;
mDNSs32 lastsuccess;
};
typedef struct DNSServiceResolver_struct DNSServiceResolver;
struct DNSServiceResolver_struct
{
DNSServiceResolver *next;
mach_port_t ClientMachPort;
ServiceInfoQuery q;
ServiceInfo i;
mDNSs32 ReportTime;
};
typedef struct DNSServiceRegistration_struct DNSServiceRegistration;
struct DNSServiceRegistration_struct
{
DNSServiceRegistration *next;
mach_port_t ClientMachPort;
mDNSBool autoname;
mDNSBool autorename;
domainlabel name;
ServiceRecordSet s;
};
static DNSServiceDomainEnumeration *DNSServiceDomainEnumerationList = NULL;
static DNSServiceBrowser *DNSServiceBrowserList = NULL;
static DNSServiceResolver *DNSServiceResolverList = NULL;
static DNSServiceRegistration *DNSServiceRegistrationList = NULL;
#if MACOSX_MDNS_MALLOC_DEBUGGING
char _malloc_options[] = "AXZ";
static void validatelists(mDNS *const m)
{
DNSServiceDomainEnumeration *e;
DNSServiceBrowser *b;
DNSServiceResolver *l;
DNSServiceRegistration *r;
AuthRecord *rr;
CacheRecord *cr;
DNSQuestion *q;
mDNSs32 slot;
for (e = DNSServiceDomainEnumerationList; e; e=e->next)
if (e->ClientMachPort == 0 || e->ClientMachPort == (mach_port_t)~0)
LogMsg("!!!! DNSServiceDomainEnumerationList: %p is garbage (%X) !!!!", e, e->ClientMachPort);
for (b = DNSServiceBrowserList; b; b=b->next)
if (b->ClientMachPort == 0 || b->ClientMachPort == (mach_port_t)~0)
LogMsg("!!!! DNSServiceBrowserList: %p is garbage (%X) !!!!", b, b->ClientMachPort);
for (l = DNSServiceResolverList; l; l=l->next)
if (l->ClientMachPort == 0 || l->ClientMachPort == (mach_port_t)~0)
LogMsg("!!!! DNSServiceResolverList: %p is garbage (%X) !!!!", l, l->ClientMachPort);
for (r = DNSServiceRegistrationList; r; r=r->next)
if (r->ClientMachPort == 0 || r->ClientMachPort == (mach_port_t)~0)
LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r, r->ClientMachPort);
for (rr = m->ResourceRecords; rr; rr=rr->next)
if (rr->RecordType == 0 || rr->RecordType == 0xFF)
LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr, rr->RecordType);
for (rr = m->DuplicateRecords; rr; rr=rr->next)
if (rr->RecordType == 0 || rr->RecordType == 0xFF)
LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr, rr->RecordType);
for (q = m->Questions; q; q=q->next)
if (q->ThisQInterval == (mDNSs32)~0)
LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q, q->ThisQInterval);
for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
for (cr = mDNSStorage.rrcache_hash[slot]; cr; cr=cr->next)
if (cr->RecordType == 0 || cr->RecordType == 0xFF)
LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot, rr, rr->RecordType);
}
void *mallocL(char *msg, unsigned int size)
{
unsigned long *mem = malloc(size+8);
if (!mem)
{
LogMsg("malloc( %s : %d ) failed", msg, size);
return(NULL);
}
else
{
LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
mem[0] = 0xDEAD1234;
mem[1] = size;
memset(&mem[2], 0xFF, size);
validatelists(&mDNSStorage);
return(&mem[2]);
}
}
void freeL(char *msg, void *x)
{
if (!x)
LogMsg("free( %s @ NULL )!", msg);
else
{
unsigned long *mem = ((unsigned long *)x) - 2;
if (mem[0] != 0xDEAD1234)
{ LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
if (mem[1] > 8000)
{ LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; }
LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
memset(mem, 0xFF, mem[1]+8);
validatelists(&mDNSStorage);
free(mem);
}
}
#endif
mDNSlocal void FreeDNSServiceRegistration(DNSServiceRegistration *x)
{
while (x->s.Extras)
{
ExtraResourceRecord *extras = x->s.Extras;
x->s.Extras = x->s.Extras->next;
if (extras->r.resrec.rdata != &extras->r.rdatastorage)
freeL("Extra RData", extras->r.resrec.rdata);
freeL("ExtraResourceRecord", extras);
}
if (x->s.RR_TXT.resrec.rdata != &x->s.RR_TXT.rdatastorage)
freeL("TXT RData", x->s.RR_TXT.resrec.rdata);
if (x->s.SubTypes) freeL("ServiceSubTypes", x->s.SubTypes);
freeL("DNSServiceRegistration", x);
}
mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
{
DNSServiceDomainEnumeration **e = &DNSServiceDomainEnumerationList;
DNSServiceBrowser **b = &DNSServiceBrowserList;
DNSServiceResolver **l = &DNSServiceResolverList;
DNSServiceRegistration **r = &DNSServiceRegistrationList;
while (*e && (*e)->ClientMachPort != ClientMachPort) e = &(*e)->next;
if (*e)
{
DNSServiceDomainEnumeration *x = *e;
*e = (*e)->next;
if (m && m != x)
LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->dom.qname.c, m, x);
else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort, x->dom.qname.c);
mDNS_StopGetDomains(&mDNSStorage, &x->dom);
mDNS_StopGetDomains(&mDNSStorage, &x->def);
freeL("DNSServiceDomainEnumeration", x);
return;
}
while (*b && (*b)->ClientMachPort != ClientMachPort) b = &(*b)->next;
if (*b)
{
DNSServiceBrowser *x = *b;
*b = (*b)->next;
if (m && m != x)
LogMsg("%5d: DNSServiceBrowser(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->q.qname.c, m, x);
else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort, x->q.qname.c);
mDNS_StopBrowse(&mDNSStorage, &x->q);
while (x->results)
{
DNSServiceBrowserResult *r = x->results;
x->results = x->results->next;
freeL("DNSServiceBrowserResult", r);
}
freeL("DNSServiceBrowser", x);
return;
}
while (*l && (*l)->ClientMachPort != ClientMachPort) l = &(*l)->next;
if (*l)
{
DNSServiceResolver *x = *l;
*l = (*l)->next;
if (m && m != x)
LogMsg("%5d: DNSServiceResolver(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->i.name.c, m, x);
else LogOperation("%5d: DNSServiceResolver(%##s) STOP", ClientMachPort, x->i.name.c);
mDNS_StopResolveService(&mDNSStorage, &x->q);
freeL("DNSServiceResolver", x);
return;
}
while (*r && (*r)->ClientMachPort != ClientMachPort) r = &(*r)->next;
if (*r)
{
DNSServiceRegistration *x = *r;
*r = (*r)->next;
x->autorename = mDNSfalse;
if (m && m != x)
LogMsg("%5d: DNSServiceRegistration(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->s.RR_SRV.resrec.name.c, m, x);
else LogOperation("%5d: DNSServiceRegistration(%##s) STOP", ClientMachPort, x->s.RR_SRV.resrec.name.c);
if (mDNS_DeregisterService(&mDNSStorage, &x->s) != mStatus_NoError)
FreeDNSServiceRegistration(x);
return;
}
LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort);
}
#define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
mDNSlocal void AbortClientWithLogMessage(mach_port_t c, char *reason, char *msg, void *m)
{
DNSServiceDomainEnumeration *e = DNSServiceDomainEnumerationList;
DNSServiceBrowser *b = DNSServiceBrowserList;
DNSServiceResolver *l = DNSServiceResolverList;
DNSServiceRegistration *r = DNSServiceRegistrationList;
while (e && e->ClientMachPort != c) e = e->next;
while (b && b->ClientMachPort != c) b = b->next;
while (l && l->ClientMachPort != c) l = l->next;
while (r && r->ClientMachPort != c) r = r->next;
if (e) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c, e->dom.qname.c, reason, msg);
else if (b) LogMsg("%5d: Browser(%##s) %s%s", c, b->q.qname.c, reason, msg);
else if (l) LogMsg("%5d: Resolver(%##s) %s%s", c, l->i.name.c, reason, msg);
else if (r) LogMsg("%5d: Registration(%##s) %s%s", c, r->s.RR_SRV.resrec.name.c, reason, msg);
else LogMsg("%5d: (%s) %s, but no record of client can be found!", c, reason, msg);
AbortClient(c, m);
}
mDNSlocal mDNSBool CheckForExistingClient(mach_port_t c)
{
DNSServiceDomainEnumeration *e = DNSServiceDomainEnumerationList;
DNSServiceBrowser *b = DNSServiceBrowserList;
DNSServiceResolver *l = DNSServiceResolverList;
DNSServiceRegistration *r = DNSServiceRegistrationList;
while (e && e->ClientMachPort != c) e = e->next;
while (b && b->ClientMachPort != c) b = b->next;
while (l && l->ClientMachPort != c) l = l->next;
while (r && r->ClientMachPort != c) r = r->next;
if (e) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c, e->dom.qname.c);
if (b) LogMsg("%5d: Browser(%##s) already exists!", c, b->q.qname.c);
if (l) LogMsg("%5d: Resolver(%##s) already exists!", c, l->i.name.c);
if (r) LogMsg("%5d: Registration(%##s) already exists!", c, r->s.RR_SRV.resrec.name.c);
return(e || b || l || r);
}
mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIndex size, void *info)
{
mach_msg_header_t *msg = (mach_msg_header_t *)voidmsg;
(void)unusedport; (void)size; (void)info; if (msg->msgh_id == MACH_NOTIFY_DEAD_NAME)
{
const mach_dead_name_notification_t *const deathMessage = (mach_dead_name_notification_t *)msg;
AbortClient(deathMessage->not_port, NULL);
mach_port_destroy( mach_task_self(), deathMessage->not_port );
}
}
mDNSlocal void EnableDeathNotificationForClient(mach_port_t ClientMachPort, void *m)
{
mach_port_t prev;
kern_return_t r = mach_port_request_notification(mach_task_self(), ClientMachPort, MACH_NOTIFY_DEAD_NAME, 0,
client_death_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
if (r != KERN_SUCCESS)
AbortClientWithLogMessage(ClientMachPort, "died/deallocated before we could enable death notification", "", m);
}
mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
kern_return_t status;
#pragma unused(m)
char buffer[MAX_ESCAPED_DOMAIN_NAME];
DNSServiceDomainEnumerationReplyResultType rt;
DNSServiceDomainEnumeration *x = (DNSServiceDomainEnumeration *)question->QuestionContext;
debugf("FoundDomain: %##s PTR %##s", answer->name.c, answer->rdata->u.name.c);
if (answer->rrtype != kDNSType_PTR) return;
if (!x) { debugf("FoundDomain: DNSServiceDomainEnumeration is NULL"); return; }
if (AddRecord)
{
if (question == &x->dom) rt = DNSServiceDomainEnumerationReplyAddDomain;
else rt = DNSServiceDomainEnumerationReplyAddDomainDefault;
}
else
{
if (question == &x->dom) rt = DNSServiceDomainEnumerationReplyRemoveDomain;
else return;
}
LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
x->ClientMachPort, x->dom.qname.c, answer->rdata->u.name.c,
!AddRecord ? "RemoveDomain" :
question == &x->dom ? "AddDomain" : "AddDomainDefault");
ConvertDomainNameToCString(&answer->rdata->u.name, buffer);
status = DNSServiceDomainEnumerationReply_rpc(x->ClientMachPort, rt, buffer, 0, MDNS_MM_TIMEOUT);
if (status == MACH_SEND_TIMED_OUT)
AbortBlockedClient(x->ClientMachPort, "enumeration", x);
}
mDNSexport kern_return_t provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver, mach_port_t client,
int regDom)
{
(void)unusedserver; mStatus err = mStatus_NoError;
const char *errormsg = "Unknown";
if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
mDNS_DomainType dt1 = regDom ? mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
mDNS_DomainType dt2 = regDom ? mDNS_DomainTypeRegistrationDefault : mDNS_DomainTypeBrowseDefault;
const DNSServiceDomainEnumerationReplyResultType rt = DNSServiceDomainEnumerationReplyAddDomainDefault;
DNSServiceDomainEnumeration *x = mallocL("DNSServiceDomainEnumeration", sizeof(*x));
if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
x->ClientMachPort = client;
x->next = DNSServiceDomainEnumerationList;
DNSServiceDomainEnumerationList = x;
verbosedebugf("%5d: Enumerate %s Domains", client, regDom ? "Registration" : "Browsing");
kern_return_t status = DNSServiceDomainEnumerationReply_rpc(x->ClientMachPort, rt, "local.", 0, MDNS_MM_TIMEOUT);
if (status == MACH_SEND_TIMED_OUT)
{ AbortBlockedClient(x->ClientMachPort, "local enumeration", x); return(mStatus_UnknownErr); }
err = mDNS_GetDomains(&mDNSStorage, &x->dom, dt1, mDNSInterface_Any, FoundDomain, x);
if (!err) err = mDNS_GetDomains(&mDNSStorage, &x->def, dt2, mDNSInterface_Any, FoundDomain, x);
if (err) { AbortClient(client, x); errormsg = "mDNS_GetDomains"; goto fail; }
LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client, x->dom.qname.c);
EnableDeathNotificationForClient(client, x);
return(mStatus_NoError);
fail:
LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client, regDom, errormsg, err);
return(err);
}
mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
(void)m;
if (answer->rrtype != kDNSType_PTR)
{ LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer->rrtype); return; }
domainlabel name;
domainname type, domain;
if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain))
{
LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
answer->name.c, answer->rdata->u.name.c);
return;
}
DNSServiceBrowserResult *x = mallocL("DNSServiceBrowserResult", sizeof(*x));
if (!x) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer->rdata->u.name.c); return; }
verbosedebugf("FoundInstance: %s %##s", AddRecord ? "Add" : "Rmv", answer->rdata->u.name.c);
AssignDomainName(x->result, answer->rdata->u.name);
if (AddRecord)
x->resultType = DNSServiceBrowserReplyAddInstance;
else x->resultType = DNSServiceBrowserReplyRemoveInstance;
x->next = NULL;
DNSServiceBrowser *browser = (DNSServiceBrowser *)question->QuestionContext;
DNSServiceBrowserResult **p = &browser->results;
while (*p) p = &(*p)->next;
*p = x;
}
mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver, mach_port_t client,
DNSCString regtype, DNSCString domain)
{
(void)unusedserver; mStatus err = mStatus_NoError;
const char *errormsg = "Unknown";
if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
domainname t, d;
if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Illegal regtype"; goto badparam; }
if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Illegal domain"; goto badparam; }
DNSServiceBrowser *x = mallocL("DNSServiceBrowser", sizeof(*x));
if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
x->ClientMachPort = client;
x->results = NULL;
x->lastsuccess = 0;
x->next = DNSServiceBrowserList;
DNSServiceBrowserList = x;
LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", client, t.c, d.c);
err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSInterface_Any, FoundInstance, x);
if (err) { AbortClient(client, x); errormsg = "mDNS_StartBrowse"; goto fail; }
EnableDeathNotificationForClient(client, x);
return(mStatus_NoError);
badparam:
err = mStatus_BadParamErr;
fail:
LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client, regtype, domain, errormsg, err);
return(err);
}
mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
{
kern_return_t status;
DNSServiceResolver *x = (DNSServiceResolver *)query->ServiceInfoQueryContext;
NetworkInterfaceInfoOSX *ifx = (NetworkInterfaceInfoOSX *)query->info->InterfaceID;
if (query->info->InterfaceID == (mDNSInterfaceID)~0) ifx = mDNSNULL;
struct sockaddr_storage interface;
struct sockaddr_storage address;
char cstring[1024];
int i, pstrlen = query->info->TXTinfo[0];
(void)m;
if (query->info->TXTlen > sizeof(cstring)) return;
bzero(&interface, sizeof(interface));
bzero(&address, sizeof(address));
if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv4)
{
struct sockaddr_in *sin = (struct sockaddr_in*)&interface;
sin->sin_len = sizeof(*sin);
sin->sin_family = AF_INET;
sin->sin_port = 0;
sin->sin_addr.s_addr = ifx->ifinfo.ip.ip.v4.NotAnInteger;
}
else if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv6)
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&interface;
sin6->sin6_len = sizeof(*sin6);
sin6->sin6_family = AF_INET6;
sin6->sin6_flowinfo = 0;
sin6->sin6_port = 0;
sin6->sin6_addr = *(struct in6_addr*)&ifx->ifinfo.ip.ip.v6;
sin6->sin6_scope_id = ifx->scope_id;
}
if (query->info->ip.type == mDNSAddrType_IPv4)
{
struct sockaddr_in *sin = (struct sockaddr_in*)&address;
sin->sin_len = sizeof(*sin);
sin->sin_family = AF_INET;
sin->sin_port = query->info->port.NotAnInteger;
sin->sin_addr.s_addr = query->info->ip.ip.v4.NotAnInteger;
}
else
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&address;
sin6->sin6_len = sizeof(*sin6);
sin6->sin6_family = AF_INET6;
sin6->sin6_port = query->info->port.NotAnInteger;
sin6->sin6_flowinfo = 0;
sin6->sin6_addr = *(struct in6_addr*)&query->info->ip.ip.v6;
sin6->sin6_scope_id = ifx ? ifx->scope_id : 0;
}
for (i=1; i<query->info->TXTlen; i++)
{
if (--pstrlen >= 0)
cstring[i-1] = query->info->TXTinfo[i];
else
{
cstring[i-1] = 1;
pstrlen = query->info->TXTinfo[i];
}
}
cstring[i-1] = 0;
LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%d", x->ClientMachPort,
x->i.name.c, &query->info->ip, (int)query->info->port.b[0] << 8 | query->info->port.b[1]);
status = DNSServiceResolverReply_rpc(x->ClientMachPort,
(char*)&interface, (char*)&address, cstring, 0, MDNS_MM_TIMEOUT);
if (status == MACH_SEND_TIMED_OUT)
AbortBlockedClient(x->ClientMachPort, "resolve", x);
}
mDNSexport kern_return_t provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver, mach_port_t client,
DNSCString name, DNSCString regtype, DNSCString domain)
{
(void)unusedserver; mStatus err = mStatus_NoError;
const char *errormsg = "Unknown";
if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
domainlabel n;
domainname t, d, srv;
if (!name[0] || !MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; }
if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Bad Domain"; goto badparam; }
if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; }
DNSServiceResolver *x = mallocL("DNSServiceResolver", sizeof(*x));
if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
x->ClientMachPort = client;
x->i.InterfaceID = mDNSInterface_Any;
x->i.name = srv;
x->ReportTime = (mDNSPlatformTimeNow() + 130 * mDNSPlatformOneSecond) | 1;
if (SameDomainLabel(t.c, (mDNSu8*)"\x6_ichat")) x->ReportTime = 0;
x->next = DNSServiceResolverList;
DNSServiceResolverList = x;
LogOperation("%5d: DNSServiceResolver(%##s) START", client, x->i.name.c);
err = mDNS_StartResolveService(&mDNSStorage, &x->q, &x->i, FoundInstanceInfo, x);
if (err) { AbortClient(client, x); errormsg = "mDNS_StartResolveService"; goto fail; }
EnableDeathNotificationForClient(client, x);
return(mStatus_NoError);
badparam:
err = mStatus_BadParamErr;
fail:
LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client, name, regtype, domain, errormsg, err);
return(err);
}
mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result)
{
DNSServiceRegistration *x = (DNSServiceRegistration*)sr->ServiceContext;
if (result == mStatus_NoError)
{
kern_return_t status;
LogOperation("%5d: DNSServiceRegistration(%##s) Name Registered", x->ClientMachPort, sr->RR_SRV.resrec.name.c);
status = DNSServiceRegistrationReply_rpc(x->ClientMachPort, result, MDNS_MM_TIMEOUT);
if (status == MACH_SEND_TIMED_OUT)
AbortBlockedClient(x->ClientMachPort, "registration success", x);
}
else if (result == mStatus_NameConflict)
{
LogOperation("%5d: DNSServiceRegistration(%##s) Name Conflict", x->ClientMachPort, sr->RR_SRV.resrec.name.c);
if (x->autoname)
mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
else
{
kern_return_t status = DNSServiceRegistrationReply_rpc(x->ClientMachPort, result, MDNS_MM_TIMEOUT);
if (status == MACH_SEND_TIMED_OUT)
AbortBlockedClient(x->ClientMachPort, "registration conflict", x);
}
}
else if (result == mStatus_MemFree)
{
if (x->autorename)
{
debugf("RegCallback renaming %#s to %#s", x->name.c, mDNSStorage.nicelabel.c);
x->autorename = mDNSfalse;
x->name = mDNSStorage.nicelabel;
mDNS_RenameAndReregisterService(m, &x->s, &x->name);
}
else
{
DNSServiceRegistration **r = &DNSServiceRegistrationList;
while (*r && *r != x) r = &(*r)->next;
if (*r)
{
LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", sr->RR_SRV.resrec.name.c);
*r = (*r)->next;
}
LogOperation("%5d: DNSServiceRegistration(%##s) Memory Free", x->ClientMachPort, sr->RR_SRV.resrec.name.c);
FreeDNSServiceRegistration(x);
}
}
else
LogMsg("%5d: DNSServiceRegistration(%##s) Unknown Result %ld",
x->ClientMachPort, sr->RR_SRV.resrec.name.c, result);
}
mDNSlocal void CheckForDuplicateRegistrations(DNSServiceRegistration *x, domainname *srv, mDNSIPPort port)
{
int count = 1; AuthRecord *rr;
for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
if (rr->resrec.rrtype == kDNSType_SRV &&
rr->resrec.rdata->u.srv.port.NotAnInteger == port.NotAnInteger &&
SameDomainName(&rr->resrec.name, srv))
count++;
if (count > 1)
LogMsg("%5d: Client application registered %d identical instances of service %##s port %d.",
x->ClientMachPort, count, srv->c, (int)port.b[0] << 8 | port.b[1]);
}
mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver, mach_port_t client,
DNSCString name, DNSCString regtype, DNSCString domain, int notAnIntPort, DNSCString txtRecord)
{
(void)unusedserver; mStatus err = mStatus_NoError;
const char *errormsg = "Unknown";
if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
AuthRecord *SubTypes = mDNSNULL;
mDNSu32 i, NumSubTypes = 0;
char *comma = regtype;
while (*comma && *comma != ',') comma++;
if (*comma) {
*comma = 0; char *p = comma + 1; while (*p)
{
if ( !(*p && *p != ',')) { errormsg = "Bad Service SubType"; goto badparam; }
while (*p && *p != ',') p++;
if (*p) *p++ = 0;
NumSubTypes++;
}
}
domainlabel n;
domainname t, d;
domainname srv;
if (!name[0]) n = mDNSStorage.nicelabel;
else if (!MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; }
if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Bad Domain"; goto badparam; }
if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; }
mDNSIPPort port;
port.NotAnInteger = notAnIntPort;
unsigned char txtinfo[1024] = "";
unsigned int data_len = 0;
unsigned int size = sizeof(RDataBody);
unsigned char *pstring = &txtinfo[data_len];
char *ptr = txtRecord;
while (*ptr)
{
if (++data_len >= sizeof(txtinfo)) { errormsg = "TXT record too long"; goto badtxt; }
if (*ptr == 1) {
pstring = &txtinfo[data_len];
pstring[0] = 0;
ptr++;
}
else
{
if (pstring[0] == 255) { errormsg = "TXT record invalid (component longer than 255)"; goto badtxt; }
pstring[++pstring[0]] = *ptr++;
}
}
data_len++;
if (size < data_len)
size = data_len;
DNSServiceRegistration *x = mallocL("DNSServiceRegistration", sizeof(*x) - sizeof(RDataBody) + size);
if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
if (NumSubTypes)
{
SubTypes = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
if (!SubTypes) { freeL("DNSServiceRegistration", x); err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
for (i = 0; i < NumSubTypes; i++)
{
comma++; MakeDomainNameFromDNSNameString(&SubTypes[i].resrec.name, comma);
while (*comma) comma++; }
}
x->ClientMachPort = client;
x->autoname = (!name[0]);
x->autorename = mDNSfalse;
x->name = n;
x->next = DNSServiceRegistrationList;
DNSServiceRegistrationList = x;
LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\") START", x->ClientMachPort, name, regtype, domain);
if (port.NotAnInteger) CheckForDuplicateRegistrations(x, &srv, port);
err = mDNS_RegisterService(&mDNSStorage, &x->s,
&x->name, &t, &d, mDNSNULL, port, txtinfo, data_len, SubTypes, NumSubTypes, mDNSInterface_Any, RegCallback, x);
if (err) { AbortClient(client, x); errormsg = "mDNS_RegisterService"; goto fail; }
EnableDeathNotificationForClient(client, x);
return(mStatus_NoError);
badtxt:
LogMsg("%5d: TXT record: %.100s...", client, txtRecord);
badparam:
err = mStatus_BadParamErr;
fail:
LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
client, name, regtype, domain, notAnIntPort, errormsg, err);
return(err);
}
mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
{
(void)m; if (result == mStatus_ConfigChanged)
{
DNSServiceRegistration *r;
for (r = DNSServiceRegistrationList; r; r=r->next)
if (r->autoname && !SameDomainLabel(r->name.c, mDNSStorage.nicelabel.c))
{
debugf("NetworkChanged renaming %#s to %#s", r->name.c, mDNSStorage.nicelabel.c);
r->autorename = mDNStrue;
mDNS_DeregisterService(&mDNSStorage, &r->s);
}
}
else if (result == mStatus_GrowCache)
{
mDNSu32 numrecords = m->rrcache_size;
CacheRecord *storage = mallocL("mStatus_GrowCache", sizeof(CacheRecord) * numrecords);
if (storage) mDNS_GrowCache(&mDNSStorage, storage, numrecords);
}
}
mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver, mach_port_t client,
int type, const char *data, mach_msg_type_number_t data_len, uint32_t ttl, natural_t *reference)
{
(void)unusedserver; mStatus err = mStatus_NoError;
const char *errormsg = "Unknown";
domainname *name = (domainname *)"";
if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
DNSServiceRegistration *x = DNSServiceRegistrationList;
while (x && x->ClientMachPort != client) x = x->next;
if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; }
name = &x->s.RR_SRV.resrec.name;
if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; }
unsigned int size = sizeof(RDataBody);
if (size < data_len)
size = data_len;
ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
if (!extra) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
extra->r.resrec.rrtype = type;
extra->r.rdatastorage.MaxRDLength = size;
extra->r.resrec.rdlength = data_len;
memcpy(&extra->r.rdatastorage.u.data, data, data_len);
LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
client, x->s.RR_SRV.resrec.name.c, type, data_len, extra);
err = mDNS_AddRecordToService(&mDNSStorage, &x->s, extra, &extra->r.rdatastorage, ttl);
*reference = (natural_t)extra;
if (err) { errormsg = "mDNS_AddRecordToService"; goto fail; }
return(mStatus_NoError);
fail:
LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client, name->c, type, data_len, errormsg, err);
return(err);
}
mDNSlocal void UpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData)
{
(void)m; if (OldRData != &rr->rdatastorage)
freeL("Old RData", OldRData);
}
mDNSexport kern_return_t provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver, mach_port_t client,
natural_t reference, const char *data, mach_msg_type_number_t data_len, uint32_t ttl)
{
(void)unusedserver; mStatus err = mStatus_NoError;
const char *errormsg = "Unknown";
domainname *name = (domainname *)"";
if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
DNSServiceRegistration *x = DNSServiceRegistrationList;
while (x && x->ClientMachPort != client) x = x->next;
if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; }
name = &x->s.RR_SRV.resrec.name;
if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; }
unsigned int size = sizeof(RDataBody);
if (size < data_len)
size = data_len;
AuthRecord *rr = &x->s.RR_TXT;
if (reference) {
ExtraResourceRecord *e = x->s.Extras;
while (e && e != (ExtraResourceRecord*)reference) e = e->next;
if (!e) { err = mStatus_BadReferenceErr; errormsg = "No such record"; goto fail; }
rr = &e->r;
}
RData *newrdata = mallocL("RData", sizeof(*newrdata) - sizeof(RDataBody) + size);
if (!newrdata) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
newrdata->MaxRDLength = size;
memcpy(&newrdata->u, data, data_len);
LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, new length %d)",
client, x->s.RR_SRV.resrec.name.c, reference, data_len);
err = mDNS_Update(&mDNSStorage, rr, ttl, data_len, newrdata, UpdateCallback);
if (err) { errormsg = "mDNS_Update"; goto fail; }
return(mStatus_NoError);
fail:
LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client, name->c, reference, data_len, errormsg, err);
return(err);
}
mDNSexport kern_return_t provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver, mach_port_t client,
natural_t reference)
{
(void)unusedserver; mStatus err = mStatus_NoError;
const char *errormsg = "Unknown";
domainname *name = (domainname *)"";
if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
DNSServiceRegistration *x = DNSServiceRegistrationList;
while (x && x->ClientMachPort != client) x = x->next;
if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; }
name = &x->s.RR_SRV.resrec.name;
LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s, %X)", client, x->s.RR_SRV.resrec.name.c, reference);
ExtraResourceRecord *extra = (ExtraResourceRecord*)reference;
err = mDNS_RemoveRecordFromService(&mDNSStorage, &x->s, extra);
if (err) { errormsg = "mDNS_RemoveRecordFromService (No such record)"; goto fail; }
if (extra->r.resrec.rdata != &extra->r.rdatastorage)
freeL("Extra RData", extra->r.resrec.rdata);
freeL("ExtraResourceRecord", extra);
return(mStatus_NoError);
fail:
LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%##s, %X) failed: %s (%ld)", client, name->c, reference, errormsg, err);
return(err);
}
mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
{
mig_reply_error_t *request = msg;
mig_reply_error_t *reply;
mach_msg_return_t mr;
int options;
(void)port; (void)size; (void)info;
reply = CFAllocatorAllocate(NULL, provide_DNSServiceDiscoveryRequest_subsystem.maxsize, 0);
(void) DNSServiceDiscoveryRequest_server(&request->Head, &reply->Head);
if (!(reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (reply->RetCode != KERN_SUCCESS))
{
if (reply->RetCode == MIG_NO_REPLY)
{
CFAllocatorDeallocate(NULL, reply);
return;
}
request->Head.msgh_remote_port = MACH_PORT_NULL;
mach_msg_destroy(&request->Head);
}
if (reply->Head.msgh_remote_port == MACH_PORT_NULL)
{
if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
mach_msg_destroy(&reply->Head);
CFAllocatorDeallocate(NULL, reply);
return;
}
options = MACH_SEND_MSG;
if (MACH_MSGH_BITS_REMOTE(reply->Head.msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE)
options |= MACH_SEND_TIMEOUT;
mr = mach_msg(&reply->Head,
options,
reply->Head.msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
switch (mr)
{
case MACH_SEND_INVALID_DEST:
case MACH_SEND_TIMED_OUT:
mach_msg_destroy(&reply->Head);
break;
default :
break;
}
CFAllocatorDeallocate(NULL, reply);
}
mDNSlocal kern_return_t registerBootstrapService()
{
kern_return_t status;
mach_port_t service_send_port, service_rcv_port;
debugf("Registering Bootstrap Service");
status = bootstrap_check_in(bootstrap_port, (char*)kmDNSBootstrapName, &service_rcv_port);
if (status == KERN_SUCCESS)
{
server_priv_port = bootstrap_port;
restarting_via_mach_init = TRUE;
}
else if (status == BOOTSTRAP_UNKNOWN_SERVICE)
{
status = bootstrap_create_server(bootstrap_port, "/usr/sbin/mDNSResponder", getuid(),
FALSE , &server_priv_port);
if (status != KERN_SUCCESS) return status;
status = bootstrap_create_service(server_priv_port, (char*)kmDNSBootstrapName, &service_send_port);
if (status != KERN_SUCCESS)
{
mach_port_deallocate(mach_task_self(), server_priv_port);
return status;
}
status = bootstrap_check_in(server_priv_port, (char*)kmDNSBootstrapName, &service_rcv_port);
if (status != KERN_SUCCESS)
{
mach_port_deallocate(mach_task_self(), server_priv_port);
mach_port_deallocate(mach_task_self(), service_send_port);
return status;
}
assert(service_send_port == service_rcv_port);
}
mach_port_destroy(mach_task_self(), service_rcv_port);
return status;
}
mDNSlocal kern_return_t destroyBootstrapService()
{
debugf("Destroying Bootstrap Service");
return bootstrap_register(server_priv_port, (char*)kmDNSBootstrapName, MACH_PORT_NULL);
}
mDNSlocal void ExitCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
{
(void)port; (void)msg; (void)size; (void)info;
LogMsg("%s stopping", mDNSResponderVersionString);
debugf("ExitCallback: destroyBootstrapService");
if (!debug_mode)
destroyBootstrapService();
debugf("ExitCallback: Aborting MIG clients");
while (DNSServiceDomainEnumerationList)
AbortClient(DNSServiceDomainEnumerationList->ClientMachPort, DNSServiceDomainEnumerationList);
while (DNSServiceBrowserList)
AbortClient(DNSServiceBrowserList ->ClientMachPort, DNSServiceBrowserList);
while (DNSServiceResolverList)
AbortClient(DNSServiceResolverList ->ClientMachPort, DNSServiceResolverList);
while (DNSServiceRegistrationList)
AbortClient(DNSServiceRegistrationList ->ClientMachPort, DNSServiceRegistrationList);
debugf("ExitCallback: mDNS_Close");
mDNS_Close(&mDNSStorage);
#if ENABLE_UDS
if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
#endif
exit(0);
}
mDNSlocal void HandleSIGTERM(int signal)
{
(void)signal; debugf(" ");
debugf("SIGINT/SIGTERM");
mach_msg_header_t header;
header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
header.msgh_remote_port = exit_m_port;
header.msgh_local_port = MACH_PORT_NULL;
header.msgh_size = sizeof(header);
header.msgh_id = 0;
if (mach_msg_send(&header) != MACH_MSG_SUCCESS)
{ LogMsg("HandleSIGTERM: mach_msg_send failed; Exiting immediately."); exit(-1); }
}
mDNSlocal void INFOCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
{
(void)port; (void)msg; (void)size; (void)info; DNSServiceDomainEnumeration *e;
DNSServiceBrowser *b;
DNSServiceResolver *l;
DNSServiceRegistration *r;
mDNSs32 slot;
CacheRecord *rr;
mDNSu32 CacheUsed = 0, CacheActive = 0;
LogMsg("%s ---- BEGIN STATE LOG ----", mDNSResponderVersionString);
for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
for (rr = mDNSStorage.rrcache_hash[slot]; rr; rr=rr->next)
{
CacheUsed++;
if (rr->CRActiveQuestion) CacheActive++;
LogMsg("%s %-5s%-6s%s", rr->CRActiveQuestion ? "Active: " : "Inactive:", DNSTypeName(rr->resrec.rrtype),
((NetworkInterfaceInfoOSX *)rr->resrec.InterfaceID)->ifa_name, GetRRDisplayString(&mDNSStorage, rr));
usleep(1000); }
if (mDNSStorage.rrcache_totalused != CacheUsed)
LogMsg("Cache use mismatch: rrcache_totalused is %lu, true count %lu", mDNSStorage.rrcache_totalused, CacheUsed);
if (mDNSStorage.rrcache_active != CacheActive)
LogMsg("Cache use mismatch: rrcache_active is %lu, true count %lu", mDNSStorage.rrcache_active, CacheActive);
LogMsg("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed, CacheActive);
for (e = DNSServiceDomainEnumerationList; e; e=e->next)
LogMsg("%5d: DomainEnumeration %##s", e->ClientMachPort, e->dom.qname.c);
for (b = DNSServiceBrowserList; b; b=b->next)
LogMsg("%5d: ServiceBrowse %##s", b->ClientMachPort, b->q.qname.c);
for (l = DNSServiceResolverList; l; l=l->next)
LogMsg("%5d: ServiceResolve %##s", l->ClientMachPort, l->i.name.c);
for (r = DNSServiceRegistrationList; r; r=r->next)
LogMsg("%5d: ServiceRegistration %##s", r->ClientMachPort, r->s.RR_SRV.resrec.name.c);
udsserver_info();
LogMsg("%s ---- END STATE LOG ----", mDNSResponderVersionString);
}
mDNSlocal void HandleSIGINFO(int signal)
{
(void)signal; mach_msg_header_t header;
header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
header.msgh_remote_port = info_m_port;
header.msgh_local_port = MACH_PORT_NULL;
header.msgh_size = sizeof(header);
header.msgh_id = 0;
if (mach_msg_send(&header) != MACH_MSG_SUCCESS)
LogMsg("HandleSIGINFO: mach_msg_send failed; No state log will be generated.");
}
mDNSlocal kern_return_t mDNSDaemonInitialize(void)
{
mStatus err;
CFMachPortRef d_port = CFMachPortCreate(NULL, ClientDeathCallback, NULL, NULL);
CFMachPortRef s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL);
CFMachPortRef e_port = CFMachPortCreate(NULL, ExitCallback, NULL, NULL);
CFMachPortRef i_port = CFMachPortCreate(NULL, INFOCallback, NULL, NULL);
mach_port_t m_port = CFMachPortGetPort(s_port);
char *MachServerName = mDNSMacOSXSystemBuildNumber(NULL) < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
kern_return_t status = bootstrap_register(bootstrap_port, MachServerName, m_port);
CFRunLoopSourceRef d_rls = CFMachPortCreateRunLoopSource(NULL, d_port, 0);
CFRunLoopSourceRef s_rls = CFMachPortCreateRunLoopSource(NULL, s_port, 0);
CFRunLoopSourceRef e_rls = CFMachPortCreateRunLoopSource(NULL, e_port, 0);
CFRunLoopSourceRef i_rls = CFMachPortCreateRunLoopSource(NULL, i_port, 0);
if (status)
{
if (status == 1103)
LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
else
LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status), status);
return(status);
}
err = mDNS_Init(&mDNSStorage, &PlatformStorage,
rrcachestorage, RR_CACHE_SIZE,
mDNS_Init_AdvertiseLocalAddresses,
mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
if (err) { LogMsg("Daemon start: mDNS_Init failed %ld", err); return(err); }
client_death_port = CFMachPortGetPort(d_port);
exit_m_port = CFMachPortGetPort(e_port);
info_m_port = CFMachPortGetPort(i_port);
CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls, kCFRunLoopDefaultMode);
CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls, kCFRunLoopDefaultMode);
CFRunLoopAddSource(CFRunLoopGetCurrent(), e_rls, kCFRunLoopDefaultMode);
CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls, kCFRunLoopDefaultMode);
CFRelease(d_rls);
CFRelease(s_rls);
CFRelease(e_rls);
CFRelease(i_rls);
if (debug_mode) printf("Service registered with Mach Port %d\n", m_port);
#if ENABLE_UDS
err = udsserver_init();
if (err) { LogMsg("Daemon start: udsserver_init failed"); return err; }
err = udsserver_add_rl_source();
if (err) { LogMsg("Daemon start: udsserver_add_rl_source failed"); return err; }
#endif
return(err);
}
mDNSlocal mDNSs32 mDNSDaemonIdle(void)
{
mDNSs32 nextevent = mDNS_Execute(&mDNSStorage);
mDNSs32 now = mDNSPlatformTimeNow();
DNSServiceBrowser *b = DNSServiceBrowserList;
while (b)
{
DNSServiceBrowser *x = b;
b = b->next;
if (x->results) {
while (x->results)
{
DNSServiceBrowserResult *const r = x->results;
domainlabel name;
domainname type, domain;
DeconstructServiceName(&r->result, &name, &type, &domain); char cname[MAX_DOMAIN_LABEL+1]; char ctype[MAX_ESCAPED_DOMAIN_NAME];
char cdom [MAX_ESCAPED_DOMAIN_NAME];
ConvertDomainLabelToCString_unescaped(&name, cname);
ConvertDomainNameToCString(&type, ctype);
ConvertDomainNameToCString(&domain, cdom);
DNSServiceDiscoveryReplyFlags flags = (r->next) ? DNSServiceDiscoverReplyFlagsMoreComing : 0;
kern_return_t status = DNSServiceBrowserReply_rpc(x->ClientMachPort, r->resultType, cname, ctype, cdom, flags, 1);
if (status == MACH_SEND_TIMED_OUT)
{
if (nextevent - now > mDNSPlatformOneSecond)
nextevent = now + mDNSPlatformOneSecond;
break;
}
else
{
x->lastsuccess = now;
x->results = x->results->next;
freeL("DNSServiceBrowserResult", r);
}
}
if (now - x->lastsuccess >= 60 * mDNSPlatformOneSecond)
AbortBlockedClient(x->ClientMachPort, "browse", x);
}
}
DNSServiceResolver *l;
for (l = DNSServiceResolverList; l; l=l->next)
if (l->ReportTime && now - l->ReportTime >= 0)
{
l->ReportTime = 0;
LogMsg("%5d: DNSServiceResolver(%##s) has remained active for over two minutes. "
"This places considerable burden on the network.", l->ClientMachPort, l->i.name.c);
}
return(nextevent);
}
mDNSexport int main(int argc, char **argv)
{
int i;
kern_return_t status;
FILE *fp;
for (i=1; i<argc; i++)
{
if (!strcmp(argv[i], "-d")) debug_mode = 1;
}
signal(SIGINT, HandleSIGTERM); signal(SIGTERM, HandleSIGTERM);
signal(SIGINFO, HandleSIGINFO);
if (!debug_mode)
registerBootstrapService();
if (!debug_mode && !restarting_via_mach_init)
exit(0);
if (!debug_mode)
{
int fd = open(_PATH_DEVNULL, O_RDWR, 0);
if (fd != -1)
{
if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
(void)close (fd);
}
}
fp = fopen(PID_FILE, "w");
if (fp != NULL)
{
fprintf(fp, "%d\n", getpid());
fclose(fp);
}
LogMsg("%s starting", mDNSResponderVersionString);
status = mDNSDaemonInitialize();
const struct passwd *pw = getpwnam( "nobody");
if ( pw != NULL)
setuid( pw->pw_uid);
else
setuid(-2);
if (status == 0)
{
int numevents = 0;
int RunLoopStatus = kCFRunLoopRunTimedOut;
while (RunLoopStatus == kCFRunLoopRunTimedOut)
{
mDNSs32 nextevent = mDNSDaemonIdle();
#if ENABLE_UDS
nextevent = udsserver_idle(nextevent);
#endif
mDNSs32 ticks = nextevent - mDNSPlatformTimeNow();
if (ticks < 1) ticks = 1;
CFAbsoluteTime interval = (CFAbsoluteTime)ticks / (CFAbsoluteTime)mDNSPlatformOneSecond;
verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents, ticks);
numevents = 0;
RunLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, interval, true);
while (RunLoopStatus == kCFRunLoopRunHandledSource)
{
numevents++;
RunLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, true);
}
}
LogMsg("ERROR: CFRunLoopRun Exiting.");
mDNS_Close(&mDNSStorage);
}
destroyBootstrapService();
return(status);
}
mDNSexport const char mDNSResponderVersionString[] = STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";