diff --git a/net/portmapper/portmapper.go b/net/portmapper/portmapper.go index a0ec0795a..0bf4e3028 100644 --- a/net/portmapper/portmapper.go +++ b/net/portmapper/portmapper.go @@ -492,8 +492,9 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) { } buf := make([]byte, 1500) + pcpHeard := false // true when we get any PCP response for { - if res.PCP && res.PMP && res.UPnP { + if pcpHeard && res.PMP && res.UPnP { // Nothing more to discover. return res, nil } @@ -515,13 +516,24 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) { } case pcpPort: // same as pmpPort if pres, ok := parsePCPResponse(buf[:n]); ok { - if pres.OpCode == pcpOpReply|pcpOpAnnounce && pres.ResultCode == pcpCodeOK { - c.logf("Got PCP response: epoch: %v", pres.Epoch) - res.PCP = true + if pres.OpCode == pcpOpReply|pcpOpAnnounce { + pcpHeard = true c.mu.Lock() c.pcpSawTime = time.Now() c.mu.Unlock() - continue + switch pres.ResultCode { + case pcpCodeOK: + c.logf("Got PCP response: epoch: %v", pres.Epoch) + res.PCP = true + continue + case pcpCodeNotAuthorized: + // A PCP service is running, but refuses to + // provide port mapping services. + res.PCP = false + continue + default: + // Fall through to unexpected log line. + } } c.logf("unexpected PCP probe response: %+v", pres) } @@ -546,7 +558,8 @@ const ( pcpVersion = 2 pcpPort = 5351 - pcpCodeOK = 0 + pcpCodeOK = 0 + pcpCodeNotAuthorized = 2 pcpOpReply = 0x80 // OR'd into request's op code on response pcpOpAnnounce = 0