From 4af311eaa716c382b6e84dd30b211258b07924ce Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 18 Jun 2020 13:10:44 +0200 Subject: mDNSResponder: Update to v878.240.1 The sources can be obtained via: https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-878.240.1.tar.gz Update #4010. --- mDNSResponder/Makefile | 2 +- mDNSResponder/mDNSCore/DNSCommon.c | 4 ++-- mDNSResponder/mDNSCore/DNSCommon.h | 7 +++++++ mDNSResponder/mDNSCore/mDNS.c | 33 ++++++++++++++++++++++++--------- mDNSResponder/mDNSCore/uDNS.c | 18 ++++++++++-------- mDNSResponder/mDNSCore/uDNS.h | 2 ++ mDNSResponder/mDNSShared/dns_sd.h | 2 +- 7 files changed, 47 insertions(+), 21 deletions(-) diff --git a/mDNSResponder/Makefile b/mDNSResponder/Makefile index 8b97eacc..78adbd5e 100644 --- a/mDNSResponder/Makefile +++ b/mDNSResponder/Makefile @@ -17,7 +17,7 @@ include $(MAKEFILEPATH)/pb_makefiles/platform.make -MVERS = "mDNSResponder-878.230.2" +MVERS = "mDNSResponder-878.240.1" VER = ifneq ($(strip $(GCC_VERSION)),) diff --git a/mDNSResponder/mDNSCore/DNSCommon.c b/mDNSResponder/mDNSCore/DNSCommon.c index a249b967..f3150762 100644 --- a/mDNSResponder/mDNSCore/DNSCommon.c +++ b/mDNSResponder/mDNSCore/DNSCommon.c @@ -3467,8 +3467,8 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage rr->resrec.rrtype = (mDNSu16) ((mDNSu16)ptr[0] << 8 | ptr[1]); rr->resrec.rrclass = (mDNSu16)(((mDNSu16)ptr[2] << 8 | ptr[3]) & kDNSClass_Mask); rr->resrec.rroriginalttl = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]); - if (rr->resrec.rroriginalttl > 0x70000000UL / mDNSPlatformOneSecond && (mDNSs32)rr->resrec.rroriginalttl != -1) - rr->resrec.rroriginalttl = 0x70000000UL / mDNSPlatformOneSecond; + if (rr->resrec.rroriginalttl > mDNSMaximumTTLSeconds && (mDNSs32)rr->resrec.rroriginalttl != -1) + rr->resrec.rroriginalttl = mDNSMaximumTTLSeconds; // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly. pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]); diff --git a/mDNSResponder/mDNSCore/DNSCommon.h b/mDNSResponder/mDNSCore/DNSCommon.h index b100a400..48dfe102 100644 --- a/mDNSResponder/mDNSCore/DNSCommon.h +++ b/mDNSResponder/mDNSCore/DNSCommon.h @@ -110,6 +110,13 @@ extern mDNSu32 mDNSRandom(mDNSu32 max); // Returns pseudo-random result from #define mDNSIsUpperCase(X) ((X) >= 'A' && (X) <= 'Z') #define mDNSIsLowerCase(X) ((X) >= 'a' && (X) <= 'z') #define mDNSIsLetter(X) (mDNSIsUpperCase(X) || mDNSIsLowerCase(X)) + +// We believe we have adequate safeguards to protect against cache poisoning. +// In the event that someone does find a workable cache poisoning attack, we want to limit the lifetime of the poisoned entry. +// We set the maximum allowable TTL to one hour. +// With the 25% correction factor to avoid the DNS Zeno's paradox bug, that gives us an actual maximum lifetime of 75 minutes. + +#define mDNSMaximumTTLSeconds (mDNSu32)3600 #define mDNSValidHostChar(X, notfirst, notlast) (mDNSIsLetter(X) || mDNSIsDigit(X) || ((notfirst) && (notlast) && (X) == '-') ) diff --git a/mDNSResponder/mDNSCore/mDNS.c b/mDNSResponder/mDNSCore/mDNS.c index 10504d09..9e1ac506 100755 --- a/mDNSResponder/mDNSCore/mDNS.c +++ b/mDNSResponder/mDNSCore/mDNS.c @@ -7171,7 +7171,7 @@ mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const m const mDNSu8 *const limit = response->data + sizeof(response->data); const mDNSu8 *ptr = query->data; AuthRecord *rr; - mDNSu32 maxttl = 0x70000000; + mDNSu32 maxttl = mDNSMaximumTTLSeconds; int i; // Initialize the response fields so we can answer the questions @@ -8075,19 +8075,25 @@ struct UDPSocket_struct mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port }; -mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question, mDNSBool tcp) +mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question, mDNSBool tcp, DNSQuestion ** suspiciousQ) { DNSQuestion *q; for (q = m->Questions; q; q=q->next) { if (!tcp && !q->LocalSocket) continue; - if (mDNSSameIPPort(tcp ? q->tcpSrcPort : q->LocalSocket->port, port) && - mDNSSameOpaque16(q->TargetQID, id) && + if (mDNSSameIPPort(tcp ? q->tcpSrcPort : q->LocalSocket->port, port) && q->qtype == question->qtype && q->qclass == question->qclass && q->qnamehash == question->qnamehash && SameDomainName(&q->qname, &question->qname)) - return(q); + { + if (mDNSSameOpaque16(q->TargetQID, id)) return(q); + else + { + if (!tcp && suspiciousQ) *suspiciousQ = q; + return(mDNSNULL); + } + } } return(mDNSNULL); } @@ -8413,7 +8419,7 @@ mDNSlocal void mDNSCoreReceiveNoDNSSECAnswers(mDNS *const m, const DNSMessage *c DNSQuestion pktq; DNSQuestion *qptr = mDNSNULL; ptr = getQuestion(response, ptr, end, InterfaceID, &pktq); - if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &pktq, !dstaddr)) && + if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &pktq, !dstaddr, mDNSNULL)) && qptr->ValidatingResponse) { DNSQuestion *next, *q; @@ -8457,7 +8463,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage * DNSQuestion q; DNSQuestion *qptr = mDNSNULL; ptr = getQuestion(response, ptr, end, InterfaceID, &q); - if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr))) + if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr, mDNSNULL))) { CacheRecord *rr, *neg = mDNSNULL; CacheGroup *cg = CacheGroupForName(m, q.qnamehash, &q.qname); @@ -9037,9 +9043,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // packet number, then we deduce they are old and delete them for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++) { - DNSQuestion q, *qptr = mDNSNULL; + DNSQuestion q, *qptr = mDNSNULL, *suspiciousForQ = mDNSNULL; ptr = getQuestion(response, ptr, end, InterfaceID, &q); - if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr))) + if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr, &suspiciousForQ))) { if (!failure) { @@ -9102,6 +9108,15 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, returnEarly = mDNStrue; } } + else if (!InterfaceID && suspiciousForQ) + { + // If a response is suspicious for a question, then reissue the question via TCP + LogInfo("mDNSCoreReceiveResponse: Server %p responded suspiciously to query %##s (%s) qID %d != rID: %d", + suspiciousForQ->qDNSServer, q.qname.c, DNSTypeName(q.qtype), + mDNSVal16(suspiciousForQ->TargetQID), mDNSVal16(response->h.id)); + uDNS_RestartQuestionAsTCP(m, suspiciousForQ, srcaddr, srcport); + return; + } } if (returnEarly) { diff --git a/mDNSResponder/mDNSCore/uDNS.c b/mDNSResponder/mDNSCore/uDNS.c index 2d6d14e9..1f9b1543 100755 --- a/mDNSResponder/mDNSCore/uDNS.c +++ b/mDNSResponder/mDNSCore/uDNS.c @@ -3925,14 +3925,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW) { if (!srcaddr) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring"); - else - { - // Don't reuse TCP connections. We might have failed over to a different DNS server - // while the first TCP connection is in progress. We need a new TCP connection to the - // new DNS server. So, always try to establish a new connection. - if (qptr->tcp) { DisposeTCPConn(qptr->tcp); qptr->tcp = mDNSNULL; } - qptr->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, mDNSNULL, qptr, mDNSNULL); - } + else uDNS_RestartQuestionAsTCP(m, qptr, srcaddr, srcport); } } @@ -5745,6 +5738,15 @@ mDNSexport domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mD return mDNSNULL; } +mDNSexport void uDNS_RestartQuestionAsTCP(mDNS *m, DNSQuestion *const q, const mDNSAddr *const srcaddr, const mDNSIPPort srcport) +{ + // Don't reuse TCP connections. We might have failed over to a different DNS server + // while the first TCP connection is in progress. We need a new TCP connection to the + // new DNS server. So, always try to establish a new connection. + if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; } + q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, mDNSNULL, q, mDNSNULL); +} + mDNSlocal void FlushAddressCacheRecords(mDNS *const m) { mDNSu32 slot; diff --git a/mDNSResponder/mDNSCore/uDNS.h b/mDNSResponder/mDNSCore/uDNS.h index 27b7acee..d3141dd5 100755 --- a/mDNSResponder/mDNSCore/uDNS.h +++ b/mDNSResponder/mDNSCore/uDNS.h @@ -129,6 +129,8 @@ extern void uDNS_SetupWABQueries(mDNS *const m); extern void uDNS_StartWABQueries(mDNS *const m, int queryType); extern void uDNS_StopWABQueries(mDNS *const m, int queryType); extern domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal); + +extern void uDNS_RestartQuestionAsTCP(mDNS *m, DNSQuestion *const q, const mDNSAddr *const srcaddr, const mDNSIPPort srcport); typedef enum { diff --git a/mDNSResponder/mDNSShared/dns_sd.h b/mDNSResponder/mDNSShared/dns_sd.h index 2f530917..3495c6e6 100644 --- a/mDNSResponder/mDNSShared/dns_sd.h +++ b/mDNSResponder/mDNSShared/dns_sd.h @@ -66,7 +66,7 @@ */ #ifndef _DNS_SD_H -#define _DNS_SD_H 8803002 +#define _DNS_SD_H 8804001 #ifdef __cplusplus extern "C" { -- cgit v1.2.3