include /Developer/Makefiles/pb_makefiles/platform.make
-MVERS = "mDNSResponder-171.4"
+MVERS = "mDNSResponder-176.2"
DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
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
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;
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);
}
(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",
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)" : ""
);
// 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;
{
// 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);
{
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
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
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
#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
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
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);
}
}
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.
}
}
+// 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)
{
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;
{
//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
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; }
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);
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)
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;
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 &&
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);
{
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);
// 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))
{
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);
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)
{
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
}
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;
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));
}
// 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;
question->CNAMEReferrals = 0;
question->qDNSServer = mDNSNULL;
+ question->unansweredQueries = 0;
question->nta = mDNSNULL;
question->servAddr = zeroAddr;
question->servPort = zeroIPPort;
question->ntries = 0;
question->id = zeroOpaque64;
+ question->LocalSocket = mDNSNULL;
+
if (question->DuplicateOf) question->AuthInfo = question->DuplicateOf->AuthInfo;
for (i=0; i<DupSuppressInfoSize; i++)
// 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);
// *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.
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;
}
// ***************************************************************************
m->SuppressStdPort53Queries = 0;
m->ServiceRegistrations = mDNSNULL;
- m->NextMessageID = 0;
m->DNSServers = mDNSNULL;
m->Router = zeroAddr;
m->UPnPInterfaceID = 0;
m->SSDPSocket = mDNSNULL;
+ m->SSDPMulticast = mDNSfalse;
m->UPnPRouterPort = zeroIPPort;
m->UPnPSOAPPort = zeroIPPort;
m->UPnPRouterURL = mDNSNULL;
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);
}
}
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
// 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
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;
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;
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
#define mDNS_StopAdvertiseDomains mDNS_Deregister
extern mDNSOpaque16 mDNS_NewMessageID(mDNS *const m);
+
+extern DNSServer *GetServerForName(mDNS *m, const domainname *name);
// ***************************************************************************
#if 0
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);
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);
// 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
};
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
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
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);
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);
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)
{
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;
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));
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))
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
{
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);
}
{
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
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)
{
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.
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;
}
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);
}
}
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; }
}
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
}
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);
}
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
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;
}
}
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);
}
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
}
// 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);
}
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);
}
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);
}
}
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));
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
// 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];
};
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
//#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
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)
// 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)
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;
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));
}
"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_ */
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
#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"
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);
}
}
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
#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
{ 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);
// 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);
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
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
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
{
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);
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] = "";
// 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))
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); }
// 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; }
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;
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)
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);
}
close(ss->sktv6);
ss->sktv6 = -1;
}
+ if (ss->closeFlag) *ss->closeFlag = 1;
}
mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
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;
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
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
// 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
; 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\$"))
"__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",
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()
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)
*/
#ifndef _DNS_SD_H
-#define _DNS_SD_H 1710400
+#define _DNS_SD_H 1760200
#ifdef __cplusplus
extern "C" {