]> git.saurik.com Git - apple/mdnsresponder.git/commitdiff
mDNSResponder-176.2.tar.gz mac-os-x-1055 v176.2
authorApple <opensource@apple.com>
Thu, 14 Aug 2008 20:51:50 +0000 (20:51 +0000)
committerApple <opensource@apple.com>
Thu, 14 Aug 2008 20:51:50 +0000 (20:51 +0000)
16 files changed:
Makefile
mDNSCore/DNSCommon.c
mDNSCore/DNSCommon.h
mDNSCore/mDNS.c
mDNSCore/mDNSEmbeddedAPI.h
mDNSCore/uDNS.c
mDNSCore/uDNS.h
mDNSMacOSX/LegacyNATTraversal.c
mDNSMacOSX/daemon.c
mDNSMacOSX/helper-main.c
mDNSMacOSX/mDNSMacOSX.c
mDNSMacOSX/mDNSMacOSX.h
mDNSMacOSX/mDNSResponder.sb
mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
mDNSPosix/mDNSUNP.c
mDNSShared/dns_sd.h

index ef3c0ee4a993a5ef5eff344a27c4f4902e7ac395..8f6dfb89bc81ea234b078327cca9298ac21d7115 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 
 include /Developer/Makefiles/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-171.4"
+MVERS = "mDNSResponder-176.2"
 
 DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
 
index bffef7b13e64dfe67d13c9668b5451dd9b7360e1..deda1b90b8e33922eacfc17e43e52e4fc51eb5f0 100644 (file)
@@ -17,6 +17,9 @@
     Change History (most recent first):
 
 $Log: DNSCommon.c,v $
+Revision 1.199.2.1  2008/07/25 07:25:08  mcguire
+merge of <rdar://3988320&6041178> to SUSB for <rdar://problem/5662487&6090114>
+
 Revision 1.199  2008/03/14 19:58:38  mcguire
 <rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
 Make sure we add the record when sending LLQ refreshes
@@ -586,6 +589,17 @@ mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd,
        return(buffer);
        }
 
+// Long-term we need to make this cross-platform, either by using our own embedded RC4 code
+// to generate the pseudo-random sequence, or by adding another mDNSPlatformXXX() call.
+// The former would be preferable because it makes our code self-contained, so it will run anywhere.
+// The latter is less desirable because it increases the burden on people writing platform support layers
+// to now implement one more function (and an important one at that, that needs to be cryptographically strong).
+// For now, as a temporary fix, if we're building mDNSResponder for OS X we just use arc4random() directly here.
+
+#if _BUILDING_XCODE_PROJECT_
+#include <stdlib.h>
+#endif
+
 mDNSexport mDNSu32 mDNSRandom(mDNSu32 max)             // Returns pseudo-random result from zero to max inclusive
        {
        static mDNSu32 seed = 0;
@@ -598,7 +612,14 @@ mDNSexport mDNSu32 mDNSRandom(mDNSu32 max)         // Returns pseudo-random result from
                for (i=0; i<100; i++) seed = seed * 21 + 1;             // And mix it up a bit
                }
        while (mask < max) mask = (mask << 1) | 1;
-       do seed = seed * 21 + 1; while ((seed & mask) > max);
+
+#if _BUILDING_XCODE_PROJECT_
+       do seed = arc4random();
+#else
+       do seed = seed * 21 + 1;
+#endif
+       while ((seed & mask) > max);
+
        return (seed & mask);
        }
 
@@ -2525,14 +2546,21 @@ mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg,
        (X) == kDNSFlag1_RC_NotZone  ? "NotZone"  : "??" )
 
 // Note: DumpPacket expects the packet header fields in host byte order, not network byte order
-mDNSexport void DumpPacket(mDNS *const m, mDNSBool sent, char *transport, const mDNSAddr *addr, mDNSIPPort port, const DNSMessage *const msg, const mDNSu8 *const end)
+mDNSexport void DumpPacket(mDNS *const m, mDNSBool sent, char *transport,
+       const mDNSAddr *srcaddr, mDNSIPPort srcport,
+       const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end)
        {
        mDNSBool IsUpdate = ((msg->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update);
        const mDNSu8 *ptr = msg->data;
        int i;
        DNSQuestion q;
+       char sbuffer[64], dbuffer[64] = "";
+       if (sent) sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "port "        )] = 0;
+       else      sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "%#a:", srcaddr)] = 0;
+       if (dstaddr || !mDNSIPPortIsZero(dstport))
+               dbuffer[mDNS_snprintf(dbuffer, sizeof(dbuffer), " to %#a:%d", dstaddr, mDNSVal16(dstport))] = 0;
 
-       LogMsg("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes %s %#a:%d%s --",
+       LogMsg("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes from %s%d%s%s --",
                sent ? "Sent" : "Received", transport,
                DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
                msg->h.flags.b[0] & kDNSFlag0_QR_Response ? "Response" : "Query",
@@ -2547,7 +2575,7 @@ mDNSexport void DumpPacket(mDNS *const m, mDNSBool sent, char *transport, const
                msg->h.flags.b[1] & kDNSFlag1_CD ? "CD " : "",
                mDNSVal16(msg->h.id),
                end - msg->data,
-               sent ? "to" : "from", addr, mDNSVal16(port),
+               sbuffer, mDNSVal16(srcport), dbuffer,
                (msg->h.flags.b[0] & kDNSFlag0_TC) ? " (truncated)" : ""
                );
 
@@ -2572,10 +2600,15 @@ mDNSexport void DumpPacket(mDNS *const m, mDNSBool sent, char *transport, const
 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
 struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
 
+struct UDPSocket_struct
+       {
+       mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
+       };
+
 // Note: When we sign a DNS message using DNSDigest_SignMessage(), the current real-time clock value is used, which
 // is why we generally defer signing until we send the message, to ensure the signature is as fresh as possible.
 mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
-    mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo)
+    mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo)
        {
        mStatus status = mStatus_NoError;
        const mDNSu16 numQuestions   = msg->h.numQuestions;
@@ -2613,7 +2646,7 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
                        {
                        // Send the packet on the wire
                        if (!sock)
-                               status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, dst, dstport);
+                               status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, src, dst, dstport);
                        else
                                {
                                mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg);
@@ -2639,7 +2672,7 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
                {
                ptr = (mDNSu8 *)&msg->h.numAdditionals;
                msg->h.numAdditionals = (mDNSu16)ptr[0] << 8 | (mDNSu16)ptr[1];
-               DumpPacket(m, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", dst, dstport, msg, end);
+               DumpPacket(m, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", mDNSNULL, src ? src->port : MulticastDNSPort, dst, dstport, msg, end);
                }
 
        // put the final integer value back the way it was
index 655603104d275336cc38a0c4dfcccef015471f59..52169dea4f8c82d3c14a85b91e993c3b2cbb70c9 100644 (file)
@@ -17,6 +17,9 @@
     Change History (most recent first):
 
 $Log: DNSCommon.h,v $
+Revision 1.60  2008/07/24 20:23:03  cheshire
+<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
+
 Revision 1.59  2008/03/14 19:58:38  mcguire
 <rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
 Make sure we add the record when sending LLQ refreshes
@@ -321,7 +324,9 @@ extern const mDNSu8 *LocateLLQOptData(const DNSMessage *const msg, const mDNSu8
 extern const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end);
 extern const mDNSu8 *LocateLeaseOptData(const DNSMessage *const msg, const mDNSu8 *const end);
 extern mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end);
-extern void DumpPacket(mDNS *const m, mDNSBool sent, char *type, const mDNSAddr *addr, mDNSIPPort port, const DNSMessage *const msg, const mDNSu8 *const end);
+extern void DumpPacket(mDNS *const m, mDNSBool sent, char *transport,
+       const mDNSAddr *srcaddr, mDNSIPPort srcport,
+       const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end);
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -330,7 +335,7 @@ extern void DumpPacket(mDNS *const m, mDNSBool sent, char *type, const mDNSAddr
 #endif
 
 extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
-       mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo);
+       mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo);
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
index 34a3c7c915b83a43c5216b92a42d1237eb362e20..e8323b7cacfb892ee7c4c5f5f1f5fd0ba2d1d994 100755 (executable)
     Change History (most recent first):
 
 $Log: mDNS.c,v $
+Revision 1.777.4.4  2008/08/14 20:43:59  cheshire
+<rdar://problem/6143846> Back to My Mac not working with Time Capsule shared volume
+
+Revision 1.777.4.3  2008/07/29 20:46:05  mcguire
+<rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
+merge r1.782 & r1.783 from <rdar://problem/3988320>
+
+Revision 1.777.4.2  2008/07/29 20:13:52  mcguire
+<rdar://problem/6090024> BTMM: alternate SSDP queries between multicast & unicast
+merged r1.781 for <rdar://problem/5736845>
+
+Revision 1.777.4.1  2008/07/29 19:17:55  mcguire
+<rdar://problem/6090046> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
+merge r1.779, r.1780 from <rdar://problem/6041178>
+
+Revision 1.777  2008/06/19 01:20:48  mcguire
+<rdar://problem/4206534> Use all configured DNS servers
+
 Revision 1.776  2008/04/17 20:14:14  cheshire
 <rdar://problem/5870023> CurrentAnswers/LargeAnswers/UniqueAnswers counter mismatch
 
@@ -1793,7 +1811,7 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d
                        rr->NR_AdditionalTo = mDNSNULL;
                        }
 
-               if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, dest, MulticastDNSPort, mDNSNULL, mDNSNULL);
+               if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL);
                }
        }
 
@@ -2101,8 +2119,8 @@ mDNSlocal void SendResponses(mDNS *const m)
                                numAnnounce,               numAnnounce               == 1 ? "" : "s",
                                numAnswer,                 numAnswer                 == 1 ? "" : "s",
                                m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
-                       if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
-                       if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
+                       if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
+                       if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
                        if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
                        if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; }
                        // There might be more things to send on this interface, so go around one more time and try again.
@@ -2340,6 +2358,18 @@ mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name,
                }
        }
 
+// If we get no answer for a AAAA query, then before doing an automatic implicit ReconfirmAntecedents
+// we check if we have an address record for the same name. If we do have an IPv4 address for a given
+// name but not an IPv6 address, that's okay (it just means the device doesn't do IPv6) so the failure
+// to get a AAAA response is not grounds to doubt the PTR/SRV chain that lead us to that name.
+mDNSlocal CacheRecord *CacheHasAddressTypeForName(mDNS *const m, const domainname *const name, const mDNSu32 namehash)
+       {
+       CacheGroup *const cg = CacheGroupForName(m, HashSlot(name), namehash, name);
+       CacheRecord *cr = cg ? cg->members : mDNSNULL;
+       while (cr && !RRTypeIsAddressType(cr->resrec.rrtype)) cr=cr->next;
+       return(cr);
+       }
+
 // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
 mDNSlocal void ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time)
        {
@@ -2489,7 +2519,7 @@ mDNSlocal void SendQueries(mDNS *const m)
                                const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
                                InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
                                qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
-                               mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL);
+                               mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, q->LocalSocket, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL);
                                q->ThisQInterval    *= QuestionIntervalStep;
                                if (q->ThisQInterval > MaxQuestionInterval)
                                        q->ThisQInterval = MaxQuestionInterval;
@@ -2532,10 +2562,13 @@ mDNSlocal void SendQueries(mDNS *const m)
                                        {
                                        //LogOperation("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
                                        q->SendQNow = mDNSInterfaceMark;        // Mark this question for sending on all interfaces
+                                       debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d",
+                                               q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval / InitialQuestionInterval, q->RequestUnicast);
                                        q->ThisQInterval *= QuestionIntervalStep;
                                        if (q->ThisQInterval > MaxQuestionInterval)
                                                q->ThisQInterval = MaxQuestionInterval;
-                                       else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep2)
+                                       else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep3 && !q->RequestUnicast &&
+                                                       !(RRTypeIsAddressType(q->qtype) && CacheHasAddressTypeForName(m, &q->qname, q->qnamehash)))
                                                {
                                                // Generally don't need to log this.
                                                // It's not especially noteworthy if a query finds no results -- this usually happens for domain
@@ -2738,8 +2771,8 @@ mDNSlocal void SendQueries(mDNS *const m)
                                m->omsg.h.numQuestions,   m->omsg.h.numQuestions   == 1 ? "" : "s",
                                m->omsg.h.numAnswers,     m->omsg.h.numAnswers     == 1 ? "" : "s",
                                m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID);
-                       if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
-                       if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
+                       if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
+                       if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
                        if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
                        if (++pktcount >= 1000)
                                { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
@@ -2934,8 +2967,8 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
                                if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
                                        q->ThisQInterval > InitialQuestionInterval * QuestionIntervalStep3 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
                                        {
-                                       LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst; restarting exponential backoff sequence",
-                                               q->qname.c, DNSTypeName(q->qtype));
+                                       LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst (%d); restarting exponential backoff sequence (%d)",
+                                               q->qname.c, DNSTypeName(q->qtype), q->RecentAnswerPkts, q->ThisQInterval);
                                        q->LastQTime      = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4);
                                        q->ThisQInterval  = InitialQuestionInterval;
                                        SetNextQueryTime(m,q);
@@ -2944,6 +2977,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
                        verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
                                rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
                        q->CurrentAnswers++;
+                       q->unansweredQueries = 0;
                        if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
                        if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
                        if (q->CurrentAnswers > 4000)
@@ -4400,10 +4434,11 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg,
                        m->omsg.h.numAnswers,     m->omsg.h.numAnswers     == 1 ? "" : "s",
                        m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s",
                        srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type);
-               mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, srcaddr, srcport, mDNSNULL, mDNSNULL);
+               mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, mDNSNULL, srcaddr, srcport, mDNSNULL, mDNSNULL);
                }
        }
 
+#if 0
 mDNSlocal mDNSBool TrustedSource(const mDNS *const m, const mDNSAddr *const srcaddr)
        {
        DNSServer *s;
@@ -4413,12 +4448,19 @@ mDNSlocal mDNSBool TrustedSource(const mDNS *const m, const mDNSAddr *const srca
                if (mDNSSameAddress(srcaddr, &s->addr)) return(mDNStrue);
        return(mDNSfalse);
        }
+#endif
+
+struct UDPSocket_struct
+       {
+       mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
+       };
 
-mDNSlocal const DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSOpaque16 id, const DNSQuestion *const question)
+mDNSlocal const DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question)
        {
        DNSQuestion *q;
        for (q = m->Questions; q; q=q->next)
-               if (mDNSSameOpaque16(q->TargetQID, id)                 &&
+               if (mDNSSameIPPort(q->LocalSocket ? q->LocalSocket->port : MulticastDNSPort, port) &&
+                       mDNSSameOpaque16(q->TargetQID,         id)         &&
                        q->qtype                  == question->qtype       &&
                        q->qclass                 == question->qclass      &&
                        q->qnamehash              == question->qnamehash   &&
@@ -4427,22 +4469,23 @@ mDNSlocal const DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *con
        return(mDNSNULL);
        }
 
-mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSOpaque16 id, const CacheRecord *const rr)
+mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSIPPort port, const mDNSOpaque16 id, const CacheRecord *const rr)
        {
        DNSQuestion *q;
        (void)id;
+       (void)srcaddr;
        for (q = m->Questions; q; q=q->next)
                if (ResourceRecordAnswersQuestion(&rr->resrec, q))
                        {
                        if (!mDNSOpaque16IsZero(q->TargetQID))
                                {
-                               // For now we don't do this check -- for LLQ updates, the ID doesn't seem to match the ID in the question
-                               // if (mDNSSameOpaque16(q->TargetQID, id)
+                               debugf("ExpectingUnicastResponseForRecord msg->h.id %d q->TargetQID %d for %s", mDNSVal16(id), mDNSVal16(q->TargetQID), CRDisplayString(m, rr));
+                               if (mDNSSameOpaque16(q->TargetQID, id))
                                        {
-                                       if (mDNSSameAddress(srcaddr, &q->Target))                   return(mDNStrue);
-                                       if (mDNSSameOpaque16(q->TargetQID, id))                     return(mDNStrue);
+                                       if (mDNSSameIPPort(q->LocalSocket ? q->LocalSocket->port : MulticastDNSPort, port)) return(mDNStrue);
+                               //      if (mDNSSameAddress(srcaddr, &q->Target))                   return(mDNStrue);
                                //      if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
-                                       if (TrustedSource(m, srcaddr))                              return(mDNStrue);
+                               //      if (TrustedSource(m, srcaddr))                              return(mDNStrue);
                                        LogOperation("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a] from %#a: %s",
                                                q->qname.c, DNSTypeName(q->qtype), &q->Target, srcaddr, CRDisplayString(m, rr));
                                        return(mDNSfalse);
@@ -4635,7 +4678,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                        {
                        DNSQuestion q;
                        ptr = getQuestion(response, ptr, end, InterfaceID, &q);
-                       if (ptr && ExpectingUnicastResponseForQuestion(m, response->h.id, &q))
+                       if (ptr && (!dstaddr || ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q)))
                                {
                                CacheRecord *rr;
                                const mDNSu32 slot = HashSlot(&q.qname);
@@ -4678,7 +4721,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
 
                // If response was not sent via LL multicast,
                // then see if it answers a recent query of ours, which would also make it acceptable for caching.
-               if (!AcceptableResponse) AcceptableResponse = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, response->h.id, &m->rec.r);
+               if (!AcceptableResponse) AcceptableResponse = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r);
 
                // 1. Check that this packet resource record does not conflict with any of ours
                if (mDNSOpaque16IsZero(response->h.id))
@@ -4964,7 +5007,7 @@ exit:
                {
                DNSQuestion q;
                ptr = getQuestion(response, ptr, end, InterfaceID, &q);
-               if (ptr && ExpectingUnicastResponseForQuestion(m, response->h.id, &q))
+               if (ptr && (!dstaddr || ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q)))
                        {
                        CacheRecord *rr, *neg = mDNSNULL;
                        mDNSu32 slot = HashSlot(&q.qname);
@@ -5084,11 +5127,6 @@ mDNSexport void MakeNegativeCacheRecord(mDNS *const m, const domainname *const n
        m->rec.r.NextInCFList       = mDNSNULL;
        }
 
-struct UDPSocket_struct
-       {
-       mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
-       };
-       
 mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end,
        const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport,
        const mDNSInterfaceID InterfaceID)
@@ -5147,7 +5185,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co
                        {
                        ifid = mDNSInterface_Any;
                        if (mDNS_LogLevel >= MDNS_LOG_VERBOSE_DEBUG)
-                               DumpPacket(m, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, msg, end);
+                               DumpPacket(m, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
                        uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport);
                        // Note: mDNSCore also needs to get access to received unicast responses
                        }
@@ -5226,6 +5264,11 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
                                q->nta               = question->nta;
                                q->servAddr          = question->servAddr;
                                q->servPort          = question->servPort;
+                               q->qDNSServer        = question->qDNSServer;
+                               q->unansweredQueries = question->unansweredQueries;
+
+                               q->TargetQID         = question->TargetQID;
+                               q->LocalSocket       = question->LocalSocket;
 
                                q->state             = question->state;
                        //      q->tcp               = question->tcp;
@@ -5234,8 +5277,13 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
                                q->ntries            = question->ntries;
                                q->id                = question->id;
 
+                               question->LocalSocket = mDNSNULL;
                                question->nta        = mDNSNULL;        // If we've got a GetZoneData in progress, transfer it to the newly active question
                        //      question->tcp        = mDNSNULL;
+
+                               if (q->LocalSocket)
+                                       LogOperation("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+
                                if (q->nta)
                                        {
                                        LogOperation("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
@@ -5256,7 +5304,7 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
        }
 
 // Look up a DNS Server, matching by name in split-dns configurations.
-mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name)
+mDNSexport DNSServer *GetServerForName(mDNS *m, const domainname *name)
     {
        DNSServer *curmatch = mDNSNULL, *p;
        int curmatchlen = -1, ncount = name ? CountLabels(name) : 0;
@@ -5379,6 +5427,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
                question->CNAMEReferrals    = 0;
 
                question->qDNSServer        = mDNSNULL;
+               question->unansweredQueries = 0;
                question->nta               = mDNSNULL;
                question->servAddr          = zeroAddr;
                question->servPort          = zeroIPPort;
@@ -5391,6 +5440,8 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
                question->ntries            = 0;
                question->id                = zeroOpaque64;
 
+               question->LocalSocket       = mDNSNULL;
+
                if (question->DuplicateOf) question->AuthInfo = question->DuplicateOf->AuthInfo;
 
                for (i=0; i<DupSuppressInfoSize; i++)
@@ -5418,6 +5469,18 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
                        // this routine with the question list data structures in an inconsistent state.
                        if (!mDNSOpaque16IsZero(question->TargetQID))
                                {
+                               // We don't want to make a separate UDP socket for LLQs because (when we're using NAT)
+                               // they all share a single NAT mapping for receiving inbound add/remove events.
+                               if (!question->DuplicateOf && !question->LongLived)
+                                       {
+                                       question->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
+                                       debugf("mDNS_StartQuery_internal: dup %p %##s (%s) port %d",
+                                               question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype), question->LocalSocket ? mDNSVal16(question->LocalSocket->port) : -1);
+                                       // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion)
+                                       // then we don't fail the query; we just let it use our pre-canned permanent socket, which is okay (it should
+                                       // never happen in normal operation, and even if it does we still have our cryptographically strong transaction ID).
+                                       }
+
                                question->qDNSServer = GetServerForName(m, &question->qname);
                                ActivateUnicastQuery(m, question, mDNSfalse);
 
@@ -5529,6 +5592,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
        // *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query.
        if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
        if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
+       if (question->LocalSocket) { mDNSPlatformUDPClose(question->LocalSocket); question->LocalSocket = mDNSNULL; }
        if (!mDNSOpaque16IsZero(question->TargetQID) && question->LongLived)
                {
                // Scan our list to see if any more wide-area LLQs remain. If not, stop our NAT Traversal.
@@ -6929,13 +6993,21 @@ mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
        return(mDNS_Register(m, rr));
        }
        
-mDNSOpaque16 mDNS_NewMessageID(mDNS * const m)
+mDNSexport mDNSOpaque16 mDNS_NewMessageID(mDNS * const m)
        {
-       static mDNSBool randomized = mDNSfalse;
-
-       if (!randomized) { m->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; }
-       if (m->NextMessageID == 0) m->NextMessageID++;
-       return mDNSOpaque16fromIntVal(m->NextMessageID++);
+       mDNSOpaque16 id;
+       int i;
+       for (i=0; i<10; i++)
+               {
+               AuthRecord *r;
+               DNSQuestion *q;
+               id = mDNSOpaque16fromIntVal(1 + mDNSRandom(0xFFFE));
+               for (r = m->ResourceRecords; r; r=r->next) if (mDNSSameOpaque16(id, r->id       )) continue;
+               for (q = m->Questions;       q; q=q->next) if (mDNSSameOpaque16(id, q->TargetQID)) continue;
+               break;
+               }
+       debugf("mDNS_NewMessageID: %5d", mDNSVal16(id));
+       return id;
        }
 
 // ***************************************************************************
@@ -7052,7 +7124,6 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        m->SuppressStdPort53Queries = 0;
 
        m->ServiceRegistrations     = mDNSNULL;
-       m->NextMessageID            = 0;
        m->DNSServers               = mDNSNULL;
 
        m->Router                   = zeroAddr;
@@ -7085,6 +7156,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
 
        m->UPnPInterfaceID          = 0;
        m->SSDPSocket               = mDNSNULL;
+       m->SSDPMulticast            = mDNSfalse;
        m->UPnPRouterPort           = zeroIPPort;
        m->UPnPSOAPPort             = zeroIPPort;
        m->UPnPRouterURL            = mDNSNULL;
@@ -7152,6 +7224,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
                                        s, s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), s ? s->domain.c : (mDNSu8*)"",
                                        q->qname.c, DNSTypeName(q->qtype));
                                q->qDNSServer = s;
+                               q->unansweredQueries = 0;
                                ActivateUnicastQuery(m, q, mDNStrue);
                                }
                        }
index 72b9e1f27bb4b51460230a6a48ae152fb6c84b97..1f1c52fb5fd19e760e91f22e5d716bd929bef5f4 100755 (executable)
     Change History (most recent first):
 
 $Log: mDNSEmbeddedAPI.h,v $
+Revision 1.468.2.3  2008/07/29 20:46:57  mcguire
+<rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
+merge r1.474 from <rdar://problem/3988320>
+
+Revision 1.468.2.2  2008/07/29 19:44:38  mcguire
+<rdar://problem/6090024> BTMM: alternate SSDP queries between multicast & unicast
+merge r1.472, r1.473 for <rdar://problem/5736845>
+
+Revision 1.468.2.1  2008/07/29 19:10:53  mcguire
+<rdar://problem/6090041> Use all configured DNS servers
+merege 1.470 from <rdar://problem/4206534>
+
 Revision 1.468  2008/03/06 02:48:34  mcguire
 <rdar://problem/5321824> write status to the DS
 
@@ -1801,6 +1813,7 @@ struct DNSQuestion_struct
 
        // Wide Area fields. These are used internally by the uDNS core
        DNSServer            *qDNSServer;               // Caching server for this query (in the absence of an SRV saying otherwise)
+       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
@@ -1820,6 +1833,7 @@ struct DNSQuestion_struct
        mDNSAddr              Target;                   // Non-zero if you want to direct queries to a specific unicast target address
        mDNSIPPort            TargetPort;               // Must be set if Target is set
        mDNSOpaque16          TargetQID;                // Must be set if Target is set
+       UDPSocket            *LocalSocket;
        domainname            qname;
        mDNSu16               qtype;
        mDNSu16               qclass;
@@ -2007,7 +2021,6 @@ struct mDNS_struct
        mDNSs32 SuppressStdPort53Queries;       // Wait before allowing the next standard unicast query to the user's configured DNS server
 
        ServiceRecordSet *ServiceRegistrations;
-       mDNSu16           NextMessageID;
        DNSServer        *DNSServers;           // list of DNS servers
 
        mDNSAddr          Router;
@@ -2045,6 +2058,7 @@ struct mDNS_struct
        tcpLNTInfo       *tcpInfoUnmapList;                     // list of pending unmap requests
        mDNSInterfaceID   UPnPInterfaceID;
        UDPSocket        *SSDPSocket;               // For SSDP request/response
+       mDNSBool          SSDPMulticast;            // whether we should send the SSDP query via multicast
        mDNSIPPort        UPnPRouterPort;                       // port we send discovery messages to
        mDNSIPPort        UPnPSOAPPort;                         // port we send SOAP messages to
        mDNSu8           *UPnPRouterURL;                        // router's URL string
@@ -2325,6 +2339,8 @@ extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainT
 #define        mDNS_StopAdvertiseDomains mDNS_Deregister
 
 extern mDNSOpaque16 mDNS_NewMessageID(mDNS *const m);
+               
+extern DNSServer *GetServerForName(mDNS *m, const domainname *name);
 
 // ***************************************************************************
 #if 0
@@ -2578,7 +2594,7 @@ extern mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCache
 extern mStatus  mDNSPlatformInit        (mDNS *const m);
 extern void     mDNSPlatformClose       (mDNS *const m);
 extern mStatus  mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
-mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport);
+mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstport);
 
 extern void     mDNSPlatformLock        (const mDNS *const m);
 extern void     mDNSPlatformUnlock      (const mDNS *const m);
@@ -2643,7 +2659,7 @@ extern mStatus    mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, m
 extern void       mDNSPlatformTCPCloseConnection(TCPSocket *sock);
 extern long       mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed);
 extern long       mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len);
-extern UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, mDNSIPPort port);
+extern UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport);
 extern void       mDNSPlatformUDPClose(UDPSocket *sock);
 extern void       mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst);
 
@@ -2762,21 +2778,21 @@ struct CompileTimeAssertionChecks_mDNS
        // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
        // 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_ResourceRecord      [(sizeof(ResourceRecord)       <=    40) ? 1 : -1];
-       char sizecheck_AuthRecord          [(sizeof(AuthRecord)           <=  1290) ? 1 : -1];
-       char sizecheck_CacheRecord         [(sizeof(CacheRecord)          <=   170) ? 1 : -1];
-       char sizecheck_CacheGroup          [(sizeof(CacheGroup)           <=   170) ? 1 : -1];
-       char sizecheck_DNSQuestion         [(sizeof(DNSQuestion)          <=   560) ? 1 : -1];
-       char sizecheck_ZoneData            [(sizeof(ZoneData)             <=  1600) ? 1 : -1];
-       char sizecheck_NATTraversalInfo    [(sizeof(NATTraversalInfo)     <=   140) ? 1 : -1];
-       char sizecheck_HostnameInfo        [(sizeof(HostnameInfo)         <=  3000) ? 1 : -1];
-       char sizecheck_DNSServer           [(sizeof(DNSServer)            <=   300) ? 1 : -1];
-       char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <=  4000) ? 1 : -1];
-       char sizecheck_ServiceRecordSet    [(sizeof(ServiceRecordSet)     <=  5700) ? 1 : -1];
-       char sizecheck_DomainAuthInfo      [(sizeof(DomainAuthInfo)       <=  6000) ? 1 : -1];
-       char sizecheck_ServiceInfoQuery    [(sizeof(ServiceInfoQuery)     <=  2900) ? 1 : -1];
+       char sizecheck_ResourceRecord      [(sizeof(ResourceRecord)       <=    56) ? 1 : -1];
+       char sizecheck_AuthRecord          [(sizeof(AuthRecord)           <=  1416) ? 1 : -1];
+       char sizecheck_CacheRecord         [(sizeof(CacheRecord)          <=   200) ? 1 : -1];
+       char sizecheck_CacheGroup          [(sizeof(CacheGroup)           <=   184) ? 1 : -1];
+       char sizecheck_DNSQuestion         [(sizeof(DNSQuestion)          <=   720) ? 1 : -1];
+       char sizecheck_ZoneData            [(sizeof(ZoneData)             <=  1552) ? 1 : -1];
+       char sizecheck_NATTraversalInfo    [(sizeof(NATTraversalInfo)     <=   192) ? 1 : -1];
+       char sizecheck_HostnameInfo        [(sizeof(HostnameInfo)         <=  3304) ? 1 : -1];
+       char sizecheck_DNSServer           [(sizeof(DNSServer)            <=   312) ? 1 : -1];
+       char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <=  4392) ? 1 : -1];
+       char sizecheck_ServiceRecordSet    [(sizeof(ServiceRecordSet)     <=  6248) ? 1 : -1];
+       char sizecheck_DomainAuthInfo      [(sizeof(DomainAuthInfo)       <=  6544) ? 1 : -1];
+       char sizecheck_ServiceInfoQuery    [(sizeof(ServiceInfoQuery)     <=  2912) ? 1 : -1];
 #if APPLE_OSX_mDNSResponder
-       char sizecheck_ClientTunnel        [(sizeof(ClientTunnel)         <=  1040) ? 1 : -1];
+       char sizecheck_ClientTunnel        [(sizeof(ClientTunnel)         <=  1064) ? 1 : -1];
 #endif
        };
 
index e063fc58ccc281adcd962c72adbd9ebede097c7b..d649f19074c7565ef3da5c3f1335361b9f5b5f93 100755 (executable)
        Change History (most recent first):
 
 $Log: uDNS.c,v $
+Revision 1.553.2.4  2008/07/29 20:47:44  mcguire
+<rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
+merge r1.567 & r1.568 from <rdar://problem/3988320>
+
+Revision 1.553.2.3  2008/07/29 19:09:21  mcguire
+<rdar://problem/6090041> Use all configured DNS servers
+merge r1.558-r1.565 from <rdar://problem/4206534>
+
+Revision 1.553.2.2  2008/07/29 18:50:09  mcguire
+<rdar://problem/6090002> LLQ refresh randomization not working properly
+merge r1.555 & r1.556 from <rdar://problem/5787898>
+
 Revision 1.553.2.1  2008/03/14 20:11:25  mcguire
 <rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
 Make sure we add the record when sending LLQ refreshes
@@ -1297,6 +1309,31 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
        return(*p);
        }
 
+mDNSlocal void PushDNSServerToEnd(mDNS *const m, DNSQuestion *q)
+       {
+       DNSServer **p = &m->DNSServers;
+       
+       if (m->mDNS_busy != m->mDNS_reentrancy+1)
+               LogMsg("PushDNSServerToEnd: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+
+       if (!q->qDNSServer)
+               {
+               LogMsg("PushDNSServerToEnd: Null DNS server for %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), q->unansweredQueries);
+               return;
+               }
+
+       LogOperation("PushDNSServerToEnd: Pushing DNS server %#a:%d (%##s) due to %d unanswered queries for %##s (%s)", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype));
+
+       while (*p)
+               {
+               if (*p == q->qDNSServer) *p = q->qDNSServer->next;
+               else p=&(*p)->next;
+               }
+
+       *p = q->qDNSServer;
+       q->qDNSServer->next = mDNSNULL; 
+       }
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark - authorization management
@@ -1452,7 +1489,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info)
                        end = (mDNSu8 *)&u + sizeof(NATPortMapRequest);
                        }
 
-               err = mDNSPlatformSendUDP(m, (mDNSu8 *)&u, end, 0, &m->Router, NATPMPPort);
+               err = mDNSPlatformSendUDP(m, (mDNSu8 *)&u, end, 0, mDNSNULL, &m->Router, NATPMPPort);
 
 #ifdef _LEGACY_NAT_TRAVERSAL_
                if (mDNSIPPortIsZero(m->UPnPSOAPPort)) LNT_SendDiscoveryMsg(m);
@@ -1759,7 +1796,7 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const
        if (responsePtr) responsePtr = putLLQ(&m->omsg, responsePtr, q, llq, mDNSfalse);
        if (responsePtr)
                {
-               mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
+               mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
                if (err)
                        {
                        LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
@@ -1776,19 +1813,20 @@ mDNSlocal void SetLLQTimer(mDNS *const m, DNSQuestion *const q, const LLQOptData
        q->LastQTime     = m->timenow;
        q->expire        = m->timenow + lease;
        q->ThisQInterval = lease/2 + mDNSRandom(lease/10);
+       debugf("SetLLQTimer setting %##s (%s) to %d %d", q->qname.c, DNSTypeName(q->qtype), lease/mDNSPlatformOneSecond, q->ThisQInterval/mDNSPlatformOneSecond);
        SetNextQueryTime(m, q);
        }
 
 mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const q, const LLQOptData *const llq)
        {
        if (rcode && rcode != kDNSFlag1_RC_NXDomain)
-               { LogMsg("ERROR: recvSetupResponse %##s - rcode && rcode != kDNSFlag1_RC_NXDomain", q->qname.c); return; }
+               { LogMsg("ERROR: recvSetupResponse %##s (%s) - rcode && rcode != kDNSFlag1_RC_NXDomain", q->qname.c, DNSTypeName(q->qtype)); return; }
 
        if (llq->llqOp != kLLQOp_Setup)
-               { LogMsg("ERROR: recvSetupResponse %##s - bad op %d", q->qname.c, llq->llqOp); return; }
+               { LogMsg("ERROR: recvSetupResponse %##s (%s) - bad op %d", q->qname.c, DNSTypeName(q->qtype), llq->llqOp); return; }
 
        if (llq->vers != kLLQ_Vers)
-               { LogMsg("ERROR: recvSetupResponse %##s - bad vers %d", q->qname.c, llq->vers); return; }
+               { LogMsg("ERROR: recvSetupResponse %##s (%s) - bad vers %d", q->qname.c, DNSTypeName(q->qtype), llq->vers); return; }
 
        if (q->state == LLQ_InitialRequest)
                {
@@ -1823,7 +1861,7 @@ mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const
                        q->id = llq->id;
                        }
 
-               if (llq->err) { LogMsg("ERROR: recvSetupResponse %##s code %d from server", q->qname.c, llq->err); StartLLQPolling(m,q); return; }
+               if (llq->err) { LogMsg("ERROR: recvSetupResponse %##s (%s) code %d from server", q->qname.c, DNSTypeName(q->qtype), llq->err); StartLLQPolling(m,q); return; }
                if (!mDNSSameOpaque64(&q->id, &llq->id))
                        { LogMsg("recvSetupResponse - ID changed.  discarding"); return; } // this can happen rarely (on packet loss + reordering)
                q->state         = LLQ_Established;
@@ -1849,7 +1887,8 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co
                                debugf("uDNS_recvLLQResponse found %##s (%s) %d %#a %#a %X %X %X %X %d",
                                        q->qname.c, DNSTypeName(q->qtype), q->state, srcaddr, &q->servAddr,
                                        opt->OptData.llq.id.l[0], opt->OptData.llq.id.l[1], q->id.l[0], q->id.l[1], opt->OptData.llq.llqOp);
-                               if (q->state == LLQ_Poll)
+                               if (q->state == LLQ_Poll) debugf("uDNS_LLQ_Events: q->state == LLQ_Poll msg->h.id %d q->TargetQID %d", mDNSVal16(msg->h.id), mDNSVal16(q->TargetQID));
+                               if (q->state == LLQ_Poll && mDNSSameOpaque16(msg->h.id, q->TargetQID))
                                        {
                                        m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
                                        LogOperation("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
@@ -1860,15 +1899,16 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co
                                        SetNextQueryTime(m, q);
                                        return uDNS_LLQ_Entire;         // uDNS_LLQ_Entire means flush stale records; assume a large effective TTL
                                        }
+                               // Note: In LLQ Event packets, the msg->h.id does not match our q->TargetQID, because in that case the msg->h.id nonce is selected by the server
                                else if (opt && q->state == LLQ_Established && opt->OptData.llq.llqOp == kLLQOp_Event && mDNSSameOpaque64(&opt->OptData.llq.id, &q->id))
                                        {
                                        mDNSu8 *ackEnd;
-                                       if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
                                        //debugf("Sending LLQ ack for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
                                        InitializeDNSMessage(&m->omsg.h, msg->h.id, ResponseFlags);
                                        ackEnd = putLLQ(&m->omsg, m->omsg.data, mDNSNULL, &opt->OptData.llq, mDNSfalse);
-                                       if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, srcaddr, srcport, mDNSNULL, mDNSNULL);
+                                       if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, q->LocalSocket, srcaddr, srcport, mDNSNULL, mDNSNULL);
                                        m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
+                                       debugf("uDNS_LLQ_Events: q->state == LLQ_Established msg->h.id %d q->TargetQID %d", mDNSVal16(msg->h.id), mDNSVal16(q->TargetQID));
                                        return uDNS_LLQ_Events;
                                        }
                                if (opt && mDNSSameOpaque16(msg->h.id, q->TargetQID))
@@ -1978,7 +2018,7 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
                        AuthInfo = q->AuthInfo;         // Need to add TSIG to this message
                        }
 
-               err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo);
+               err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, mDNSNULL, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo);
                if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %ld", err); err = mStatus_UnknownErr; goto exit; }
 
                // Record time we sent this question
@@ -1986,7 +2026,8 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
                        {
                        mDNS_Lock(m);
                        q->LastQTime = m->timenow;
-                       q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
+                       if (q->ThisQInterval < (256 * mDNSPlatformOneSecond))   // Now we have a TCP connection open, make sure we wait at least 256 seconds before retrying
+                               q->ThisQInterval = (256 * mDNSPlatformOneSecond);
                        SetNextQueryTime(m, q);
                        mDNS_Unlock(m);
                        }
@@ -1998,7 +2039,7 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
                        {
                        mDNSu8 *lenptr = (mDNSu8 *)&tcpInfo->replylen;
                        n = mDNSPlatformReadTCP(sock, lenptr + tcpInfo->nread, 2 - tcpInfo->nread, &closed);
-                       if (n < 0) { LogMsg("ERROR:tcpCallback - attempt to read message length failed (%d)", n); err = mStatus_ConnFailed; goto exit; }
+                       if (n < 0) { LogMsg("ERROR: tcpCallback - attempt to read message length failed (%d)", n); err = mStatus_ConnFailed; goto exit; }
                        else if (closed)
                                {
                                // It's perfectly fine for this socket to close after the first reply. The server might
@@ -2081,7 +2122,7 @@ exit:
                                q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
                                SetNextQueryTime(m, q);
                                }
-                       // ConnFailed is actually okay.  It just means that the server closed the connection but the LLQ is still okay.
+                       // ConnFailed may be actually okay. It just means that the server closed the connection but the LLQ may still be okay.
                        // If the error isn't ConnFailed, then the LLQ is in bad shape.
                        if (err != mStatus_ConnFailed)
                                {
@@ -2128,7 +2169,7 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
                mDNSPlatformMemCopy(&info->request, msg, info->requestLen);
                }
 
-       if (!info->sock) { LogMsg("SendServiceRegistration: uanble to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
+       if (!info->sock) { LogMsg("SendServiceRegistration: unable to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
        err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpCallback, info);
 
        // Probably suboptimal here.
@@ -2226,7 +2267,7 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
                        end = putLLQ(&m->omsg, m->omsg.data, q, &llqData, mDNStrue);
                        if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m,q); return; }
        
-                       mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL);
+                       mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL);
        
                        // update question state
                        q->state         = LLQ_InitialRequest;
@@ -2392,7 +2433,7 @@ mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
                }
        else
                {
-               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
+               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
                if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err);
                }
 
@@ -2726,7 +2767,7 @@ mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
                }
        else
                {
-               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
+               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
                if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto exit; }
                }
 
@@ -2872,7 +2913,7 @@ mDNSlocal void hostnameGetPublicAddressCallback(mDNS *m, NATTraversalInfo *n)
                if (h->arv4.resrec.RecordType)
                        {
                        if (mDNSSameIPv4Address(h->arv4.resrec.rdata->u.ipv4, n->ExternalAddress)) return;      // If address unchanged, do nothing
-                       LogMsg("Updating hostname %##s IPv4 from %.4a to %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &h->arv4.resrec.rdata->u.ipv4, &n->ExternalAddress);
+                       LogOperation("Updating hostname %##s IPv4 from %.4a to %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &h->arv4.resrec.rdata->u.ipv4, &n->ExternalAddress);
                        mDNS_Deregister(m, &h->arv4);   // mStatus_MemFree callback will re-register with new address
                        }
                else
@@ -3360,7 +3401,7 @@ mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr)
                }
        else
                {
-               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
+               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
                if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %ld", err);
                }
 
@@ -3828,7 +3869,12 @@ mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *c
                        if (result == DNSServer_Passed)         // Unblock any questions that were waiting for this result
                                for (q = m->Questions; q; q=q->next)
                                        if (q->qDNSServer == s && !NoTestQuery(q))
-                                               { q->LastQTime = m->timenow - q->ThisQInterval; m->NextScheduledQuery = m->timenow; }
+                                               {
+                                               q->ThisQInterval = INIT_UCAST_POLL_INTERVAL / QuestionIntervalStep;
+                                               q->unansweredQueries = 0;
+                                               q->LastQTime = m->timenow - q->ThisQInterval;
+                                               m->NextScheduledQuery = m->timenow;
+                                               }
                        }
 
        return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further
@@ -3940,7 +3986,7 @@ mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q)
        if (q->ReqLease)
                if ((q->state == LLQ_Established && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0)
                        {
-                       LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d minutes", q->qname.c, DNSTypeName(q->qtype), LLQ_POLL_INTERVAL/3600);
+                       LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d seconds", q->qname.c, DNSTypeName(q->qtype), LLQ_POLL_INTERVAL / mDNSPlatformOneSecond);
                        StartLLQPolling(m,q);
                        return;
                        }
@@ -3973,7 +4019,7 @@ mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q)
                }
        else
                {
-               mStatus err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, mDNSNULL);
+               mStatus err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, mDNSNULL);
                if (err)
                        {
                        LogMsg("sendLLQRefresh: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
@@ -4168,7 +4214,7 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
                        }
                else
                        {
-                       mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
+                       mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
                        if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err);
                        if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr);          // Don't touch rr after this
                        }
@@ -4356,15 +4402,42 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
        // We repeat the check above (rather than just making this the "else" case) because startLLQHandshake can change q->state to LLQ_Poll
        if (!(q->LongLived && q->state != LLQ_Poll))
                {
+               if (q->unansweredQueries >= MAX_UCAST_UNANSWERED_QUERIES)
+                       {
+                       DNSServer *orig = q->qDNSServer;
+                       
+#if LogAllOperations || MDNS_DEBUGMSGS
+                       char buffer[1024];
+
+                       mDNS_snprintf(buffer, sizeof(buffer), orig ? "%#a:%d (%##s)" : "null", &orig->addr, mDNSVal16(orig->port), orig->domain.c);
+                       LogOperation("Sent %d unanswered queries for %##s (%s) to %s", q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype), buffer);
+#endif
+
+                       PushDNSServerToEnd(m, q);
+                       q->qDNSServer = GetServerForName(m, &q->qname);
+
+                       if (q->qDNSServer != orig)
+                               {
+#if LogAllOperations || MDNS_DEBUGMSGS
+                               mDNS_snprintf(buffer, sizeof(buffer), q->qDNSServer ? "%#a:%d (%##s)" : "null", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c);
+                               LogOperation("Server for %##s (%s) changed to %s", q->qname.c, DNSTypeName(q->qtype), buffer);
+#endif
+                               q->ThisQInterval = q->ThisQInterval / QuestionIntervalStep; // Decrease interval one step so we don't quickly bounce between servers for queries that will not be answered.
+                               }
+
+                       q->unansweredQueries = 0;
+                       }
+
                if (q->qDNSServer && q->qDNSServer->teststate != DNSServer_Disabled)
                        {
                        mDNSu8 *end = m->omsg.data;
                        mStatus err = mStatus_NoError;
                        mDNSBool private = mDNSfalse;
 
+                       InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
+
                        if (q->qDNSServer->teststate != DNSServer_Untested || NoTestQuery(q))
                                {
-                               InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
                                end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
                                private = (q->AuthInfo && q->AuthInfo->AutoTunnel);
                                }
@@ -4373,13 +4446,12 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                                LogOperation("Sending DNS test query to %#a:%d", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port));
                                q->ThisQInterval = INIT_UCAST_POLL_INTERVAL / QuestionIntervalStep;
                                q->qDNSServer->lasttest = m->timenow;
-                               InitializeDNSMessage(&m->omsg.h, mDNS_NewMessageID(m), uQueryFlags);
                                end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN);
                                }
 
                        if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q)))
                                {
-                               //LogMsg("uDNS_CheckCurrentQuestion %d %p %##s (%s)", sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
+                               //LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
                                if (private)
                                        {
                                        if (q->nta) CancelGetZoneData(m, q->nta);
@@ -4388,7 +4460,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                                        }
                                else
                                        {
-                                       err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL);
+                                       err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL);
                                        m->SuppressStdPort53Queries = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+99)/100);
                                        }
                                }
@@ -4397,6 +4469,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                        else
                                {
                                q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep;     // Only increase interval if send succeeded
+                               q->unansweredQueries++;
                                if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL)
                                        q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
                                LogOperation("Increased ThisQInterval to %d for %##s (%s)", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype));
@@ -4428,6 +4501,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                        MakeNegativeCacheRecord(m, &q->qname, q->qnamehash, q->qtype, q->qclass, 60);
                        // Inactivate this question until the next change of DNS servers (do this before AnswerCurrentQuestionWithResourceRecord)
                        q->ThisQInterval = 0;
+                       q->unansweredQueries = 0;
                        CreateNewCacheEntry(m, slot, cg);
                        m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
                        // MUST NOT touch m->CurrentQuestion (or q) after this -- client callback could have deleted it
@@ -4912,6 +4986,6 @@ struct CompileTimeAssertionChecks_uDNS
        // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
        // 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)      <=  9100) ? 1 : -1];
-       char sizecheck_SearchListElem[(sizeof(SearchListElem) <=  3800) ? 1 : -1];
+       char sizecheck_tcpInfo_t     [(sizeof(tcpInfo_t)      <=  9056) ? 1 : -1];
+       char sizecheck_SearchListElem[(sizeof(SearchListElem) <=  3880) ? 1 : -1];
        };
index 2676a2c19f130990141fd1954247b33cd31bb1b9..3a66ab6edbbf0a3319c396860b375853ac79125f 100755 (executable)
     Change History (most recent first):
 
 $Log: uDNS.h,v $
+Revision 1.92  2008/06/19 23:42:03  mcguire
+<rdar://problem/4206534> Use all configured DNS servers
+
+Revision 1.91  2008/06/19 01:20:50  mcguire
+<rdar://problem/4206534> Use all configured DNS servers
+
 Revision 1.90  2007/12/22 02:25:30  cheshire
 <rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
 
@@ -225,6 +231,7 @@ Revision 1.33  2006/07/05 22:53:28  cheshire
 //#define MAX_UCAST_POLL_INTERVAL (1 * 60 * mDNSPlatformOneSecond)
 #define LLQ_POLL_INTERVAL       (15 * 60 * mDNSPlatformOneSecond) // Polling interval for zones w/ an advertised LLQ port (ie not static zones) if LLQ fails due to NAT, etc.
 #define RESPONSE_WINDOW (60 * mDNSPlatformOneSecond)         // require server responses within one minute of request
+#define MAX_UCAST_UNANSWERED_QUERIES 2                       // the number of unanswered queries from any one uDNS server before trying another server
 
 #define DEFAULT_UPDATE_LEASE 7200
 
index b1a23b6c3e09315dc4427ef72bf923bc8bfb6ea1..0653dfcd03a39b131d4ad4f477395a847420dc93 100644 (file)
     Change History (most recent first):
 
 $Log: LegacyNATTraversal.c,v $
+Revision 1.48  2008/07/24 20:23:04  cheshire
+<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
+
+Revision 1.47  2008/07/18 21:37:46  mcguire
+<rdar://problem/5736845> BTMM: alternate SSDP queries between multicast & unicast
+
+Revision 1.46  2008/05/13 01:51:12  mcguire
+<rdar://problem/5839161> UPnP compatibility workaround for Netgear WGT624
+
 Revision 1.45  2007/12/06 00:22:27  mcguire
 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
 
@@ -206,9 +215,10 @@ mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n);
 // referencing a service we care about (WANIPConnection), look for the "controlURL" header immediately following, and copy the addressing and URL info we need
 mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
        {
-       mDNS    *m   = tcpInfo->m;
-       char    *ptr = (char *)tcpInfo->Reply;
-       char    *end = (char *)tcpInfo->Reply + tcpInfo->nread;
+       mDNS    *m    = tcpInfo->m;
+       char    *ptr  = (char *)tcpInfo->Reply;
+       char    *end  = (char *)tcpInfo->Reply + tcpInfo->nread;
+       char    *stop = mDNSNULL;
 
        // find the service we care about
        while (ptr && ptr != end)
@@ -228,7 +238,13 @@ mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
        ptr += 11;                                                      // skip over "controlURL>"
        if (ptr >= end) { LogOperation("handleLNTDeviceDescriptionResponse: past end of buffer and no body!"); return; } // check ptr again in case we skipped over the end of the buffer
 
-       // is there an address string "http://"? starting from where we left off
+       // find the end of the controlURL element
+       for (stop = ptr; stop != end; stop++) { if (*stop == '<') { end = stop; break; } }
+
+       // fill in default port
+       m->UPnPSOAPPort = m->UPnPRouterPort;
+
+       // is there an address string "http://"?
        if (strncasecmp(ptr, "http://", 7) == 0)
                {
                int  i;
@@ -246,50 +262,41 @@ mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
                
                strncpy((char *)m->UPnPSOAPAddressString, ptr, i);                              // copy the address string
                m->UPnPSOAPAddressString[i] = '\0';                                                             // terminate the string
+               
+               stop = ptr; // remember where to stop (just after "http://")
+               ptr = addrPtr; // move ptr past the rest of what we just processed
+               
+               // find the port number in the string
+               for (addrPtr--;addrPtr>stop;addrPtr--)
+                       {
+                       if (*addrPtr == ':')
+                               {
+                               int port;
+                               addrPtr++; // skip over ':'
+                               port = (int)strtol(addrPtr, mDNSNULL, 10);
+                               m->UPnPSOAPPort = mDNSOpaque16fromIntVal(port);         // store it properly converted
+                               break;
+                               }
+                       }
                }
-       
+
        if (m->UPnPSOAPAddressString == mDNSNULL) m->UPnPSOAPAddressString = m->UPnPRouterAddressString; // just copy the pointer, don't allocate more memory
        LogOperation("handleLNTDeviceDescriptionResponse: SOAP address string [%s]", m->UPnPSOAPAddressString);
 
-       // find port and router URL, starting after the "http://" if it was there
-       while (ptr && ptr != end)
+       // ptr should now point to the first character we haven't yet processed
+       if (ptr != end)
                {
-               if (*ptr == ':')                                                                                // found the port number
-                       {
-                       int port;
-                       ptr++;                                                                          // skip over ':'
-                       if (ptr == end) { LogOperation("handleLNTDeviceDescriptionResponse: reached end of buffer and no address!"); return; }
-                       port = (int)strtol(ptr, (char **)mDNSNULL, 10);                         // get the port
-                       m->UPnPSOAPPort = mDNSOpaque16fromIntVal(port);         // store it properly converted
-                       }
-               else if (*ptr == '/')                                                                   // found SOAP URL
-                       {
-                       int j;
-                       char *urlPtr = mDNSNULL;
-                       if (mDNSIPPortIsZero(m->UPnPSOAPPort)) m->UPnPSOAPPort = m->UPnPRouterPort;     // fill in default port if we didn't find one before
-
-                       urlPtr = ptr;
-                       for (j = 0; urlPtr && urlPtr != end; j++, urlPtr++) if (*urlPtr == '<') break;  // first find the next '<' and count the chars
-                       if (urlPtr == mDNSNULL || urlPtr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find SOAP URL string"); return; }
-
-                       // allocate the buffer (len j+2 because we're copying from the first '/' and so we have space to terminate the string)
-                       if (m->UPnPSOAPURL != mDNSNULL) mDNSPlatformMemFree(m->UPnPSOAPURL);
-                       if ((m->UPnPSOAPURL = (mDNSu8 *)mDNSPlatformMemAllocate(j+1)) == mDNSNULL) { LogMsg("can't mDNSPlatformMemAllocate SOAP URL"); return; }
-                       
-                       // now copy
-                       strncpy((char *)m->UPnPSOAPURL, ptr, j);                        // this URL looks something like "/uuid:0013-108c-4b3f0000f3dc"
-                       m->UPnPSOAPURL[j] = '\0';                                       // terminate the string
-                       break;                                                                  // we've got everything we need, so get out here
-                       }
-               ptr++;  // continue
+               // allocate the buffer
+               if (m->UPnPSOAPURL != mDNSNULL) mDNSPlatformMemFree(m->UPnPSOAPURL);
+               if ((m->UPnPSOAPURL = (mDNSu8 *)mDNSPlatformMemAllocate(end - ptr + 1)) == mDNSNULL) { LogMsg("can't mDNSPlatformMemAllocate SOAP URL"); return; }
+               
+               // now copy
+               strncpy((char *)m->UPnPSOAPURL, ptr, end - ptr); // this URL looks something like "/uuid:0013-108c-4b3f0000f3dc"
+               m->UPnPSOAPURL[end - ptr] = '\0';                                // terminate the string
                }
 
        // if we get to the end and haven't found the URL fill in the defaults
-       if (m->UPnPSOAPURL == mDNSNULL)
-               {
-               m->UPnPSOAPURL  = m->UPnPRouterURL;                             // just copy the pointer, don't allocate more memory
-               m->UPnPSOAPPort = m->UPnPRouterPort;
-               }
+       if (m->UPnPSOAPURL == mDNSNULL) m->UPnPSOAPURL = m->UPnPRouterURL;      // just copy the pointer, don't allocate more memory
        
        LogOperation("handleLNTDeviceDescriptionResponse: SOAP URL [%s] port %d", m->UPnPSOAPURL, mDNSVal16(m->UPnPSOAPPort));
        }
@@ -825,14 +832,20 @@ mDNSexport void LNT_SendDiscoveryMsg(mDNS *m)
                "ST:urn:schemas-upnp-org:service:WANIPConnection:1\r\n"
                "Man:\"ssdp:discover\"\r\n"
                "MX:3\r\n\r\n";
+       static const mDNSAddr multicastDest = { mDNSAddrType_IPv4, { { { 239, 255, 255, 250 } } } };
+       
+       // Always send the first SSDP packet via unicast
+       if (m->retryIntervalGetAddr <= NATMAP_INIT_RETRY) m->SSDPMulticast = mDNSfalse;
 
        LogOperation("LNT_SendDiscoveryMsg Router %.4a Current External Address %.4a", &m->Router.ip.v4, &m->ExternalAddress);
 
        if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSIPv4AddressIsZero(m->ExternalAddress))
                {
                if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(m, zeroIPPort); LogOperation("LNT_SendDiscoveryMsg created SSDPSocket %p", &m->SSDPSocket); }
-               mDNSPlatformSendUDP(m, msg, msg + sizeof(msg) - 1, 0, &m->Router, SSDPPort);
+               mDNSPlatformSendUDP(m, msg, msg + sizeof(msg) - 1, 0, m->SSDPSocket, m->SSDPMulticast ? &multicastDest : &m->Router, SSDPPort);
                }
+               
+       m->SSDPMulticast = !m->SSDPMulticast;
        }
 
 #endif /* _LEGACY_NAT_TRAVERSAL_ */
index f36174fc7faa1cba5917e3fe9aafc364123a0e1b..25b2e439e9641e61950e2396a89d6b6deadd94f4 100644 (file)
     Change History (most recent first):
 
 $Log: daemon.c,v $
+Revision 1.360  2008/03/13 20:55:16  mcguire
+<rdar://problem/5769316> fix deprecated warnings/errors
+Additional cleanup: use a conditional macro instead of lots of #if
+
+Revision 1.359  2008/03/12 23:02:58  mcguire
+<rdar://problem/5769316> fix deprecated warnings/errors
+
 Revision 1.358  2008/03/06 21:26:11  cheshire
 Moved duplicated STRINGIFY macro from individual C files to DNSCommon.h
 
@@ -372,6 +379,12 @@ Revision 1.261  2006/01/06 01:22:28  cheshire
 #include <sandbox.h>
 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
 
+#if TARGET_OS_EMBEDDED
+#include <bootstrap_priv.h>
+
+#define bootstrap_register(A,B,C) bootstrap_register2((A),(B),(C),0)
+#endif
+
 #include "DNSServiceDiscoveryRequestServer.h"
 #include "DNSServiceDiscoveryReply.h"
 
@@ -2137,14 +2150,14 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void)
                s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL);
                m_port = CFMachPortGetPort(s_port);
                char *MachServerName = OSXVers < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
-               kern_return_t      status = bootstrap_register(bootstrap_port, MachServerName, m_port);
+               kern_return_t status = bootstrap_register(bootstrap_port, MachServerName, m_port);
        
                if (status)
                        {
                        if (status == 1103)
-                               LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
+                               LogMsg("bootstrap_register() failed: A copy of the daemon is apparently already running");
                        else
-                               LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status), status);
+                               LogMsg("bootstrap_register() failed: %s %d", mach_error_string(status), status);
                        return(status);
                        }
                }
index 03efad4c6b385f4c78e90f86ad6a7d9e463ba640..af019b3b2786b94e6ee3c713cfafa4e6f3aae239 100644 (file)
     Change History (most recent first):
 
 $Log: helper-main.c,v $
+Revision 1.15  2008/03/13 20:55:16  mcguire
+<rdar://problem/5769316> fix deprecated warnings/errors
+Additional cleanup: use a conditional macro instead of lots of #if
+
+Revision 1.14  2008/03/12 23:02:59  mcguire
+<rdar://problem/5769316> fix deprecated warnings/errors
+
 Revision 1.13  2007/09/21 16:13:14  cheshire
 Additional Tiger compatibility fix: After bootstrap_check_in, we need to give
 ourselves a Mach "send" right to the port, otherwise our ten-second idle timeout
@@ -84,7 +91,10 @@ Revision 1.1  2007/08/08 22:34:58  mcguire
 #include "helpermsgServer.h"
 
 #if TARGET_OS_EMBEDDED
+#include <bootstrap_priv.h>
 #define NO_SECURITYFRAMEWORK 1
+
+#define bootstrap_register(A,B,C) bootstrap_register2((A),(B),(C),0)
 #endif
 
 #ifndef LAUNCH_JOBKEY_MACHSERVICES
@@ -247,9 +257,11 @@ static mach_port_t register_service(const char *service_name)
                { helplog(ASL_LEVEL_ERR, "mach_port_allocate: %s", mach_error_string(kr)); goto error; }
        if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
                { helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %s", mach_error_string(kr)); goto error; }
+
        // XXX bootstrap_register does not modify its second argument, but the prototype does not include const.
        if (KERN_SUCCESS != (kr = bootstrap_register(bootstrap_port, (char *)service_name, port)))
                { helplog(ASL_LEVEL_ERR, "bootstrap_register failed: %s", mach_error_string(kr)); goto error; }
+
        return port;
 error:
        if (MACH_PORT_NULL != port) mach_port_deallocate(mach_task_self(), port);
@@ -291,12 +303,12 @@ int main(int ac, char *av[])
        // Explicitly ensure that our Keychain operations utilize the system domain.
        SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
 #endif
-       if (!opt_debug)
+       port = checkin(kmDNSHelperServiceName);
+       if (!port)
                {
-               port = checkin(kmDNSHelperServiceName);
-               if (!port) helplog(ASL_LEVEL_ERR, "Launchd provided no launchdata; will open Mach port explicitly");
+               helplog(ASL_LEVEL_ERR, "Launchd provided no launchdata; will open Mach port explicitly");
+               port = register_service(kmDNSHelperServiceName);
                }
-       if (!port) port = register_service(kmDNSHelperServiceName);
 
        if (maxidle) actualidle = maxidle;
        initialize_timer(port);
index 6cfb6a47c01e7ae23b04c89071f26bc4de24d6ce..cc139802cf235fe2988e6a62fffad811be687c88 100644 (file)
     Change History (most recent first):
 
 $Log: mDNSMacOSX.c,v $
+Revision 1.536.2.2  2008/07/30 01:08:17  mcguire
+<rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
+merge r1.540 from <rdar://problem/3988320>
+
+Revision 1.536.2.1  2008/07/29 20:48:10  mcguire
+<rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
+merge r1.539 from <rdar://problem/3988320>
+
 Revision 1.536  2008/03/25 01:27:30  mcguire
 <rdar://problem/5810718> Status sometimes wrong when link goes down
 
@@ -1002,17 +1010,12 @@ mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
        return result;
        }
 
-struct UDPSocket_struct
-       {
-       mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCore expects every UDPSocket_struct to begin with mDNSIPPort port
-       KQSocketSet ss;
-       };
-
 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
 // OR send via our primary v4 unicast socket
+// UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
-       mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
+       mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstPort)
        {
        // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
        // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
@@ -1032,10 +1035,7 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
                sin_to->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
                s = m->p->permanentsockets.sktv4;
 
-#ifdef _LEGACY_NAT_TRAVERSAL_
-               if (m->SSDPSocket && mDNSSameIPPort(dstPort, SSDPPort))
-                       s = m->SSDPSocket->ss.sktv4;
-#endif _LEGACY_NAT_TRAVERSAL_
+               if (src) { s = src->ss.sktv4; debugf("mDNSPlatformSendUDP using port %d %d %d", mDNSVal16(src->ss.port), m->p->permanentsockets.sktv4, s); }
 
                if (info)       // Specify outgoing interface
                        {
@@ -1216,9 +1216,9 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
 
 mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
        {
-       const KQSocketSet *const ss = (const KQSocketSet *)context;
+       KQSocketSet *const ss = (KQSocketSet *)context;
        mDNS *const m = ss->m;
-       int err, count = 0;
+       int err = 0, count = 0, closed = 0;
 
        if (filter != EVFILT_READ)
                LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
@@ -1230,10 +1230,10 @@ mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
                LogMsg("myKQSocketCallBack: sktv6 %d", ss->sktv6);
                }
 
-       while (1)
+       while (!closed)
                {
                mDNSAddr senderAddr, destAddr;
-               mDNSIPPort senderPort, destPort = (m->SSDPSocket && ss == &m->SSDPSocket->ss ? m->SSDPSocket->port : MulticastDNSPort);
+               mDNSIPPort senderPort;
                struct sockaddr_storage from;
                size_t fromlen = sizeof(from);
                char packetifname[IF_NAMESIZE] = "";
@@ -1279,7 +1279,17 @@ mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
 //             LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
 //                     &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
 
-               mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, destPort, InterfaceID);
+               // mDNSCoreReceive may close the socket we're reading from.  We must break out of our
+               // loop when that happens, or we may try to read from an invalid FD.  We do this by
+               // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
+               // if it closes the socketset.
+               ss->closeFlag = &closed;
+
+               mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
+
+               // if we didn't close, we can safely dereference the socketset, and should to
+               // reset the closeFlag, since it points to something on the stack
+               if (!closed) ss->closeFlag = mDNSNULL;
                }
 
        if (err < 0 && (errno != EWOULDBLOCK || count == 0))
@@ -1740,6 +1750,8 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa
        const int twofivefive = 255;
        mStatus err = mStatus_NoError;
        char *errstr = mDNSNULL;
+       
+       cp->closeFlag = mDNSNULL;
 
        int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
        if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
@@ -1777,7 +1789,7 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa
                // And start listening for packets
                struct sockaddr_in listening_sockaddr;
                listening_sockaddr.sin_family      = AF_INET;
-               listening_sockaddr.sin_port        = port.NotAnInteger;
+               listening_sockaddr.sin_port        = port.NotAnInteger;         // Pass in opaque ID without any byte swapping
                listening_sockaddr.sin_addr.s_addr = 0; // Want to receive multicasts AND unicasts on this socket
                err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
                if (err) { errstr = "bind"; goto fail; }
@@ -1823,7 +1835,7 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa
                mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
                listening_sockaddr6.sin6_len         = sizeof(listening_sockaddr6);
                listening_sockaddr6.sin6_family      = AF_INET6;
-               listening_sockaddr6.sin6_port        = port.NotAnInteger;
+               listening_sockaddr6.sin6_port        = port.NotAnInteger;               // Pass in opaque ID without any byte swapping
                listening_sockaddr6.sin6_flowinfo    = 0;
                listening_sockaddr6.sin6_addr        = in6addr_any; // Want to receive multicasts AND unicasts on this socket
                listening_sockaddr6.sin6_scope_id    = 0;
@@ -1845,7 +1857,7 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa
        fail:
        // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
        if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
-               LogMsg("%s error %ld errno %d (%s)", errstr, err, errno, strerror(errno));
+               LogMsg("%s skt %d port %d error %ld errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
 
        // If we got a "bind" failure with an EADDRINUSE error for our shared mDNS port, display error alert
        if (!strcmp(errstr, "bind") && mDNSSameIPPort(port, MulticastDNSPort) && errno == EADDRINUSE)
@@ -1859,24 +1871,33 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa
        return(err);
        }
 
-mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort port)
+mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
        {
+       int i;
        mStatus err;
+       mDNSIPPort port = requestedport;
        UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
        if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
        memset(p, 0, sizeof(UDPSocket));
+       p->ss.port  = zeroIPPort;
        p->ss.m     = m;
        p->ss.sktv4 = -1;
        p->ss.sktv6 = -1;
-       p->port = zeroIPPort;
-       err = SetupSocket(&p->ss, port, AF_INET, &p->port);
+
+       for (i=0; i<10000; i++) // Try at most 10000 times to get a unique random port
+               {
+               // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
+               if (mDNSIPPortIsZero(requestedport)) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
+               err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
+               if (!err) break;
+               }
        if (err)
                {
                // In customer builds we don't want to log failures with port 5351, because this is a known issue
                // of failing to bind to this port when Internet Sharing has already bound to it
-               if (mDNSSameIPPort(port, NATPMPPort))
-                       LogOperation("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port));
-               else LogMsg     ("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port));
+               if (mDNSSameIPPort(requestedport, NATPMPPort))
+                       LogOperation("mDNSPlatformUDPSocket: SetupSocket %d failed error %ld errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
+               else LogMsg     ("mDNSPlatformUDPSocket: SetupSocket %d failed error %ld errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
                freeL("UDPSocket", p);
                return(mDNSNULL);
                }
@@ -1895,6 +1916,7 @@ mDNSlocal void CloseSocketSet(KQSocketSet *ss)
                close(ss->sktv6);
                ss->sktv6 = -1;
                }
+       if (ss->closeFlag) *ss->closeFlag = 1;
        }
 
 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
@@ -4311,6 +4333,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
                mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
                }
 
+       m->p->permanentsockets.port  = MulticastDNSPort;
        m->p->permanentsockets.m     = m;
        m->p->permanentsockets.sktv4 = m->p->permanentsockets.sktv6 = -1;
        m->p->permanentsockets.kqsv4.KQcallback = m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
index a721c1172590260240ce21b1bf5f9cd0a227b7ff..17fd2b961c726edfe8fc96cc56bd7e7446e3eda9 100644 (file)
     Change History (most recent first):
 
 $Log: mDNSMacOSX.h,v $
+Revision 1.79  2008/07/30 00:55:56  mcguire
+<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
+Additional fixes so that we know when a socket has been closed while in a loop reading from it
+
+Revision 1.78  2008/07/25 22:34:11  mcguire
+fix sizecheck issues for 64bit
+
+Revision 1.77  2008/07/24 20:23:04  cheshire
+<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
+
+Revision 1.76  2008/07/01 01:40:01  mcguire
+<rdar://problem/5823010> 64-bit fixes
+
 Revision 1.75  2007/12/14 00:45:21  cheshire
 Add SleepLimit and SleepCookie, for when we need to delay sleep until TLS/TCP record deregistration completes
 
@@ -124,13 +137,21 @@ typedef struct
 
 typedef struct
        {
+       mDNSIPPort port; // MUST BE FIRST FIELD -- UDPSocket_struct begins with a KQSocketSet,
+       // and mDNSCore requires every UDPSocket_struct to begin with a mDNSIPPort port
        mDNS                    *m;
        int                      sktv4;
        KQueueEntry                              kqsv4;
        int                      sktv6;
        KQueueEntry                  kqsv6;
+       int                     *closeFlag;
        } KQSocketSet;
 
+struct UDPSocket_struct
+       {
+       KQSocketSet ss;         // First field of KQSocketSet has to be mDNSIPPort -- mDNSCore requires every UDPSocket_struct to begin with mDNSIPPort port
+       };
+
 struct NetworkInterfaceInfoOSX_struct
        {
        NetworkInterfaceInfo     ifinfo;                        // MUST be the first element in this structure
@@ -222,8 +243,8 @@ struct CompileTimeAssertionChecks_mDNSMacOSX
        // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
        // 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_NetworkInterfaceInfoOSX[(sizeof(NetworkInterfaceInfoOSX) <=  4100) ? 1 : -1];
-       char sizecheck_mDNS_PlatformSupport   [(sizeof(mDNS_PlatformSupport)    <=   268) ? 1 : -1];
+       char sizecheck_NetworkInterfaceInfoOSX[(sizeof(NetworkInterfaceInfoOSX) <=  4456) ? 1 : -1];
+       char sizecheck_mDNS_PlatformSupport   [(sizeof(mDNS_PlatformSupport)    <=   368) ? 1 : -1];
        };
 
 #ifdef  __cplusplus
index b0307f910ce8fd08d0dbb24fbb02f7b6f79feea3..8f8ab2c778c6a518f80e42898df384971cbf0fd2 100644 (file)
 ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ;
 ; $Log: mDNSResponder.sb,v $
+; Revision 1.25.2.1  2008/07/29 20:48:34  mcguire
+; <rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
+; merge r1.27 from <rdar://problem/3988320>
+;
 ; Revision 1.25  2008/03/17 18:04:41  mcguire
 ; <rdar://problem/5800476> SC now reads preference file
 ;
 (allow file-read*     file-write*     (regex "^/private/var/run/mDNSResponder\$"))
 
 ; Allow us to read system version, settings, and other miscellaneous necessary file system accesses
+(allow file-read-data                 (regex "^/dev/urandom$"))
 (allow file-read-data                 (regex "^/usr/sbin(/mDNSResponder)?\$"))         ; Needed for CFCopyVersionDictionary()
 (allow file-read-data                 (regex "^/usr/share/icu/.*\$"))
 (allow file-read-data                 (regex "^/usr/share/zoneinfo/.*\$"))
-(allow file-read-data                 (regex "^/System/Library/CoreServices/SystemVersion.*\$"))
 (allow file-read-data                 (regex "^/Library/Preferences/SystemConfiguration/preferences\.plist\$"))
 (allow file-read-data                 (regex "^/Library/Preferences/(ByHost/)?\.GlobalPreferences.*\.plist\$"))
 (allow file-read-data                 (regex "^/Library/Preferences/com\.apple\.security.*\.plist\$"))
 (allow file-read-data                 (regex "^/Library/Preferences/com\.apple\.crypto\.plist\$"))
 (allow file-read-data                 (regex "^/Library/Security/Trust Settings/Admin\.plist\$"))
+(allow file-read-data                 (regex "^/System/Library/CoreServices/SystemVersion.*\$"))
 (allow file-read-data                 (regex "^/System/Library/Preferences/com\.apple\.security.*\.plist\$"))
 (allow file-read-data                 (regex "^/System/Library/Preferences/com\.apple\.crypto\.plist\$"))
 
index df36500ad4071ac5c9f5fb5367a1713f038f65ad..cb961b86ca9d350a2be42a521370f8aad6db03c4 100644 (file)
                                        "__MigTypeCheck=1",
                                        "mDNSResponderVersion=${MVERS}",
                                        _LEGACY_NAT_TRAVERSAL_,
+                                       "_BUILDING_XCODE_PROJECT_=1",
                                );
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
                                MVERS = "\"(Engineering Build)\"";
+                               OTHER_CFLAGS = "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS";
                                PREBINDING = NO;
                                WARNING_CFLAGS = (
                                        "-W",
index 2c9f32f721e12a31a715dc1960082f67ca26bc5f..852883d7baea669b66b7c78b5984889b686a8f17 100755 (executable)
     Change History (most recent first):
 
 $Log: mDNSUNP.c,v $
+Revision 1.36  2008/04/21 18:21:22  mkrochma
+<rdar://problem/5877307> Need to free ifi_netmask
+Submitted by Igor Seleznev
+
 Revision 1.35  2007/11/15 21:36:19  cheshire
 <rdar://problem/5289340> POSIX: Off by one overflow in get_ifi_info_linuxv6()
 
@@ -550,6 +554,8 @@ free_ifi_info(struct ifi_info *ifihead)
     for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
         if (ifi->ifi_addr != NULL)
             free(ifi->ifi_addr);
+        if (ifi->ifi_netmask != NULL)
+            free(ifi->ifi_netmask);
         if (ifi->ifi_brdaddr != NULL)
             free(ifi->ifi_brdaddr);
         if (ifi->ifi_dstaddr != NULL)
index cc4169b3995f799d2245d13911707dea4aa343f1..b5ecbb6f6719d921936d8596decefc9d71a09659 100644 (file)
@@ -77,7 +77,7 @@
  */
 
 #ifndef _DNS_SD_H
-#define _DNS_SD_H 1710400
+#define _DNS_SD_H 1760200
 
 #ifdef  __cplusplus
     extern "C" {