mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-26 20:38:40 +00:00
net/portmapper: be smarter about selecting a UPnP device
Previously, we would select the first WANIPConnection2 (and related) client from the root device, without any additional checks. However, some routers expose multiple UPnP devices in various states, and simply picking the first available one can result in attempting to perform a portmap with a device that isn't functional. Instead, mimic what the miniupnpc code does, and prefer devices that are (a) reporting as Connected, and (b) have a valid external IP address. For our use-case, we additionally prefer devices that have an external IP address that's a public address, to increase the likelihood that we can obtain a direct connection from peers. Finally, we split out fetching the root device (getUPnPRootDevice) from selecting the best service within that root device (selectBestService), and add some extensive tests for various UPnP server behaviours. RELNOTE=Improve UPnP portmapping when multiple UPnP services exist Updates #8364 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: I71795cd80be6214dfcef0fe83115a5e3fe4b8753
This commit is contained in:
@@ -1015,6 +1015,30 @@ var (
|
||||
// received a UPnP response from a port other than the UPnP port.
|
||||
metricUPnPResponseAlternatePort = clientmetric.NewCounter("portmap_upnp_response_alternate_port")
|
||||
|
||||
// metricUPnPSelectSingle counts the number of times that only a single
|
||||
// UPnP device was available in selectBestService.
|
||||
metricUPnPSelectSingle = clientmetric.NewCounter("portmap_upnp_select_single")
|
||||
|
||||
// metricUPnPSelectMultiple counts the number of times that we need to
|
||||
// select from among multiple UPnP devices in selectBestService.
|
||||
metricUPnPSelectMultiple = clientmetric.NewCounter("portmap_upnp_select_multiple")
|
||||
|
||||
// metricUPnPSelectExternalPublic counts the number of times that
|
||||
// selectBestService picked a UPnP device with an external public IP.
|
||||
metricUPnPSelectExternalPublic = clientmetric.NewCounter("portmap_upnp_select_external_public")
|
||||
|
||||
// metricUPnPSelectExternalPrivate counts the number of times that
|
||||
// selectBestService picked a UPnP device with an external private IP.
|
||||
metricUPnPSelectExternalPrivate = clientmetric.NewCounter("portmap_upnp_select_external_private")
|
||||
|
||||
// metricUPnPSelectUp counts the number of times that selectBestService
|
||||
// picked a UPnP device that was up but with no external IP.
|
||||
metricUPnPSelectUp = clientmetric.NewCounter("portmap_upnp_select_up")
|
||||
|
||||
// metricUPnPSelectNone counts the number of times that selectBestService
|
||||
// picked a UPnP device that is not up.
|
||||
metricUPnPSelectNone = clientmetric.NewCounter("portmap_upnp_select_none")
|
||||
|
||||
// metricUPnPParseErr counts the number of times we failed to parse a UPnP response.
|
||||
metricUPnPParseErr = clientmetric.NewCounter("portmap_upnp_parse_err")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user