mirror of
https://github.com/tailscale/tailscale.git
synced 2025-01-07 08:07:42 +00:00
net/portmapper: relax source port check for UPnP responses
Per a packet capture provided, some gateways will reply to a UPnP discovery packet with a UDP packet with a source port that does not come from the UPnP port. Accept these packets with a log message. Updates #7377 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: I5d4d5b2a0275009ed60f15c20b484fe2025d094b
This commit is contained in:
parent
51eb0b2cb7
commit
f6cd24499b
@ -805,33 +805,48 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ip = ip.Unmap()
|
ip = ip.Unmap()
|
||||||
|
|
||||||
|
handleUPnPResponse := func() {
|
||||||
|
metricUPnPResponse.Add(1)
|
||||||
|
|
||||||
|
if ip != gw {
|
||||||
|
// https://github.com/tailscale/tailscale/issues/5502
|
||||||
|
c.logf("UPnP discovery response from %v, but gateway IP is %v", ip, gw)
|
||||||
|
}
|
||||||
|
meta, err := parseUPnPDiscoResponse(buf[:n])
|
||||||
|
if err != nil {
|
||||||
|
metricUPnPParseErr.Add(1)
|
||||||
|
c.logf("unrecognized UPnP discovery response; ignoring: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
metricUPnPOK.Add(1)
|
||||||
|
c.logf("[v1] UPnP reply %+v, %q", meta, buf[:n])
|
||||||
|
res.UPnP = true
|
||||||
|
c.mu.Lock()
|
||||||
|
c.uPnPSawTime = time.Now()
|
||||||
|
if c.uPnPMeta != meta {
|
||||||
|
c.logf("UPnP meta changed: %+v", meta)
|
||||||
|
c.uPnPMeta = meta
|
||||||
|
metricUPnPUpdatedMeta.Add(1)
|
||||||
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
port := uint16(addr.(*net.UDPAddr).Port)
|
port := uint16(addr.(*net.UDPAddr).Port)
|
||||||
switch port {
|
switch port {
|
||||||
case c.upnpPort():
|
case c.upnpPort():
|
||||||
metricUPnPResponse.Add(1)
|
|
||||||
if mem.Contains(mem.B(buf[:n]), mem.S(":InternetGatewayDevice:")) {
|
if mem.Contains(mem.B(buf[:n]), mem.S(":InternetGatewayDevice:")) {
|
||||||
if ip != gw {
|
handleUPnPResponse()
|
||||||
// https://github.com/tailscale/tailscale/issues/5502
|
|
||||||
c.logf("UPnP discovery response from %v, but gateway IP is %v", ip, gw)
|
|
||||||
}
|
|
||||||
meta, err := parseUPnPDiscoResponse(buf[:n])
|
|
||||||
if err != nil {
|
|
||||||
metricUPnPParseErr.Add(1)
|
|
||||||
c.logf("unrecognized UPnP discovery response; ignoring: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
metricUPnPOK.Add(1)
|
|
||||||
c.logf("[v1] UPnP reply %+v, %q", meta, buf[:n])
|
|
||||||
res.UPnP = true
|
|
||||||
c.mu.Lock()
|
|
||||||
c.uPnPSawTime = time.Now()
|
|
||||||
if c.uPnPMeta != meta {
|
|
||||||
c.logf("UPnP meta changed: %+v", meta)
|
|
||||||
c.uPnPMeta = meta
|
|
||||||
metricUPnPUpdatedMeta.Add(1)
|
|
||||||
}
|
|
||||||
c.mu.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// https://github.com/tailscale/tailscale/issues/7377
|
||||||
|
if mem.Contains(mem.B(buf[:n]), mem.S(":InternetGatewayDevice:")) {
|
||||||
|
c.logf("UPnP discovery response from non-UPnP port %d", port)
|
||||||
|
metricUPnPResponseAlternatePort.Add(1)
|
||||||
|
handleUPnPResponse()
|
||||||
|
}
|
||||||
|
|
||||||
case c.pxpPort(): // same value for PMP and PCP
|
case c.pxpPort(): // same value for PMP and PCP
|
||||||
metricPXPResponse.Add(1)
|
metricPXPResponse.Add(1)
|
||||||
if pres, ok := parsePCPResponse(buf[:n]); ok {
|
if pres, ok := parsePCPResponse(buf[:n]); ok {
|
||||||
@ -983,6 +998,10 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) {
|
|||||||
// metricUPnPResponse counts the number of times we received a UPnP response.
|
// metricUPnPResponse counts the number of times we received a UPnP response.
|
||||||
metricUPnPResponse = clientmetric.NewCounter("portmap_upnp_response")
|
metricUPnPResponse = clientmetric.NewCounter("portmap_upnp_response")
|
||||||
|
|
||||||
|
// metricUPnPResponseAlternatePort counts the number of times we
|
||||||
|
// received a UPnP response from a port other than the UPnP port.
|
||||||
|
metricUPnPResponseAlternatePort = clientmetric.NewCounter("portmap_upnp_response_alternate_port")
|
||||||
|
|
||||||
// metricUPnPParseErr counts the number of times we failed to parse a UPnP response.
|
// metricUPnPParseErr counts the number of times we failed to parse a UPnP response.
|
||||||
metricUPnPParseErr = clientmetric.NewCounter("portmap_upnp_parse_err")
|
metricUPnPParseErr = clientmetric.NewCounter("portmap_upnp_parse_err")
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user