Import mDNSResponder-320.16, as previous import (258.14) is quite old

This commit is contained in:
pettai 2014-03-31 23:21:21 +00:00
parent dff5f859c8
commit ee071a7a97
19 changed files with 3412 additions and 864 deletions

View File

@ -736,7 +736,12 @@ static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags,
if (errorCode)
{
if (errorCode == kDNSServiceErr_NoSuchRecord) printf("No Such Record");
else printf("Error code %d", errorCode);
else if (errorCode == kDNSServiceErr_Timeout)
{
printf("No Such Record\n");
printf("Query Timed Out\n");
exit(1);
}
}
printf("\n");
@ -947,7 +952,7 @@ static void getip(const char *const name, struct sockaddr_storage *result)
if (addrs) freeaddrinfo(addrs);
}
static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const char *host, const char *ip)
static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const char *host, const char *ip, DNSServiceFlags flags)
{
// Call getip() after the call DNSServiceCreateConnection().
// On the Win32 platform, WinSock must be initialized for getip() to succeed.
@ -955,11 +960,12 @@ static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const
// DNSServiceCreateConnection() is called before getip() is.
struct sockaddr_storage hostaddr;
getip(ip, &hostaddr);
flags |= kDNSServiceFlagsUnique;
if (hostaddr.ss_family == AF_INET)
return(DNSServiceRegisterRecord(sdref, &record, kDNSServiceFlagsUnique, opinterface, host,
return(DNSServiceRegisterRecord(sdref, &record, flags, opinterface, host,
kDNSServiceType_A, kDNSServiceClass_IN, 4, &((struct sockaddr_in *)&hostaddr)->sin_addr, 240, MyRegisterRecordCallback, (void*)host));
else if (hostaddr.ss_family == AF_INET6)
return(DNSServiceRegisterRecord(sdref, &record, kDNSServiceFlagsUnique, opinterface, host,
return(DNSServiceRegisterRecord(sdref, &record, flags, opinterface, host,
kDNSServiceType_AAAA, kDNSServiceClass_IN, 16, &((struct sockaddr_in6*)&hostaddr)->sin6_addr, 240, MyRegisterRecordCallback, (void*)host));
else return(kDNSServiceErr_BadParam);
}
@ -971,9 +977,8 @@ static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const
#define HexPair(P) ((HexVal((P)[0]) << 4) | HexVal((P)[1]))
static DNSServiceErrorType RegisterService(DNSServiceRef *sdref,
const char *nam, const char *typ, const char *dom, const char *host, const char *port, int argc, char **argv)
const char *nam, const char *typ, const char *dom, const char *host, const char *port, int argc, char **argv, DNSServiceFlags flags)
{
DNSServiceFlags flags = 0;
uint16_t PortAsNumber = atoi(port);
Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
unsigned char txt[2048] = "";
@ -1008,7 +1013,7 @@ static DNSServiceErrorType RegisterService(DNSServiceRef *sdref,
//flags |= kDNSServiceFlagsAllowRemoteQuery;
//flags |= kDNSServiceFlagsNoAutoRename;
return(DNSServiceRegister(sdref, flags, opinterface, nam, typ, dom, host, registerPort.NotAnInteger, (uint16_t) (ptr-txt), txt, reg_reply, NULL));
}
@ -1025,6 +1030,7 @@ int main(int argc, char **argv)
DNSServiceErrorType err;
char buffer[TypeBufferSize], *typ, *dom;
int opi;
DNSServiceFlags flags = 0;
// Extract the program name from argv[0], which by convention contains the path to this executable.
// Note that this is just a voluntary convention, not enforced by the kernel --
@ -1063,6 +1069,14 @@ int main(int argc, char **argv)
printf("Using P2P\n");
}
if (argc > 1 && !strcasecmp(argv[1], "-includep2p"))
{
argc--;
argv++;
flags |= kDNSServiceFlagsIncludeP2P;
printf("Including P2P\n");
}
if (argc > 2 && !strcmp(argv[1], "-i"))
{
opinterface = if_nametoindex(argv[2]);
@ -1073,7 +1087,7 @@ int main(int argc, char **argv)
}
if (argc < 2) goto Fail; // Minimum command line is the command name and one argument
operation = getfirstoption(argc, argv, "EFBZLRPQqCAUNTMISV"
operation = getfirstoption(argc, argv, "EFBZLlRPQqtCAUNTMISV"
#if HAS_NAT_PMP_API
"X"
#endif
@ -1104,7 +1118,7 @@ int main(int argc, char **argv)
typ = gettype(buffer, typ);
if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string
printf("Browsing for %s%s%s\n", typ, dom[0] ? "." : "", dom);
err = DNSServiceBrowse(&client, 0, opinterface, typ, dom, browse_reply, NULL);
err = DNSServiceBrowse(&client, flags, opinterface, typ, dom, browse_reply, NULL);
break;
case 'Z': typ = (argc < opi+1) ? "" : argv[opi+0];
@ -1117,40 +1131,44 @@ int main(int argc, char **argv)
err = DNSServiceBrowse(&sc1, kDNSServiceFlagsShareConnection, opinterface, typ, dom, zonedata_browse, NULL);
break;
case 'L': if (argc < opi+2) goto Fail;
typ = (argc < opi+2) ? "" : argv[opi+1];
dom = (argc < opi+3) ? "local" : argv[opi+2];
typ = gettype(buffer, typ);
if (dom[0] == '.' && dom[1] == 0) dom = "local"; // We allow '.' on the command line as a synonym for "local"
printf("Lookup %s.%s.%s\n", argv[opi+0], typ, dom);
err = DNSServiceResolve(&client, 0, opinterface, argv[opi+0], typ, dom, resolve_reply, NULL);
break;
case 'l':
case 'L': {
DNSServiceFlags rflags = 0;
if (argc < opi+2) goto Fail;
typ = (argc < opi+2) ? "" : argv[opi+1];
dom = (argc < opi+3) ? "local" : argv[opi+2];
typ = gettype(buffer, typ);
if (dom[0] == '.' && dom[1] == 0) dom = "local"; // We allow '.' on the command line as a synonym for "local"
printf("Lookup %s.%s.%s\n", argv[opi+0], typ, dom);
if (operation == 'l') rflags |= kDNSServiceFlagsWakeOnResolve;
err = DNSServiceResolve(&client, rflags, opinterface, argv[opi+0], typ, dom, resolve_reply, NULL);
break;
}
case 'R': if (argc < opi+4) goto Fail;
typ = (argc < opi+2) ? "" : argv[opi+1];
dom = (argc < opi+3) ? "" : argv[opi+2];
typ = gettype(buffer, typ);
if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string
err = RegisterService(&client, argv[opi+0], typ, dom, NULL, argv[opi+3], argc-(opi+4), argv+(opi+4));
err = RegisterService(&client, argv[opi+0], typ, dom, NULL, argv[opi+3], argc-(opi+4), argv+(opi+4), flags);
break;
case 'P': if (argc < opi+6) goto Fail;
err = DNSServiceCreateConnection(&client_pa);
if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); }
err = RegisterProxyAddressRecord(client_pa, argv[opi+4], argv[opi+5]);
//err = RegisterProxyAddressRecord(client_pa, "two", argv[opi+5]);
err = RegisterProxyAddressRecord(client_pa, argv[opi+4], argv[opi+5], flags);
if (err) break;
err = RegisterService(&client, argv[opi+0], gettype(buffer, argv[opi+1]), argv[opi+2], argv[opi+4], argv[opi+3], argc-(opi+6), argv+(opi+6));
//DNSServiceRemoveRecord(client_pa, record, 0);
//DNSServiceRemoveRecord(client_pa, record, 0);
err = RegisterService(&client, argv[opi+0], gettype(buffer, argv[opi+1]), argv[opi+2], argv[opi+4], argv[opi+3], argc-(opi+6), argv+(opi+6), flags);
break;
case 't':
case 'q':
case 'Q':
case 'C': {
uint16_t rrtype, rrclass;
DNSServiceFlags flags = kDNSServiceFlagsReturnIntermediates;
flags |= kDNSServiceFlagsReturnIntermediates;
if (operation == 'q') flags |= kDNSServiceFlagsSuppressUnusable;
if (operation == 't') flags |= (kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsTimeout);
if (argc < opi+1) goto Fail;
rrtype = (argc <= opi+1) ? kDNSServiceType_A : GetRRType(argv[opi+1]);
rrclass = (argc <= opi+2) ? kDNSServiceClass_IN : atoi(argv[opi+2]);
@ -1186,8 +1204,8 @@ int main(int argc, char **argv)
static const char TXT1[] = "\xC" "First String" "\xD" "Second String" "\xC" "Third String";
static const char TXT2[] = "\xD" "Fourth String" "\xC" "Fifth String" "\xC" "Sixth String";
printf("Registering Service Test._testdualtxt._tcp.local.\n");
err = DNSServiceRegister(&client, 0, opinterface, "Test", "_testdualtxt._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT1)-1, TXT1, reg_reply, NULL);
if (!err) err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_TXT, sizeof(TXT2)-1, TXT2, 0);
err = DNSServiceRegister(&client, flags, opinterface, "Test", "_testdualtxt._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT1)-1, TXT1, reg_reply, NULL);
if (!err) err = DNSServiceAddRecord(client, &record, flags, kDNSServiceType_TXT, sizeof(TXT2)-1, TXT2, 0);
break;
}
@ -1318,7 +1336,7 @@ Fail:
// NOT static -- otherwise the compiler may optimize it out
// The "@(#) " pattern is a special prefix the "what" command looks for
const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion);
#if _BUILDING_XCODE_PROJECT_
// If the process crashes, then this string will be magically included in the automatically-generated crash log

View File

@ -989,8 +989,31 @@ mDNSexport void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText)
// Set up a AuthRecord with sensible default values.
// These defaults may be overwritten with new values before mDNS_Register is called
mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context)
mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, AuthRecType artype, mDNSRecordCallback Callback, void *Context)
{
//
// LocalOnly auth record can be created with LocalOnly InterfaceID or a valid InterfaceID.
// Most of the applications normally create with LocalOnly InterfaceID and we store them as
// such, so that we can deliver the response to questions that specify LocalOnly InterfaceID.
// LocalOnly resource records can also be created with valid InterfaceID which happens today
// when we create LocalOnly records for /etc/hosts.
if (InterfaceID == mDNSInterface_LocalOnly && artype != AuthRecordLocalOnly)
{
LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch LocalOnly record InterfaceID %p called with artype %d", InterfaceID, artype);
return;
}
else if (InterfaceID == mDNSInterface_P2P && artype != AuthRecordP2P)
{
LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch P2P record InterfaceID %p called with artype %d", InterfaceID, artype);
return;
}
else if (!InterfaceID && (artype == AuthRecordP2P || artype == AuthRecordLocalOnly))
{
LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch InterfaceAny record InterfaceID %p called with artype %d", InterfaceID, artype);
return;
}
// Don't try to store a TTL bigger than we can represent in platform time units
if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond)
ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond;
@ -1033,6 +1056,7 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD
rr->AddressProxy = zeroAddr;
rr->TimeRcvd = 0;
rr->TimeExpire = 0;
rr->ARType = artype;
// Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal)
// Field Group 4: Transient uDNS state for Authoritative Records (set in mDNS_Register_internal)
@ -1074,6 +1098,12 @@ mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID I
q->ForceMCast = mDNSfalse;
q->ReturnIntermed = mDNSfalse;
q->SuppressUnusable = mDNSfalse;
q->SearchListIndex = 0;
q->AppendSearchDomains = 0;
q->RetryWithSearchDomains = mDNSfalse;
q->TimeoutQuestion = 0;
q->WakeOnResolve = 0;
q->qnameOrig = mDNSNULL;
q->QuestionCallback = callback;
q->QuestionContext = context;
}
@ -1186,6 +1216,13 @@ mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBod
mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
{
// LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
// are handled in LocalOnlyRecordAnswersQuestion
if ((rr->InterfaceID == mDNSInterface_LocalOnly) || (rr->InterfaceID == mDNSInterface_P2P))
{
LogMsg("SameNameRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
return mDNSfalse;
}
if (rr->InterfaceID &&
q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
@ -1205,6 +1242,14 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr
mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
{
// LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
// are handled in LocalOnlyRecordAnswersQuestion
if ((rr->InterfaceID == mDNSInterface_LocalOnly) || (rr->InterfaceID == mDNSInterface_P2P))
{
LogMsg("ResourceRecordAnswersQuestion: ERROR!! called with LocalOnly/P2P ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
return mDNSfalse;
}
if (rr->InterfaceID &&
q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
@ -1213,10 +1258,6 @@ mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr
if (!rr->InterfaceID && rr->rDNSServer != q->qDNSServer) return(mDNSfalse);
// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question.
// This also covers the case where the ResourceRecord is mDNSInterface_LocalOnly and the question is expecting a unicast
// DNS response. We don't want a local process to be able to create a fake LocalOnly address record for "www.bigbank.com"
// which would then cause other applications (e.g. Safari) to connect to the wrong address. If we decide to support this later,
// the restrictions need to be at least as strict as the restrictions on who can edit /etc/hosts and put fake addresses there.
if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
// RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
@ -1226,8 +1267,91 @@ mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr
return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
}
// We have a separate function to handle LocalOnly AuthRecords because they can be created with
// a valid InterfaceID (e.g., scoped /etc/hosts) and can be used to answer unicast questions unlike
// multicast resource records (which has a valid InterfaceID) which can't be used to answer
// unicast questions. ResourceRecordAnswersQuestion/SameNameRecordAnswersQuestion can't tell whether
// a resource record is multicast or LocalOnly by just looking at the ResourceRecord because
// LocalOnly records are truly identified by ARType in the AuthRecord. As P2P and LocalOnly record
// are kept in the same hash table, we use the same function to make it easy for the callers when
// they walk the hash table to answer LocalOnly/P2P questions
//
mDNSexport mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const ar, const DNSQuestion *const q)
{
ResourceRecord *rr = &ar->resrec;
// mDNSInterface_Any questions can be answered with LocalOnly/P2P records in this function. AuthRecord_Any
// records are handled in ResourceRecordAnswersQuestion/SameNameRecordAnswersQuestion
if (RRAny(ar))
{
LogMsg("LocalOnlyRecordAnswersQuestion: ERROR!! called with regular AuthRecordAny %##s", rr->name->c);
return mDNSfalse;
}
// Questions with mDNSInterface_LocalOnly InterfaceID should be answered with all resource records that are
// *local* to the machine. These include resource records that have InterfaceID set to mDNSInterface_LocalOnly,
// mDNSInterface_Any and any other real InterfaceID. Hence, LocalOnly questions should not be checked against
// the InterfaceID in the resource record.
//
// mDNSInterface_Unicast does not indicate any scope and hence treat them like mDNSInterface_Any.
if (rr->InterfaceID &&
q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly && q->InterfaceID != mDNSInterface_Unicast &&
rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
// Entries in /etc/hosts are added as LocalOnly resource records. The LocalOnly resource records
// may have a scope e.g., fe80::1%en0. The question may be scoped or not: the InterfaceID may be set
// to mDNSInterface_Any, mDNSInterface_LocalOnly or a real InterfaceID (scoped).
//
// 1) Question: Any, LocalOnly Record: no scope. This question should be answered with this record.
//
// 2) Question: Any, LocalOnly Record: scoped. This question should be answered with the record because
// traditionally applications never specify scope e.g., getaddrinfo, but need to be able
// to get to /etc/hosts entries.
//
// 3) Question: Scoped (LocalOnly or InterfaceID), LocalOnly Record: no scope. This is the inverse of (2).
// If we register a LocalOnly record, we need to answer a LocalOnly question. If the /etc/hosts has a
// non scoped entry, it may not make sense to answer a scoped question. But we can't tell these two
// cases apart. As we currently answer LocalOnly question with LocalOnly record, we continue to do so.
//
// 4) Question: Scoped (LocalOnly or InterfaceID), LocalOnly Record: scoped. LocalOnly questions should be
// answered with any resource record where as if it has a valid InterfaceID, the scope should match.
//
// (1) and (2) is bypassed because we check for a non-NULL InterfaceID above. For (3), the InterfaceID is NULL
// and hence bypassed above. For (4) we bypassed LocalOnly questions and checked the scope of the record
// against the question.
//
// For P2P, InterfaceIDs of the question and the record should match.
// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question.
// LocalOnly authoritative answers are exempt. LocalOnly authoritative answers are used for /etc/host entries.
// We don't want a local process to be able to create a fake LocalOnly address record for "www.bigbank.com" which would then
// cause other applications (e.g. Safari) to connect to the wrong address. The rpc to register records filters out records
// with names that don't end in local and have mDNSInterface_LocalOnly set.
//
// Note: The check is bypassed for LocalOnly and for P2P it is not needed as only .local records are registered and for
// a question to match its names, it also has to end in .local and that question can't be a unicast question (See
// Question_uDNS macro and its usage). As P2P does not enforce .local only registrations we still make this check
// and also makes it future proof.
if (ar->ARType != AuthRecordLocalOnly && rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
// RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
}
mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
{
// LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
// are handled in LocalOnlyRecordAnswersQuestion
if ((rr->InterfaceID == mDNSInterface_LocalOnly) || (rr->InterfaceID == mDNSInterface_P2P))
{
LogMsg("AnyTypeRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
return mDNSfalse;
}
if (rr->InterfaceID &&
q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
@ -1245,12 +1369,20 @@ mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr,
return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
}
// This is called only when the caller knows that it is a Unicast Resource Record and it is a Unicast Question
// and hence we don't need InterfaceID checks like above. Though this may not be a big optimization, the main
// reason we need this is that we can't compare DNSServers between the question and the resource record because
// the resource record may not be completely initialized e.g., mDNSCoreReceiveResponse
mDNSexport mDNSBool UnicastResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
// This is called with both unicast resource record and multicast resource record. The question that
// received the unicast response could be the regular unicast response from a DNS server or a response
// to a mDNS QU query. The main reason we need this function is that we can't compare DNSServers between the
// question and the resource record because the resource record is not completely initialized in
// mDNSCoreReceiveResponse when this function is called.
mDNSexport mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const rr, const DNSQuestion *const q)
{
// For resource records created using multicast, the InterfaceIDs have to match
if (rr->InterfaceID &&
q->InterfaceID && rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question.
if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
// RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
@ -1746,7 +1878,7 @@ mDNSexport mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, co
mDNSexport mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *const msg, mDNSu8 *const ptr, mDNSu8 *const end)
{
AuthRecord prereq;
mDNS_SetupResourceRecord(&prereq, mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
mDNS_SetupResourceRecord(&prereq, mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, AuthRecordAny, mDNSNULL, mDNSNULL);
AssignDomainName(&prereq.namestorage, name);
prereq.resrec.rrtype = kDNSQType_ANY;
prereq.resrec.rrclass = kDNSClass_NONE;
@ -1816,7 +1948,7 @@ mDNSexport mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domain
mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease)
{
AuthRecord rr;
mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
rr.resrec.rrclass = NormalMaxDNSMessageData;
rr.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record
rr.resrec.rdestimate = sizeof(rdataOPT);
@ -1831,7 +1963,7 @@ mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease)
mDNSexport mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease, mDNSu8 *limit)
{
AuthRecord rr;
mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
rr.resrec.rrclass = NormalMaxDNSMessageData;
rr.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record
rr.resrec.rdestimate = sizeof(rdataOPT);
@ -1850,7 +1982,7 @@ mDNSexport mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *
mDNSu8 *h = hinfo.rdatastorage.u.data;
mDNSu16 len = 2 + m->HIHardware.c[0] + m->HISoftware.c[0];
mDNSu8 *newptr;
mDNS_SetupResourceRecord(&hinfo, mDNSNULL, mDNSInterface_Any, kDNSType_HINFO, 0, kDNSRecordTypeUnique, mDNSNULL, mDNSNULL);
mDNS_SetupResourceRecord(&hinfo, mDNSNULL, mDNSInterface_Any, kDNSType_HINFO, 0, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
AppendDomainLabel(&hinfo.namestorage, &m->hostlabel);
AppendDomainName (&hinfo.namestorage, &authInfo->domain);
hinfo.resrec.rroriginalttl = 0;
@ -2156,7 +2288,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
case kDNSType_OPT: {
rdataOPT *opt = rr->resrec.rdata->u.opt;
rr->resrec.rdlength = 0;
while (ptr < end && (mDNSu8 *)(opt+1) < &rr->resrec.rdata->u.data[MaximumRDSize])
while (ptr < end && (mDNSu8 *)(opt+1) < rr->resrec.rdata->u.data + MaximumRDSize)
{
const rdataOPT *const currentopt = opt;
if (ptr + 4 > end) { LogInfo("GetLargeResourceRecord: OPT RDATA ptr + 4 > end"); goto fail; }
@ -2593,6 +2725,7 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
}
if (m->NewLocalOnlyQuestions) return(m->timenow);
if (m->NewLocalRecords && AnyLocalRecordReady(m)) return(m->timenow);
if (m->NewLocalOnlyRecords) return(m->timenow);
if (m->SPSProxyListChanged) return(m->timenow);
if (m->LocalRemoveEvents) return(m->timenow);
@ -2618,12 +2751,13 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
if (e - m->NextScheduledProbe > 0) e = m->NextScheduledProbe;
if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
}
if (e - m->NextScheduledStopTime > 0) e = m->NextScheduledStopTime;
return(e);
}
mDNSexport void ShowTaskSchedulingError(mDNS *const m)
{
AuthRecord *rr;
mDNS_Lock(m);
LogMsg("Task Scheduling Error: Continuously busy for more than a second");
@ -2640,9 +2774,11 @@ mDNSexport void ShowTaskSchedulingError(mDNS *const m)
if (m->NewLocalRecords)
{
AuthRecord *rr = AnyLocalRecordReady(m);
rr = AnyLocalRecordReady(m);
if (rr) LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, rr));
}
if (m->NewLocalOnlyRecords) LogMsg("Task Scheduling Error: NewLocalOnlyRecords");
if (m->SPSProxyListChanged) LogMsg("Task Scheduling Error: SPSProxyListChanged");
if (m->LocalRemoveEvents) LogMsg("Task Scheduling Error: LocalRemoveEvents");

View File

@ -164,7 +164,8 @@ extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *c
extern mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool AnyTypeRecordAnswersQuestion (const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool UnicastResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const rr, const DNSQuestion *const q);
extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd);
@ -226,6 +227,7 @@ extern mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *ptr,
#pragma mark - DNS Message Parsing Functions
#endif
#define AuthHashSlot(X) (DomainNameHashValue(X) % AUTH_HASH_SLOTS)
#define HashSlot(X) (DomainNameHashValue(X) % CACHE_HASH_SLOTS)
extern mDNSu32 DomainNameHashValue(const domainname *const name);
extern void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength);

View File

@ -1345,7 +1345,7 @@ mDNSexport void DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthI
MD5_Update(&c, (mDNSu8 *)msg, (unsigned long)(*end - (mDNSu8 *)msg));
// Construct TSIG RR, digesting variables as apporpriate
mDNS_SetupResourceRecord(&tsig, mDNSNULL, 0, kDNSType_TSIG, 0, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
mDNS_SetupResourceRecord(&tsig, mDNSNULL, 0, kDNSType_TSIG, 0, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
// key name
AssignDomainName(&tsig.namestorage, &info->keyname);

File diff suppressed because it is too large Load Diff

View File

@ -112,7 +112,10 @@
// In the event that structures are not packed correctly, mDNS_Init() will detect this and report an error, so the
// developer will know what's wrong, and can investigate what needs to be done on that compiler to provide proper packing.
#ifndef packedstruct
#if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
#ifdef __packed
#define packedstruct struct __packed
#define packedunion union __packed
#elif ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
#define packedstruct struct __attribute__((__packed__))
#define packedunion union __attribute__((__packed__))
#else
@ -348,6 +351,7 @@ enum
mStatus_NATPortMappingDisabled = -65565, // NAT supports NAT-PMP or UPnP but it's disabled by the administrator
mStatus_NoRouter = -65566,
mStatus_PollingMode = -65567,
mStatus_Timeout = -65568,
// -65568 to -65786 currently unused; available for allocation
// tcp connection status
@ -406,6 +410,13 @@ typedef struct { mDNSu8 c[256]; } UTF8str255; // Null-terminated C string
#define kStandardTTL (3600UL * 100 / 80)
#define kHostNameTTL 120UL
// Some applications want to register their SRV records with a lower ttl so that in case the server
// using a dynamic port number restarts, the clients will not have stale information for more than
// 10 seconds
#define kHostNameSmallTTL 10UL
// Multicast DNS uses announcements (gratuitous responses) to update peer caches.
// This means it is feasible to use relatively larger TTL values than we might otherwise
// use, because we have a cache coherency protocol to keep the peer caches up to date.
@ -424,6 +435,7 @@ typedef struct AuthRecord_struct AuthRecord;
typedef struct ServiceRecordSet_struct ServiceRecordSet;
typedef struct CacheRecord_struct CacheRecord;
typedef struct CacheGroup_struct CacheGroup;
typedef struct AuthGroup_struct AuthGroup;
typedef struct DNSQuestion_struct DNSQuestion;
typedef struct ZoneData_struct ZoneData;
typedef struct mDNS_struct mDNS;
@ -1036,6 +1048,21 @@ enum
DNSServer_FlagNew = 2
};
enum
{
McastResolver_FlagDelete = 1,
McastResolver_FlagNew = 2
};
typedef struct McastResolver
{
struct McastResolver *next;
mDNSInterfaceID interface;
mDNSu32 flags; // Set when we're planning to delete this from the list
domainname domain;
mDNSu32 timeout; // timeout value for questions
} McastResolver;
typedef struct DNSServer
{
struct DNSServer *next;
@ -1050,6 +1077,7 @@ typedef struct DNSServer
mDNSs32 penaltyTime; // amount of time this server is penalized
mDNSBool scoped; // interface should be matched against question only
// if scoped is set
mDNSu32 timeout; // timeout value for questions
} DNSServer;
typedef struct // Size is 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit
@ -1108,6 +1136,45 @@ typedef enum
mergeState_DontMerge = 1 // Set on fatal error conditions to disable merging
} mergeState_t;
struct AuthGroup_struct // Header object for a list of AuthRecords with the same name
{
AuthGroup *next; // Next AuthGroup object in this hash table bucket
mDNSu32 namehash; // Name-based (i.e. case insensitive) hash of name
AuthRecord *members; // List of CacheRecords with this same name
AuthRecord **rrauth_tail; // Tail end of that list
domainname *name; // Common name for all AuthRecords in this list
AuthRecord *NewLocalOnlyRecords;
// Size to here is 20 bytes when compiling 32-bit; 40 bytes when compiling 64-bit
mDNSu8 namestorage[InlineCacheGroupNameSize];
};
#define AUTH_HASH_SLOTS 499
#define FORALL_AUTHRECORDS(SLOT,AG,AR) \
for ((SLOT) = 0; (SLOT) < AUTH_HASH_SLOTS; (SLOT)++) \
for ((AG)=m->rrauth.rrauth_hash[(SLOT)]; (AG); (AG)=(AG)->next) \
for ((AR) = (AG)->members; (AR); (AR)=(AR)->next)
typedef union AuthEntity_union AuthEntity;
union AuthEntity_union { AuthEntity *next; AuthGroup ag; };
typedef struct {
mDNSu32 rrauth_size; // Total number of available auth entries
mDNSu32 rrauth_totalused; // Number of auth entries currently occupied
mDNSu32 rrauth_report;
mDNSu8 rrauth_lock; // For debugging: Set at times when these lists may not be modified
AuthEntity *rrauth_free;
AuthGroup *rrauth_hash[AUTH_HASH_SLOTS];
}AuthHash;
// AuthRecordAny includes mDNSInterface_Any and interface specific auth records (anything
// other than P2P or LocalOnly)
typedef enum
{
AuthRecordAny, // registered for *Any, NOT including P2P interfaces
AuthRecordAnyIncludeP2P, // registered for *Any, including P2P interfaces
AuthRecordLocalOnly,
AuthRecordP2P // discovered over D2D/P2P framework
} AuthRecType;
struct AuthRecord_struct
{
// For examples of how to set up this structure for use in mDNS_Register(),
@ -1134,6 +1201,7 @@ struct AuthRecord_struct
mDNSAddr AddressProxy; // For reverse-mapping Sleep Proxy PTR records, address in question
mDNSs32 TimeRcvd; // In platform time units
mDNSs32 TimeExpire; // In platform time units
AuthRecType ARType; // LocalOnly, P2P or Normal ?
// Field Group 3: Transient state for Authoritative Records
mDNSu8 Acknowledged; // Set if we've given the success callback to the client
@ -1218,12 +1286,21 @@ struct AuthRecord_struct
#define Question_uDNS(Q) ((Q)->InterfaceID == mDNSInterface_Unicast || \
((Q)->InterfaceID != mDNSInterface_LocalOnly && (Q)->InterfaceID != mDNSInterface_P2P && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname)))
#define RRLocalOnly(rr) ((rr)->ARType == AuthRecordLocalOnly || (rr)->ARType == AuthRecordP2P)
#define RRAny(rr) ((rr)->ARType == AuthRecordAny || (rr)->ARType == AuthRecordAnyIncludeP2P)
// Question (A or AAAA) that is suppressed currently because IPv4 or IPv6 address
// is not available locally for A or AAAA question respectively
#define QuerySuppressed(Q) ((Q)->SuppressUnusable && (Q)->SuppressQuery)
#define PrivateQuery(Q) ((Q)->AuthInfo && (Q)->AuthInfo->AutoTunnel)
// Normally we always lookup the cache and /etc/hosts before sending the query on the wire. For single label
// queries (A and AAAA) that are unqualified (indicated by AppendSearchDomains), we want to append search
// domains before we try them as such
#define ApplySearchDomainsFirst(q) ((q)->AppendSearchDomains && (CountLabels(&((q)->qname))) == 1)
// Wrapper struct for Auth Records for higher-level code that cannot use the AuthRecord's ->next pointer field
typedef struct ARListElem
{
@ -1242,6 +1319,7 @@ struct CacheGroup_struct // Header object for a list of CacheRecords with the
mDNSu8 namestorage[InlineCacheGroupNameSize];
};
struct CacheRecord_struct
{
CacheRecord *next; // Next in list; first element of structure for efficiency reasons
@ -1391,25 +1469,29 @@ enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 };
#define MD5_LEN 16
#define AutoTunnelUnregistered(X) ( \
(X)->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered && \
(X)->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered && \
(X)->AutoTunnelService. resrec.RecordType == kDNSRecordTypeUnregistered && \
(X)->AutoTunnel6Record. resrec.RecordType == kDNSRecordTypeUnregistered )
(X)->AutoTunnelHostRecord. resrec.RecordType == kDNSRecordTypeUnregistered && \
(X)->AutoTunnelDeviceInfo. resrec.RecordType == kDNSRecordTypeUnregistered && \
(X)->AutoTunnelService. resrec.RecordType == kDNSRecordTypeUnregistered && \
(X)->AutoTunnel6Record. resrec.RecordType == kDNSRecordTypeUnregistered && \
(X)->AutoTunnel6MetaRecord.resrec.RecordType == kDNSRecordTypeUnregistered )
// Internal data structure to maintain authentication information
typedef struct DomainAuthInfo
{
struct DomainAuthInfo *next;
mDNSs32 deltime; // If we're planning to delete this DomainAuthInfo, the time we want it deleted
mDNSBool AutoTunnel;
const char* AutoTunnel; // If NULL, this is not an AutoTunnel DAI. Otherwise, this is prepended to the IPSec identifier
AuthRecord AutoTunnelHostRecord; // User-visible hostname; used as SRV target for AutoTunnel services
AuthRecord AutoTunnelTarget; // Opaque hostname of tunnel endpoint; used as SRV target for AutoTunnelService record
AuthRecord AutoTunnelDeviceInfo; // Device info of tunnel endpoint
AuthRecord AutoTunnelService; // Service record (possibly NAT-Mapped) of IKE daemon implementing tunnel endpoint
AuthRecord AutoTunnel6Record; // AutoTunnel AAAA Record obtained from Connectivityd
AuthRecord AutoTunnel6Record; // AutoTunnel AAAA record obtained from awacsd
AuthRecord AutoTunnel6MetaRecord; // Notify remote peers to connect to the relay servers for potential outbound connections from this host
NATTraversalInfo AutoTunnelNAT;
domainname domain;
domainname keyname;
domainname hostname;
mDNSIPPort port;
char b64keydata[32];
mDNSu8 keydata_ipad[HMAC_LEN]; // padded key for inner hash rounds
mDNSu8 keydata_opad[HMAC_LEN]; // padded key for outer hash rounds
@ -1452,6 +1534,10 @@ struct DNSQuestion_struct
mDNSs32 LastQTxTime; // Last time this Q was sent on one (but not necessarily all) interfaces
mDNSu32 CNAMEReferrals; // Count of how many CNAME redirections we've done
mDNSBool SuppressQuery; // This query should be suppressed and not sent on the wire
mDNSu8 LOAddressAnswers; // Number of answers from the local only auth records that are
// answering A, AAAA and CNAME (/etc/hosts)
mDNSu8 WakeOnResolveCount; // Number of wakes that should be sent on resolve
mDNSs32 StopTime; // Time this question should be stopped by giving them a negative answer
// Wide Area fields. These are used internally by the uDNS core
UDPSocket *LocalSocket;
@ -1460,7 +1546,7 @@ struct DNSQuestion_struct
mDNSOpaque64 validDNSServers; // Valid DNSServers for this question
mDNSu16 noServerResponse; // At least one server did not respond.
mDNSu16 triedAllServersOnce; // Tried all DNS servers once
mDNSu8 unansweredQueries;// The number of unanswered queries to this server
mDNSu8 unansweredQueries;// The number of unanswered queries to this server
ZoneData *nta; // Used for getting zone data for private or LLQ query
mDNSAddr servAddr; // Address and port learned from _dns-llq, _dns-llq-tls or _dns-query-tls SRV query
@ -1493,6 +1579,13 @@ struct DNSQuestion_struct
mDNSBool ForceMCast; // Set by client to force mDNS query, even for apparently uDNS names
mDNSBool ReturnIntermed; // Set by client to request callbacks for intermediate CNAME/NXDOMAIN results
mDNSBool SuppressUnusable; // Set by client to suppress unusable queries to be sent on the wire
mDNSBool RetryWithSearchDomains; // Retry with search domains if there is no entry in the cache or AuthRecords
mDNSu8 TimeoutQuestion; // Timeout this question if there is no reply in configured time
mDNSu8 WakeOnResolve; // Send wakeup on resolve
mDNSs8 SearchListIndex; // Index into SearchList; Used by the client layer but not touched by core
mDNSs8 AppendSearchDomains; // Search domains can be appended for this query
mDNSs8 AppendLocalSearchDomains; // Search domains ending in .local can be appended for this query
domainname *qnameOrig; // Copy of the original question name if it is not fully qualified
mDNSQuestionCallback *QuestionCallback;
void *QuestionContext;
};
@ -1555,6 +1648,7 @@ struct ZoneData_struct
extern ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *callbackInfo);
extern void CancelGetZoneData(mDNS *const m, ZoneData *nta);
extern mDNSBool IsGetZoneDataQuestion(DNSQuestion *q);
typedef struct DNameListElem
{
@ -1573,6 +1667,7 @@ typedef struct DNameListElem
typedef struct ClientTunnel
{
struct ClientTunnel *next;
const char *prefix;
domainname dstname;
mDNSBool MarkedForDeletion;
mDNSv6Addr loc_inner;
@ -1634,20 +1729,24 @@ struct NetworkInterfaceInfo_struct
mDNSu8 Advertise; // False if you are only searching on this interface
mDNSu8 McastTxRx; // Send/Receive multicast on this { InterfaceID, address family } ?
mDNSu8 NetWake; // Set if Wake-On-Magic-Packet is enabled on this interface
mDNSu8 Loopback; // Set if this is the loopback interface
};
#define SLE_DELETE 0x00000001
#define SLE_WAB_QUERY_STARTED 0x00000002
typedef struct SearchListElem
{
struct SearchListElem *next;
domainname domain;
int flag; // -1 means delete, 0 means unchanged, +1 means newly added
int flag;
mDNSInterfaceID InterfaceID;
DNSQuestion BrowseQ;
DNSQuestion DefBrowseQ;
DNSQuestion AutomaticBrowseQ;
DNSQuestion RegisterQ;
DNSQuestion DefRegisterQ;
DNSQuestion DirQ;
int numDirAnswers;
int numCfAnswers;
ARListElem *AuthRecs;
} SearchListElem;
@ -1670,9 +1769,8 @@ typedef void mDNSCallback(mDNS *const m, mStatus result);
enum // Bit flags -- i.e. values should be 1, 2, 4, 8, etc.
{
mDNS_KnownBug_PhantomInterfaces = 1,
mDNS_KnownBug_LimitedIPv6 = 2,
mDNS_KnownBug_LossySyslog = 4 // <rdar://problem/6561888>
mDNS_KnownBug_LimitedIPv6 = 1,
mDNS_KnownBug_LossySyslog = 2 // <rdar://problem/6561888>
};
enum
@ -1741,12 +1839,15 @@ struct mDNS_struct
mDNSs32 NextScheduledSPRetry; // Time next sleep proxy registration action is required.
// Only valid if SleepLimit is nonzero and DelaySleep is zero.
mDNSs32 NextScheduledStopTime; // Next time to stop a question
// These fields only required for mDNS Searcher...
DNSQuestion *Questions; // List of all registered questions, active and inactive
DNSQuestion *NewQuestions; // Fresh questions not yet answered from cache
DNSQuestion *CurrentQuestion; // Next question about to be examined in AnswerLocalQuestions()
DNSQuestion *LocalOnlyQuestions; // Questions with InterfaceID set to mDNSInterface_LocalOnly or mDNSInterface_P2P
DNSQuestion *NewLocalOnlyQuestions; // Fresh local-only or P2P questions not yet answered
DNSQuestion *RestartQuestion; // Questions that are being restarted (stop followed by start)
mDNSu32 rrcache_size; // Total number of available cache entries
mDNSu32 rrcache_totalused; // Number of cache entries currently occupied
mDNSu32 rrcache_active; // Number of cache entries currently occupied by records that answer active questions
@ -1755,6 +1856,8 @@ struct mDNS_struct
CacheGroup *rrcache_hash[CACHE_HASH_SLOTS];
mDNSs32 rrcache_nextcheck[CACHE_HASH_SLOTS];
AuthHash rrauth;
// Fields below only required for mDNS Responder...
domainlabel nicelabel; // Rich text label encoded using canonically precomposed UTF-8
domainlabel hostlabel; // Conforms to RFC 1034 "letter-digit-hyphen" ARPANET host name rules
@ -1764,8 +1867,9 @@ struct mDNS_struct
AuthRecord DeviceInfo;
AuthRecord *ResourceRecords;
AuthRecord *DuplicateRecords; // Records currently 'on hold' because they are duplicates of existing records
AuthRecord *NewLocalRecords; // Fresh AuthRecords (both local-only and public) not yet delivered to our local-only questions
AuthRecord *NewLocalRecords; // Fresh AuthRecords (public) not yet delivered to our local-only questions
AuthRecord *CurrentRecord; // Next AuthRecord about to be examined
mDNSBool NewLocalOnlyRecords; // Fresh AuthRecords (local only) not yet delivered to our local questions
NetworkInterfaceInfo *HostInterfaces;
mDNSs32 ProbeFailTime;
mDNSu32 NumFailedProbes;
@ -1776,6 +1880,7 @@ struct mDNS_struct
mDNSs32 NextSRVUpdate; // Time to perform delayed update
DNSServer *DNSServers; // list of DNS servers
McastResolver *McastResolvers; // list of Mcast Resolvers
mDNSAddr Router;
mDNSAddr AdvertisedV4; // IPv4 address pointed to by hostname
@ -1790,10 +1895,15 @@ struct mDNS_struct
HostnameInfo *Hostnames; // List of registered hostnames + hostname metadata
mDNSv6Addr AutoTunnelHostAddr; // IPv6 address advertised for AutoTunnel services on this machine
mDNSBool AutoTunnelHostAddrActive;
mDNSv6Addr AutoTunnelRelayAddr; // IPv6 address advertised for AutoTunnel Relay services on this machine
// AutoTunnel Relay address has two distinct uses
// AutoTunnelRelayAddrIn: If non-zero, it means that this host can be reached (inbound connection) through the relay
// AutoTunnelRelayAddrOut: If non-zero, it means that this host can use the relay to reach (outbound connection) the
// other hosts through the relay
mDNSv6Addr AutoTunnelRelayAddrIn;
mDNSv6Addr AutoTunnelRelayAddrOut;
domainlabel AutoTunnelLabel; // Used to construct hostname for *IPv4* address of tunnel endpoints
mDNSBool RegisterSearchDomains;
mDNSBool StartWABQueries; // Start WAB queries for the purpose of domain enumeration
mDNSBool RegisterAutoTunnel6;
// NAT-Traversal fields
@ -2027,6 +2137,7 @@ extern mStatus mDNS_Init (mDNS *const m, mDNS_PlatformSupport *const p,
extern void mDNS_ConfigChanged(mDNS *const m);
extern void mDNS_GrowCache (mDNS *const m, CacheEntity *storage, mDNSu32 numrecords);
extern void mDNS_GrowAuth (mDNS *const m, AuthEntity *storage, mDNSu32 numrecords);
extern void mDNS_StartExit (mDNS *const m);
extern void mDNS_FinalExit (mDNS *const m);
#define mDNS_Close(m) do { mDNS_StartExit(m); mDNS_FinalExit(m); } while(0)
@ -2098,14 +2209,21 @@ typedef enum { mDNS_Dereg_normal, mDNS_Dereg_rapid, mDNS_Dereg_conflict, mDNS_De
// and the default domain in which to register in the case where the user has made no selection.
extern void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context);
mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, AuthRecType artype, mDNSRecordCallback Callback, void *Context);
// mDNS_RegisterService() flags parameter bit definitions
enum
{
regFlagIncludeP2P = 0x1, // include P2P interfaces when using mDNSInterface_Any
regFlagKnownUnique = 0x2 // client guarantees that SRV and TXT record names are unique
};
extern mStatus mDNS_RegisterService (mDNS *const m, ServiceRecordSet *sr,
const domainlabel *const name, const domainname *const type, const domainname *const domain,
const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
AuthRecord *SubTypes, mDNSu32 NumSubTypes,
const mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context);
extern mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl);
mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context, mDNSu32 flags);
extern mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl, mDNSu32 includeP2P);
extern mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, mDNSRecordCallback MemFreeCallback, void *Context);
extern mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname);
extern mStatus mDNS_DeregisterService_drt(mDNS *const m, ServiceRecordSet *sr, mDNS_Dereg_type drt);
@ -2114,7 +2232,7 @@ extern mStatus mDNS_DeregisterService_drt(mDNS *const m, ServiceRecordSet *sr, m
extern mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr,
const domainlabel *const name, const domainname *const type, const domainname *const domain,
const domainname *const host,
const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context);
const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context, mDNSBool includeP2P);
#define mDNS_DeregisterNoSuchService mDNS_Deregister
extern void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID InterfaceID, const domainname *const name,
@ -2152,7 +2270,7 @@ extern mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID I
extern DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID);
extern DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question);
extern void SetValidDNSServers(mDNS *m, DNSQuestion *question);
extern mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question);
// ***************************************************************************
#if 0
@ -2314,9 +2432,6 @@ extern mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr); // returns true for RFC1
#define mDNSv4AddressIsLoopback(X) ((X)->b[0] == 127 && (X)->b[1] == 0 && (X)->b[2] == 0 && (X)->b[3] == 1)
#define mDNSv6AddressIsLoopback(X) ((((X)->l[0] | (X)->l[1] | (X)->l[2]) == 0) && ((X)->b[12] == 0 && (X)->b[13] == 0 && (X)->b[14] == 0 && (X)->b[15] == 1))
#define mDNSAddressIsLoopback(X) ( \
((X)->type == mDNSAddrType_IPv4) ? mDNSv4AddressIsLoopback(&(X)->ip.v4) : \
((X)->type == mDNSAddrType_IPv6) ? mDNSv6AddressIsLoopback(&(X)->ip.v6) : mDNSfalse)
// ***************************************************************************
#if 0
#pragma mark -
@ -2330,10 +2445,11 @@ extern mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr); // returns true for RFC1
// domain name format. The shared secret must be a null-terminated base64 encoded string. A minimum size of
// 16 bytes (128 bits) is recommended for an MD5 hash as per RFC 2485.
// Calling this routine multiple times for a zone replaces previously entered values. Call with a NULL key
// to dissable authentication for the zone.
// to disable authentication for the zone. A non-NULL autoTunnelPrefix means this is an AutoTunnel domain,
// and the value is prepended to the IPSec identifier (used for key lookup)
extern mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel);
const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, const char *autoTunnelPrefix);
extern void RecreateNATMappings(mDNS *const m);
@ -2357,13 +2473,15 @@ extern void RecreateNATMappings(mDNS *const m);
extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext);
extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router);
extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped);
extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped, mDNSu32 timeout);
extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q);
extern void mDNS_AddSearchDomain(const domainname *const domain);
extern void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID);
extern McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, mDNSu32 timeout);
// We use ((void *)0) here instead of mDNSNULL to avoid compile warnings on gcc 4.2
#define mDNS_AddSearchDomain_CString(X) \
do { domainname d__; if (((X) != (void*)0) && MakeDomainNameFromDNSNameString(&d__, (X)) && d__.c[0]) mDNS_AddSearchDomain(&d__); } while(0)
#define mDNS_AddSearchDomain_CString(X, I) \
do { domainname d__; if (((X) != (void*)0) && MakeDomainNameFromDNSNameString(&d__, (X)) && d__.c[0]) mDNS_AddSearchDomain(&d__, I); } while(0)
// Routines called by the core, exported by DNSDigest.c
@ -2478,7 +2596,7 @@ mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *resu
// and interface indexes in order to support the DNS-SD API. If your target platform does not support
// multiple interfaces and/or does not support the DNS-SD API, these functions can be empty.
extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex);
extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id);
extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange);
// Every platform support module must provide the following functions if it is to support unicast DNS
// and Dynamic Update.
@ -2531,7 +2649,9 @@ extern void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, m
extern mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *router);
extern void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status);
extern void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep);
extern void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason);
extern void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration);
extern mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf);
#ifdef _LEGACY_NAT_TRAVERSAL_
// Support for legacy NAT traversal protocols, implemented by the platform layer and callable by the core.
@ -2587,7 +2707,11 @@ extern void mDNSCoreInitComplete(mDNS *const m, mStatus result);
extern void mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end,
const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
extern void mDNSCoreRestartQueries(mDNS *const m);
extern void mDNSCoreRestartQueries(mDNS *const m);
typedef void (*FlushCache)(mDNS *const m);
typedef void (*CallbackBeforeStartQuery)(mDNS *const m, void *context);
extern void mDNSCoreRestartAddressQueries(mDNS *const m, mDNSBool SearchDomainsChanged, FlushCache flushCacheRecords,
CallbackBeforeStartQuery beforeQueryStart, void *context);
extern mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m);
extern void mDNSCoreMachineSleep(mDNS *const m, mDNSBool wake);
extern mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now);
@ -2606,9 +2730,19 @@ extern void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
extern void CompleteDeregistration(mDNS *const m, AuthRecord *rr);
extern void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord);
extern char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID);
extern void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer *new);
extern void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer *newServer);
extern void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr);
extern void CheckSuppressUnusableQuestions(mDNS *const m);
extern void RetrySearchDomainQuestions(mDNS *const m);
// Used only in logging to restrict the number of /etc/hosts entries printed
extern void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result);
// exported for using the hash for /etc/hosts AuthRecords
extern AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name);
extern AuthGroup *AuthGroupForRecord(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr);
extern AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
extern AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
extern mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype);
// For now this AutoTunnel stuff is specific to Mac OS X.
// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
@ -2619,7 +2753,6 @@ extern void SetupLocalAutoTunnelInterface_internal(mDNS *const m, mDNSBool servi
extern void UpdateAutoTunnelDomainStatuses(const mDNS *const m);
extern mStatus ActivateLocalProxy(mDNS *const m, char *ifname);
extern void RemoveAutoTunnel6Record(mDNS *const m);
extern void SetupConndConfigChanges(mDNS *const m);
extern mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr);
#endif
@ -2741,6 +2874,17 @@ extern mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr);
// 60 = 1 W
// 90 = 1 kW
typedef enum
{
mDNSSleepProxyMetric_Dedicated = 20,
mDNSSleepProxyMetric_PrimaryHardware = 30,
mDNSSleepProxyMetric_PrimarySoftware = 40,
mDNSSleepProxyMetric_SecondaryHardware = 50,
mDNSSleepProxyMetric_SecondarySoftware = 60,
mDNSSleepProxyMetric_IncidentalHardware = 70,
mDNSSleepProxyMetric_IncidentalSoftware = 80
} mDNSSleepProxyMetric;
extern void mDNSCoreBeSleepProxyServer_internal(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower);
#define mDNSCoreBeSleepProxyServer(M,S,P,MP,TP) \
do { mDNS_Lock(m); mDNSCoreBeSleepProxyServer_internal((M),(S),(P),(MP),(TP)); mDNS_Unlock(m); } while(0)
@ -2801,17 +2945,17 @@ struct CompileTimeAssertionChecks_mDNS
char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1208) ? 1 : -1];
char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 184) ? 1 : -1];
char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 184) ? 1 : -1];
char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 752) ? 1 : -1];
char sizecheck_ZoneData [(sizeof(ZoneData) <= 1588) ? 1 : -1];
char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 786) ? 1 : -1];
char sizecheck_ZoneData [(sizeof(ZoneData) <= 1624) ? 1 : -1];
char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 192) ? 1 : -1];
char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3050) ? 1 : -1];
char sizecheck_DNSServer [(sizeof(DNSServer) <= 320) ? 1 : -1];
char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 6750) ? 1 : -1];
char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 6850) ? 1 : -1];
char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5500) ? 1 : -1];
char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7550) ? 1 : -1];
char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 3050) ? 1 : -1];
char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7968) ? 1 : -1];
char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 3200) ? 1 : -1];
#if APPLE_OSX_mDNSResponder
char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1104) ? 1 : -1];
char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1148) ? 1 : -1];
#endif
};

View File

@ -20,6 +20,9 @@
* Any dynamic run-time requirements should be handled by the platform layer below or client layer above
*/
#if APPLE_OSX_mDNSResponder
#include <TargetConditionals.h>
#endif
#include "uDNS.h"
#if(defined(_MSC_VER))
@ -98,7 +101,7 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mDNSu32 random)
#pragma mark - Name Server List Management
#endif
mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped)
mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped, mDNSu32 timeout)
{
DNSServer **p = &m->DNSServers;
DNSServer *tmp = mDNSNULL;
@ -146,6 +149,7 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
(*p)->flags = DNSServer_FlagNew;
(*p)->teststate = /* DNSServer_Untested */ DNSServer_Passed;
(*p)->lasttest = m->timenow - INIT_UCAST_POLL_INTERVAL;
(*p)->timeout = timeout;
AssignDomainName(&(*p)->domain, d);
(*p)->next = mDNSNULL;
}
@ -345,17 +349,25 @@ mDNSexport DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const n
// MUST be called with the lock held
mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel)
const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, const char *autoTunnelPrefix)
{
DNSQuestion *q;
DomainAuthInfo **p = &m->AuthInfoList;
if (!info || !b64keydata) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info, b64keydata); return(mStatus_BadParamErr); }
LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, AutoTunnel ? " AutoTunnel" : "");
LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s%s%s", domain->c, keyname->c, autoTunnelPrefix ? " prefix " : "", autoTunnelPrefix ? autoTunnelPrefix : "");
info->AutoTunnel = AutoTunnel;
info->AutoTunnel = autoTunnelPrefix;
AssignDomainName(&info->domain, domain);
AssignDomainName(&info->keyname, keyname);
if (hostname)
AssignDomainName(&info->hostname, hostname);
else
info->hostname.c[0] = 0;
if (port)
info->port = *port;
else
info->port = zeroIPPort;
mDNS_snprintf(info->b64keydata, sizeof(info->b64keydata), "%s", b64keydata);
if (DNSDigest_ConstructHMACKeyfromBase64(info, b64keydata) < 0)
@ -372,12 +384,13 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
// Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo
// being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use.
info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
info->AutoTunnelHostRecord.namestorage.c[0] = 0;
info->AutoTunnelTarget .resrec.RecordType = kDNSRecordTypeUnregistered;
info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
info->AutoTunnelService .resrec.RecordType = kDNSRecordTypeUnregistered;
info->AutoTunnel6Record .resrec.RecordType = kDNSRecordTypeUnregistered;
info->AutoTunnelHostRecord .resrec.RecordType = kDNSRecordTypeUnregistered;
info->AutoTunnelHostRecord .namestorage.c[0] = 0;
info->AutoTunnelTarget .resrec.RecordType = kDNSRecordTypeUnregistered;
info->AutoTunnelDeviceInfo .resrec.RecordType = kDNSRecordTypeUnregistered;
info->AutoTunnelService .resrec.RecordType = kDNSRecordTypeUnregistered;
info->AutoTunnel6Record .resrec.RecordType = kDNSRecordTypeUnregistered;
info->AutoTunnel6MetaRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
info->AutoTunnelNAT.clientContext = mDNSNULL;
info->next = mDNSNULL;
*p = info;
@ -553,6 +566,9 @@ mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalIn
{
LogMsg("Error! Tried to add a NAT traversal that's already in the active list: request %p Prot %d Int %d TTL %d",
traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease);
#if ForceAlerts
*(long*)0 = 0;
#endif
return(mStatus_AlreadyRegistered);
}
if (traversal->Protocol && traversal->Protocol == (*n)->Protocol && mDNSSameIPPort(traversal->IntPort, (*n)->IntPort) &&
@ -698,7 +714,7 @@ mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *
// !!!KRS implement me
// format opt rr (fields not specified are zero-valued)
mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
opt->rrclass = NormalMaxDNSMessageData;
opt->rdlength = sizeof(rdataOPT); // One option in this OPT record
opt->rdestimate = sizeof(rdataOPT);
@ -1572,6 +1588,12 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt
zd->question.ForceMCast = mDNSfalse;
zd->question.ReturnIntermed = mDNStrue;
zd->question.SuppressUnusable = mDNSfalse;
zd->question.SearchListIndex = 0;
zd->question.AppendSearchDomains = 0;
zd->question.RetryWithSearchDomains = mDNSfalse;
zd->question.TimeoutQuestion = 0;
zd->question.WakeOnResolve = 0;
zd->question.qnameOrig = mDNSNULL;
zd->question.QuestionCallback = GetZoneData_QuestionCallback;
zd->question.QuestionContext = zd;
@ -1600,15 +1622,46 @@ mDNSexport ZoneData *StartGetZoneData(mDNS *const m, const domainname *const nam
zd->ZoneDataContext = ZoneDataContext;
zd->question.QuestionContext = zd;
AssignDomainName(&zd->question.qname, zd->CurrentSOA);
mDNS_DropLockBeforeCallback(); // GetZoneData_StartQuery expects to be called from a normal callback, so we emulate that here
GetZoneData_StartQuery(m, zd, kDNSType_SOA);
if (AuthInfo && AuthInfo->AutoTunnel && !mDNSIPPortIsZero(AuthInfo->port))
{
LogInfo("StartGetZoneData: Bypassing SOA, SRV query for %##s", AuthInfo->domain.c);
// We bypass SOA and SRV queries if we know the hostname and port already from the configuration.
// Today this is only true for AutoTunnel. As we bypass, we need to infer a few things:
//
// 1. Zone name is the same as the AuthInfo domain
// 2. ZoneClass is kDNSClass_IN which should be a safe assumption
//
// If we want to make this bypass mechanism work for non-AutoTunnels also, (1) has to hold
// good. Otherwise, it has to be configured also.
AssignDomainName(&zd->ZoneName, &AuthInfo->domain);
zd->ZoneClass = kDNSClass_IN;
AssignDomainName(&zd->Host, &AuthInfo->hostname);
zd->Port = AuthInfo->port;
AssignDomainName(&zd->question.qname, &zd->Host);
GetZoneData_StartQuery(m, zd, kDNSType_A);
}
else
{
if (AuthInfo && AuthInfo->AutoTunnel) LogInfo("StartGetZoneData: Not Bypassing SOA, SRV query for %##s", AuthInfo->domain.c);
AssignDomainName(&zd->question.qname, zd->CurrentSOA);
GetZoneData_StartQuery(m, zd, kDNSType_SOA);
}
mDNS_ReclaimLockAfterCallback();
return zd;
}
// Returns if the question is a GetZoneData question. These questions are special in
// that they are created internally while resolving a private query or LLQs.
mDNSexport mDNSBool IsGetZoneDataQuestion(DNSQuestion *q)
{
if (q->QuestionCallback == GetZoneData_QuestionCallback) return(mDNStrue);
else return(mDNSfalse);
}
// GetZoneData queries are a special case -- even if we have a key for them, we don't do them privately,
// because that would result in an infinite loop (i.e. to do a private query we first need to get
// the _dns-query-tls SRV record for the zone, and we can't do *that* privately because to do so
@ -1664,7 +1717,7 @@ mDNSlocal void UpdateAllServiceRecords(mDNS *const m, AuthRecord *rr, mDNSBool r
}
else
{
// Clearing SRVchanged is a safety measure. If our pewvious dereg never
// Clearing SRVchanged is a safety measure. If our pevious dereg never
// came back and we had a target change, we are starting fresh
r->SRVChanged = mDNSfalse;
// if it is already registered or in the process of registering, then don't
@ -1709,7 +1762,7 @@ mDNSlocal void CompleteRecordNatMap(mDNS *m, NATTraversalInfo *n)
if (!rr->nta || mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4))
{
LogInfo("CompleteRecordNatMap called for %s but no zone information!", ARDisplayString(m, rr));
// We need to clear out the NATinfo state so that it will result in re-acuqiring the mapping
// We need to clear out the NATinfo state so that it will result in re-acquiring the mapping
// and hence this callback called again.
if (rr->NATinfo.clientContext)
{
@ -1802,8 +1855,13 @@ mDNSlocal void StartRecordNatMap(mDNS *m, AuthRecord *rr)
else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) protocol = NATOp_MapUDP;
else { LogMsg("StartRecordNatMap: could not determine transport protocol of service %##s", rr->resrec.name->c); return; }
//LogMsg("StartRecordNatMap: clientContext %p IntPort %d srv.port %d %s",
// rr->NATinfo.clientContext, mDNSVal16(rr->NATinfo.IntPort), mDNSVal16(rr->resrec.rdata->u.srv.port), ARDisplayString(m, rr));
if (rr->NATinfo.clientContext) mDNS_StopNATOperation_internal(m, &rr->NATinfo);
rr->NATinfo.Protocol = protocol;
// Shouldn't be trying to set IntPort here --
// BuildUpdateMessage overwrites srs->RR_SRV.resrec.rdata->u.srv.port with external (mapped) port number
rr->NATinfo.IntPort = rr->resrec.rdata->u.srv.port;
rr->NATinfo.RequestedPort = rr->resrec.rdata->u.srv.port;
rr->NATinfo.NATLease = 0; // Request default lease
@ -1818,6 +1876,19 @@ mDNSlocal void StartRecordNatMap(mDNS *m, AuthRecord *rr)
// record is temporarily left in the ResourceRecords list so that we can initialize later
// when the target is resolvable. Similarly, when host name changes, we enter regState_NoTarget
// and we do the same.
// This UnlinkResourceRecord routine is very worrying. It bypasses all the normal cleanup performed
// by mDNS_Deregister_internal and just unceremoniously cuts the record from the active list.
// This is why re-regsitering this record was producing syslog messages like this:
// "Error! Tried to add a NAT traversal that's already in the active list"
// Right now UnlinkResourceRecord is fortunately only called by RegisterAllServiceRecords,
// which then immediately calls mDNS_Register_internal to re-register the record, which probably
// masked more serious problems. Any other use of UnlinkResourceRecord is likely to lead to crashes.
// For now we'll workaround that specific problem by explicitly calling mDNS_StopNATOperation_internal,
// but long-term we should either stop cancelling the record registration and then re-registering it,
// or if we really do need to do this for some reason it should be done via the usual
// mDNS_Deregister_internal path instead of just cutting the record from the list.
mDNSlocal mStatus UnlinkResourceRecord(mDNS *const m, AuthRecord *const rr)
{
AuthRecord **list = &m->ResourceRecords;
@ -1826,6 +1897,15 @@ mDNSlocal mStatus UnlinkResourceRecord(mDNS *const m, AuthRecord *const rr)
{
*list = rr->next;
rr->next = mDNSNULL;
// Temporary workaround to cancel any active NAT mapping operation
if (rr->NATinfo.clientContext)
{
mDNS_StopNATOperation_internal(m, &rr->NATinfo);
rr->NATinfo.clientContext = mDNSNULL;
if (rr->resrec.rrtype == kDNSType_SRV) rr->resrec.rdata->u.srv.port = rr->NATinfo.IntPort;
}
return(mStatus_NoError);
}
LogMsg("UnlinkResourceRecord:ERROR!! - no such active record %##s", rr->resrec.name->c);
@ -2022,7 +2102,7 @@ mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h)
{
if (!mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4) && h->arv4.resrec.RecordType == kDNSRecordTypeUnregistered)
{
mDNS_SetupResourceRecord(&h->arv4, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, HostnameCallback, h);
mDNS_SetupResourceRecord(&h->arv4, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, AuthRecordAny, HostnameCallback, h);
AssignDomainName(&h->arv4.namestorage, &h->fqdn);
h->arv4.resrec.rdata->u.ipv4 = m->AdvertisedV4.ip.v4;
h->arv4.state = regState_Unregistered;
@ -2048,7 +2128,7 @@ mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h)
if (!mDNSIPv6AddressIsZero(m->AdvertisedV6.ip.v6) && h->arv6.resrec.RecordType == kDNSRecordTypeUnregistered)
{
mDNS_SetupResourceRecord(&h->arv6, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeKnownUnique, HostnameCallback, h);
mDNS_SetupResourceRecord(&h->arv6, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, HostnameCallback, h);
AssignDomainName(&h->arv6.namestorage, &h->fqdn);
h->arv6.resrec.rdata->u.ipv6 = m->AdvertisedV6.ip.v6;
h->arv6.state = regState_Unregistered;
@ -2189,6 +2269,12 @@ mDNSlocal void GetStaticHostname(mDNS *m)
q->ForceMCast = mDNSfalse;
q->ReturnIntermed = mDNStrue;
q->SuppressUnusable = mDNSfalse;
q->SearchListIndex = 0;
q->AppendSearchDomains = 0;
q->RetryWithSearchDomains = mDNSfalse;
q->TimeoutQuestion = 0;
q->WakeOnResolve = 0;
q->qnameOrig = mDNSNULL;
q->QuestionCallback = FoundStaticHostname;
q->QuestionContext = mDNSNULL;
@ -2927,7 +3013,7 @@ mDNSlocal mDNSBool SendGroupUpdates(mDNS *const m)
}
spaceleft -= rrSize;
oldnext = next;
LogInfo("SendGroupUpdates: Building a message with resource record %s, next %p, state %d", ARDisplayString(m, rr), next, rr->state);
LogInfo("SendGroupUpdates: Building a message with resource record %s, next %p, state %d, ttl %d", ARDisplayString(m, rr), next, rr->state, rr->resrec.rroriginalttl);
if (!(next = BuildUpdateMessage(m, next, rr, limit)))
{
// We calculated the space and if we can't fit in, we had some bug in the calculation,
@ -3071,7 +3157,7 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err, mDNSu
rr->updateError = err;
#if APPLE_OSX_mDNSResponder
if (err == mStatus_BadSig) UpdateAutoTunnelDomainStatuses(m);
if (err == mStatus_BadSig || err == mStatus_BadKey) UpdateAutoTunnelDomainStatuses(m);
#endif
SetRecordRetry(m, rr, random);
@ -4030,7 +4116,6 @@ mDNSlocal const mDNSu8 *mDNS_WABLabels[] =
(const mDNSu8 *)"\002lb",
(const mDNSu8 *)"\001r",
(const mDNSu8 *)"\002dr",
(const mDNSu8 *)"\002cf",
(const mDNSu8 *)mDNSNULL,
};
@ -4569,28 +4654,41 @@ mDNSexport void SleepRecordRegistrations(mDNS *m)
}
}
mDNSexport void mDNS_AddSearchDomain(const domainname *const domain)
mDNSexport void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID)
{
SearchListElem **p;
SearchListElem *tmp = mDNSNULL;
// Check to see if we already have this domain in our list
for (p = &SearchList; *p; p = &(*p)->next)
if (SameDomainName(&(*p)->domain, domain))
if (((*p)->InterfaceID == InterfaceID) && SameDomainName(&(*p)->domain, domain))
{
// If domain is already in list, and marked for deletion, change it to "leave alone"
if ((*p)->flag == -1) (*p)->flag = 0;
// If domain is already in list, and marked for deletion, unmark the delete
// Be careful not to touch the other flags that may be present
LogInfo("mDNS_AddSearchDomain already in list %##s", domain->c);
return;
if ((*p)->flag & SLE_DELETE) (*p)->flag &= ~SLE_DELETE;
tmp = *p;
*p = tmp->next;
tmp->next = mDNSNULL;
break;
}
// if domain not in list, add to list, mark as add (1)
*p = mDNSPlatformMemAllocate(sizeof(SearchListElem));
if (!*p) { LogMsg("ERROR: mDNS_AddSearchDomain - malloc"); return; }
mDNSPlatformMemZero(*p, sizeof(SearchListElem));
AssignDomainName(&(*p)->domain, domain);
(*p)->flag = 1; // add
(*p)->next = mDNSNULL;
LogInfo("mDNS_AddSearchDomain created new %##s", domain->c);
// move to end of list so that we maintain the same order
while (*p) p = &(*p)->next;
if (tmp) *p = tmp;
else
{
// if domain not in list, add to list, mark as add (1)
*p = mDNSPlatformMemAllocate(sizeof(SearchListElem));
if (!*p) { LogMsg("ERROR: mDNS_AddSearchDomain - malloc"); return; }
mDNSPlatformMemZero(*p, sizeof(SearchListElem));
AssignDomainName(&(*p)->domain, domain);
(*p)->next = mDNSNULL;
(*p)->InterfaceID = InterfaceID;
LogInfo("mDNS_AddSearchDomain created new %##s, InterfaceID %p", domain->c, InterfaceID);
}
}
mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
@ -4599,95 +4697,6 @@ mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus r
if (result == mStatus_MemFree) mDNSPlatformMemFree(rr->RecordContext);
}
#if APPLE_OSX_mDNSResponder
mDNSlocal void CheckAutoTunnel6Registration(mDNS *const m, mDNSBool RegisterAutoTunnel6)
{
LogInfo("CheckAutoTunnel6Registration: Current value RegisterAutoTunnel6 %d, New value %d", m->RegisterAutoTunnel6, RegisterAutoTunnel6);
if (!RegisterAutoTunnel6)
{
// We are not supposed to register autotunnel6. If we had previously registered
// autotunnel6, deregister it now.
if (m->RegisterAutoTunnel6)
{
m->RegisterAutoTunnel6 = mDNSfalse;
LogInfo("CheckAutoTunnel6Registration: Removing AutoTunnel6");
RemoveAutoTunnel6Record(m);
}
else LogInfo("CheckAutoTunnel6Registration: Already Removed AutoTunnel6");
}
else
{
// We are supposed to register autotunnel6. If we had previously de-registered
// autotunnel6, re-register it now.
if (!m->RegisterAutoTunnel6)
{
m->RegisterAutoTunnel6 = mDNStrue;
LogInfo("CheckAutoTunnel6Registration: Adding AutoTunnel6");
SetupConndConfigChanges(m);
}
else LogInfo("CheckAutoTunnel6Registration: already Added AutoTunnel6");
}
}
#endif
mDNSlocal void FoundDirDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
SearchListElem *slElem = question->QuestionContext;
mDNSBool RegisterAutoTunnel6 = mDNStrue;
char *res = "DisableInboundRelay";
LogInfo("FoundDirDomain: InterfaceID %p %s Question %##s Answer %s", answer->InterfaceID, AddRecord ? "Add" : "Rmv", question->qname.c, RRDisplayString(m, answer));
if (answer->rrtype != kDNSType_TXT)
{
LogMsg("FoundDirDomain: answer type is not TXT %s for question %##s", DNSTypeName(answer->rrtype), question->qname.c);
return;
}
if (answer->RecordType == kDNSRecordTypePacketNegative)
{
LogInfo("FoundDirDomain: Negative answer for %##s", question->qname.c);
return;
}
if (answer->InterfaceID == mDNSInterface_LocalOnly)
{
LogInfo("FoundDirDomain: LocalOnly interfaceID for %##s", question->qname.c);
return;
}
// TXT record is encoded as <len><data>
if (answer->rdlength != mDNSPlatformStrLen(res) + 1)
{
LogInfo("FoundDirDomain: Invalid TXT record to disable %##s, length %d", question->qname.c, answer->rdlength);
return;
}
// Compare the data (excluding the len byte)
if (!mDNSPlatformMemSame(&answer->rdata->u.txt.c[1], res, answer->rdlength - 1))
{
LogInfo("FoundDirDomain: Invalid TXT record to disable %##s", question->qname.c);
return;
}
// It is sufficient for one answer to disable registration of autotunnel6. But we should
// have zero answers across all domains to register autotunnel6.
if (AddRecord)
{
slElem->numDirAnswers++;
RegisterAutoTunnel6 = mDNSfalse;
}
else
{
const SearchListElem *s;
slElem->numDirAnswers--;
if (slElem->numDirAnswers < 0) LogMsg("FoundDirDomain: numDirAnswers less than zero %d", slElem->numDirAnswers);
// See if any domain (including the slElem) has any answers
for (s=SearchList; s; s=s->next)
if (s->numDirAnswers) { RegisterAutoTunnel6 = mDNSfalse; break; }
}
#if APPLE_OSX_mDNSResponder
CheckAutoTunnel6Registration(m, RegisterAutoTunnel6);
#endif
}
mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
SearchListElem *slElem = question->QuestionContext;
@ -4711,7 +4720,7 @@ mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceR
{
ARListElem *arElem = mDNSPlatformMemAllocate(sizeof(ARListElem));
if (!arElem) { LogMsg("ERROR: FoundDomain out of memory"); return; }
mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem);
mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, AuthRecordLocalOnly, FreeARElemCallback, arElem);
MakeDomainNameFromDNSNameString(&arElem->ar.namestorage, name);
AppendDNSNameString (&arElem->ar.namestorage, "local");
AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
@ -4758,7 +4767,7 @@ mDNSexport void udns_validatelists(void *const v)
DomainAuthInfo *info;
for (info = m->AuthInfoList; info; info = info->next)
if (info->next == (DomainAuthInfo *)~0 || info->AutoTunnel == (mDNSBool)~0)
if (info->next == (DomainAuthInfo *)~0 || info->AutoTunnel == (const char*)~0)
LogMemCorruption("m->AuthInfoList: %p is garbage (%X)", info, info->AutoTunnel);
HostnameInfo *hi;
@ -4773,68 +4782,50 @@ mDNSexport void udns_validatelists(void *const v)
}
#endif
mDNSlocal void mDNS_StartDirQuestion(mDNS *const m, DNSQuestion *question, domainname *domain, void *context)
{
AssignDomainName (&question->qname, (const domainname*)"\002cf" "\007_dns-sd" "\x04_udp");
AppendDomainName (&question->qname, domain);
question->InterfaceID = mDNSInterface_Any;
question->Target = zeroAddr;
question->qtype = kDNSType_TXT;
question->qclass = kDNSClass_IN;
question->LongLived = mDNSfalse;
question->ExpectUnique = mDNStrue;
question->ForceMCast = mDNSfalse;
question->ReturnIntermed = mDNSfalse;
question->SuppressUnusable = mDNSfalse;
question->QuestionCallback = FoundDirDomain;
question->QuestionContext = context;
LogInfo("mDNS_StartDirQuestion: Start DIR domain question %##s", question->qname.c);
if (mDNS_StartQuery(m, question))
LogMsg("mDNS_StartDirQuestion: ERROR!! cannot start _dir._dns-sd query");
}
// This should probably move to the UDS daemon -- the concept of legacy clients and automatic registration / automatic browsing
// is really a UDS API issue, not something intrinsic to uDNS
mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m)
mDNSexport mStatus uDNS_SetupSearchDomains(mDNS *const m, int action)
{
SearchListElem **p = &SearchList, *ptr;
const SearchListElem *s;
mDNSBool RegisterAutoTunnel6 = mDNStrue;
mStatus err;
// step 1: mark each element for removal (-1)
for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = -1;
// step 1: mark each element for removal
for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag |= SLE_DELETE;
// Client has requested domain enumeration or automatic browse -- time to make sure we have the search domains from the platform layer
// Make sure we have the search domains from the platform layer so that if we start the WAB
// queries below, we have the latest information
mDNS_Lock(m);
m->RegisterSearchDomains = mDNStrue;
mDNSPlatformSetDNSConfig(m, mDNSfalse, m->RegisterSearchDomains, mDNSNULL, mDNSNULL, mDNSNULL);
mDNSPlatformSetDNSConfig(m, mDNSfalse, mDNStrue, mDNSNULL, mDNSNULL, mDNSNULL);
mDNS_Unlock(m);
if (action & UDNS_START_WAB_QUERY)
m->StartWABQueries = mDNStrue;
// delete elems marked for removal, do queries for elems marked add
while (*p)
{
ptr = *p;
LogInfo("RegisterSearchDomains %d %p %##s", ptr->flag, ptr->AuthRecs, ptr->domain.c);
if (ptr->flag == -1) // remove
LogInfo("uDNS_SetupSearchDomains:action %d: Flags %d, AuthRecs %p, InterfaceID %p %##s", action, ptr->flag, ptr->AuthRecs, ptr->InterfaceID, ptr->domain.c);
if (ptr->flag & SLE_DELETE)
{
ARListElem *arList = ptr->AuthRecs;
ptr->AuthRecs = mDNSNULL;
*p = ptr->next;
// If the user has "local" in their DNS searchlist, we ignore that for the purposes of domain enumeration queries
// Note: Stopping a question will not generate the RMV events for the question (handled in FoundDirDomain)
// and hence we need to recheck all the domains to see if we need to register/deregister _autotunnel6.
// This is done at the end.
if (!SameDomainName(&ptr->domain, &localdomain))
// We suppressed the domain enumeration for scoped search domains below. When we enable that
// enable this.
if ((ptr->flag & SLE_WAB_QUERY_STARTED) &&
!SameDomainName(&ptr->domain, &localdomain) && (ptr->InterfaceID == mDNSInterface_Any))
{
mDNS_StopGetDomains(m, &ptr->BrowseQ);
mDNS_StopGetDomains(m, &ptr->RegisterQ);
mDNS_StopGetDomains(m, &ptr->DefBrowseQ);
mDNS_StopGetDomains(m, &ptr->DefRegisterQ);
mDNS_StopGetDomains(m, &ptr->AutomaticBrowseQ);
mDNS_StopGetDomains(m, &ptr->DirQ);
}
mDNSPlatformMemFree(ptr);
// deregister records generated from answers to the query
@ -4844,49 +4835,121 @@ mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m)
arList = arList->next;
debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c);
err = mDNS_Deregister(m, &dereg->ar);
if (err) LogMsg("uDNS_RegisterSearchDomains ERROR!! mDNS_Deregister returned %d", err);
if (err) LogMsg("uDNS_SetupSearchDomains:: ERROR!! mDNS_Deregister returned %d", err);
// Memory will be freed in the FreeARElemCallback
}
continue;
}
if (ptr->flag == 1) // add
if ((action & UDNS_START_WAB_QUERY) && !(ptr->flag & SLE_WAB_QUERY_STARTED))
{
// If the user has "local" in their DNS searchlist, we ignore that for the purposes of domain enumeration queries
if (!SameDomainName(&ptr->domain, &localdomain))
// If the user has "local" in their DNS searchlist, we ignore that for the purposes of domain enumeration queries.
// Also, suppress the domain enumeration for scoped search domains for now until there is a need.
if (!SameDomainName(&ptr->domain, &localdomain) && (ptr->InterfaceID == mDNSInterface_Any))
{
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->AutomaticBrowseQ, mDNS_DomainTypeBrowseAutomatic, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
err1 = mDNS_GetDomains(m, &ptr->BrowseQ, mDNS_DomainTypeBrowse, &ptr->domain, ptr->InterfaceID, FoundDomain, ptr);
err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ, mDNS_DomainTypeBrowseDefault, &ptr->domain, ptr->InterfaceID, FoundDomain, ptr);
err3 = mDNS_GetDomains(m, &ptr->RegisterQ, mDNS_DomainTypeRegistration, &ptr->domain, ptr->InterfaceID, FoundDomain, ptr);
err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ, mDNS_DomainTypeRegistrationDefault, &ptr->domain, ptr->InterfaceID, FoundDomain, ptr);
err5 = mDNS_GetDomains(m, &ptr->AutomaticBrowseQ, mDNS_DomainTypeBrowseAutomatic, &ptr->domain, ptr->InterfaceID, FoundDomain, ptr);
if (err1 || err2 || err3 || err4 || err5)
LogMsg("uDNS_RegisterSearchDomains: GetDomains for domain %##s returned error(s):\n"
LogMsg("uDNS_SetupSearchDomains: 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_DomainTypeBrowseAutomatic)\n",
ptr->domain.c, err1, err2, err3, err4, err5);
mDNS_StartDirQuestion(m, &ptr->DirQ, &ptr->domain, ptr);
ptr->flag |= SLE_WAB_QUERY_STARTED;
}
ptr->flag = 0;
}
if (ptr->flag) { LogMsg("uDNS_RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); }
p = &ptr->next;
}
// if there is any domain has answers, need to deregister autotunnel6
for (s=SearchList; s; s=s->next)
if (s->numDirAnswers) { RegisterAutoTunnel6 = mDNSfalse; break; }
#if APPLE_OSX_mDNSResponder
CheckAutoTunnel6Registration(m, RegisterAutoTunnel6);
#endif
return mStatus_NoError;
}
mDNSexport domainname *uDNS_GetNextSearchDomain(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal)
{
SearchListElem *p = SearchList;
int count = *searchIndex;
(void) m; // unused
if (count < 0) { LogMsg("uDNS_GetNextSearchDomain: count %d less than zero", count); return mDNSNULL; }
// skip the domains that we already looked at before
for (; count; count--) p = p->next;
while (p)
{
int labels = CountLabels(&p->domain);
if (labels > 0)
{
const domainname *d = SkipLeadingLabels(&p->domain, labels - 1);
if (SameDomainLabel(d->c, (const mDNSu8 *)"\x4""arpa"))
{
LogInfo("uDNS_GetNextSearchDomain: skipping search domain %##s, InterfaceID %p", p->domain.c, p->InterfaceID);
(*searchIndex)++;
p = p->next;
continue;
}
if (ignoreDotLocal && SameDomainLabel(d->c, (const mDNSu8 *)"\x5""local"))
{
LogInfo("uDNS_GetNextSearchDomain: skipping local domain %##s, InterfaceID %p", p->domain.c, p->InterfaceID);
(*searchIndex)++;
p = p->next;
continue;
}
}
// Point to the next one in the list which we will look at next time.
(*searchIndex)++;
// When we are appending search domains in a ActiveDirectory domain, the question's InterfaceID
// set to mDNSInterface_Unicast. Match the unscoped entries in that case.
if (((InterfaceID == mDNSInterface_Unicast) && (p->InterfaceID == mDNSInterface_Any)) ||
p->InterfaceID == InterfaceID)
{
LogInfo("uDNS_GetNextSearchDomain returning domain %##s, InterfaceID %p", p->domain.c, p->InterfaceID);
return &p->domain;
}
LogInfo("uDNS_GetNextSearchDomain skipping domain %##s, InterfaceID %p", p->domain.c, p->InterfaceID);
p = p->next;
}
return mDNSNULL;
}
mDNSlocal void FlushAddressCacheRecords(mDNS *const m)
{
mDNSu32 slot;
CacheGroup *cg;
CacheRecord *cr;
FORALL_CACHERECORDS(slot, cg, cr)
{
if (cr->resrec.InterfaceID) continue;
// If a resource record can answer A or AAAA, they need to be flushed so that we will
// never used to deliver an ADD or RMV
if (RRTypeAnswersQuestionType(&cr->resrec, kDNSType_A) ||
RRTypeAnswersQuestionType(&cr->resrec, kDNSType_AAAA))
{
LogInfo("FlushAddressCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr));
mDNS_PurgeCacheResourceRecord(m, cr);
}
}
}
// Retry questions which has seach domains appended
mDNSexport void RetrySearchDomainQuestions(mDNS *const m)
{
// Purge all the A/AAAA cache records and restart the queries. mDNSCoreRestartAddressQueries
// does this. When we restart the question, we first want to try the new search domains rather
// than use the entries that is already in the cache. When we appended search domains, we might
// have created cache entries which is no longer valid as there are new search domains now
LogInfo("RetrySearchDomainQuestions: Calling mDNSCoreRestartAddressQueries");
mDNSCoreRestartAddressQueries(m, mDNStrue, FlushAddressCacheRecords, mDNSNULL, mDNSNULL);
}
// 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)
@ -4903,5 +4966,5 @@ struct CompileTimeAssertionChecks_uDNS
// other overly-large structures instead of having a pointer to them, can inadvertently
// cause structure sizes (and therefore memory usage) to balloon unreasonably.
char sizecheck_tcpInfo_t [(sizeof(tcpInfo_t) <= 9056) ? 1 : -1];
char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 4800) ? 1 : -1];
char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 5000) ? 1 : -1];
};

View File

@ -53,6 +53,11 @@
// 5 minutes
#define MAX_UPDATE_REFRESH_COUNT 5
#define MIN_UPDATE_REFRESH_TIME (5 * 60 * mDNSPlatformOneSecond)
// For questions that use kDNSServiceFlagsTimeout and we don't have a matching resolver e.g., no dns servers,
// then use the default value of 30 seconds
#define DEFAULT_UDNS_TIMEOUT 30 // in seconds
// Entry points into unicast-specific routines
extern void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo);
@ -91,7 +96,16 @@ extern void UpdateAllSRVRecords(mDNS *m);
extern void CheckNATMappings(mDNS *m);
extern mStatus uDNS_SetupDNSConfig(mDNS *const m);
extern mStatus uDNS_RegisterSearchDomains(mDNS *const m);
// uDNS_SetupSearchDomains by default adds search domains. It also can be called with one or
// more values for "action" which does the following:
//
// -UDNS_START_WAB_QUERY - start Wide Area Bonjour (domain enumeration) queries
#define UDNS_START_WAB_QUERY 0x00000001
extern mStatus uDNS_SetupSearchDomains(mDNS *const m, int action);
extern domainname *uDNS_GetNextSearchDomain(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal);
typedef enum
{

View File

@ -47,8 +47,13 @@ extern int daemon(int, int);
#include "mDNSPosix.h"
#include "mDNSUNP.h" // For daemon()
#include "uds_daemon.h"
#include "DNSCommon.h"
#include "PlatformCommon.h"
#ifndef MDNSD_USER
#define MDNSD_USER "nobody"
#endif
#define CONFIG_FILE "/etc/mdnsd.conf"
static domainname DynDNSZone; // Default wide-area zone for service registration
static domainname DynDNSHostname;
@ -89,8 +94,10 @@ static void Reconfigure(mDNS *m)
mDNSAddr DynDNSIP;
const mDNSAddr dummy = { mDNSAddrType_IPv4, { { { 1, 1, 1, 1 } } } };;
mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
mDNS_Lock(m);
if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0)
LogMsg("Unable to parse DNS server list. Unicast DNS-SD unavailable");
mDNS_Unlock(m);
ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL);
mDNSPlatformSourceAddrForDest(&DynDNSIP, &dummy);
if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
@ -121,8 +128,40 @@ mDNSlocal void ParseCmdLinArgs(int argc, char **argv)
mDNSlocal void DumpStateLog(mDNS *const m)
// Dump a little log of what we've been up to.
{
DNSServer *s;
PosixNetworkInterface *i;
LogMsg("---- BEGIN STATE LOG ----");
udsserver_info(m);
LogMsgNoIdent("----- Network Interfaces -------");
for (i = (PosixNetworkInterface*)(m->HostInterfaces);
i; i = (PosixNetworkInterface *)(i->coreIntf.next)) {
LogMsg("%p %p %d %s%s%s%s%s %-8s %#a", i,
(void *)(i->coreIntf.InterfaceID), i->index,
i->coreIntf.InterfaceActive ? "-" : "D",
i->coreIntf.IPv4Available ? "4" : "-",
i->coreIntf.IPv6Available ? "6" : "-",
i->coreIntf.Advertise ? "A" : "-",
i->coreIntf.McastTxRx ? "M" : "-",
i->intfName, &(i->coreIntf.ip));
}
LogMsgNoIdent("--------- DNS Servers ----------");
if (!mDNSStorage.DNSServers) LogMsgNoIdent("<None>");
else
{
for (s = m->DNSServers; s; s = s->next)
{
LogMsgNoIdent("DNS Server %##s %#a:%d %s",
s->domain.c, &s->addr, mDNSVal16(s->port),
s->teststate == DNSServer_Untested ? "(Untested)" :
s->teststate == DNSServer_Passed ? "" :
s->teststate == DNSServer_Failed ? "(Failed)" :
s->teststate == DNSServer_Disabled ? "(Disabled)" : "(Unknown state)");
}
}
LogMsg("---- END STATE LOG ----");
}
@ -134,6 +173,10 @@ mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit.
mDNSPosixListenForSignalInEventLoop(SIGINT);
mDNSPosixListenForSignalInEventLoop(SIGTERM);
mDNSPosixListenForSignalInEventLoop(SIGUSR1);
#ifdef HAVE_SIGINFO
mDNSPosixListenForSignalInEventLoop(SIGUSR2);
mDNSPosixListenForSignalInEventLoop(SIGINFO);
#endif
mDNSPosixListenForSignalInEventLoop(SIGPIPE);
mDNSPosixListenForSignalInEventLoop(SIGHUP) ;
@ -160,7 +203,22 @@ mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit.
(void) mDNSPosixRunEventLoopOnce(m, &timeout, &signals, &gotData);
if (sigismember(&signals, SIGHUP )) Reconfigure(m);
#ifdef HAVE_SIGINFO
/* use OSX-compatible signals since we can, and gain enhanced debugging */
if (sigismember(&signals, SIGINFO)) DumpStateLog(m);
if (sigismember(&signals, SIGUSR1))
{
mDNS_LoggingEnabled = mDNS_LoggingEnabled ? 0 : 1;
LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled");
}
if (sigismember(&signals, SIGUSR2))
{
mDNS_PacketLoggingEnabled = mDNS_PacketLoggingEnabled ? 0 : 1;
LogMsg("SIGUSR2: Packet Logging %s", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
}
#else
if (sigismember(&signals, SIGUSR1)) DumpStateLog(m);
#endif
// SIGPIPE happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up.
if (sigismember(&signals, SIGPIPE)) LogMsg("Received SIGPIPE - ignoring");
if (sigismember(&signals, SIGINT) || sigismember(&signals, SIGTERM)) break;
@ -187,11 +245,21 @@ int main(int argc, char **argv)
// Now that we're finished with anything privileged, switch over to running as "nobody"
if (mStatus_NoError == err)
{
const struct passwd *pw = getpwnam("nobody");
const struct passwd *pw = getpwnam(MDNSD_USER);
if (pw != NULL)
{
setgid(pw->pw_gid);
setuid(pw->pw_uid);
}
else
LogMsg("WARNING: mdnsd continuing as root because user \"nobody\" does not exist");
#ifdef MDNSD_NOROOT
{
LogMsg("WARNING: mdnsd exiting because user \""MDNSD_USER"\" does not exist");
err = mStatus_Invalid;
}
#else
LogMsg("WARNING: mdnsd continuing as root because user \""MDNSD_USER"\" does not exist");
#endif
}
if (mStatus_NoError == err)
@ -250,9 +318,9 @@ asm(".desc ___crashreporter_info__, 0x10");
// For convenience when using the "strings" command, this is the last thing in the file
#if mDNSResponderVersion > 1
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder-" STRINGIFY(mDNSResponderVersion);
#elif MDNS_VERSIONSTR_NODTS
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)";
#else
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ")";
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)";
#endif

View File

@ -411,6 +411,26 @@ mDNSexport void mDNSPlatformTLSTearDownCerts(void)
{
}
mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
{
(void) m;
(void) allowSleep;
(void) reason;
}
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
#pragma mark - /etc/hosts support
#endif
mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
{
(void)m; // unused
(void)rr;
(void)result;
}
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark ***** DDNS Config Platform Functions
#endif
@ -482,7 +502,7 @@ mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
mDNSAddr DNSAddr;
DNSAddr.type = mDNSAddrType_IPv4;
DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, &DNSAddr, UnicastDNSPort, mDNSfalse);
mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, &DNSAddr, UnicastDNSPort, mDNSfalse, 0);
numOfServers++;
}
}
@ -523,9 +543,10 @@ mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const
return (mDNSInterfaceID) intf;
}
mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
{
PosixNetworkInterface *intf;
(void) suppressNetworkChange; // Unused
assert(m != NULL);
@ -1406,6 +1427,23 @@ mDNSexport mDNSs32 mDNSPlatformUTC(void)
return time(NULL);
}
mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
{
(void) m;
(void) InterfaceID;
(void) EthAddr;
(void) IPAddr;
(void) iteration;
}
mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf)
{
(void) rr;
(void) intf;
return 1;
}
mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
{
if (*nfds < s + 1) *nfds = s + 1;

View File

@ -55,7 +55,7 @@
#endif
#if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX && !defined(sun)
#if !defined(__NetBSD__)
#if defined(__FreeBSD__) || defined(__DragonFly__)
#include <net/if_var.h>
#endif
#include <netinet/in_var.h>
@ -278,6 +278,24 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
if ((flags & IFF_UP) == 0)
continue; /* ignore if interface not up */
/* Skip addresses we can't use */
#ifdef SIOCGIFAFLAG_IN6
if (ifr->ifr_addr.sa_family == AF_INET6) {
struct in6_ifreq ifr6;
if (sockf6 == -1)
sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
memset(&ifr6, 0, sizeof(ifr6));
memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name));
memcpy(&ifr6.ifr_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_addr));
if (ioctl(sockf6, SIOCGIFAFLAG_IN6, &ifr6) < 0)
goto gotError;
if (ifr6.ifr_ifru.ifru_flags6 &
(IN6_IFF_NOTREADY | IN6_IFF_DETACHED))
continue;
}
#endif
ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
if (ifi == NULL) {
goto gotError;

View File

@ -129,7 +129,7 @@ mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const fi
{
DomainAuthInfo *info = (DomainAuthInfo*)mDNSPlatformMemAllocate(sizeof(*info));
// for now we assume keyname = service reg domain and we use same key for service and hostname registration
err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, mDNSfalse);
err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0, NULL);
if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c);
}

View File

@ -16,7 +16,7 @@
.\"
.Dd April 2004 \" Date
.Dt dns-sd 1 \" Document Title
.Os Darwin \" Operating System
.Os NetBSD \" Operating System
.\"
.Sh NAME
.Nm dns-sd
@ -43,11 +43,6 @@ The library API that
.Nm
uses is documented in
.Pa /usr/include/dns_sd.h .
The
.Nm
command replaces the older
.Xr mDNS 1
command.
.Pp
The
.Nm
@ -181,14 +176,11 @@ window.
.Pa /usr/bin/dns-sd \" Pathname
.\"
.Sh SEE ALSO
.Xr mDNS 1
.Xr mDNSResponder 8
.\"
.Sh BUGS
.Nm
bugs are tracked in Apple Radar component "mDNSResponder".
.Xr mdnsd 8
.\"
.Sh HISTORY
The
.Nm
command first appeared in Mac OS X 10.4 (Tiger).
command first appeared in
.Nx 6.0 ,
having originated in Mac OS X 10.4 (Tiger).

View File

@ -77,7 +77,7 @@
*/
#ifndef _DNS_SD_H
#define _DNS_SD_H 2581400
#define _DNS_SD_H 3201600
#ifdef __cplusplus
extern "C" {
@ -341,7 +341,7 @@ enum
* lock or take similar appropriate precautions to serialize those calls.
*/
kDNSServiceFlagsSuppressUnusable = 0x8000
kDNSServiceFlagsSuppressUnusable = 0x8000,
/*
* This flag is meaningful only in DNSServiceQueryRecord which suppresses unusable queries on the
* wire. If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name)
@ -351,6 +351,26 @@ enum
* "hostname".
*/
kDNSServiceFlagsTimeout = 0x10000,
/*
* When kDNServiceFlagsTimeout is passed to DNSServiceQueryRecord or DNSServiceGetAddrInfo, the query is
* stopped after a certain number of seconds have elapsed. The time at which the query will be stopped
* is determined by the system and cannot be configured by the user. The query will be stopped irrespective
* of whether a response was given earlier or not. When the query is stopped, the callback will be called
* with an error code of kDNSServiceErr_Timeout and a NULL sockaddr will be returned for DNSServiceGetAddrInfo
* and zero length rdata will be returned for DNSServiceQueryRecord.
*/
kDNSServiceFlagsIncludeP2P = 0x20000,
/*
* Include P2P interfaces when kDNSServiceInterfaceIndexAny is specified.
* By default, specifying kDNSServiceInterfaceIndexAny does not include P2P interfaces.
*/
kDNSServiceFlagsWakeOnResolve = 0x40000
/*
* This flag is meaningful only in DNSServiceResolve. When set, it tries to send a magic packet
* to wake up the client.
*/
};
/* Possible protocols for DNSServiceNATPortMappingCreate(). */
@ -488,7 +508,8 @@ enum
kDNSServiceErr_NATPortMappingUnsupported = -65564, /* NAT doesn't support NAT-PMP or UPnP */
kDNSServiceErr_NATPortMappingDisabled = -65565, /* NAT supports NAT-PMP or UPnP but it's disabled by the administrator */
kDNSServiceErr_NoRouter = -65566, /* No router currently configured (probably no network connectivity) */
kDNSServiceErr_PollingMode = -65567
kDNSServiceErr_PollingMode = -65567,
kDNSServiceErr_Timeout = -65568
/* mDNS Error codes are in the range
* FFFE FF00 (-65792) to FFFE FFFF (-65537) */
@ -599,10 +620,10 @@ enum
* interface via which the service can be accessed.
*
* If applications pass kDNSServiceInterfaceIndexAny to DNSServiceBrowse
* or DNSServiceQueryRecord, the operation will also include P2P. In this
* case, if a service instance or the record being queried is found over P2P,
* the resulting ADD event will indicate kDNSServiceInterfaceIndexP2P as the
* interface index.
* or DNSServiceQueryRecord, they must set the kDNSServiceFlagsIncludeP2P flag
* to include P2P. In this case, if a service instance or the record being queried
* is found over P2P, the resulting ADD event will indicate kDNSServiceInterfaceIndexP2P
* as the interface index.
*/
#define kDNSServiceInterfaceIndexAny 0
@ -2394,6 +2415,7 @@ DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
#endif //__APPLE_API_PRIVATE
#if !defined(__NetBSD__)
/* Some C compiler cleverness. We can make the compiler check certain things for us,
* and report errors at compile-time if anything is wrong. The usual way to do this would
* be to use a run-time "if" statement or the conventional run-time "assert" mechanism, but
@ -2405,6 +2427,7 @@ struct CompileTimeAssertionChecks_DNS_SD
{
char assert0[(sizeof(union _TXTRecordRef_t) == 16) ? 1 : -1];
};
#endif
#ifdef __cplusplus
}

View File

@ -363,4 +363,4 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
// NOT static -- otherwise the compiler may optimize it out
// The "@(#) " pattern is a special prefix the "what" command looks for
const char VersionString_SCCS_libdnssd[] = "@(#) libdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
const char VersionString_SCCS_libdnssd[] = "@(#) libdns_sd " STRINGIFY(mDNSResponderVersion);

View File

@ -31,6 +31,8 @@
#include "dnssd_ipc.h"
static int gDaemonErr = kDNSServiceErr_NoError;
#if defined(_WIN32)
#define _SSIZE_T
@ -56,6 +58,7 @@
static int g_initWinsock = 0;
#define LOG_WARNING kDebugLevelWarning
#define LOG_INFO kDebugLevelInfo
static void syslog( int priority, const char * message, ...)
{
va_list args;
@ -88,6 +91,8 @@
// Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
//#define USE_NAMED_ERROR_RETURN_SOCKET 1
#define DNSSD_CLIENT_TIMEOUT 10 // In seconds
#ifndef CTL_PATH_PREFIX
#define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
#endif
@ -165,14 +170,14 @@ static int write_all(dnssd_sock_t sd, char *buf, size_t len)
if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
syslog(LOG_WARNING, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
if (!defunct)
syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %zd/%ld %d %s", sd,
(long)num_written, (long)len,
(num_written < 0) ? dnssd_errno : 0,
(num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
else
syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
#else
syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %zd/%ld %d %s", sd,
(long)num_written, (long)len,
(num_written < 0) ? dnssd_errno : 0,
(num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
@ -196,6 +201,9 @@ static int read_all(dnssd_sock_t sd, char *buf, int len)
while (len)
{
ssize_t num_read = recv(sd, buf, len, 0);
// It is valid to get an interrupted system call error e.g., somebody attaching
// in a debugger, retry without failing
if ((num_read < 0) && (errno == EINTR)) { syslog(LOG_INFO, "dnssd_clientstub read_all: EINTR continue"); continue; }
if ((num_read == 0) || (num_read < 0) || (num_read > len))
{
int printWarn = 0;
@ -262,6 +270,39 @@ static int more_bytes(dnssd_sock_t sd)
return (ret > 0);
}
// Wait for daemon to write to socket
static int wait_for_daemon(dnssd_sock_t sock, int timeout)
{
#ifndef WIN32
// At this point the next operation (accept() or read()) on this socket may block for a few milliseconds waiting
// for the daemon to respond, but that's okay -- the daemon is a trusted service and we know if won't take more
// than a few milliseconds to respond. So we'll forego checking for readability of the socket.
(void) sock;
(void) timeout;
#else
// Windows on the other hand suffers from 3rd party software (primarily 3rd party firewall software) that
// interferes with proper functioning of the TCP protocol stack. Because of this and because we depend on TCP
// to communicate with the system service, we want to make sure that the next operation on this socket (accept() or
// read()) doesn't block indefinitely.
if (!gDaemonErr)
{
struct timeval tv;
fd_set set;
FD_ZERO(&set);
FD_SET(sock, &set);
tv.tv_sec = timeout;
tv.tv_usec = 0;
if (!select((int)(sock + 1), &set, NULL, NULL, &tv))
{
syslog(LOG_WARNING, "dnssd_clientstub wait_for_daemon timed out");
gDaemonErr = kDNSServiceErr_Timeout;
}
}
#endif
return gDaemonErr;
}
/* create_hdr
*
* allocate and initialize an ipc message header. Value of len should initially be the
@ -353,7 +394,6 @@ static void FreeDNSServiceOp(DNSServiceOp *x)
x->ProcessReply = NULL;
x->AppCallback = NULL;
x->AppContext = NULL;
x->rec = NULL;
#if _DNS_SD_LIBDISPATCH
if (x->disp_source) dispatch_release(x->disp_source);
x->disp_source = NULL;
@ -445,7 +485,7 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
else
{
#ifdef SO_NOSIGPIPE
const unsigned long optval = 1;
int optval = 1;
#endif
*ref = NULL;
sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
@ -612,7 +652,10 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
#else
if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0)
{
syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
// write_all already prints an error message if there is an error writing to
// the socket except for DEFUNCT. Logging here is unnecessary and also wrong
// in the case of DEFUNCT sockets
syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
goto cleanup;
}
@ -626,6 +669,7 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
// but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond.
dnssd_sockaddr_t daddr;
dnssd_socklen_t len = sizeof(daddr);
if ((err = wait_for_daemon(listenfd, DNSSD_CLIENT_TIMEOUT)) != kDNSServiceErr_NoError) goto cleanup;
errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
if (!dnssd_SocketValid(errsd)) deliver_request_bailout("accept");
#else
@ -711,10 +755,13 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
// but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond.
if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
err = kDNSServiceErr_NoError;
else if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
else
err = ntohl(err);
else if ((err = wait_for_daemon(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError)
{
if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
else
err = ntohl(err);
}
//syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err);
@ -1094,6 +1141,16 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve
if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
// Need a real InterfaceID for WakeOnResolve
if ((flags & kDNSServiceFlagsWakeOnResolve) != 0 &&
((interfaceIndex == kDNSServiceInterfaceIndexAny) ||
(interfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
(interfaceIndex == kDNSServiceInterfaceIndexUnicast) ||
(interfaceIndex == kDNSServiceInterfaceIndexP2P)))
{
return kDNSServiceErr_BadParam;
}
err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, callBack, context);
if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL

View File

@ -40,6 +40,7 @@
# define dnssd_SocketValid(s) ((s) != INVALID_SOCKET)
# define dnssd_EWOULDBLOCK WSAEWOULDBLOCK
# define dnssd_EINTR WSAEINTR
# define dnssd_ECONNRESET WSAECONNRESET
# define dnssd_sock_t SOCKET
# define dnssd_socklen_t int
# define dnssd_close(sock) closesocket(sock)
@ -63,6 +64,7 @@ extern char *win32_strerror(int inErrorCode);
# define dnssd_SocketValid(s) ((s) >= 0)
# define dnssd_EWOULDBLOCK EWOULDBLOCK
# define dnssd_EINTR EINTR
# define dnssd_ECONNRESET ECONNRESET
# define dnssd_EPIPE EPIPE
# define dnssd_sock_t int
# define dnssd_socklen_t unsigned int
@ -104,7 +106,10 @@ extern char *win32_strerror(int inErrorCode);
// structures correctly anyway, so a plain "struct" is usually fine. In the event that structures are not packed
// correctly, our compile-time assertion checks will catch it and prevent inadvertent generation of non-working code.
#ifndef packedstruct
#if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
#ifdef __packed
#define packedstruct struct __packed
#define packedunion union __packed
#elif ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
#define packedstruct struct __attribute__((__packed__))
#define packedunion union __attribute__((__packed__))
#else
@ -116,7 +121,7 @@ extern char *win32_strerror(int inErrorCode);
typedef enum
{
request_op_none = 0, // No request yet received on this connection
connection_request = 1, // connected socket via DNSServiceCreateConnection()
connection_request = 1, // connected socket via DNSServiceConnect()
reg_record_request, // reg/remove record only valid for connected sockets
remove_record_request,
enumeration_request,

File diff suppressed because it is too large Load Diff

View File

@ -60,6 +60,7 @@ extern int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs);
extern void machserver_automatic_browse_domain_changed(const domainname *d, mDNSBool add);
extern void machserver_automatic_registration_domain_changed(const domainname *d, mDNSBool add);
// External support
extern void mDNSInitPacketFilter(void);
extern void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype);
extern void external_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype);
extern void external_start_advertising_service(const ResourceRecord *const resourceRecord);