Bug 1700309 - Retry DNS query when RESOLVE_IP_HINT is set r=necko-reviewers,dragana

Differential Revision: https://phabricator.services.mozilla.com/D109819
This commit is contained in:
Kershaw Chang 2021-03-26 10:33:19 +00:00
parent df6401195e
commit abe7361f8b
2 changed files with 128 additions and 6 deletions

View File

@ -1229,11 +1229,21 @@ nsresult DnsAndConnectSocket::TransportSetup::ResolveHost(
nullptr, NS_NET_STATUS_RESOLVING_HOST, 0);
}
return dns->AsyncResolveNative(
nsresult rv = dns->AsyncResolveNative(
mHost, nsIDNSService::RESOLVE_TYPE_DEFAULT, mDnsFlags, nullptr,
dnsAndSock, gSocketTransportService,
dnsAndSock->mEnt->mConnInfo->GetOriginAttributes(),
getter_AddRefs(mDNSRequest));
if (NS_FAILED(rv) && (mDnsFlags & nsIDNSService::RESOLVE_IP_HINT)) {
mDnsFlags &= ~nsIDNSService::RESOLVE_IP_HINT;
return dns->AsyncResolveNative(
mHost, nsIDNSService::RESOLVE_TYPE_DEFAULT, mDnsFlags, nullptr,
dnsAndSock, gSocketTransportService,
dnsAndSock->mEnt->mConnInfo->GetOriginAttributes(),
getter_AddRefs(mDNSRequest));
}
return rv;
}
nsresult DnsAndConnectSocket::TransportSetup::OnLookupComplete(

View File

@ -9,6 +9,7 @@ ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
let prefs;
let h2Port;
let listen;
let trrServer;
const dns = Cc["@mozilla.org/network/dns-service;1"].getService(
Ci.nsIDNSService
@ -63,7 +64,7 @@ function setup() {
}
setup();
registerCleanupFunction(() => {
registerCleanupFunction(async () => {
prefs.clearUserPref("network.trr.mode");
prefs.clearUserPref("network.http.spdy.enabled");
prefs.clearUserPref("network.http.spdy.enabled.http2");
@ -80,6 +81,8 @@ registerCleanupFunction(() => {
prefs.clearUserPref("network.dns.upgrade_with_https_rr");
prefs.clearUserPref("network.dns.use_https_rr_as_altsvc");
prefs.clearUserPref("network.dns.native-is-localhost");
prefs.clearUserPref("network.dns.disablePrefetch");
await trrServer.stop();
});
class DNSListener {
@ -103,7 +106,7 @@ DNSListener.prototype.QueryInterface = ChromeUtils.generateQI([
// Test if IP hint addresses can be accessed as regular A/AAAA records.
add_task(async function testStoreIPHint() {
let trrServer = new TRRServer();
trrServer = new TRRServer();
registerCleanupFunction(async () => {
await trrServer.stop();
});
@ -230,6 +233,8 @@ add_task(async function testStoreIPHint() {
Ci.nsIDNSService.RESOLVE_IP_HINT | Ci.nsIDNSService.RESOLVE_DISABLE_IPV6,
["1.2.3.4", "5.6.7.8"]
);
await trrServer.stop();
});
function makeChan(url) {
@ -241,14 +246,14 @@ function makeChan(url) {
return chan;
}
function channelOpenPromise(chan) {
function channelOpenPromise(chan, flags) {
return new Promise(resolve => {
function finish(req, buffer) {
resolve([req, buffer]);
}
let internal = chan.QueryInterface(Ci.nsIHttpChannelInternal);
internal.setWaitForHTTPSSVCRecord();
chan.asyncOpen(new ChannelListener(finish, null, CL_ALLOW_UNKNOWN_CL));
chan.asyncOpen(new ChannelListener(finish, null, flags));
});
}
@ -286,7 +291,7 @@ add_task(async function testConnectionWithIPHint() {
);
// The connection should be succeeded since the IP hint is 127.0.0.1.
let chan = makeChan(`http://test.iphint.com:8080/`);
let chan = makeChan(`http://test.iphint.com:8080/server-timing`);
// Note that the partitionKey stored in DNS cache would be
// "%28https%2Ciphint.com%29". The http request to test.iphint.com will be
// upgraded to https and the ip hint address will be used by the https
@ -298,4 +303,111 @@ add_task(async function testConnectionWithIPHint() {
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
false
);
await trrServer.stop();
});
// Test the case that we failed to use IP Hint address because DNS cache
// is bypassed.
add_task(async function testIPHintWithFreshDNS() {
trrServer = new TRRServer();
await trrServer.start();
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.setCharPref(
"network.trr.uri",
`https://foo.example.com:${trrServer.port}/dns-query`
);
// To make sure NS_HTTP_REFRESH_DNS not be cleared.
Services.prefs.setBoolPref("network.dns.disablePrefetch", true);
await trrServer.registerDoHAnswers("test.iphint.org", "HTTPS", {
answers: [
{
name: "test.iphint.org",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 0,
name: "svc.iphint.net",
values: [],
},
},
],
});
await trrServer.registerDoHAnswers("svc.iphint.net", "HTTPS", {
answers: [
{
name: "svc.iphint.net",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 1,
name: "svc.iphint.net",
values: [
{ key: "alpn", value: "h2" },
{ key: "port", value: h2Port },
{ key: "ipv4hint", value: "127.0.0.1" },
],
},
},
],
});
let listener = new DNSListener();
let request = dns.asyncResolve(
"test.iphint.org",
dns.RESOLVE_TYPE_HTTPSSVC,
0,
null, // resolverInfo
listener,
mainThread,
defaultOriginAttributes
);
let [inRequest, inRecord, inStatus] = await listener;
Assert.equal(inRequest, request, "correct request was used");
Assert.equal(inStatus, Cr.NS_OK, "status OK");
let answer = inRecord.QueryInterface(Ci.nsIDNSHTTPSSVCRecord).records;
Assert.equal(answer[0].priority, 1);
Assert.equal(answer[0].name, "svc.iphint.net");
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
true
);
let chan = makeChan(`https://test.iphint.org/server-timing`);
chan.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
let [req] = await channelOpenPromise(
chan,
CL_EXPECT_FAILURE | CL_ALLOW_UNKNOWN_CL
);
// Failed because there no A record for "svc.iphint.net".
Assert.equal(req.status, Cr.NS_ERROR_UNKNOWN_HOST);
await trrServer.registerDoHAnswers("svc.iphint.net", "A", {
answers: [
{
name: "svc.iphint.net",
ttl: 55,
type: "A",
flush: false,
data: "127.0.0.1",
},
],
});
chan = makeChan(`https://test.iphint.org/server-timing`);
chan.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
[req] = await channelOpenPromise(chan);
Assert.equal(req.protocolVersion, "h2");
let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
Assert.equal(internal.remotePort, h2Port);
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
false
);
await trrServer.stop();
});