[GH-ISSUE #1555] Should resolver always use source port randomization? #697

Closed
opened 2026-03-15 23:52:27 +03:00 by kerem · 8 comments
Owner

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!

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](https://community.netgear.com/t5/NETGEAR-Armor/Scanning-attack-Google-nest-hub/td-p/2129631), [2](https://community.netgear.com/t5/NETGEAR-Armor/Armor-Blocking-Repetitive-Port-Scan-Attacks-on-Google-Nest-Hub/m-p/2130323#M5249)). Armor reports that these "attacks" are coming from 8.8.8.8, i.e. Google DNS. trust-dns uses [source port randomization](https://www.jpcert.or.jp/english/at/2014/at140016.html) as a [mitigation](https://github.com/bluejekyll/trust-dns/blob/v0.21.0-alpha.2/crates/proto/src/udp/udp_client_stream.rs#L29) 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](https://community.netgear.com/t5/NETGEAR-Armor/Armor-Blocking-Repetitive-Port-Scan-Attacks-on-Google-Nest-Hub/m-p/2134100#M5303)). 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!
kerem 2026-03-15 23:52:27 +03:00
Author
Owner

@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.

might it make sense for source port randomization to be configurable (i.e. disable-able) in the trust-dns resolver?

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.

is it possible that source port randomization is not the default on other systems' DNS resolvers?

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.

<!-- gh-comment-id:924980860 --> @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. > might it make sense for source port randomization to be configurable (i.e. disable-able) in the trust-dns resolver? 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. > is it possible that source port randomization is not the default on other systems' DNS resolvers? 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.
Author
Owner

@peterthejohnston commented on GitHub (Sep 29, 2021):

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.

That makes sense. 👍

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.

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 range 49152–65535 for 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 range 32768–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 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.

That's a good point, and something we can consider if we need a short term mitigation for this issue.

<!-- gh-comment-id:930238096 --> @peterthejohnston commented on GitHub (Sep 29, 2021): > 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. That makes sense. 👍 > 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. 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](https://github.com/bluejekyll/trust-dns/blob/v0.21.0-alpha.3/crates/proto/src/udp/udp_stream.rs#L216) `1024–65535`, which is the designated range for non-well-known ports from [RFC 6056](https://datatracker.ietf.org/doc/html/rfc6056#section-2.1), the IANA [suggests](https://datatracker.ietf.org/doc/html/rfc6335#section-6) the more specific range `49152–65535` for ephemeral ports. This is what [Windows uses](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd197515(v=ws.10)?redirectedfrom=MSDN) for DNS queries, and from some experimentation it looks like macOS uses that range as well; Wikipedia [suggests](https://en.wikipedia.org/wiki/Ephemeral_port) that "many Linux kernels use the port range `32768–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 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. That's a good point, and something we can consider if we need a short term mitigation for this issue.
Author
Owner

@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?

<!-- gh-comment-id:930474088 --> @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?
Author
Owner

@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.

<!-- gh-comment-id:930509618 --> @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.
Author
Owner

@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.

<!-- gh-comment-id:930527725 --> @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.
Author
Owner

@bluejekyll commented on GitHub (Sep 29, 2021):

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 range 49152–65535 for 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 range 32768–60999"

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.

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?

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:

  • Other OSes are not reusing UDP sockets/ports, so this seems like it isn't needed to resolve the issue.
  • They do restrict their port range to a narrowing and higher range
  • We could use the native socket handling from the OS, but this would require flags per OS that is correct vs. ones that are not

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.

<!-- gh-comment-id:930560646 --> @bluejekyll commented on GitHub (Sep 29, 2021): > 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 range 49152–65535 for 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 range 32768–60999" 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. > 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? 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: - Other OSes are not reusing UDP sockets/ports, so this seems like it isn't needed to resolve the issue. - They do restrict their port range to a narrowing and higher range - We could use the native socket handling from the OS, but this would require flags per OS that is correct vs. ones that are not 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.
Author
Owner

@tamird commented on GitHub (Sep 29, 2021):

If behaving like other DNS resolvers means having less control over the allocated port range, then that might make sense.

Ah, meaning that the system would allocate the port only out of the ephemeral range? We should check that Fuchsia does that.

<!-- gh-comment-id:930563553 --> @tamird commented on GitHub (Sep 29, 2021): > If behaving like other DNS resolvers means having less control over the allocated port range, then that might make sense. Ah, meaning that the system would allocate the port only out of the ephemeral range? We should check that Fuchsia does that.
Author
Owner

@peterthejohnston commented on GitHub (Sep 29, 2021):

We should check that Fuchsia does that.

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 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 see, that makes sense. I agree with your summary. I'll put up a PR to restrict requested ports to the IANA range.

<!-- gh-comment-id:930571926 --> @peterthejohnston commented on GitHub (Sep 29, 2021): > We should check that Fuchsia does that. Looks like gVisor allocates ports [16000 and above](https://cs.opensource.google/gvisor/gvisor/+/master:pkg/tcpip/ports/ports.go;l=30;drc=570ca571805d6939c4c24b6a88660eefaf558ae7) for ephemeral usage, which is a wider range than IANA suggests but still narrower than what trust-dns currently uses. > 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 see, that makes sense. I agree with your summary. I'll put up a PR to restrict requested ports to the IANA range.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/hickory-dns#697
No description provided.