diff --git a/net/portmapper/portmapper.go b/net/portmapper/portmapper.go index 69c1947ad..b1a8bcfb5 100644 --- a/net/portmapper/portmapper.go +++ b/net/portmapper/portmapper.go @@ -737,6 +737,7 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) { // See https://github.com/tailscale/tailscale/issues/3197 for // an example of a device that strictly implements UPnP, and // only responds to multicast queries. + metricUPnPSent.Add(1) uc.WriteTo(uPnPPacket, upnpAddr) uc.WriteTo(uPnPPacket, upnpMulticastAddr) } @@ -762,11 +763,14 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) { port := uint16(addr.(*net.UDPAddr).Port) switch port { case c.upnpPort(): + metricUPnPResponse.Add(1) if ip == gw && mem.Contains(mem.B(buf[:n]), mem.S(":InternetGatewayDevice:")) { meta, err := parseUPnPDiscoResponse(buf[:n]) if err != nil { + metricUPnPParseErr.Add(1) c.logf("unrecognized UPnP discovery response; ignoring") } + metricUPnPOK.Add(1) c.logf("[v1] UPnP reply %+v, %q", meta, buf[:n]) res.UPnP = true c.mu.Lock() @@ -774,6 +778,7 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) { if c.uPnPMeta != meta { c.logf("UPnP meta changed: %+v", meta) c.uPnPMeta = meta + metricUPnPUpdatedMeta.Add(1) } c.mu.Unlock() } @@ -858,6 +863,7 @@ var uPnPPacket = []byte("M-SEARCH * HTTP/1.1\r\n" + "MAN: \"ssdp:discover\"\r\n" + "MX: 2\r\n\r\n") +// PCP/PMP metrics var ( // metricPCPOK counts the number of times // we received a successful PCP response. @@ -899,3 +905,22 @@ var ( // we received a PCP not authorized result code. metricPMPNotAuthorized = clientmetric.NewCounter("portmap_pmp_not_authorized") ) + +// UPnP metrics +var ( + // metricUPnPSent counts the number of times we sent a UPnP request. + metricUPnPSent = clientmetric.NewCounter("portmap_upnp_sent") + + // metricUPnPResponse counts the number of times we received a UPnP response. + metricUPnPResponse = clientmetric.NewCounter("portmap_upnp_response") + + // metricUPnPParseErr counts the number of times we failed to parse a UPnP response. + metricUPnPParseErr = clientmetric.NewCounter("portmap_upnp_parse_err") + + // metricUPnPOK counts the number of times we received a usable UPnP response. + metricUPnPOK = clientmetric.NewCounter("portmap_upnp_ok") + + // metricUPnPUpdatedMeta counts the number of times + // we received a UPnP response with a new meta. + metricUPnPUpdatedMeta = clientmetric.NewCounter("portmap_upnp_updated_meta") +)