diff --git a/src/tools/mdnssd/DNSCommon.c b/src/tools/mdnssd/DNSCommon.c index 3ec6e3851915e307fa54b5cc1213037ee7137e51..e526068339376d5531e58df93b1f201a40671560 100644 --- a/src/tools/mdnssd/DNSCommon.c +++ b/src/tools/mdnssd/DNSCommon.c @@ -1369,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); diff --git a/src/tools/mdnssd/DNSCommon.h b/src/tools/mdnssd/DNSCommon.h index 08c636d9c7536faffef6a5690b8632d1bae0b855..5df4ce410d9329b48166abae695126a22958b227 100644 --- a/src/tools/mdnssd/DNSCommon.h +++ b/src/tools/mdnssd/DNSCommon.h @@ -164,7 +164,7 @@ 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); diff --git a/src/tools/mdnssd/DNSDigest.c b/src/tools/mdnssd/DNSDigest.c index b4a0158cc336db45fd407698cbcc4366b0d2b74c..98d23dbdd1117b052beff35be969398580d852a5 100644 --- a/src/tools/mdnssd/DNSDigest.c +++ b/src/tools/mdnssd/DNSDigest.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002-2011 Apple Computer, Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -571,9 +571,16 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num); #endif #endif +// None of the invocations of the following macros actually use the result, +// so cast them to void to avoid any compiler warnings/errors about not using +// the result (e.g. when using clang). +// If the resultant values need to be used at some point, these must be changed. +#define HOST_c2l(c,l) ((void)_HOST_c2l(c,l)) +#define HOST_l2c(l,c) ((void)_HOST_l2c(l,c)) + #if defined(DATA_ORDER_IS_BIG_ENDIAN) -#define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++)))<<24), \ +#define _HOST_c2l(c,l) (l =(((unsigned long)(*((c)++)))<<24), \ l|=(((unsigned long)(*((c)++)))<<16), \ l|=(((unsigned long)(*((c)++)))<< 8), \ l|=(((unsigned long)(*((c)++))) ), \ @@ -601,7 +608,7 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num); case 2: l|=((unsigned long)(*(--(c))))<<16; \ case 1: l|=((unsigned long)(*(--(c))))<<24; \ } } -#define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \ +#define _HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \ *((c)++)=(unsigned char)(((l)>>16)&0xff), \ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ *((c)++)=(unsigned char)(((l) )&0xff), \ @@ -609,7 +616,7 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num); #elif defined(DATA_ORDER_IS_LITTLE_ENDIAN) -#define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++))) ), \ +#define _HOST_c2l(c,l) (l =(((unsigned long)(*((c)++))) ), \ l|=(((unsigned long)(*((c)++)))<< 8), \ l|=(((unsigned long)(*((c)++)))<<16), \ l|=(((unsigned long)(*((c)++)))<<24), \ @@ -637,7 +644,7 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num); case 2: l|=((unsigned long)(*(--(c))))<< 8; \ case 1: l|=((unsigned long)(*(--(c)))); \ } } -#define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ +#define _HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ *((c)++)=(unsigned char)(((l)>>16)&0xff), \ *((c)++)=(unsigned char)(((l)>>24)&0xff), \ diff --git a/src/tools/mdnssd/dns_sd.h b/src/tools/mdnssd/dns_sd.h index 5416a604c6fc5c0788d14450d016daaf9c0d0ddb..3caa6a85865e7cb5251135d53a24a5fe224790fa 100644 --- a/src/tools/mdnssd/dns_sd.h +++ b/src/tools/mdnssd/dns_sd.h @@ -77,7 +77,7 @@ */ #ifndef _DNS_SD_H -#define _DNS_SD_H 3200500 +#define _DNS_SD_H 3331000 #ifdef __cplusplus extern "C" { diff --git a/src/tools/mdnssd/dnssd_ipc.h b/src/tools/mdnssd/dnssd_ipc.h index d41edc8725257619f6a38475a6a3a1d739ede9fc..748bbdf2139f62ee170958254a07e374c423bb32 100644 --- a/src/tools/mdnssd/dnssd_ipc.h +++ b/src/tools/mdnssd/dnssd_ipc.h @@ -152,7 +152,7 @@ typedef enum } reply_op_t; #if defined(_WIN64) -# pragma pack(4) +# pragma pack(push,4) #endif // Define context object big enough to hold a 64-bit pointer, @@ -176,6 +176,10 @@ typedef packedstruct // index/socket pair uniquely identifies a record. (Used to select records for removal by DNSServiceRemoveRecord()) } ipc_msg_hdr; +#if defined(_WIN64) +# pragma pack(pop) +#endif + // routines to write to and extract data from message buffers. // caller responsible for bounds checking. // ptr is the address of the pointer to the start of the field. diff --git a/src/tools/mdnssd/mDNS.c b/src/tools/mdnssd/mDNS.c old mode 100755 new mode 100644 index 11c66715bb07710d14d42ea9a2cd11390e414de0..9de7f92c181e52d18396ca86ded4b193cf557508 --- a/src/tools/mdnssd/mDNS.c +++ b/src/tools/mdnssd/mDNS.c @@ -349,7 +349,7 @@ mDNSexport mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterface if (addr->type == mDNSAddrType_IPv6) { - if (mDNSv6AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue); + if (mDNSv6AddressIsLinkLocal(&addr->ip.v6)) return(mDNStrue); for (intf = m->HostInterfaces; intf; intf = intf->next) if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) && @@ -1730,7 +1730,7 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d } if (m->omsg.h.numAnswers) - mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL); + mDNSSendDNSMessage(m, &m->omsg, responseptr, InterfaceID, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL); } } @@ -3285,6 +3285,22 @@ mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAdd #pragma mark - RR List Management & Task Management #endif +// Whenever a question is answered, reset its state so that we don't query +// the network repeatedly. This happens first time when we answer the question and +// and later when we refresh the cache. +mDNSlocal void ResetQuestionState(mDNS *const m, DNSQuestion *q) + { + q->LastQTime = m->timenow; + q->LastQTxTime = m->timenow; + q->RecentAnswerPkts = 0; + q->ThisQInterval = MaxQuestionInterval; + q->RequestUnicast = mDNSfalse; + // Reset unansweredQueries so that we don't penalize this server later when we + // start sending queries when the cache expires. + q->unansweredQueries = 0; + debugf("ResetQuestionState: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + } + // Note: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list. // Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this. // In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion, @@ -3343,12 +3359,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco (AddRecord == QC_add && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)))) if (ActiveQuestion(q) && (mDNSOpaque16IsZero(q->TargetQID) || !q->LongLived)) { - q->LastQTime = m->timenow; - q->LastQTxTime = m->timenow; - q->RecentAnswerPkts = 0; - q->ThisQInterval = MaxQuestionInterval; - q->RequestUnicast = mDNSfalse; - debugf("AnswerCurrentQuestionWithResourceRecord: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + ResetQuestionState(m, q); } if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us @@ -6278,6 +6289,8 @@ mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, return(mDNSNULL); } +// This function is called when we receive a unicast response. This could be the case of a unicast response from the +// DNS server or a response to the QU query. Hence, the cache record's InterfaceId can be both NULL or non-NULL (QU case) mDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSIPPort port, const mDNSOpaque16 id, const CacheRecord *const rr, mDNSBool tcp) { @@ -6285,12 +6298,9 @@ mDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m, (void)id; (void)srcaddr; - // Unicast records have zero as InterfaceID - if (rr->resrec.InterfaceID) return mDNSNULL; - for (q = m->Questions; q; q=q->next) { - if (!q->DuplicateOf && UnicastResourceRecordAnswersQuestion(&rr->resrec, q)) + if (!q->DuplicateOf && ResourceRecordAnswersUnicastResponse(&rr->resrec, q)) { if (!mDNSOpaque16IsZero(q->TargetQID)) { @@ -6867,12 +6877,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, if (!q->DuplicateOf && !q->LongLived && ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q)) { - q->LastQTime = m->timenow; - q->LastQTxTime = m->timenow; - q->RecentAnswerPkts = 0; - q->ThisQInterval = MaxQuestionInterval; - q->RequestUnicast = mDNSfalse; - q->unansweredQueries = 0; + ResetQuestionState(m, q); debugf("mDNSCoreReceiveResponse: Set MaxQuestionInterval for %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype)); break; // Why break here? Aren't there other questions we might want to look at?-- SC July 2010 } @@ -7146,8 +7151,14 @@ exit: // If we already had a negative cache entry just update it, else make one or more new negative cache entries if (neg) { - debugf("Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg)); + debugf("mDNSCoreReceiveResponse: Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg)); RefreshCacheRecord(m, neg, negttl); + // When we created the cache for the first time and answered the question, the question's + // interval was set to MaxQuestionInterval. If the cache is about to expire and we are resending + // the queries, the interval should still be at MaxQuestionInterval. If the query is being + // restarted (setting it to InitialQuestionInterval) for other reasons e.g., wakeup, + // we should reset its question interval here to MaxQuestionInterval. + ResetQuestionState(m, qptr); } else while (1) { @@ -7817,6 +7828,55 @@ mDNSlocal mDNSu32 GetTimeoutForMcastQuestion(mDNS *m, DNSQuestion *question) return ( curmatch ? curmatch->timeout : DEFAULT_MCAST_TIMEOUT); } +// Returns true if it is a Domain Enumeration Query +mDNSexport mDNSBool DomainEnumQuery(const domainname *qname) + { + const mDNSu8 *mDNS_DEQLabels[] = { (const mDNSu8 *)"\001b", (const mDNSu8 *)"\002db", (const mDNSu8 *)"\002lb", + (const mDNSu8 *)"\001r", (const mDNSu8 *)"\002dr", (const mDNSu8 *)mDNSNULL, }; + const domainname *d = qname; + const mDNSu8 *label; + int i = 0; + + // We need at least 3 labels (DEQ prefix) + one more label to make a meaningful DE query + if (CountLabels(qname) < 4) { debugf("DomainEnumQuery: question %##s, not enough labels", qname->c); return mDNSfalse; } + + label = (const mDNSu8 *)d; + while (mDNS_DEQLabels[i] != (const mDNSu8 *)mDNSNULL) + { + if (SameDomainLabel(mDNS_DEQLabels[i], label)) {debugf("DomainEnumQuery: DEQ %##s, label1 match", qname->c); break;} + i++; + } + if (mDNS_DEQLabels[i] == (const mDNSu8 *)mDNSNULL) + { + debugf("DomainEnumQuery: Not a DEQ %##s, label1 mismatch", qname->c); + return mDNSfalse; + } + debugf("DomainEnumQuery: DEQ %##s, label1 match", qname->c); + + // CountLabels already verified the number of labels + d = (const domainname *)(d->c + 1 + d->c[0]); // Second Label + label = (const mDNSu8 *)d; + if (!SameDomainLabel(label, (const mDNSu8 *)"\007_dns-sd")) + { + debugf("DomainEnumQuery: Not a DEQ %##s, label2 mismatch", qname->c); + return(mDNSfalse); + } + debugf("DomainEnumQuery: DEQ %##s, label2 match", qname->c); + + d = (const domainname *)(d->c + 1 + d->c[0]); // Third Label + label = (const mDNSu8 *)d; + if (!SameDomainLabel(label, (const mDNSu8 *)"\004_udp")) + { + debugf("DomainEnumQuery: Not a DEQ %##s, label3 mismatch", qname->c); + return(mDNSfalse); + } + debugf("DomainEnumQuery: DEQ %##s, label3 match", qname->c); + + debugf("DomainEnumQuery: Question %##s is a Domain Enumeration query", qname->c); + + return mDNStrue; + } + // Sets all the Valid DNS servers for a question mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question) { @@ -7826,8 +7886,10 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question) int bettermatch, currcount; int index = 0; mDNSu32 timeout = 0; + mDNSBool DEQuery; question->validDNSServers = zeroOpaque64; + DEQuery = DomainEnumQuery(&question->qname); for (curr = m->DNSServers; curr; curr = curr->next) { debugf("SetValidDNSServers: Parsing DNS server Address %#a (Domain %##s), Scope: %d", &curr->addr, curr->domain.c, curr->scoped); @@ -7847,7 +7909,9 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question) { debugf("SetValidDNSServers: Scoped DNS server %#a (Domain %##s) with Interface Any", &curr->addr, curr->domain.c); continue; } currcount = CountLabels(&curr->domain); - if ((!curr->scoped && (!question->InterfaceID || (question->InterfaceID == mDNSInterface_Unicast))) || (curr->interface == question->InterfaceID)) + if ((!DEQuery || !curr->cellIntf) && + ((!curr->scoped && (!question->InterfaceID || (question->InterfaceID == mDNSInterface_Unicast))) || + (curr->interface == question->InterfaceID))) { bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen); @@ -7864,6 +7928,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question) " Timeout %d, interface %p", question->qname.c, &curr->addr, curr->domain.c, curr->scoped, index, curr->timeout, curr->interface); timeout += curr->timeout; + if (DEQuery) debugf("DomainEnumQuery: Question %##s, DNSServer %#a, cell %d", question->qname.c, &curr->addr, curr->cellIntf); bit_set_opaque64(question->validDNSServers, index); } } diff --git a/src/tools/mdnssd/mDNSEmbeddedAPI.h b/src/tools/mdnssd/mDNSEmbeddedAPI.h index 3d6c12a4ec300f5e8d6f0ac1a94c3a702abb8eb6..7310dc56e3d263e04cb7edbec81b7c0c97d50af9 100755 --- a/src/tools/mdnssd/mDNSEmbeddedAPI.h +++ b/src/tools/mdnssd/mDNSEmbeddedAPI.h @@ -1075,6 +1075,7 @@ typedef struct DNSServer mDNSBool scoped; // interface should be matched against question only // if scoped is set mDNSu32 timeout; // timeout value for questions + mDNSBool cellIntf; // Resolver from Cellular Interface ? } DNSServer; typedef struct // Size is 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit @@ -2468,7 +2469,7 @@ 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, mDNSu32 timeout); +extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped, mDNSu32 timeout, mDNSBool cellIntf); extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q); extern void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID); @@ -2653,8 +2654,8 @@ extern mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const Netw extern void LNT_SendDiscoveryMsg(mDNS *m); extern void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, const mDNSu8 *const data, const mDNSu16 len); extern mStatus LNT_GetExternalAddress(mDNS *m); -extern mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *n); -extern mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n); +extern mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *const n); +extern mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *const n); extern void LNT_ClearState(mDNS *const m); #endif // _LEGACY_NAT_TRAVERSAL_ @@ -2729,6 +2730,7 @@ extern void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer extern void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr); extern void CheckSuppressUnusableQuestions(mDNS *const m); extern void RetrySearchDomainQuestions(mDNS *const m); +extern mDNSBool DomainEnumQuery(const domainname *qname); // Used only in logging to restrict the number of /etc/hosts entries printed extern void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result); @@ -2943,7 +2945,7 @@ struct CompileTimeAssertionChecks_mDNS 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_DNSServer [(sizeof(DNSServer) <= 328) ? 1 : -1]; char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 6850) ? 1 : -1]; char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5500) ? 1 : -1]; char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7808) ? 1 : -1]; diff --git a/src/tools/mdnssd/mDNSPosix.c b/src/tools/mdnssd/mDNSPosix.c index e56ad9118965e446cb9faabe436a39172b0149c3..a1868709dbe3e146da696d0f42beebffa3f4a226 100755 --- a/src/tools/mdnssd/mDNSPosix.c +++ b/src/tools/mdnssd/mDNSPosix.c @@ -27,6 +27,7 @@ * understand why variable y is not of type "char*" just proves the point that poor code * layout leads people to unfortunate misunderstandings about how the C language really works.) */ + #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above #include "DNSCommon.h" #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform @@ -158,8 +159,12 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms assert(msg != NULL); assert(end != NULL); assert((((char *) end) - ((char *) msg)) > 0); - assert(dstPort.NotAnInteger != 0); + if (dstPort.NotAnInteger == 0) + { + LogMsg("mDNSPlatformSendUDP: Invalid argument -dstPort is set to 0"); + return PosixErrorToStatus(EINVAL); + } if (dst->type == mDNSAddrType_IPv4) { struct sockaddr_in *sin = (struct sockaddr_in*)&to; @@ -501,7 +506,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, 0); + mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, &DNSAddr, UnicastDNSPort, mDNSfalse, 0, mDNSfalse); numOfServers++; } } @@ -710,16 +715,10 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf { struct ipv6_mreq imr6; struct sockaddr_in6 bindAddr6; - #if defined(IPV6_RECVPKTINFO) - if (err == 0) - { - err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVPKTINFO, &kOn, sizeof(kOn)); - if (err < 0) { err = errno; perror("setsockopt - IPV6_RECVPKTINFO"); } - } - #elif defined(IPV6_PKTINFO) +#if defined(IPV6_PKTINFO) if (err == 0) { - err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_PKTINFO, &kOn, sizeof(kOn)); + err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_PKTINFO, &kOn, sizeof(kOn)); if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); } } #else @@ -728,7 +727,7 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf #if defined(IPV6_HOPLIMIT) if (err == 0) { - err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_HOPLIMIT, &kOn, sizeof(kOn)); + err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_HOPLIMIT, &kOn, sizeof(kOn)); if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); } } #endif @@ -846,6 +845,7 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct // Set up the fields required by the mDNS core. SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL); SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL); + //LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask); strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname)); intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0; diff --git a/src/tools/mdnssd/mDNSUNP.c b/src/tools/mdnssd/mDNSUNP.c index e6835cd49b0d9ca0e57030dac285cbc9dd19b347..8027676cfe3bafc7d58bc271f03846533a77210b 100755 --- a/src/tools/mdnssd/mDNSUNP.c +++ b/src/tools/mdnssd/mDNSUNP.c @@ -14,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #include "mDNSUNP.h" #include <errno.h> @@ -81,7 +82,7 @@ void plen_to_mask(int plen, char *addr) { /* Gets IPv6 interface information from the /proc filesystem in linux*/ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) { - struct ifi_info *ifi, *ifihead, **ifipnext; + struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr; FILE *fp; char addr[8][5]; int flags, myflags, index, plen, scope; @@ -91,6 +92,8 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) struct sockaddr_in6 *sin6; struct in6_addr *addrptr; int err; + int sockfd = -1; + struct ifreq ifr; res0=NULL; ifihead = NULL; @@ -98,6 +101,10 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) lastname[0] = 0; if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) { + sockfd = socket(AF_INET6, SOCK_DGRAM, 0); + if (sockfd < 0) { + goto gotError; + } while (fscanf(fp, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n", addr[0],addr[1],addr[2],addr[3], @@ -114,8 +121,10 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info)); if (ifi == NULL) { goto gotError; - } - + } + + ifipold = *ifipnext; /* need this later */ + ifiptr = ifipnext; *ifipnext = ifi; /* prev points to this new one */ ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ @@ -160,9 +169,25 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) /* Add interface index */ ifi->ifi_index = index; - /* If interface is in /proc then it is up*/ - ifi->ifi_flags = IFF_UP; - + /* Add interface flags*/ + memcpy(ifr.ifr_name, ifname, IFNAMSIZ); + if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * If the main interface is configured with no IP address but + * an alias interface exists with an IP address, you get + * EADDRNOTAVAIL for the main interface + */ + free(ifi->ifi_addr); + free(ifi); + ifipnext = ifiptr; + *ifipnext = ifipold; + continue; + } else { + goto gotError; + } + } + ifi->ifi_flags = ifr.ifr_flags; freeaddrinfo(res0); res0=NULL; } @@ -179,6 +204,9 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) res0=NULL; } done: + if (sockfd != -1) { + assert(close(sockfd) == 0); + } return(ifihead); /* pointer to first structure in linked list */ } #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX @@ -186,7 +214,7 @@ struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) struct ifi_info *get_ifi_info(int family, int doaliases) { int junk; - struct ifi_info *ifi, *ifihead, **ifipnext; + struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr; int sockfd, sockf6, len, lastlen, flags, myflags; #ifdef NOT_HAVE_IF_NAMETOINDEX int index = 200; @@ -278,9 +306,11 @@ struct ifi_info *get_ifi_info(int family, int doaliases) if (ifi == NULL) { goto gotError; } - *ifipnext = ifi; /* prev points to this new one */ - ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ - + ifipold = *ifipnext; /* need this later */ + ifiptr = ifipnext; + *ifipnext = ifi; /* prev points to this new one */ + ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ + ifi->ifi_flags = flags; /* IFF_xxx values */ ifi->ifi_myflags = myflags; /* IFI_xxx values */ #ifndef NOT_HAVE_IF_NAMETOINDEX @@ -309,7 +339,23 @@ struct ifi_info *get_ifi_info(int family, int doaliases) memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in)); #ifdef SIOCGIFNETMASK - if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError; + if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * If the main interface is configured with no IP address but + * an alias interface exists with an IP address, you get + * EADDRNOTAVAIL for the main interface + */ + free(ifi->ifi_addr); + free(ifi); + ifipnext = ifiptr; + *ifipnext = ifipold; + continue; + } else { + goto gotError; + } + } + ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); if (ifi->ifi_netmask == NULL) goto gotError; sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr; @@ -384,7 +430,22 @@ struct ifi_info *get_ifi_info(int family, int doaliases) memset(&ifr6, 0, sizeof(ifr6)); memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name )); memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr)); - if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError; + if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * If the main interface is configured with no IP address but + * an alias interface exists with an IP address, you get + * EADDRNOTAVAIL for the main interface + */ + free(ifi->ifi_addr); + free(ifi); + ifipnext = ifiptr; + *ifipnext = ifipold; + continue; + } else { + goto gotError; + } + } ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6)); if (ifi->ifi_netmask == NULL) goto gotError; sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr; @@ -575,9 +636,9 @@ struct in_pktinfo } #endif -#if defined(IPV6_PKTINFO) && HAVE_IPV6 - if (cmptr->cmsg_level == IPPROTO_IPV6 && - cmptr->cmsg_type == IPV6_PKTINFO) { +#if defined(IPV6_PKTINFO) && HAVE_IPV6 + if (cmptr->cmsg_level == IPPROTO_IPV6 && + cmptr->cmsg_type == IPV6_2292_PKTINFO) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr; struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr); @@ -596,7 +657,7 @@ struct in_pktinfo #if defined(IPV6_HOPLIMIT) && HAVE_IPV6 if (cmptr->cmsg_level == IPPROTO_IPV6 && - cmptr->cmsg_type == IPV6_HOPLIMIT) { + cmptr->cmsg_type == IPV6_2292_HOPLIMIT) { *ttl = *(int*)CMSG_DATA(cmptr); continue; } diff --git a/src/tools/mdnssd/mDNSUNP.h b/src/tools/mdnssd/mDNSUNP.h index 59b5501b37bf5c58a42879893a8f275f3eb94753..6b04601f5095287e926f656e4b5200887e10614f 100755 --- a/src/tools/mdnssd/mDNSUNP.h +++ b/src/tools/mdnssd/mDNSUNP.h @@ -25,6 +25,15 @@ #ifdef HAVE_LINUX #include <linux/socket.h> +#define IPV6_2292_PKTINFO IPV6_2292PKTINFO +#define IPV6_2292_HOPLIMIT IPV6_2292HOPLIMIT +#else +// The following are the supported non-linux posix OSes - +// netbsd, freebsd and openbsd. +#if HAVE_IPV6 +#define IPV6_2292_PKTINFO 19 +#define IPV6_2292_HOPLIMIT 20 +#endif #endif #ifdef __cplusplus diff --git a/src/tools/mdnssd/main.cpp b/src/tools/mdnssd/main.cpp deleted file mode 100644 index 40ce0a533e71c2280cff08a5a4eca23bf482ef29..0000000000000000000000000000000000000000 --- a/src/tools/mdnssd/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include <QtCore/QCoreApplication> - -int main(int argc, char *argv[]) -{ - QCoreApplication a(argc, argv); - - return a.exec(); -} diff --git a/src/tools/mdnssd/mdnssd.pro b/src/tools/mdnssd/mdnssd.pro index 3eac277fd422719d5e6bfc3efdfbe9f20a31b495..2272a5bf6174a0bde0e31cbe01c39cb7fba33e15 100644 --- a/src/tools/mdnssd/mdnssd.pro +++ b/src/tools/mdnssd/mdnssd.pro @@ -51,7 +51,7 @@ HEADERS += \ QMAKE_CXXFLAGS += -Wno-unused-but-set-variable } linux-* { -DEFINES += NOT_HAVE_SA_LEN USES_NETLINK HAVE_LINUX TARGET_OS_LINUX +DEFINES += _GNU_SOURCE HAVE_IPV6 NOT_HAVE_SA_LEN USES_NETLINK HAVE_LINUX TARGET_OS_LINUX } macx { DEFINES += HAVE_IPV6 __MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 __APPLE_USE_RFC_2292 diff --git a/src/tools/mdnssd/uDNS.c b/src/tools/mdnssd/uDNS.c index 513150bef08ad8fa6d513b2e7e46cedc31639665..57cfc1a689e65361c568fd2c88a5e792ea92f469 100755 --- a/src/tools/mdnssd/uDNS.c +++ b/src/tools/mdnssd/uDNS.c @@ -101,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, mDNSu32 timeout) +mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped, mDNSu32 timeout, mDNSBool cellIntf) { DNSServer **p = &m->DNSServers; DNSServer *tmp = mDNSNULL; @@ -150,6 +150,7 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons (*p)->teststate = /* DNSServer_Untested */ DNSServer_Passed; (*p)->lasttest = m->timenow - INIT_UCAST_POLL_INTERVAL; (*p)->timeout = timeout; + (*p)->cellIntf = cellIntf; AssignDomainName(&(*p)->domain, d); (*p)->next = mDNSNULL; } @@ -4108,56 +4109,6 @@ mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr) #pragma mark - Periodic Execution Routines #endif -mDNSlocal const mDNSu8 *mDNS_WABLabels[] = - { - (const mDNSu8 *)"\001b", - (const mDNSu8 *)"\002db", - (const mDNSu8 *)"\002lb", - (const mDNSu8 *)"\001r", - (const mDNSu8 *)"\002dr", - (const mDNSu8 *)mDNSNULL, - }; - -// Returns true if it is a WAB question -mDNSlocal mDNSBool WABQuestion(const domainname *qname) - { - const mDNSu8 *sd = (const mDNSu8 *)"\007_dns-sd"; - const mDNSu8 *prot = (const mDNSu8 *)"\004_udp"; - const domainname *d = qname; - const mDNSu8 *label; - int i = 0; - - // We need at least 3 labels (WAB prefix) + one more label to make - // a meaningful WAB query - if (CountLabels(qname) < 4) { debugf("WABQuestion: question %##s, not enough labels", qname->c); return mDNSfalse; } - - label = (const mDNSu8 *)d; - while (mDNS_WABLabels[i] != (const mDNSu8 *)mDNSNULL) - { - if (SameDomainLabel(mDNS_WABLabels[i], label)) {debugf("WABquestion: WAB question %##s, label1 match", qname->c); break;} - i++; - } - if (mDNS_WABLabels[i] == (const mDNSu8 *)mDNSNULL) - { - debugf("WABquestion: Not a WAB question %##s, label1 mismatch", qname->c); - return mDNSfalse; - } - // CountLabels already verified the number of labels - d = (const domainname *)(d->c + 1 + d->c[0]); // Second Label - label = (const mDNSu8 *)d; - if (!SameDomainLabel(label, sd)){ debugf("WABquestion: Not a WAB question %##s, label2 mismatch", qname->c);return(mDNSfalse); } - debugf("WABquestion: WAB question %##s, label2 match", qname->c); - - d = (const domainname *)(d->c + 1 + d->c[0]); // Third Label - label = (const mDNSu8 *)d; - if (!SameDomainLabel(label, prot)){ debugf("WABquestion: Not a WAB question %##s, label3 mismatch", qname->c);return(mDNSfalse); } - debugf("WABquestion: WAB question %##s, label3 match", qname->c); - - LogInfo("WABquestion: Question %##s is a WAB question", qname->c); - - return mDNStrue; - } - // The question to be checked is not passed in as an explicit parameter; // instead it is implicit that the question to be checked is m->CurrentQuestion. mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) @@ -4285,7 +4236,14 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) q->ThisQInterval = LLQ_POLL_INTERVAL; LogInfo("uDNS_CheckCurrentQuestion: private non polling question for %##s (%s) will be retried in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval); } - debugf("Increased ThisQInterval to %d for %##s (%s)", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype)); + if (q->qDNSServer->cellIntf) + { + // We don't want to retransmit too soon. Schedule our first retransmisson at + // MIN_UCAST_RETRANS_TIMEOUT seconds. + if (q->ThisQInterval < MIN_UCAST_RETRANS_TIMEOUT) + q->ThisQInterval = MIN_UCAST_RETRANS_TIMEOUT; + } + debugf("uDNS_CheckCurrentQuestion: Increased ThisQInterval to %d for %##s (%s), cell %d", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer->cellIntf); } q->LastQTime = m->timenow; SetNextQueryTime(m, q); @@ -4351,7 +4309,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) // For some of the WAB queries that we generate form within the mDNSResponder, most of the home routers // don't understand and return ServFail/NXDomain. In those cases, we don't want to try too often. We try // every fifteen minutes in that case - MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, (WABQuestion(&q->qname) ? 60 * 15 : 60), mDNSInterface_Any, q->qDNSServer); + MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, (DomainEnumQuery(&q->qname) ? 60 * 15 : 60), mDNSInterface_Any, q->qDNSServer); q->unansweredQueries = 0; // We're already using the m->CurrentQuestion pointer, so CacheRecordAdd can't use it to walk the question list. // To solve this problem we set rr->DelayDelivery to a nonzero value (which happens to be 'now') so that we diff --git a/src/tools/mdnssd/uDNS.h b/src/tools/mdnssd/uDNS.h index 2dfaf51ec8c99208b0db823a97a8b0c3fd562d33..8e46ffa77d4e7ec3fe8c86fa01d8a4104c1f1a48 100755 --- a/src/tools/mdnssd/uDNS.h +++ b/src/tools/mdnssd/uDNS.h @@ -35,6 +35,10 @@ #define MAX_UCAST_UNANSWERED_QUERIES 2 // the number of unanswered queries from any one uDNS server before trying another server #define DNSSERVER_PENALTY_TIME (60 * mDNSPlatformOneSecond) // number of seconds for which new questions don't pick this server +// On some interfaces, we want to delay the first retransmission to a minimum of 2 seconds +// rather than the default (1 second). +#define MIN_UCAST_RETRANS_TIMEOUT (2 * mDNSPlatformOneSecond) + #define DEFAULT_UPDATE_LEASE 7200 #define QuestionIntervalStep 3