summaryrefslogtreecommitdiffstats
path: root/mDNSResponder/mDNSCore/uDNS.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-09-19 08:53:26 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-09-20 11:23:32 +0200
commitf01edf10244ccd53e098abdc1773c1aa0e4c5f8d (patch)
tree958a1ee323520629c4f027de1d4c56715949aa5c /mDNSResponder/mDNSCore/uDNS.c
parentmDNSResponder: Update to v625.41.2 (diff)
downloadrtems-libbsd-f01edf10244ccd53e098abdc1773c1aa0e4c5f8d.tar.bz2
mDNSResponder: Update to v765.1.2
The sources can be obtained via: https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-765.1.2.tar.gz Move mDNS_StartResolveService() and mDNS_StopResolveService() to an RTEMS-specific file (rtemsbsd/mdns/mDNSResolveService.c) using the v576.30.4 implementation. Apple removed these functions without explanation. Update #3522.
Diffstat (limited to 'mDNSResponder/mDNSCore/uDNS.c')
-rwxr-xr-xmDNSResponder/mDNSCore/uDNS.c801
1 files changed, 502 insertions, 299 deletions
diff --git a/mDNSResponder/mDNSCore/uDNS.c b/mDNSResponder/mDNSCore/uDNS.c
index 3ba88b5c..694c745c 100755
--- a/mDNSResponder/mDNSCore/uDNS.c
+++ b/mDNSResponder/mDNSCore/uDNS.c
@@ -124,7 +124,7 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
return mDNSNULL;
}
- if (!d)
+ if (!d)
d = (const domainname *)"";
LogInfo("mDNS_AddDNSServer(%d): Adding %#a for %##s, InterfaceID %p, serviceID %u, scoped %d, resGroupID %d req_A is %s req_AAAA is %s cell %s req_DO is %s",
@@ -135,11 +135,11 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
while (*p) // Check if we already have this {interface,address,port,domain} tuple registered + reqA/reqAAAA bits
{
- if ((*p)->scoped == scoped && (*p)->interface == interface && (*p)->serviceID == serviceID && (*p)->teststate != DNSServer_Disabled &&
- mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d) &&
+ if ((*p)->scoped == scoped && (*p)->interface == interface && (*p)->serviceID == serviceID &&
+ mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d) &&
(*p)->req_A == reqA && (*p)->req_AAAA == reqAAAA)
{
- if (!((*p)->flags & DNSServer_FlagDelete))
+ if (!((*p)->flags & DNSServer_FlagDelete))
debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr, mDNSVal16(port), d->c, interface);
tmp = *p;
*p = tmp->next;
@@ -192,8 +192,6 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
(*p)->addr = *addr;
(*p)->port = port;
(*p)->flags = DNSServer_FlagNew;
- (*p)->teststate = /* DNSServer_Untested */ DNSServer_Passed;
- (*p)->lasttest = m->timenow - INIT_UCAST_POLL_INTERVAL;
(*p)->timeout = timeout;
(*p)->cellIntf = cellIntf;
(*p)->req_A = reqA;
@@ -208,11 +206,13 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
(*p)->next = mDNSNULL;
}
}
- (*p)->penaltyTime = 0;
- // We always update the ID (not just when we allocate a new instance) because we could
- // be adding a new non-scoped resolver with a new ID and we want all the non-scoped
- // resolvers belong to the same group.
- (*p)->resGroupID = resGroupID;
+ if (*p) {
+ (*p)->penaltyTime = 0;
+ // We always update the ID (not just when we allocate a new instance) because we could
+ // be adding a new non-scoped resolver with a new ID and we want all the non-scoped
+ // resolvers belong to the same group.
+ (*p)->resGroupID = resGroupID;
+ }
return(*p);
}
@@ -224,7 +224,7 @@ mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 re
DNSServer *new;
DNSServer *orig = q->qDNSServer;
mDNSu8 rcode = '\0';
-
+
mDNS_CheckLock(m);
LogInfo("PenalizeDNSServer: Penalizing DNS server %#a question for question %p %##s (%s) SuppressUnusable %d",
@@ -234,11 +234,11 @@ mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 re
// return the error, then return the first error.
if (mDNSOpaque16IsZero(q->responseFlags))
q->responseFlags = responseFlags;
-
+
rcode = (mDNSu8)(responseFlags.b[1] & kDNSFlag1_RC_Mask);
// After we reset the qDNSServer to NULL, we could get more SERV_FAILS that might end up
- // peanlizing again.
+ // penalizing again.
if (!q->qDNSServer)
goto end;
@@ -482,7 +482,7 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
mDNSlocal mStatus uDNS_RequestAddress(mDNS *m)
{
mStatus err = mStatus_NoError;
-
+
if (!m->NATTraversals)
{
m->retryGetAddr = NonZeroTime(m->timenow + 0x78000000);
@@ -497,7 +497,7 @@ mDNSlocal mStatus uDNS_RequestAddress(mDNS *m)
mDNSu8* end = start + sizeof(NATAddrRequest);
err = mDNSPlatformSendUDP(m, start, end, 0, mDNSNULL, &m->Router, NATPMPPort, mDNSfalse);
debugf("uDNS_RequestAddress: Sent NAT-PMP external address request %d", err);
-
+
#ifdef _LEGACY_NAT_TRAVERSAL_
if (mDNSIPPortIsZero(m->UPnPRouterPort) || mDNSIPPortIsZero(m->UPnPSOAPPort))
{
@@ -509,7 +509,7 @@ mDNSlocal mStatus uDNS_RequestAddress(mDNS *m)
mStatus lnterr = LNT_GetExternalAddress(m);
if (lnterr)
LogMsg("uDNS_RequestAddress: LNT_GetExternalAddress returned error %d", lnterr);
-
+
err = err ? err : lnterr; // NAT-PMP error takes precedence
}
#endif // _LEGACY_NAT_TRAVERSAL_
@@ -554,7 +554,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP
LogMsg("uDNS_SendNATMsg called unexpectedly with NULL info");
return mStatus_BadParamErr;
}
-
+
// send msg if the router's address is private (which means it's non-zero)
if (mDNSv4AddrIsRFC1918(&m->Router.ip.v4))
{
@@ -567,7 +567,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP
static NATPortMapRequest NATPortReq;
static const mDNSu8* end = (mDNSu8 *)&NATPortReq + sizeof(NATPortMapRequest);
mDNSu8 *p = (mDNSu8 *)&NATPortReq.NATReq_lease;
-
+
NATPortReq.vers = NATMAP_VERS;
NATPortReq.opcode = info->Protocol;
NATPortReq.unused = zeroID;
@@ -577,7 +577,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP
p[1] = (mDNSu8)((info->NATLease >> 16) & 0xFF);
p[2] = (mDNSu8)((info->NATLease >> 8) & 0xFF);
p[3] = (mDNSu8)( info->NATLease & 0xFF);
-
+
err = mDNSPlatformSendUDP(m, (mDNSu8 *)&NATPortReq, end, 0, mDNSNULL, &m->Router, NATPMPPort, mDNSfalse);
debugf("uDNS_SendNATMsg: Sent NAT-PMP mapping request %d", err);
}
@@ -604,31 +604,31 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP
mDNSu8* start = (mDNSu8*)&req;
mDNSu8* end = start + sizeof(req);
mDNSu8* p = (mDNSu8*)&req.lifetime;
-
+
req.version = PCP_VERS;
req.opCode = PCPOp_Map;
req.reserved = zeroID;
-
+
p[0] = (mDNSu8)((info->NATLease >> 24) & 0xFF);
p[1] = (mDNSu8)((info->NATLease >> 16) & 0xFF);
p[2] = (mDNSu8)((info->NATLease >> 8) & 0xFF);
p[3] = (mDNSu8)( info->NATLease & 0xFF);
-
+
mDNSAddrMapIPv4toIPv6(&m->AdvertisedV4.ip.v4, &req.clientAddr);
-
+
req.nonce[0] = m->PCPNonce[0];
req.nonce[1] = m->PCPNonce[1];
req.nonce[2] = m->PCPNonce[2];
-
+
req.protocol = (info->Protocol == NATOp_MapUDP ? PCPProto_UDP : PCPProto_TCP);
-
+
req.reservedMapOp[0] = 0;
req.reservedMapOp[1] = 0;
req.reservedMapOp[2] = 0;
-
+
req.intPort = info->Protocol ? info->IntPort : DiscardPort;
req.extPort = info->RequestedPort;
-
+
// Since we only support IPv4, even if using the all-zeros address, map it, so
// the PCP gateway will give us an IPv4 address & not an IPv6 address.
mDNSAddrMapIPv4toIPv6(&info->NewAddress, &req.extAddress);
@@ -654,7 +654,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info, mDNSBool useP
mStatus lnterr = LNT_MapPort(m, info);
if (lnterr)
LogMsg("uDNS_SendNATMsg: LNT_MapPort returned error %d", lnterr);
-
+
err = err ? err : lnterr; // PCP error takes precedence
}
#endif // _LEGACY_NAT_TRAVERSAL_
@@ -727,7 +727,7 @@ mDNSexport void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv
m->NextScheduledNATOp = m->retryGetAddr;
last_err = err;
-
+
for (n = m->NATTraversals; n; n=n->next)
{
// We should change n->NewAddress only when n is one of:
@@ -924,7 +924,7 @@ mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *tra
{
traversal->NATLease = 0;
traversal->retryInterval = 0;
-
+
// In case we most recently sent NAT-PMP, we need to set sentNATPMP to false so
// that we'll send a NAT-PMP request to destroy the mapping. We do this because
// the NATTraversal struct has already been cut from the list, and the client
@@ -940,7 +940,7 @@ mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *tra
// would have requested an IPv4 address.
traversal->RequestedPort = zeroIPPort;
traversal->NewAddress = zerov4Addr;
-
+
uDNS_SendNATMsg(m, traversal, traversal->lastSuccessfulProtocol != NATTProtocolNATPMP);
}
@@ -1573,6 +1573,7 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
}
if (!info->sock) { LogMsg("MakeTCPConn: unable to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
+ mDNSPlatformSetSocktOpt(info->sock, mDNSTransport_TCP, Addr->type, question);
err = mDNSPlatformTCPConnect(info->sock, Addr, Port, hostname, (question ? question->InterfaceID : mDNSNULL), tcpCallback, info);
// Probably suboptimal here.
@@ -1703,6 +1704,7 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
}
}
+
// forward declaration so GetServiceTarget can do reverse lookup if needed
mDNSlocal void GetStaticHostname(mDNS *m);
@@ -1754,11 +1756,13 @@ mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE = (const domainname*)"\x
mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp";
mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE = (const domainname*)"\x0E_dns-query-tls" "\x04_tcp";
mDNSlocal const domainname *PRIVATE_LLQ_SERVICE_TYPE = (const domainname*)"\x0C_dns-llq-tls" "\x04_tcp";
+mDNSlocal const domainname *DNS_PUSH_NOTIFICATION_SERVICE_TYPE = (const domainname*)"\x0C_dns-push-tls" "\x04_tcp";
#define ZoneDataSRV(X) ( \
- (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
- (X)->ZoneService == ZoneServiceQuery ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE : (const domainname*)"" ) : \
- (X)->ZoneService == ZoneServiceLLQ ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE : PUBLIC_LLQ_SERVICE_TYPE ) : (const domainname*)"")
+ (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
+ (X)->ZoneService == ZoneServiceQuery ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE : (const domainname*)"" ) : \
+ (X)->ZoneService == ZoneServiceLLQ ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE : PUBLIC_LLQ_SERVICE_TYPE ) : \
+ (X)->ZoneService == ZoneServiceDNSPush ? DNS_PUSH_NOTIFICATION_SERVICE_TYPE : (const domainname*)"")
// Forward reference: GetZoneData_StartQuery references GetZoneData_QuestionCallback, and
// GetZoneData_QuestionCallback calls GetZoneData_StartQuery
@@ -1886,7 +1890,7 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt
zd->question.InterfaceID = mDNSInterface_Any;
zd->question.flags = 0;
zd->question.Target = zeroAddr;
- //zd->question.qname.c[0] = 0; // Already set
+ //zd->question.qname.c[0] = 0; // Already set
zd->question.qtype = qtype;
zd->question.qclass = kDNSClass_IN;
zd->question.LongLived = mDNSfalse;
@@ -1894,8 +1898,6 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt
zd->question.ForceMCast = mDNSfalse;
zd->question.ReturnIntermed = mDNStrue;
zd->question.SuppressUnusable = mDNSfalse;
- zd->question.DenyOnCellInterface = mDNSfalse;
- zd->question.DenyOnExpInterface = mDNSfalse;
zd->question.SearchListIndex = 0;
zd->question.AppendSearchDomains = 0;
zd->question.RetryWithSearchDomains = mDNSfalse;
@@ -2171,7 +2173,7 @@ mDNSlocal void StartRecordNatMap(mDNS *m, AuthRecord *rr)
else { LogMsg("StartRecordNatMap: could not determine transport protocol of service %##s", rr->resrec.name->c); return; }
//LogMsg("StartRecordNatMap: clientContext %p IntPort %d srv.port %d %s",
- // rr->NATinfo.clientContext, mDNSVal16(rr->NATinfo.IntPort), mDNSVal16(rr->resrec.rdata->u.srv.port), ARDisplayString(m, rr));
+ // rr->NATinfo.clientContext, mDNSVal16(rr->NATinfo.IntPort), mDNSVal16(rr->resrec.rdata->u.srv.port), ARDisplayString(m, rr));
if (rr->NATinfo.clientContext) mDNS_StopNATOperation_internal(m, &rr->NATinfo);
rr->NATinfo.Protocol = protocol;
@@ -2584,8 +2586,6 @@ mDNSlocal void GetStaticHostname(mDNS *m)
q->ForceMCast = mDNSfalse;
q->ReturnIntermed = mDNStrue;
q->SuppressUnusable = mDNSfalse;
- q->DenyOnCellInterface = mDNSfalse;
- q->DenyOnExpInterface = mDNSfalse;
q->SearchListIndex = 0;
q->AppendSearchDomains = 0;
q->RetryWithSearchDomains = mDNSfalse;
@@ -2645,12 +2645,30 @@ mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
// below could free the memory, and we have to make sure we don't touch hi fields after that.
mDNSBool f4 = hi->arv4.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv4.state != regState_Unregistered;
mDNSBool f6 = hi->arv6.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv6.state != regState_Unregistered;
- if (f4) LogInfo("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn);
- if (f6) LogInfo("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn);
*ptr = (*ptr)->next; // unlink
- if (f4) mDNS_Deregister_internal(m, &hi->arv4, mDNS_Dereg_normal);
- if (f6) mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal);
- // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback
+ if (f4 || f6)
+ {
+ if (f4)
+ {
+ LogInfo("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn);
+ mDNS_Deregister_internal(m, &hi->arv4, mDNS_Dereg_normal);
+ }
+ if (f6)
+ {
+ LogInfo("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn);
+ mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal);
+ }
+ // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback
+ }
+ else
+ {
+ if (hi->natinfo.clientContext)
+ {
+ mDNS_StopNATOperation_internal(m, &hi->natinfo);
+ hi->natinfo.clientContext = mDNSNULL;
+ }
+ mDNSPlatformMemFree(hi);
+ }
}
mDNS_CheckLock(m);
m->NextSRVUpdate = NonZeroTime(m->timenow);
@@ -3621,13 +3639,13 @@ mDNSlocal void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interface
// Minimum NAT-PMP packet is vers (1) opcode (1) + err (2) = 4 bytes
if (len < 4) { LogMsg("NAT-PMP message too short (%d bytes)", len); return; }
-
+
// Read multi-byte error value (field is identical in a NATPortMapReply)
AddrReply->err = (mDNSu16) ((mDNSu16)pkt[2] << 8 | pkt[3]);
-
+
if (AddrReply->err == NATErr_Vers)
{
- NATTraversalInfo *n;
+ NATTraversalInfo *n;
LogInfo("NAT-PMP version unsupported message received");
for (n = m->NATTraversals; n; n=n->next)
{
@@ -3635,7 +3653,7 @@ mDNSlocal void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interface
// and update the state variables
uDNS_SendNATMsg(m, n, mDNSfalse);
}
-
+
m->NextScheduledNATOp = m->timenow;
return;
@@ -3649,7 +3667,7 @@ mDNSlocal void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interface
LogMsg("NAT-PMP message too short (%d bytes) 0x%X 0x%X", len, AddrReply->opcode, AddrReply->err);
return;
}
-
+
// Read multi-byte upseconds value (field is identical in a NATPortMapReply)
AddrReply->upseconds = (mDNSs32) ((mDNSs32)pkt[4] << 24 | (mDNSs32)pkt[5] << 16 | (mDNSs32)pkt[6] << 8 | pkt[7]);
@@ -3726,16 +3744,16 @@ mDNSlocal void uDNS_ReceivePCPPacket(mDNS *m, const mDNSInterfaceID InterfaceID,
mDNSu8 protocol = 0;
mDNSIPPort intport = zeroIPPort;
mDNSIPPort extport = zeroIPPort;
-
+
// Minimum PCP packet is 24 bytes
if (len < 24)
{
LogMsg("uDNS_ReceivePCPPacket: message too short (%d bytes)", len);
return;
}
-
+
strippedOpCode = reply->opCode & 0x7f;
-
+
if ((reply->opCode & 0x80) == 0x00 || (strippedOpCode != PCPOp_Announce && strippedOpCode != PCPOp_Map))
{
LogMsg("uDNS_ReceivePCPPacket: unhandled opCode %u", reply->opCode);
@@ -3774,11 +3792,11 @@ mDNSlocal void uDNS_ReceivePCPPacket(mDNS *m, const mDNSInterfaceID InterfaceID,
if (strippedOpCode == PCPOp_Announce)
return;
-
+
// We globally keep track of the most recent error code for mappings.
// This seems bad to do with PCP, but best not change it now.
m->LastNATMapResultCode = reply->result;
-
+
if (!reply->result)
{
if (len < sizeof(PCPMapReply))
@@ -3786,7 +3804,7 @@ mDNSlocal void uDNS_ReceivePCPPacket(mDNS *m, const mDNSInterfaceID InterfaceID,
LogMsg("uDNS_ReceivePCPPacket: mapping response too short (%d bytes)", len);
return;
}
-
+
// Check the nonce
if (reply->nonce[0] != m->PCPNonce[0] || reply->nonce[1] != m->PCPNonce[1] || reply->nonce[2] != m->PCPNonce[2])
{
@@ -3825,7 +3843,7 @@ mDNSlocal void uDNS_ReceivePCPPacket(mDNS *m, const mDNSInterfaceID InterfaceID,
{
LogInfo("uDNS_ReceivePCPPacket: error received from server. opcode %X result %X lifetime %X epoch %X",
reply->opCode, reply->result, reply->lifetime, reply->epoch);
-
+
// If the packet is long enough, get the protocol & intport for matching to report
// the error
if (len >= sizeof(PCPMapReply))
@@ -3858,135 +3876,6 @@ mDNSexport void uDNS_ReceiveNATPacket(mDNS *m, const mDNSInterfaceID InterfaceID
LogMsg("uDNS_ReceiveNATPacket: packet with version %u (expected %u or %u)", pkt[0], PCP_VERS, NATMAP_VERS);
}
-// <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
-// <rdar://problem/4288449> Add check to avoid crashing NAT gateways that have buggy DNS relay code
-//
-// We know of bugs in home NAT gateways that cause them to crash if they receive certain DNS queries.
-// The DNS queries that make them crash are perfectly legal DNS queries, but even if they weren't,
-// the gateway shouldn't crash -- in today's world of viruses and network attacks, software has to
-// be written assuming that a malicious attacker could send them any packet, properly-formed or not.
-// Still, we don't want to be crashing people's home gateways, so we go out of our way to avoid
-// the queries that crash them.
-//
-// Some examples:
-//
-// 1. Any query where the name ends in ".in-addr.arpa." and the text before this is 32 or more bytes.
-// The query type does not need to be PTR -- the gateway will crash for any query type.
-// e.g. "ping long-name-crashes-the-buggy-router.in-addr.arpa" will crash one of these.
-//
-// 2. Any query that results in a large response with the TC bit set.
-//
-// 3. Any PTR query that doesn't begin with four decimal numbers.
-// These gateways appear to assume that the only possible PTR query is a reverse-mapping query
-// (e.g. "1.0.168.192.in-addr.arpa") and if they ever get a PTR query where the first four
-// labels are not all decimal numbers in the range 0-255, they handle that by crashing.
-// These gateways also ignore the remainder of the name following the four decimal numbers
-// -- whether or not it actually says in-addr.arpa, they just make up an answer anyway.
-//
-// The challenge therefore is to craft a query that will discern whether the DNS server
-// is one of these buggy ones, without crashing it. Furthermore we don't want our test
-// queries making it all the way to the root name servers, putting extra load on those
-// name servers and giving Apple a bad reputation. To this end we send this query:
-// dig -t ptr 1.0.0.127.dnsbugtest.1.0.0.127.in-addr.arpa.
-//
-// The text preceding the ".in-addr.arpa." is under 32 bytes, so it won't cause crash (1).
-// It will not yield a large response with the TC bit set, so it won't cause crash (2).
-// It starts with four decimal numbers, so it won't cause crash (3).
-// The name falls within the "1.0.0.127.in-addr.arpa." domain, the reverse-mapping name for the local
-// loopback address, and therefore the query will black-hole at the first properly-configured DNS server
-// it reaches, making it highly unlikely that this query will make it all the way to the root.
-//
-// Finally, the correct response to this query is NXDOMAIN or a similar error, but the
-// gateways that ignore the remainder of the name following the four decimal numbers
-// give themselves away by actually returning a result for this nonsense query.
-
-mDNSlocal const domainname *DNSRelayTestQuestion = (const domainname*)
- "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
- "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
-
-// See comments above for DNSRelayTestQuestion
-// If this is the kind of query that has the risk of crashing buggy DNS servers, we do a test question first
-mDNSlocal mDNSBool NoTestQuery(DNSQuestion *q)
-{
- int i;
- mDNSu8 *p = q->qname.c;
- if (q->AuthInfo) return(mDNStrue); // Don't need a test query for private queries sent directly to authoritative server over TLS/TCP
- if (q->qtype != kDNSType_PTR) return(mDNStrue); // Don't need a test query for any non-PTR queries
- for (i=0; i<4; i++) // If qname does not begin with num.num.num.num, can't skip the test query
- {
- if (p[0] < 1 || p[0] > 3) return(mDNSfalse);
- if ( p[1] < '0' || p[1] > '9' ) return(mDNSfalse);
- if (p[0] >= 2 && (p[2] < '0' || p[2] > '9')) return(mDNSfalse);
- if (p[0] >= 3 && (p[3] < '0' || p[3] > '9')) return(mDNSfalse);
- p += 1 + p[0];
- }
- // If remainder of qname is ".in-addr.arpa.", this is a vanilla reverse-mapping query and
- // we can safely do it without needing a test query first, otherwise we need the test query.
- return(SameDomainName((domainname*)p, (const domainname*)"\x7" "in-addr" "\x4" "arpa"));
-}
-
-// Returns mDNStrue if response was handled
-mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
- const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
-{
- const mDNSu8 *ptr = msg->data;
- DNSQuestion pktq;
- DNSServer *s;
- mDNSu32 result = 0;
-
- // 1. Find out if this is an answer to one of our test questions
- if (msg->h.numQuestions != 1) return(mDNSfalse);
- ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &pktq);
- if (!ptr) return(mDNSfalse);
- if (pktq.qtype != kDNSType_PTR || pktq.qclass != kDNSClass_IN) return(mDNSfalse);
- if (!SameDomainName(&pktq.qname, DNSRelayTestQuestion)) return(mDNSfalse);
-
- // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
- // else, if the DNS relay gave us an error or no-answer response, it passed our test
- if ((msg->h.flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0)
- result = DNSServer_Failed;
- else
- result = DNSServer_Passed;
-
- // 3. Find occurrences of this server in our list, and mark them appropriately
- for (s = m->DNSServers; s; s = s->next)
- {
- mDNSBool matchaddr = (s->teststate != result && mDNSSameAddress(srcaddr, &s->addr) && mDNSSameIPPort(srcport, s->port));
- mDNSBool matchid = (s->teststate == DNSServer_Untested && mDNSSameOpaque16(msg->h.id, s->testid));
- if (matchaddr || matchid)
- {
- DNSQuestion *q;
- s->teststate = result;
- if (result == DNSServer_Passed)
- {
- LogInfo("DNS Server %#a:%d (%#a:%d) %d passed%s",
- &s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid),
- matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent");
- }
- else
- {
- LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d (%#a:%d) %d%s",
- &s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid),
- matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent");
- }
-
- // If this server has just changed state from DNSServer_Untested to DNSServer_Passed, then retrigger any waiting questions.
- // We use the NoTestQuery() test so that we only retrigger questions that were actually blocked waiting for this test to complete.
- 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->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
-}
-
// Called from mDNSCoreReceive with the lock held
mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
{
@@ -4015,7 +3904,6 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
if (QR_OP == StdR)
{
//if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport)) return;
- if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, srcport)) return;
for (qptr = m->Questions; qptr; qptr = qptr->next)
if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW)
{
@@ -4037,7 +3925,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
mDNSs32 expire = m->timenow + (mDNSs32)lease * mDNSPlatformOneSecond;
mDNSu32 random = mDNSRandom((mDNSs32)lease * mDNSPlatformOneSecond/10);
- //rcode = kDNSFlag1_RC_ServFail; // Simulate server failure (rcode 2)
+ //rcode = kDNSFlag1_RC_ServFail; // Simulate server failure (rcode 2)
// Walk through all the records that matches the messageID. There could be multiple
// records if we had sent them in a group
@@ -4200,6 +4088,40 @@ mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneI
mDNS_Unlock(m);
}
+mDNSexport void DNSPushNotificationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
+{
+ DNSQuestion *q = (DNSQuestion *)zoneInfo->ZoneDataContext;
+ mDNS_Lock(m);
+
+ // If we get here it means that the GetZoneData operation has completed.
+ // We hold on to the zone data if it is AutoTunnel as we use the hostname
+ // in zoneInfo during the TLS connection setup.
+ q->servAddr = zeroAddr;
+ q->servPort = zeroIPPort;
+ if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr) && zoneInfo->Host.c[0])
+ {
+ q->dnsPushState = DNSPUSH_SERVERFOUND;
+ q->dnsPushServerAddr = zoneInfo->Addr;
+ q->dnsPushServerPort = zoneInfo->Port;
+ q->ntries = 0;
+ LogInfo("DNSPushNotificationGotZoneData %#a:%d", &q->dnsPushServerAddr, mDNSVal16(q->dnsPushServerPort));
+ SubscribeToDNSPushNotificationServer(m,q);
+ }
+ else
+ {
+ StartLLQPolling(m,q);
+ if (err == mStatus_NoSuchNameErr)
+ {
+ // this actually failed, so mark it by setting address to all ones
+ q->servAddr.type = mDNSAddrType_IPv4;
+ q->servAddr.ip.v4 = onesIPv4Addr;
+ q->dnsPushState = DNSPUSH_NOSERVER;
+ }
+ }
+ mDNS_Unlock(m);
+}
+
+
// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
{
@@ -4467,7 +4389,7 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
if (!rr->nta) { LogMsg("SendRecordDeregistration:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; }
err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->nta->Addr, rr->nta->Port, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err);
- //if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); // Don't touch rr after this
+ //if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); // Don't touch rr after this
}
SetRecordRetry(m, rr, 0);
return;
@@ -4690,17 +4612,35 @@ mDNSlocal void handle_unanswered_query(mDNS *const m)
if (!q->qDNSServer->req_DO)
{
- q->ValidationState = DNSSECValNotRequired;
+ q->ValidationState = DNSSECValNotRequired;
q->ValidationRequired = DNSSEC_VALIDATION_NONE;
-
+
if (q->ProxyQuestion)
q->ProxyDNSSECOK = mDNSfalse;
- LogInfo("handle_unanswered_query: unanswered query for %##s (%s), so turned off validation for %#a",
+ LogInfo("handle_unanswered_query: unanswered query for %##s (%s), so turned off validation for %#a",
q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr);
}
}
}
+mDNSlocal void uDNS_HandleLLQState(mDNS *const m, DNSQuestion *q)
+{
+ // First attempt to use DNS Push Notification.
+ if (q->dnsPushState == DNSPUSH_INIT)
+ DiscoverDNSPushNotificationServer(m, q);
+ switch (q->state)
+ {
+ case LLQ_InitialRequest: startLLQHandshake(m, q); break;
+ case LLQ_SecondaryRequest:
+ // For PrivateQueries, we need to start the handshake again as we don't do the Challenge/Response step
+ if (PrivateQuery(q)) startLLQHandshake(m, q);
+ else sendChallengeResponse(m, q, mDNSNULL);
+ break;
+ case LLQ_Established: sendLLQRefresh(m, q); break;
+ case LLQ_Poll: break; // Do nothing (handled below)
+ }
+}
+
// The question to be checked is not passed in as an explicit parameter;
// instead it is implicit that the question to be checked is m->CurrentQuestion.
mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
@@ -4710,22 +4650,10 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
if (q->LongLived)
{
- switch (q->state)
- {
- case LLQ_InitialRequest: startLLQHandshake(m, q); break;
- case LLQ_SecondaryRequest:
- // For PrivateQueries, we need to start the handshake again as we don't do the Challenge/Response step
- if (PrivateQuery(q))
- startLLQHandshake(m, q);
- else
- sendChallengeResponse(m, q, mDNSNULL);
- break;
- case LLQ_Established: sendLLQRefresh(m, q); break;
- case LLQ_Poll: break; // Do nothing (handled below)
- }
+ uDNS_HandleLLQState(m,q);
}
- handle_unanswered_query(m);
+ handle_unanswered_query(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))
{
@@ -4773,36 +4701,25 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
for (qptr = q->next ; qptr; qptr = qptr->next)
if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
}
- if (q->qDNSServer && q->qDNSServer->teststate != DNSServer_Disabled)
+ if (q->qDNSServer)
{
- mDNSu8 *end = m->omsg.data;
+ mDNSu8 *end;
mStatus err = mStatus_NoError;
mDNSBool private = mDNSfalse;
InitializeDNSMessage(&m->omsg.h, q->TargetQID, (DNSSECQuestion(q) ? DNSSecQFlags : uQueryFlags));
- if (q->qDNSServer->teststate != DNSServer_Untested || NoTestQuery(q))
- {
- end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
- if (DNSSECQuestion(q) && !q->qDNSServer->cellIntf)
- {
- if (q->ProxyQuestion)
- end = DNSProxySetAttributes(q, &m->omsg.h, &m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData);
- else
- end = putDNSSECOption(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData);
- }
- private = PrivateQuery(q);
- }
- else if (m->timenow - q->qDNSServer->lasttest >= INIT_UCAST_POLL_INTERVAL) // Make sure at least three seconds has elapsed since last test query
+ end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
+ if (DNSSECQuestion(q) && !q->qDNSServer->cellIntf)
{
- LogInfo("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;
- end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN);
- q->qDNSServer->testid = m->omsg.h.id;
+ if (q->ProxyQuestion)
+ end = DNSProxySetAttributes(q, &m->omsg.h, &m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData);
+ else
+ end = putDNSSECOption(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData);
}
+ private = PrivateQuery(q);
- if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q)))
+ if (end > m->omsg.data)
{
//LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, NextQSendTime(q) - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
if (private)
@@ -4820,7 +4737,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
{
q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
if (q->LocalSocket)
- mDNSPlatformSetuDNSSocktOpt(q->LocalSocket, &q->qDNSServer->addr, q);
+ mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, q->qDNSServer->addr.type, q);
}
if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time
else
@@ -4829,6 +4746,11 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
#if TARGET_OS_EMBEDDED
if (!err)
{
+ if (q->metrics.answered)
+ {
+ q->metrics.querySendCount = 0;
+ q->metrics.answered = mDNSfalse;
+ }
if (q->metrics.querySendCount++ == 0)
{
q->metrics.firstQueryTime = m->timenow;
@@ -4839,32 +4761,68 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
}
}
- if (err != mStatus_TransientErr) // if it is not a transient error backoff and DO NOT flood queries unnecessarily
+ if (err == mStatus_HostUnreachErr)
{
- 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;
- if (private && q->state != LLQ_Poll)
+ DNSServer *newServer;
+
+ LogInfo("uDNS_CheckCurrentQuestion: host unreachable error for DNS server %#a for question [%p] %##s (%s)",
+ &q->qDNSServer->addr, q, q->qname.c, DNSTypeName(q->qtype));
+
+ if (!StrictUnicastOrdering)
{
- // We don't want to retransmit too soon. Hence, we always schedule our first
- // retransmisson at 3 seconds rather than one second
- if (q->ThisQInterval < (3 * mDNSPlatformOneSecond))
- q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep;
- if (q->ThisQInterval > LLQ_POLL_INTERVAL)
- q->ThisQInterval = LLQ_POLL_INTERVAL;
- LogInfo("uDNS_CheckCurrentQuestion: private non polling question for %##s (%s) will be retried in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
+ q->qDNSServer->penaltyTime = NonZeroTime(m->timenow + DNSSERVER_PENALTY_TIME);
}
- if (q->qDNSServer->cellIntf)
+
+ newServer = GetServerForQuestion(m, q);
+ DNSServerChangeForQuestion(m, q, newServer);
+
+ if (q->triedAllServersOnce)
+ {
+ q->LastQTime = m->timenow;
+ }
+ else
{
- // We don't want to retransmit too soon. Schedule our first retransmisson at
- // MIN_UCAST_RETRANS_TIMEOUT seconds.
- if (q->ThisQInterval < MIN_UCAST_RETRANS_TIMEOUT)
- q->ThisQInterval = MIN_UCAST_RETRANS_TIMEOUT;
+ q->ThisQInterval = InitialQuestionInterval;
+ q->LastQTime = m->timenow - q->ThisQInterval;
}
- debugf("uDNS_CheckCurrentQuestion: Increased ThisQInterval to %d for %##s (%s), cell %d", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer->cellIntf);
+ q->unansweredQueries = 0;
+ q->noServerResponse = 1;
+ }
+ else
+ {
+ if (err != mStatus_TransientErr) // if it is not a transient error backoff and DO NOT flood queries unnecessarily
+ {
+ // If all DNS Servers are not responding, then we back-off using the multiplier UDNSBackOffMultiplier(*2).
+ // Only increase interval if send succeeded
+
+ q->ThisQInterval = q->ThisQInterval * UDNSBackOffMultiplier;
+ if ((q->ThisQInterval > 0) && (q->ThisQInterval < MinQuestionInterval)) // We do not want to retx within 1 sec
+ q->ThisQInterval = MinQuestionInterval;
+
+ q->unansweredQueries++;
+ if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL)
+ q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
+ if (private && q->state != LLQ_Poll)
+ {
+ // We don't want to retransmit too soon. Hence, we always schedule our first
+ // retransmisson at 3 seconds rather than one second
+ if (q->ThisQInterval < (3 * mDNSPlatformOneSecond))
+ q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep;
+ if (q->ThisQInterval > LLQ_POLL_INTERVAL)
+ q->ThisQInterval = LLQ_POLL_INTERVAL;
+ LogInfo("uDNS_CheckCurrentQuestion: private non polling question for %##s (%s) will be retried in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
+ }
+ if (q->qDNSServer->cellIntf)
+ {
+ // We don't want to retransmit too soon. Schedule our first retransmisson at
+ // MIN_UCAST_RETRANS_TIMEOUT seconds.
+ if (q->ThisQInterval < MIN_UCAST_RETRANS_TIMEOUT)
+ q->ThisQInterval = MIN_UCAST_RETRANS_TIMEOUT;
+ }
+ debugf("uDNS_CheckCurrentQuestion: Increased ThisQInterval to %d for %##s (%s), cell %d", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer->cellIntf);
+ }
+ q->LastQTime = m->timenow;
}
- q->LastQTime = m->timenow;
SetNextQueryTime(m, q);
}
else
@@ -4927,7 +4885,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
{
if (SameNameRecordAnswersQuestion(&rr->resrec, q))
{
- LogInfo("uDNS_CheckCurrentQuestion: Purged resourcerecord %s", CRDisplayString(m, rr));
+ LogInfo("uDNS_CheckCurrentQuestion: Purged resourcerecord %s", CRDisplayString(m, rr));
mDNS_PurgeCacheResourceRecord(m, rr);
}
}
@@ -5049,7 +5007,7 @@ mDNSexport void CheckNATMappings(mDNS *m)
const mStatus EffectiveResult = cur->NewResult ? cur->NewResult : mDNSv4AddrIsRFC1918(&EffectiveAddress) ? mStatus_DoubleNAT : mStatus_NoError;
const mDNSIPPort ExternalPort = HaveRoutable ? cur->IntPort :
!mDNSIPv4AddressIsZero(EffectiveAddress) && cur->ExpiryTime ? cur->RequestedPort : zeroIPPort;
-
+
if (!cur->Protocol || HaveRoutable || cur->ExpiryTime || cur->retryInterval > NATMAP_INIT_RETRY * 8)
{
if (!mDNSSameIPv4Address(cur->ExternalAddress, EffectiveAddress) ||
@@ -5337,8 +5295,8 @@ mDNSexport void udns_validatelists(void *const v)
DNSServer *d;
for (d = m->DNSServers; d; d=d->next)
- if (d->next == (DNSServer *)~0 || d->teststate > DNSServer_Disabled)
- LogMemCorruption("m->DNSServers: %p is garbage (%d)", d, d->teststate);
+ if (d->next == (DNSServer *)~0)
+ LogMemCorruption("m->DNSServers: %p is garbage", d);
DomainAuthInfo *info;
for (info = m->AuthInfoList; info; info = info->next)
@@ -5810,101 +5768,327 @@ struct CompileTimeAssertionChecks_uDNS
char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 5000) ? 1 : -1];
};
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - DNS Push Notification functions
+#endif
+
+mDNSlocal tcpInfo_t * GetTCPConnectionToPushServer(mDNS *m, DNSQuestion *q)
+{
+ // If we already have a question for this zone and if the server is the same, reuse it
+ DNSPushNotificationZone *zone = mDNSNULL;
+ for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
+ {
+ if (SameDomainName(&q->nta->ChildName, &zone->zoneName))
+ {
+ DNSPushNotificationServer *zoneServer = mDNSNULL;
+ for (zoneServer = zone->servers; zoneServer != mDNSNULL; zoneServer = zoneServer->next)
+ {
+ if (mDNSSameAddress(&q->dnsPushServerAddr, &zoneServer->serverAddr))
+ {
+ zone->numberOfQuestions++;
+ zoneServer->numberOfQuestions++;
+ return zoneServer->connection;
+ }
+ }
+ }
+ }
+
+ // If we have a connection to this server but it is for a differnt zone, create a new zone entry and reuse the connection
+ DNSPushNotificationServer *server = mDNSNULL;
+ for (server = m->DNSPushServers; server != mDNSNULL; server = server->next)
+ {
+ if (mDNSSameAddress(&q->dnsPushServerAddr, &server->serverAddr))
+ {
+ DNSPushNotificationZone *newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
+ newZone->numberOfQuestions = 1;
+ newZone->zoneName = q->nta->ChildName;
+ newZone->servers = server;
+
+ // Add the new zone to the begining of the list
+ newZone->next = m->DNSPushZones;
+ m->DNSPushZones = newZone;
+
+ server->numberOfQuestions++;
+ return server->connection;
+ }
+ }
+
+ // If we do not have any existing connections, create a new connection
+ DNSPushNotificationServer *newServer = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationServer));
+ DNSPushNotificationZone *newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
+
+ newServer->numberOfQuestions = 1;
+ newServer->serverAddr = q->dnsPushServerAddr;
+ newServer->connection = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->dnsPushServerAddr, q->dnsPushServerPort, &q->nta->Host, q, mDNSNULL);
+
+ newZone->numberOfQuestions = 1;
+ newZone->zoneName = q->nta->ChildName;
+ newZone->servers = newServer;
+
+ // Add the new zone to the begining of the list
+ newZone->next = m->DNSPushZones;
+ m->DNSPushZones = newZone;
+
+ newServer->next = m->DNSPushServers;
+ m->DNSPushServers = newServer;
+ return newServer->connection;
+}
+
+mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ /* Use the same NAT setup as in the LLQ case */
+ if (m->LLQNAT.clientContext != mDNSNULL) // LLQNAT just started, give it some time
+ {
+ LogInfo("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ return;
+ }
+
+ // Either we don't have {PCP, NAT-PMP, UPnP/IGD} support (ExternalPort is zero) or behind a Double NAT that may or
+ // may not have {PCP, NAT-PMP, UPnP/IGD} support (NATResult is non-zero)
+ if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort) || m->LLQNAT.Result)
+ {
+ LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s) External Port %d, NAT Result %d",
+ q->qname.c, DNSTypeName(q->qtype), mDNSVal16(m->LLQNAT.ExternalPort), m->LLQNAT.Result);
+ StartLLQPolling(m, q); // Actually sets up the NAT Auto Tunnel
+ return;
+ }
+
+ if (mDNSIPPortIsZero(q->dnsPushServerPort) && q->dnsPushState == DNSPUSH_INIT)
+ {
+ LogInfo("SubscribeToDNSPushNotificationServer: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ q->dnsPushServerAddr = zeroAddr;
+ // We know q->dnsPushServerPort is zero because of check above
+ if (q->nta) CancelGetZoneData(m, q->nta);
+ q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q);
+ return;
+ }
+
+ if (q->tcp)
+ {
+ LogInfo("SubscribeToDNSPushNotificationServer: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ DisposeTCPConn(q->tcp);
+ q->tcp = mDNSNULL;
+ }
+
+ if (!q->nta)
+ {
+ // Normally we lookup the zone data and then call this function. And we never free the zone data
+ // for "PrivateQuery". But sometimes this can happen due to some race conditions. When we
+ // switch networks, we might end up "Polling" the network e.g., we are behind a Double NAT.
+ // When we poll, we free the zone information as we send the query to the server (See
+ // PrivateQueryGotZoneData). The NAT callback (LLQNATCallback) may happen soon after that. If we
+ // are still behind Double NAT, we would have returned early in this function. But we could
+ // have switched to a network with no NATs and we should get the zone data again.
+ LogInfo("SubscribeToDNSPushNotificationServer: nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q);
+ return;
+ }
+ else if (!q->nta->Host.c[0])
+ {
+ // This should not happen. If it happens, we print a log and MakeTCPConn will fail if it can't find a hostname
+ LogMsg("SubscribeToDNSPushNotificationServer: ERROR!!: nta non NULL for %##s (%s) but HostName %d NULL, LongLived %d", q->qname.c, DNSTypeName(q->qtype), q->nta->Host.c[0], q->LongLived);
+ }
+ q->tcp = GetTCPConnectionToPushServer(m,q);
+ // If TCP failed (transient networking glitch) try again in five seconds
+ q->ThisQInterval = (q->tcp != mDNSNULL) ? q->ThisQInterval = 0 : (mDNSPlatformOneSecond * 5);
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+}
+
+
+mDNSexport void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ mDNSu8 *end = mDNSNULL;
+ InitializeDNSMessage(&m->omsg.h, zeroID, SubscribeFlags);
+ end = putQuestion(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
+ if (!end)
+ {
+ LogMsg("ERROR: SubscribeToDNSPushNotificationServer putQuestion failed");
+ return;
+ }
+
+ mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->dnsPushServerAddr, q->dnsPushServerPort, q->tcp->sock, mDNSNULL, mDNSfalse);
+
+ // update question state
+ q->dnsPushState = DNSPUSH_ESTABLISHED;
+ q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+
+}
+
+mDNSlocal void reconcileDNSPushConnection(mDNS *m, DNSQuestion *q)
+{
+ DNSPushNotificationZone *zone;
+ DNSPushNotificationServer *server;
+ // Update the counts
+ for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
+ {
+ if (SameDomainName(&zone->zoneName, &q->nta->ChildName))
+ {
+ zone->numberOfQuestions--;
+ for (server = zone->servers; server != mDNSNULL; server = server->next)
+ {
+ if (mDNSSameAddress(&server->serverAddr, &q->dnsPushServerAddr))
+ server->numberOfQuestions--;
+ }
+ }
+ }
+
+ // Now prune the lists
+ server = m->DNSPushServers;
+ DNSPushNotificationServer *nextServer = mDNSNULL;
+ while(server != mDNSNULL)
+ {
+ nextServer = server->next;
+ if (server->numberOfQuestions <= 0)
+ {
+ DisposeTCPConn(server->connection);
+ if (server == m->DNSPushServers)
+ m->DNSPushServers = nextServer;
+ mDNSPlatformMemFree(server);
+ server = nextServer;
+ }
+ else server = server->next;
+ }
+
+ zone = m->DNSPushZones;
+ DNSPushNotificationZone *nextZone = mDNSNULL;
+ while(zone != mDNSNULL)
+ {
+ nextZone = zone->next;
+ if (zone->numberOfQuestions <= 0)
+ {
+ if (zone == m->DNSPushZones)
+ m->DNSPushZones = nextZone;
+ mDNSPlatformMemFree(zone);
+ zone = nextZone;
+ }
+ else zone = zone->next;
+ }
+
+}
+
+mDNSexport void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ mDNSu8 *end = mDNSNULL;
+ InitializeDNSMessage(&m->omsg.h, q->TargetQID, UnSubscribeFlags);
+ end = putQuestion(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
+ if (!end)
+ {
+ LogMsg("ERROR: UnSubscribeToDNSPushNotificationServer - putQuestion failed");
+ return;
+ }
+
+ mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->dnsPushServerAddr, q->dnsPushServerPort, q->tcp->sock, mDNSNULL, mDNSfalse);
+
+ reconcileDNSPushConnection(m, q);
+}
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#endif
#else // !UNICAST_DISABLED
mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr)
{
- (void) m;
- (void) rr;
+ (void) m;
+ (void) rr;
- return mDNSNULL;
+ return mDNSNULL;
}
mDNSexport DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name)
{
- (void) m;
- (void) name;
+ (void) m;
+ (void) name;
- return mDNSNULL;
+ return mDNSNULL;
}
mDNSexport DomainAuthInfo *GetAuthInfoForQuestion(mDNS *m, const DNSQuestion *const q)
{
- (void) m;
- (void) q;
+ (void) m;
+ (void) q;
- return mDNSNULL;
+ return mDNSNULL;
}
mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
{
- (void) m;
- (void) q;
+ (void) m;
+ (void) q;
}
mDNSexport void DisposeTCPConn(struct tcpInfo_t *tcp)
{
- (void) tcp;
+ (void) tcp;
}
mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *m, NATTraversalInfo *traversal)
{
- (void) m;
- (void) traversal;
+ (void) m;
+ (void) traversal;
- return mStatus_UnsupportedErr;
+ return mStatus_UnsupportedErr;
}
mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal)
{
- (void) m;
- (void) traversal;
+ (void) m;
+ (void) traversal;
- return mStatus_UnsupportedErr;
+ return mStatus_UnsupportedErr;
}
mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q)
{
- (void) m;
- (void) q;
+ (void) m;
+ (void) q;
}
mDNSexport ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *ZoneDataContext)
{
- (void) m;
- (void) name;
- (void) target;
- (void) callback;
- (void) ZoneDataContext;
+ (void) m;
+ (void) name;
+ (void) target;
+ (void) callback;
+ (void) ZoneDataContext;
- return mDNSNULL;
+ return mDNSNULL;
}
mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData)
{
- (void) m;
- (void) err;
- (void) zoneData;
+ (void) m;
+ (void) err;
+ (void) zoneData;
}
mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
const mDNSAddr *const srcaddr, const mDNSIPPort srcport, DNSQuestion **matchQuestion)
{
- (void) m;
- (void) msg;
- (void) end;
- (void) srcaddr;
- (void) srcport;
- (void) matchQuestion;
+ (void) m;
+ (void) msg;
+ (void) end;
+ (void) srcaddr;
+ (void) srcport;
+ (void) matchQuestion;
- return uDNS_LLQ_Not;
+ return uDNS_LLQ_Not;
}
mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 responseFlags)
{
- (void) m;
- (void) q;
- (void) responseFlags;
+ (void) m;
+ (void) q;
+ (void) responseFlags;
}
mDNSexport void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID)
@@ -5928,7 +6112,7 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, const
(void) hostname;
(void) port;
(void) autoTunnel;
-
+
return mStatus_UnsupportedErr;
}
@@ -5938,7 +6122,7 @@ mDNSexport domainname *uDNS_GetNextSearchDomain(mDNS *const m, mDNSInterfaceID
(void) InterfaceID;
(void) searchIndex;
(void) ignoreDotLocal;
-
+
return mDNSNULL;
}
@@ -5946,7 +6130,7 @@ mDNSexport DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const n
{
(void) m;
(void) name;
-
+
return mDNSNULL;
}
@@ -5954,7 +6138,7 @@ mDNSexport mStatus mDNS_StartNATOperation(mDNS *const m, NATTraversalInfo *trave
{
(void) m;
(void) traversal;
-
+
return mStatus_UnsupportedErr;
}
@@ -5962,7 +6146,7 @@ mDNSexport mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traver
{
(void) m;
(void) traversal;
-
+
return mStatus_UnsupportedErr;
}
@@ -5983,7 +6167,7 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
(void) reqA;
(void) reqAAAA;
(void) reqDO;
-
+
return mDNSNULL;
}
@@ -6034,8 +6218,27 @@ mDNSexport void RecreateNATMappings(mDNS *const m, const mDNSu32 waitTicks)
mDNSexport mDNSBool IsGetZoneDataQuestion(DNSQuestion *q)
{
(void)q;
-
+
return mDNSfalse;
}
+mDNSexport void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ (void)m;
+ (void)q;
+}
+
+mDNSexport void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ (void)m;
+ (void)q;
+}
+
+mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ (void)m;
+ (void)q;
+}
+
#endif // !UNICAST_DISABLED
+