зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1663571 - Resolve single label DNS queries using DnsQuery_A r=necko-reviewers,dragana
Differential Revision: https://phabricator.services.mozilla.com/D91117
This commit is contained in:
Родитель
acd3c1bffc
Коммит
2da264ce5c
|
@ -8382,6 +8382,14 @@
|
|||
value: 2000
|
||||
mirror: always
|
||||
|
||||
# When true on Windows DNS resolutions for single label domains
|
||||
# (domains that don't contain a dot) will be resolved using the DnsQuery
|
||||
# API instead of PR_GetAddrInfoByName
|
||||
- name: network.dns.dns_query_single_label
|
||||
type: RelaxedAtomicBool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# The proxy type. See nsIProtocolProxyService.idl
|
||||
# PROXYCONFIG_DIRECT = 0
|
||||
# PROXYCONFIG_MANUAL = 1
|
||||
|
|
|
@ -56,47 +56,65 @@ static_assert(PR_AF_INET == AF_INET && PR_AF_INET6 == AF_INET6 &&
|
|||
// equal with the one already there. Gets the TTL value by calling
|
||||
// to DnsQuery_A and iterating through the returned
|
||||
// records to find the one with the smallest TTL value.
|
||||
static MOZ_ALWAYS_INLINE nsresult _GetMinTTLForRequestType_Windows(
|
||||
const char* aHost, uint16_t aRequestType, unsigned int* aResult) {
|
||||
MOZ_ASSERT(aHost);
|
||||
MOZ_ASSERT(aResult);
|
||||
static MOZ_ALWAYS_INLINE nsresult _CallDnsQuery_A_Windows(
|
||||
const nsACString& aHost, uint16_t aAddressFamily, DWORD aFlags,
|
||||
std::function<void(PDNS_RECORDA)> aCallback) {
|
||||
NS_ConvertASCIItoUTF16 name(aHost);
|
||||
|
||||
PDNS_RECORDA dnsData = nullptr;
|
||||
DNS_STATUS status = DnsQuery_A(
|
||||
aHost, aRequestType,
|
||||
(DNS_QUERY_STANDARD | DNS_QUERY_NO_NETBT | DNS_QUERY_NO_HOSTS_FILE |
|
||||
DNS_QUERY_NO_MULTICAST | DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE |
|
||||
DNS_QUERY_DONT_RESET_TTL_VALUES),
|
||||
nullptr, &dnsData, nullptr);
|
||||
if (status == DNS_INFO_NO_RECORDS || status == DNS_ERROR_RCODE_NAME_ERROR ||
|
||||
!dnsData) {
|
||||
LOG("No DNS records found for %s. status=%X. aRequestType = %X\n", aHost,
|
||||
status, aRequestType);
|
||||
return NS_ERROR_FAILURE;
|
||||
} else if (status != NOERROR) {
|
||||
LOG_WARNING("DnsQuery_A failed with status %X.\n", status);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
for (PDNS_RECORDA curRecord = dnsData; curRecord;
|
||||
curRecord = curRecord->pNext) {
|
||||
// Only records in the answer section are important
|
||||
if (curRecord->Flags.S.Section != DnsSectionAnswer) {
|
||||
continue;
|
||||
auto callDnsQuery_A = [&](uint16_t reqFamily) {
|
||||
PDNS_RECORDA dnsData = nullptr;
|
||||
DNS_STATUS status = DnsQuery_A(aHost.BeginReading(), reqFamily, aFlags,
|
||||
nullptr, &dnsData, nullptr);
|
||||
if (status == DNS_INFO_NO_RECORDS || status == DNS_ERROR_RCODE_NAME_ERROR ||
|
||||
!dnsData) {
|
||||
LOG("No DNS records found for %s. status=%X. reqFamily = %X\n",
|
||||
aHost.BeginReading(), status, reqFamily);
|
||||
return NS_ERROR_FAILURE;
|
||||
} else if (status != NOERROR) {
|
||||
LOG_WARNING("DnsQuery_A failed with status %X.\n", status);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (curRecord->wType == aRequestType) {
|
||||
*aResult = std::min<unsigned int>(*aResult, curRecord->dwTtl);
|
||||
} else {
|
||||
LOG("Received unexpected record type %u in response for %s.\n",
|
||||
curRecord->wType, aHost);
|
||||
for (PDNS_RECORDA curRecord = dnsData; curRecord;
|
||||
curRecord = curRecord->pNext) {
|
||||
// Only records in the answer section are important
|
||||
if (curRecord->Flags.S.Section != DnsSectionAnswer) {
|
||||
continue;
|
||||
}
|
||||
if (curRecord->wType != reqFamily) {
|
||||
continue;
|
||||
}
|
||||
|
||||
aCallback(curRecord);
|
||||
}
|
||||
|
||||
DnsFree(dnsData, DNS_FREE_TYPE::DnsFreeRecordList);
|
||||
return NS_OK;
|
||||
};
|
||||
|
||||
if (aAddressFamily == PR_AF_UNSPEC || aAddressFamily == PR_AF_INET) {
|
||||
callDnsQuery_A(DNS_TYPE_A);
|
||||
}
|
||||
|
||||
DnsFree(dnsData, DNS_FREE_TYPE::DnsFreeRecordList);
|
||||
if (aAddressFamily == PR_AF_UNSPEC || aAddressFamily == PR_AF_INET6) {
|
||||
callDnsQuery_A(DNS_TYPE_AAAA);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool recordTypeMatchesRequest(uint16_t wType, uint16_t aAddressFamily) {
|
||||
if (aAddressFamily == PR_AF_UNSPEC) {
|
||||
return wType == DNS_TYPE_A || wType == DNS_TYPE_AAAA;
|
||||
}
|
||||
if (aAddressFamily == PR_AF_INET) {
|
||||
return wType == DNS_TYPE_A;
|
||||
}
|
||||
if (aAddressFamily == PR_AF_INET6) {
|
||||
return wType == DNS_TYPE_AAAA;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE nsresult _GetTTLData_Windows(const nsACString& aHost,
|
||||
uint32_t* aResult,
|
||||
uint16_t aAddressFamily) {
|
||||
|
@ -110,13 +128,21 @@ static MOZ_ALWAYS_INLINE nsresult _GetTTLData_Windows(const nsACString& aHost,
|
|||
// In order to avoid using ANY records which are not always implemented as a
|
||||
// "Gimme what you have" request in hostname resolvers, we should send A
|
||||
// and/or AAAA requests, based on the address family requested.
|
||||
const DWORD ttlFlags =
|
||||
(DNS_QUERY_STANDARD | DNS_QUERY_NO_NETBT | DNS_QUERY_NO_HOSTS_FILE |
|
||||
DNS_QUERY_NO_MULTICAST | DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE |
|
||||
DNS_QUERY_DONT_RESET_TTL_VALUES);
|
||||
unsigned int ttl = (unsigned int)-1;
|
||||
if (aAddressFamily == PR_AF_UNSPEC || aAddressFamily == PR_AF_INET) {
|
||||
_GetMinTTLForRequestType_Windows(aHost.BeginReading(), DNS_TYPE_A, &ttl);
|
||||
}
|
||||
if (aAddressFamily == PR_AF_UNSPEC || aAddressFamily == PR_AF_INET6) {
|
||||
_GetMinTTLForRequestType_Windows(aHost.BeginReading(), DNS_TYPE_AAAA, &ttl);
|
||||
}
|
||||
_CallDnsQuery_A_Windows(
|
||||
aHost, aAddressFamily, ttlFlags,
|
||||
[&ttl, &aHost, aAddressFamily](PDNS_RECORDA curRecord) {
|
||||
if (recordTypeMatchesRequest(curRecord->wType, aAddressFamily)) {
|
||||
ttl = std::min<unsigned int>(ttl, curRecord->dwTtl);
|
||||
} else {
|
||||
LOG("Received unexpected record type %u in response for %s.\n",
|
||||
curRecord->wType, aHost.BeginReading());
|
||||
}
|
||||
});
|
||||
|
||||
if (ttl == (unsigned int)-1) {
|
||||
LOG("No useable TTL found.");
|
||||
|
@ -126,6 +152,41 @@ static MOZ_ALWAYS_INLINE nsresult _GetTTLData_Windows(const nsACString& aHost,
|
|||
*aResult = ttl;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE nsresult
|
||||
_DNSQuery_A_SingleLabel(const nsACString& aCanonHost, uint16_t aAddressFamily,
|
||||
uint16_t aFlags, AddrInfo** aAddrInfo) {
|
||||
bool setCanonName = aFlags & nsHostResolver::RES_CANON_NAME;
|
||||
nsAutoCString canonName;
|
||||
const DWORD flags = (DNS_QUERY_STANDARD | DNS_QUERY_NO_MULTICAST |
|
||||
DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE);
|
||||
nsTArray<NetAddr> addresses;
|
||||
|
||||
_CallDnsQuery_A_Windows(
|
||||
aCanonHost, aAddressFamily, flags, [&](PDNS_RECORDA curRecord) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(curRecord->wType == DNS_TYPE_A ||
|
||||
curRecord->wType == DNS_TYPE_AAAA);
|
||||
if (setCanonName) {
|
||||
canonName.Assign(curRecord->pName);
|
||||
}
|
||||
NetAddr addr{};
|
||||
addr.inet.family = AF_INET;
|
||||
addr.inet.ip = curRecord->Data.A.IpAddress;
|
||||
addresses.AppendElement(addr);
|
||||
});
|
||||
|
||||
LOG("Query for: %s has %u results", aCanonHost.BeginReading(),
|
||||
addresses.Length());
|
||||
if (addresses.IsEmpty()) {
|
||||
return NS_ERROR_UNKNOWN_HOST;
|
||||
}
|
||||
RefPtr<AddrInfo> ai(
|
||||
new AddrInfo(aCanonHost, canonName, 0, std::move(addresses)));
|
||||
ai.forget(aAddrInfo);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////
|
||||
|
@ -153,6 +214,24 @@ _GetAddrInfo_Portable(const nsACString& aCanonHost, uint16_t aAddressFamily,
|
|||
aAddressFamily = PR_AF_UNSPEC;
|
||||
}
|
||||
|
||||
#if defined(DNSQUERY_AVAILABLE)
|
||||
if (StaticPrefs::network_dns_dns_query_single_label() &&
|
||||
!aCanonHost.Contains('.') && aCanonHost != "localhost"_ns) {
|
||||
char computername[MAX_COMPUTERNAME_LENGTH + 1];
|
||||
DWORD namesize = MAX_COMPUTERNAME_LENGTH + 1;
|
||||
|
||||
// For some reason we can't use DnsQuery_A to get the computer's IP.
|
||||
if (!GetComputerNameA(computername, &namesize) ||
|
||||
!aCanonHost.Equals(nsDependentCString(computername, namesize),
|
||||
nsCaseInsensitiveCStringComparator)) {
|
||||
// This is a single label name resolve without a dot.
|
||||
// We use DNSQuery_A for these.
|
||||
return _DNSQuery_A_SingleLabel(aCanonHost, aAddressFamily, aFlags,
|
||||
aAddrInfo);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
PRAddrInfo* prai =
|
||||
PR_GetAddrInfoByName(aCanonHost.BeginReading(), aAddressFamily, prFlags);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче