mirror of
https://github.com/hickory-dns/hickory-dns.git
synced 2026-04-25 11:15:54 +03:00
[GH-ISSUE #1555] Should resolver always use source port randomization? #697
Labels
No labels
blocked
breaking-change
bug
bug:critical
bug:tests
cleanup
compliance
compliance
compliance
crate:all
crate:client
crate:native-tls
crate:proto
crate:recursor
crate:resolver
crate:resolver
crate:rustls
crate:server
crate:util
dependencies
docs
duplicate
easy
easy
enhance
enhance
enhance
feature:dns-over-https
feature:dns-over-quic
feature:dns-over-tls
feature:dnsssec
feature:global_lb
feature:mdns
feature:tsig
features:edns
has workaround
ops
perf
platform:WASM
platform:android
platform:fuchsia
platform:linux
platform:macos
platform:windows
pull-request
question
test
tools
tools
trust
unclear
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/hickory-dns#697
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @peterthejohnston on GitHub (Sep 21, 2021).
Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/1555
We've encountered an unusual issue with devices running Fuchsia (with trust-dns as the system DNS resolver) where Netgear Armor running on the device's network reports a "scanning attack" on the device (see these threads on Netgear's community forums: 1, 2). Armor reports that these "attacks" are coming from 8.8.8.8, i.e. Google DNS.
trust-dns uses source port randomization as a mitigation for DNS cache poisoning, i.e. it opens a new UDP connection with a random local ephemeral port for each request. We suspect that this is one reason Netgear Armor is mistakenly detecting port scanning from 8.8.8.8; if we're quickly sending out many DNS requests on different ports, Google DNS will send UDP packets back to multiple ports in fast succession. However, Netgear Armor should be able to tell that the incoming UDP packets from Google DNS each follow an outgoing request on that same port, and are therefore not unsolicited.
So, it looks like Netgear Armor is wrong here (and hopefully they can fix this on their end—supposedly they are working on it). But in the interest of not setting off security alerts, and since I'm not totally sure, might it make sense for source port randomization to be configurable (i.e. disable-able) in the trust-dns resolver?
Also, I was wondering, is it possible that source port randomization is not the default on other systems' DNS resolvers? Maybe it's typically done at the router level rather than the system DNS resolver level? I ask because, curiously, we're not seeing Netgear Armor's "scanning attack" alert be set off by other devices that aren't running Fuchsia, so it seems like something unique to using trust-dns with Google DNS.
I'd welcome any thoughts. Thanks!
@bluejekyll commented on GitHub (Sep 22, 2021):
Thanks for the detailed report. I'll try and find some time to read through the netgear threads on this, as they will at least be illuminating.
Yes, we can do this. Based on your description though, I think we'd end up wanting to reuse UDP sockets, and not just throw them away after every use. Does Fuchsia reuse ports immediately? I'm assuming not. This would just require a different technique for managing the UDP socket than we do today. I think the server UDP is probably a good guide here.
Yes, this is possible, but would take a bit of research into glibc/libc implementations on other OSes to see how they do this. I haven't done this. When implementing this for Trust-DNS, my thought was that eventually we'd want to build out the resolver to be capable of full top-down recursive-resolution from the root servers. That's not been done yet, but this is definitely required for that. My quick thoughts here are that for personal devices, src port randomization is probably not as important as it is for a fully recursive-resolver, but I would think most systems are also not reusing UDP sockets for multiple DNS requests. So, even if it's predictable, they would be getting some amount of randomization on the port as well. That is, to reduce the randomization, we would need to reuse UDP sockets, and I'd be interested in knowing if others do that.
That being said there is another option here–to only use TCP, this would (should) reuse the same TCP connection for all DNS resolution if there are a lot happening in succession. It can even be faster if there are a large number of requests going on. Reading your report, I wonder if something about the way the router looks up DNS information sends more requests in quick succession than other, similar, devices.
@peterthejohnston commented on GitHub (Sep 29, 2021):
That makes sense. 👍
I've done a little bit more digging here, and you are definitely right that other systems are also not reusing UDP sockets for outgoing DNS queries. However, I did notice that the range in which the ephemeral port is selected is smaller on other OSes: while trust-dns uses
1024–65535, which is the designated range for non-well-known ports from RFC 6056, the IANA suggests the more specific range49152–65535for ephemeral ports. This is what Windows uses for DNS queries, and from some experimentation it looks like macOS uses that range as well; Wikipedia suggests that "many Linux kernels use the port range32768–60999".So, maybe it would make sense to narrow the range of ports used for random selection to the IANA-suggested range? I don't know for sure if we'd want to do this, and I'm also not sure if this is related to the Netgear issue, but it's possible that Netgear Armor would not detect port scanning if we were only using ports inside the range reserved for ephemeral ports.
Either way, I still don't think this is an issue we need to "fix"—clearly Netgear Armor is somewhat broken here—but wanted to bring it to your attention.
That's a good point, and something we can consider if we need a short term mitigation for this issue.
@peterthejohnston commented on GitHub (Sep 29, 2021):
Another possibility would be for trust-dns to let the system netstack choose the port for it (and effectively delegate the randomized selection to the OS)—is there a reason trust-dns itself needs to do the random port selection?
@tamird commented on GitHub (Sep 29, 2021):
Note that delegation is likely to result in yet less control of the allocated port ranges, perhaps going against the stated goals of this issue.
@peterthejohnston commented on GitHub (Sep 29, 2021):
The primary goal of the issue, as I see it, is to see if trust-dns can behave similarly to other system DNS resolvers do with respect to source port selection for DNS queries, as long as that doesn't hurt security goals etc., since I suspect trust-dns is behaving differently in some meaningful way that caused Netgear Armor to (falsely) detect port scanning on a device running Fuchsia but not others. If behaving like other DNS resolvers means having less control over the allocated port range, then that might make sense.
@bluejekyll commented on GitHub (Sep 29, 2021):
This is great research, @peterthejohnston. Thank you for doing it, also I was completely unaware of the IANA recommendation here, TIL. I'd absolutely be open to constraining the ports to that same range, would be a relatively simple change.
I chose to do this mainly because I didn't want to assume how the underlying OS functioned given the security concerns related to spoofed responses. That is to say, rather than having a switch on each OS that correctly randomizes port selection, I decided relying on a well known RNG would be the better option. I realize that comes with some downsides. One possibly being the issue you're running into with Netgear, but the one that I've always thought people would complain more about is the potential performance hit from the randomness guarantee. That said, most people aren't using this in a performance critical way, so it's not come up. I think they tend to use the client rather than the resolver in those cases.
If you don't mind me summarizing:
To resolve this, I think the simplest thing would be to apply the IANA restrictions. The other option would be a bit more substantial change, and IMO shouldn't matter.
@tamird commented on GitHub (Sep 29, 2021):
Ah, meaning that the system would allocate the port only out of the ephemeral range? We should check that Fuchsia does that.
@peterthejohnston commented on GitHub (Sep 29, 2021):
Looks like gVisor allocates ports 16000 and above for ephemeral usage, which is a wider range than IANA suggests but still narrower than what trust-dns currently uses.
I see, that makes sense. I agree with your summary. I'll put up a PR to restrict requested ports to the IANA range.