DNS requests bypass the configured proxy. Privacy may be compromised.
Categories
(Core :: Networking: Proxy, defect, P2)
Tracking
()
People
(Reporter: ackbeat, Assigned: kershaw)
Details
(4 keywords, Whiteboard: [necko-triaged][necko-priority-queue][adv-main140+])
Attachments
(3 files)
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:134.0) Gecko/20100101 Firefox/134.0
Steps to reproduce:
In Multi-Account container I use socks proxy: socks://127.0.0.1:1080
I can confirm, that when I visit sites the DNS requests go through my proxy.
However! When there is a typo in the address, so that the domain name does not exist...
Actual results:
I see Firefox trying to use the system's default resolver. I see these DNS requests on my router.
Expected results:
Firefox should NEVER try to send requests anywhere other than the proxy, provided the proxy is configured. Does not matter if domain name exists or not. Because the original site can be easily deduced from the address with typo.
Updated•11 months ago
|
Updated•11 months ago
|
Comment 1•11 months ago
|
||
I suspect this is related to the newish fallback behavior for "DNS over HTTPS", assuming you're not using "Max Protection". You're right that the "use system settings" fallback should not ignore/override the "Proxy DNS when using SOCKS" prefs!
Could you confirm that there's no problem if you change the DNS over HTTPS settings to "Max Protection" (typo should give you an error page) or "Off" (all requests presumably honor the SOCKS setting)?
Updated•11 months ago
|
Comment 2•10 months ago
|
||
Redirect a needinfo that is pending on an inactive user to the triage owner.
:jesup, since the bug has recent activity, could you have a look please?
For more information, please visit BugBot documentation.
Comment 4•9 months ago
|
||
I am able to reproduce this issue.
Using MultiAccountContainers, if I set the proxy for a container to socks://hello:8080 and attempt to load google.com instead of the usual "This proxy is refusing connections" I get Hmm. We’re having trouble finding that site. errors, and indeed I see all of the DNS lookups for google.com in Wireshark.
This is indeed a proxy issue - I think it's the proxy error (in this case DNS) being passed presented as the error for google.com
The proxy Info coming from MAC has proxyDNS = true, which means we are leaking DNS when the proxy connection fails, which seems like a valid bug.
I think I'll try to work on this, but if I don't get to it soon, my approach would be:
- Write a unit test based on test_proxyDNS_leak.js that proxies to socks://hello:9999 - override the DNS for hello to go to localhost, and don't set up a proxy.
- add a DNS override for example.com
- make sure that loading a channel to example.com doesn't resolve the DNS entry for example.com
- Then to the fix, I assume the bug is in either in nsProtocolProxyService.cpp or mozilla::net::nsHttpChannel::OnProxyAvailable
| Assignee | ||
Comment 5•8 months ago
|
||
I believe the DNS leak is caused by the speculative connection made here.
Since we don’t set the callbacks, the tab ID for this dummy channel is -1.
As shown in the web extension code below, a valid tab ID is required for assigning proxy info:
async handleProxifiedRequest(requestInfo) {
// The following blocks potentially dangerous requests for privacy that come without a tabId
if(requestInfo.tabId === -1) {
return {};
}
As a result, the extension fails to set proxy info on the channel, which causes the DNS lookup from the speculative connection to bypass the proxy — leading to a DNS leak.
| Assignee | ||
Comment 6•8 months ago
|
||
Hi Gijs,
Do you probably know how to get the load context in RemoteWebNavigation? ideally, I'd like to do something like this.
Apparently, this._browser is a remote browser and I don't know how to get load context from it.
Thanks.
Comment 7•8 months ago
|
||
(In reply to Kershaw Chang [:kershaw] from comment #6)
Hi Gijs,
Do you probably know how to get the load context in
RemoteWebNavigation? ideally, I'd like to do something like this.
Apparently, this._browser is a remote browser and I don't know how to get load context from it.
Well, the example from SearchEngine relies on docshell which is in the child process and RemoteWebNavigation is in the parent, so that won't work.
But if you look for nsILoadContext then allegedly BrowsingContexts implement this, so you could try using this._browser.browsingContext, maybe? Does that work?
I'm a bit surprised because this is a very different discussion from the one in comment #4. Also comment #5 mentions an extension but I don't see the steps involving an extension so I don't understand how that's related...
| Assignee | ||
Comment 8•8 months ago
|
||
(In reply to :Gijs (he/him) from comment #7)
(In reply to Kershaw Chang [:kershaw] from comment #6)
Hi Gijs,
Do you probably know how to get the load context in
RemoteWebNavigation? ideally, I'd like to do something like this.
Apparently, this._browser is a remote browser and I don't know how to get load context from it.Well, the example from SearchEngine relies on
docshellwhich is in the child process andRemoteWebNavigationis in the parent, so that won't work.But if you look for
nsILoadContextthen allegedlyBrowsingContexts implement this, so you could try usingthis._browser.browsingContext, maybe? Does that work?
Unfortunately, no. I got the error below when using this._browser.browsingContext.
JavaScript error: resource://gre/modules/RemoteWebNavigation.sys.mjs, line 114: NS_ERROR_XPC_BAD_CONVERT_JS: Could not convert JavaScript argument arg 2 [nsISpeculativeConnect.speculativeConnect]
I'm a bit surprised because this is a very different discussion from the one in comment #4. Also comment #5 mentions an extension but I don't see the steps involving an extension so I don't understand how that's related...
As mentioned in comment #0, reproducing this bug requires installing the MultiAccountContainers extension.
While investigating, I found that the DNS leak originates from a speculative connection created in RemoteWebNavigation.
More details:
- The speculative connection is created here.
- For this connection, we create a dummy channel, which is used for proxy resolution.
- During proxy resolution, MultiAccountContainers should set the appropriate proxy info based on the dummy channel’s metadata.
- However, since we didn’t provide a load context, MultiAccountContainers fails to assign proxy info. As a result, the speculative connection is made without a proxy.
- Because there's no proxy assigned, Firefox performs a DNS lookup directly — which causes the leak.
Comment 9•8 months ago
|
||
(In reply to Kershaw Chang [:kershaw] from comment #8)
Thanks for the more detailed investigation and explaining it, and sorry for being slow on the uptake.
(In reply to :Gijs (he/him) from comment #7)
(In reply to Kershaw Chang [:kershaw] from comment #6)
Hi Gijs,
Do you probably know how to get the load context in
RemoteWebNavigation? ideally, I'd like to do something like this.
Apparently, this._browser is a remote browser and I don't know how to get load context from it.Well, the example from SearchEngine relies on
docshellwhich is in the child process andRemoteWebNavigationis in the parent, so that won't work.But if you look for
nsILoadContextthen allegedlyBrowsingContexts implement this, so you could try usingthis._browser.browsingContext, maybe? Does that work?Unfortunately, no. I got the error below when using
this._browser.browsingContext.JavaScript error: resource://gre/modules/RemoteWebNavigation.sys.mjs, line 114: NS_ERROR_XPC_BAD_CONVERT_JS: Could not convert JavaScript argument arg 2 [nsISpeculativeConnect.speculativeConnect]
Aha. I'm sorry for giving the wrong answer - you asked for nsILoadContext, but the interface definition for that call is: https://searchfox.org/mozilla-central/rev/e92cea05ec336d87e495fb42d02652ba2e839592/netwerk/base/nsISpeculativeConnect.idl#44 which says that needs an nsIInterfaceRequestor object.
Then AFAICT we try to get a loadContext out of that here using getInterface. But it means that passing a loadcontext directly won't work.
Instead, you should find or create (!) some object that supports getInterface (in JS) or the C++ equivalent, and can return a load context when asked via that method.
Something like this appears to work, from the browser console (at least doesn't throw or log any exceptions immediately, but I haven't checked if it creates a connection etc.):
Services.io.speculativeConnect(
makeURI("https://example.com/"),
Services.scriptSecurityManager.createNullPrincipal({}),
({QueryInterface: ChromeUtils.generateQI([Ci.nsIInterfaceRequestor]), getInterface(iid) { if (iid.equals(Ci.nsILoadContext)) { return gBrowser.selectedBrowser.browsingContext } } }),
false
);
obviously you'll want to pass the correct browser's browsingContext there, but this works from the browser console.
| Assignee | ||
Comment 10•8 months ago
|
||
Thanks a lot for the provided example.
It works, and I'll submit a patch soon.
| Assignee | ||
Comment 11•8 months ago
|
||
Updated•8 months ago
|
| Assignee | ||
Comment 12•8 months ago
|
||
Depends on D245452
Updated•8 months ago
|
Comment 13•8 months ago
|
||
Comment 14•8 months ago
|
||
Backed out for linting failures:
https://hg.mozilla.org/integration/autoland/rev/80ce77579cf09a9113b51e7a6af1828d34f5cf83
Push with failures
Failure log
TEST-UNEXPECTED-ERROR | /builds/worker/checkouts/gecko/netwerk/test/unit/test_speculative_connect.js:363:7 | 'pps' is not defined. (no-undef)
TEST-UNEXPECTED-ERROR | /builds/worker/checkouts/gecko/netwerk/test/unit/test_speculative_connect.js:367:9 | 'proxy_auth' is not defined. (no-undef)
TEST-UNEXPECTED-ERROR | /builds/worker/checkouts/gecko/netwerk/test/unit/test_speculative_connect.js:368:9 | 'proxy_isolation' is not defined. (no-undef)
TEST-UNEXPECTED-ERROR | /builds/worker/checkouts/gecko/toolkit/components/remotebrowserutils/RemoteWebNavigation.sys.mjs:16:3 | Expected to return a value at the end of method
| Assignee | ||
Updated•8 months ago
|
Comment 15•8 months ago
|
||
Comment 16•8 months ago
|
||
Backed out for causing xpcshell failures @ test_ext_proxy_speculative.js
TEST-UNEXPECTED-FAIL | xpcshell-remote.toml:toolkit/components/extensions/test/xpcshell/test_ext_proxy_speculative.js | test_speculative_connect - [test_speculative_connect : 66] Extension left running at test shutdown - "running" == "unloaded"
Comment 17•8 months ago
|
||
I think this might also fix bug 1475811.
| Assignee | ||
Updated•8 months ago
|
Comment 18•8 months ago
|
||
Comment 19•8 months ago
|
||
https://hg.mozilla.org/mozilla-central/rev/6bbb8875d5c6
https://hg.mozilla.org/mozilla-central/rev/abffbde1e3d7
Updated•8 months ago
|
Comment 20•7 months ago
|
||
The patch landed in nightly and beta is affected.
:kershaw, is this bug important enough to require an uplift?
- If yes, please nominate the patch for beta approval.
- See https://wiki.mozilla.org/Release_Management/Requesting_an_Uplift for documentation on how to request an uplift.
- If no, please set
status-firefox139towontfix.
For more information, please visit BugBot documentation.
| Assignee | ||
Comment 21•7 months ago
|
||
I think it's fine to let this ride the train, since this is a sec-low bug and we have this behavior for a long time.
Updated•7 months ago
|
Updated•7 months ago
|
Updated•6 months ago
|
Comment 22•6 months ago
|
||
Updated•6 months ago
|
Updated•7 days ago
|
Description
•