/*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: dDNS.c,v $
Revision 1.8 2005/09/12 07:13:33 herscher
<rdar://problem/4248878> Workaround for router crash. Lazily call RegisterSearchDomains rather than call it always at startup.
Revision 1.7 2005/08/10 01:43:23 herscher
Pass NULL in for the IPv6 paramter to mDNS_SetPrimaryInterfaceInfo to get this code to compile on Windows.
Revision 1.6 2005/03/23 05:54:48 cheshire
<rdar://problem/4021486> Fix build warnings
Fix %s where it should be %##s in debugf & LogMsg calls
*/
#include "dDNS.h"
#include "DNSCommon.h"
#include "uds_daemon.h"
#include <winsock2.h>
#include <iphlpapi.h>
#include <ws2tcpip.h>
typedef struct SearchListElem
{
struct SearchListElem *next;
domainname domain;
int flag;
DNSQuestion BrowseQ;
DNSQuestion DefBrowseQ;
DNSQuestion LegacyBrowseQ;
DNSQuestion RegisterQ;
DNSQuestion DefRegisterQ;
ARListElem *AuthRecs;
} SearchListElem;
// for domain enumeration and default browsing/registration
static SearchListElem *SearchList = mDNSNULL; // where we search for _browse domains
static DNSQuestion LegacyBrowseDomainQ; // our local enumeration query for _legacy._browse domains
static DNameListElem *DefBrowseList = mDNSNULL; // cache of answers to above query (where we search for empty string browses)
static DNameListElem *DefRegList = mDNSNULL; // manually generated list of domains where we register for empty string registrations
static ARListElem *SCPrefBrowseDomains = mDNSNULL; // manually generated local-only PTR records for browse domains we get from SCPreferences
static domainname dDNSRegDomain; // Default wide-area zone for service registration
static DNameListElem * dDNSBrowseDomains; // Default wide-area zone for legacy ("empty string") browses
static domainname dDNSHostname;
static mDNSBool dDNSRegisterSearchDomains = mDNSfalse;
mDNSlocal mStatus RegisterNameServers( mDNS *const m );
mDNSlocal mStatus RegisterSearchDomains( mDNS *const m );
mStatus dDNS_SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
{
if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
if (sa->sa_family == AF_INET)
{
struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
ip->type = mDNSAddrType_IPv4;
ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
return(mStatus_NoError);
}
if (sa->sa_family == AF_INET6)
{
struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
ip->type = mDNSAddrType_IPv6;
#if !defined(_WIN32)
if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
#else
if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0;
#endif
ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
return(mStatus_NoError);
}
LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
return(mStatus_Invalid);
}
mStatus dDNS_RegisterSearchDomains( mDNS * const m )
{
mStatus err = mStatus_NoError;
dDNSRegisterSearchDomains = mDNStrue;
RegisterSearchDomains( m );
return err;
}
mDNSlocal void MarkSearchListElem(domainname *domain)
{
SearchListElem *new, *ptr;
// if domain is in list, mark as pre-existent (0)
for (ptr = SearchList; ptr; ptr = ptr->next)
if (SameDomainName(&ptr->domain, domain))
{
if (ptr->flag != 1) ptr->flag = 0; // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent
break;
}
// if domain not in list, add to list, mark as add (1)
if (!ptr)
{
new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem));
if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
bzero(new, sizeof(SearchListElem));
AssignDomainName(&new->domain, domain);
new->flag = 1; // add
new->next = SearchList;
SearchList = new;
}
}
//!!!KRS here is where we will give success/failure notification to the UI
mDNSlocal void SCPrefsdDNSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
{
(void)m; // unused
debugf("SCPrefsdDNSCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
dDNSPlatformSetNameStatus(rr->resrec.name, result);
}
mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
{
ARListElem *elem = rr->RecordContext;
(void)m; // unused
if (result == mStatus_MemFree) freeL("FreeARElemCallback", elem);
}
mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
SearchListElem *slElem = question->QuestionContext;
ARListElem *arElem, *ptr, *prev;
AuthRecord *dereg;
const char *name;
mStatus err;
if (AddRecord)
{
arElem = mallocL("FoundDomain - arElem", sizeof(ARListElem));
if (!arElem) { LogMsg("ERROR: malloc"); return; }
mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem);
if (question == &slElem->BrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
else if (question == &slElem->DefBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
else if (question == &slElem->LegacyBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseLegacy];
else if (question == &slElem->RegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
else if (question == &slElem->DefRegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
else { LogMsg("FoundDomain - unknown question"); return; }
MakeDomainNameFromDNSNameString(arElem->ar.resrec.name, name);
AppendDNSNameString (arElem->ar.resrec.name, "local");
AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
err = mDNS_Register(m, &arElem->ar);
if (err)
{
LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err);
freeL("FoundDomain - arElem", arElem);
return;
}
arElem->next = slElem->AuthRecs;
slElem->AuthRecs = arElem;
}
else
{
ptr = slElem->AuthRecs;
prev = NULL;
while (ptr)
{
if (SameDomainName(&ptr->ar.resrec.rdata->u.name, &answer->rdata->u.name))
{
debugf("Deregistering PTR %##s -> %##s", ptr->ar.resrec.name->c, ptr->ar.resrec.rdata->u.name.c);
dereg = &ptr->ar;
if (prev) prev->next = ptr->next;
else slElem->AuthRecs = ptr->next;
ptr = ptr->next;
err = mDNS_Deregister(m, dereg);
if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
}
else
{
prev = ptr;
ptr = ptr->next;
}
}
}
}
mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
{
return mDNS_CopyDNameList(DefBrowseList);
}
mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
{
return mDNS_CopyDNameList(DefRegList);
}
mDNSlocal void AddDefRegDomain(domainname *d)
{
DNameListElem *newelem = NULL, *ptr;
// make sure name not already in list
for (ptr = DefRegList; ptr; ptr = ptr->next)
{
if (SameDomainName(&ptr->name, d))
{ debugf("duplicate addition of default reg domain %##s", d->c); return; }
}
newelem = mallocL("DNameListElem", sizeof(*newelem));
if (!newelem) { LogMsg("Error - malloc"); return; }
AssignDomainName(&newelem->name, d);
newelem->next = DefRegList;
DefRegList = newelem;
dDNSPlatformDefaultRegDomainChanged(d, mDNStrue);
udsserver_default_reg_domain_changed(d, mDNStrue);
}
mDNSlocal void RemoveDefRegDomain(domainname *d)
{
DNameListElem *ptr = DefRegList, *prev = NULL;
while (ptr)
{
if (SameDomainName(&ptr->name, d))
{
if (prev) prev->next = ptr->next;
else DefRegList = ptr->next;
freeL("DNameListElem", ptr);
dDNSPlatformDefaultRegDomainChanged(d, mDNSfalse);
udsserver_default_reg_domain_changed(d, mDNSfalse);
return;
}
prev = ptr;
ptr = ptr->next;
}
debugf("Requested removal of default registration domain %##s not in contained in list", d->c);
}
mDNSlocal void FoundDefBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
DNameListElem *ptr, *prev, *new;
(void)m; // unused;
(void)question; // unused
if (AddRecord)
{
new = mallocL("FoundDefBrowseDomain", sizeof(DNameListElem));
if (!new) { LogMsg("ERROR: malloc"); return; }
AssignDomainName(&new->name, &answer->rdata->u.name);
new->next = DefBrowseList;
DefBrowseList = new;
dDNSPlatformDefaultBrowseDomainChanged(&new->name, mDNStrue);
udsserver_default_browse_domain_changed(&new->name, mDNStrue);
return;
}
else
{
ptr = DefBrowseList;
prev = NULL;
while (ptr)
{
if (SameDomainName(&ptr->name, &answer->rdata->u.name))
{
dDNSPlatformDefaultBrowseDomainChanged(&ptr->name, mDNSfalse);
udsserver_default_browse_domain_changed(&ptr->name, mDNSfalse);
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 RegisterNameServers( mDNS *const m )
{
IPAddrListElem * list;
IPAddrListElem * elem;
mDNS_DeleteDNSServers(m); // deregister orig list
list = dDNSPlatformGetDNSServers();
for ( elem = list; elem; elem = elem->next )
{
LogOperation("RegisterNameServers: Adding %#a", &elem->addr);
mDNS_AddDNSServer(m, &elem->addr, NULL);
}
dDNS_FreeIPAddrList( list );
return mStatus_NoError;
}
mDNSlocal mStatus RegisterSearchDomains( mDNS *const m )
{
SearchListElem *ptr, *prev, *freeSLPtr;
DNameListElem * elem;
DNameListElem * list;
ARListElem *arList;
mStatus err;
mDNSBool dict = 1;
// step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = dict ? -1 : 0;
// get all the domains from "Search Domains" field of sharing prefs
list = dDNSPlatformGetSearchDomainList();
for ( elem = list; elem; elem = elem->next )
{
MarkSearchListElem(&elem->name);
}
mDNS_FreeDNameList( list );
list = dDNSPlatformGetDomainName();
if ( list )
{
MarkSearchListElem( &list->name );
mDNS_FreeDNameList( list );
}
list = dDNSPlatformGetReverseMapSearchDomainList( );
for ( elem = list; elem; elem = elem->next )
{
MarkSearchListElem(&elem->name);
}
mDNS_FreeDNameList( list );
if (dDNSRegDomain.c[0]) MarkSearchListElem(&dDNSRegDomain); // implicitly browse reg domain too (no-op if same as BrowseDomain)
// delete elems marked for removal, do queries for elems marked add
prev = mDNSNULL;
ptr = SearchList;
while (ptr)
{
if (ptr->flag == -1) // remove
{
mDNS_StopQuery(m, &ptr->BrowseQ);
mDNS_StopQuery(m, &ptr->RegisterQ);
mDNS_StopQuery(m, &ptr->DefBrowseQ);
mDNS_StopQuery(m, &ptr->DefRegisterQ);
mDNS_StopQuery(m, &ptr->LegacyBrowseQ);
// deregister records generated from answers to the query
arList = ptr->AuthRecs;
ptr->AuthRecs = mDNSNULL;
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);
}
// remove elem from list, delete
if (prev) prev->next = ptr->next;
else SearchList = ptr->next;
freeSLPtr = ptr;
ptr = ptr->next;
freeL("RegisterSearchDomains - freeSLPtr", freeSLPtr);
continue;
}
if (ptr->flag == 1) // add
{
mStatus err1, err2, err3, err4, err5;
err1 = mDNS_GetDomains(m, &ptr->BrowseQ, mDNS_DomainTypeBrowse, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ, mDNS_DomainTypeBrowseDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
err3 = mDNS_GetDomains(m, &ptr->RegisterQ, mDNS_DomainTypeRegistration, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ, mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
err5 = mDNS_GetDomains(m, &ptr->LegacyBrowseQ, mDNS_DomainTypeBrowseLegacy, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
if (err1 || err2 || err3 || err4 || err5)
LogMsg("GetDomains for domain %##s returned error(s):\n"
"%d (mDNS_DomainTypeBrowse)\n"
"%d (mDNS_DomainTypeBrowseDefault)\n"
"%d (mDNS_DomainTypeRegistration)\n"
"%d (mDNS_DomainTypeRegistrationDefault)"
"%d (mDNS_DomainTypeBrowseLegacy)\n",
ptr->domain.c, err1, err2, err3, err4, err5);
ptr->flag = 0;
}
if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); }
prev = ptr;
ptr = ptr->next;
}
return mStatus_NoError;
}
mDNSlocal void RegisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
{
// allocate/register legacy and non-legacy _browse PTR record
mStatus err;
ARListElem *browse = mallocL("ARListElem", sizeof(*browse));
mDNS_SetupResourceRecord(&browse->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, browse);
MakeDomainNameFromDNSNameString(browse->ar.resrec.name, mDNS_DomainTypeNames[type]);
AppendDNSNameString (browse->ar.resrec.name, "local");
AssignDomainName(&browse->ar.resrec.rdata->u.name, d);
err = mDNS_Register(m, &browse->ar);
if (err)
{
LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
freeL("ARListElem", browse);
}
else
{
browse->next = SCPrefBrowseDomains;
SCPrefBrowseDomains = browse;
}
}
mDNSlocal void DeregisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
{
ARListElem *remove, **ptr = &SCPrefBrowseDomains;
domainname lhs; // left-hand side of PTR, for comparison
MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]);
AppendDNSNameString (&lhs, "local");
while (*ptr)
{
if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
{
remove = *ptr;
*ptr = (*ptr)->next;
mDNS_Deregister(m, &remove->ar);
return;
}
else ptr = &(*ptr)->next;
}
}
// Add or remove a user-specified domain to the list of empty-string browse domains
// Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists
mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add)
{
LogMsg("%s default browse domain %##s", add ? "Adding" : "Removing", d->c);
if (add)
{
RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
}
else
{
DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
}
}
mDNSlocal void SetSCPrefsBrowseDomains(mDNS *m, DNameListElem * browseDomains, mDNSBool add)
{
DNameListElem * browseDomain;
for ( browseDomain = browseDomains; browseDomain; browseDomain = browseDomain->next )
{
if ( !browseDomain->name.c[0] )
{
LogMsg("SetSCPrefsBrowseDomains bad DDNS browse domain: %##s", browseDomain->name.c[0] ? (char*) browseDomain->name.c : "(unknown)");
}
else
{
SetSCPrefsBrowseDomain(m, &browseDomain->name, add);
}
}
}
mStatus dDNS_Setup( mDNS *const m )
{
static mDNSBool LegacyNATInitialized = mDNSfalse;
mDNSBool dict = mDNStrue;
mDNSAddr ip;
mDNSAddr r;
DNameListElem * BrowseDomains;
domainname RegDomain, fqdn;
// get fqdn, zone from SCPrefs
dDNSPlatformGetConfig(&fqdn, &RegDomain, &BrowseDomains);
// YO if (!fqdn.c[0] && !RegDomain.c[0]) ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &fqdn, &RegDomain);
if (!SameDomainName(&RegDomain, &dDNSRegDomain))
{
if (dDNSRegDomain.c[0])
{
RemoveDefRegDomain(&dDNSRegDomain);
SetSCPrefsBrowseDomain(m, &dDNSRegDomain, mDNSfalse); // if we were automatically browsing in our registration domain, stop
}
AssignDomainName(&dDNSRegDomain, &RegDomain);
if (dDNSRegDomain.c[0])
{
dDNSPlatformSetSecretForDomain(m, &dDNSRegDomain);
AddDefRegDomain(&dDNSRegDomain);
SetSCPrefsBrowseDomain(m, &dDNSRegDomain, mDNStrue);
}
}
// Add new browse domains to internal list
if ( BrowseDomains )
{
SetSCPrefsBrowseDomains( m, BrowseDomains, mDNStrue );
}
// Remove old browse domains from internal list
if ( dDNSBrowseDomains )
{
SetSCPrefsBrowseDomains( m, dDNSBrowseDomains, mDNSfalse );
mDNS_FreeDNameList( dDNSBrowseDomains );
}
// Replace the old browse domains array with the new array
dDNSBrowseDomains = BrowseDomains;
if (!SameDomainName(&fqdn, &dDNSHostname))
{
if (dDNSHostname.c[0]) mDNS_RemoveDynDNSHostName(m, &dDNSHostname);
AssignDomainName(&dDNSHostname, &fqdn);
if (dDNSHostname.c[0])
{
dDNSPlatformSetSecretForDomain(m, &fqdn); // no-op if "zone" secret, above, is to be used for hostname
mDNS_AddDynDNSHostName(m, &dDNSHostname, SCPrefsdDNSCallback, mDNSNULL);
dDNSPlatformSetNameStatus(&dDNSHostname, 1);
}
}
// get DNS settings
// YO SCDynamicStoreRef store = SCDynamicStoreCreate(mDNSNULL, CFSTR("mDNSResponder:dDNSConfigChanged"), mDNSNULL, mDNSNULL);
// YO if (!store) return;
// YO key = SCDynamicStoreKeyCreateNetworkGlobalEntity(mDNSNULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
// YO if (!key) { LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return; }
// YO dict = SCDynamicStoreCopyValue(store, key);
// YO CFRelease(key);
// handle any changes to search domains and DNS server addresses
if ( dDNSPlatformRegisterSplitDNS(m) != mStatus_NoError)
if (dict) RegisterNameServers( m ); // fall back to non-split DNS aware configuration on failure
if ( dDNSRegisterSearchDomains == mDNStrue )
dDNS_RegisterSearchDomains( m ); // note that we register name servers *before* search domains
// if (dict) CFRelease(dict);
// get IPv4 settings
// YO key = SCDynamicStoreKeyCreateNetworkGlobalEntity(mDNSNULL,kSCDynamicStoreDomainState, kSCEntNetIPv4);
// YO if (!key) { LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return; }
// YO dict = SCDynamicStoreCopyValue(store, key);
// YO CFRelease(key);
// YO CFRelease(store);
// YO if (!dict)
// YO { mDNS_SetPrimaryInterfaceInfo(m, mDNSNULL, mDNSNULL); return; } // lost v4
// handle router changes
// YO mDNSAddr r;
// YO char buf[256];
// YO r.type = mDNSAddrType_IPv4;
// YO r.ip.v4.NotAnInteger = 0;
// YO CFStringRef router = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
// YO if (router)
// YO {
// YO if (!CFStringGetCString(router, buf, 256, kCFStringEncodingUTF8))
// YO LogMsg("Could not convert router to CString");
// YO else inet_aton(buf, (struct in_addr *)&r.ip.v4);
// YO }
// handle router and primary interface changes
ip.type = r.type = mDNSAddrType_IPv4;
ip.ip.v4.NotAnInteger = r.ip.v4.NotAnInteger = 0;
if ( dDNSPlatformGetPrimaryInterface( m, &ip, &r ) == mStatus_NoError )
{
// For now, we're going to pass NULL for the IPv6 parameter so that the Windows code compiles. What needs
// to happen is that the implementation of dDNSPlatformGetPrimaryInterface() needs to call the
// IPv6 aware "GetAdaptersAddresses" rather than GetAdaptersInfo().
mDNS_SetPrimaryInterfaceInfo(m, &ip, NULL, r.ip.v4.NotAnInteger ? &r : mDNSNULL);
}
return mStatus_NoError;
}
// Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
// 1) query for b._dns-sd._udp.local on LocalOnly interface
// (.local manually generated via explicit callback)
// 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
// 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
// 4) result above should generate a callback from question in (1). result added to global list
// 5) global list delivered to client via GetSearchDomainList()
// 6) client calls to enumerate domains now go over LocalOnly interface
// (!!!KRS may add outgoing interface in addition)
mStatus dDNS_InitDNSConfig(mDNS *const m)
{
mStatus err;
static AuthRecord LocalRegPTR;
// start query for domains to be used in default (empty string domain) browses
err = mDNS_GetDomains(m, &LegacyBrowseDomainQ, mDNS_DomainTypeBrowseLegacy, NULL, mDNSInterface_LocalOnly, FoundDefBrowseDomain, NULL);
// provide .local automatically
SetSCPrefsBrowseDomain(m, &localdomain, mDNStrue);
// <rdar://problem/4055653> dns-sd -E does not return "local."
// register registration domain "local"
mDNS_SetupResourceRecord(&LocalRegPTR, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, NULL, NULL);
MakeDomainNameFromDNSNameString(LocalRegPTR.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeRegistration]);
AppendDNSNameString (LocalRegPTR.resrec.name, "local");
AssignDomainName(&LocalRegPTR.resrec.rdata->u.name, &localdomain);
err = mDNS_Register(m, &LocalRegPTR);
if (err)
{
LogMsg("ERROR: dDNS_InitDNSConfig - mDNS_Register returned error %d", err);
}
return mStatus_NoError;
}
void
dDNS_FreeIPAddrList(IPAddrListElem * list)
{
IPAddrListElem * fptr;
while (list)
{
fptr = list;
list = list->next;
mDNSPlatformMemFree(fptr);
}
}
syntax highlighted by Code2HTML, v. 0.9.1