tailcfg, net/portmapper, wgengine/magicsock: add NetInfo.HavePortMap

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/1474/head
Brad Fitzpatrick 4 years ago committed by Brad Fitzpatrick
parent 79d8288f0a
commit ef7bac2895

@ -63,6 +63,13 @@ type Client struct {
pmpMapping *pmpMapping // non-nil if we have a PMP mapping pmpMapping *pmpMapping // non-nil if we have a PMP mapping
} }
// HaveMapping reports whether we have a current valid mapping.
func (c *Client) HaveMapping() bool {
c.mu.Lock()
defer c.mu.Unlock()
return c.pmpMapping != nil && c.pmpMapping.useUntil.After(time.Now())
}
// pmpMapping is an already-created PMP mapping. // pmpMapping is an already-created PMP mapping.
// //
// All fields are immutable once created. // All fields are immutable once created.

@ -431,6 +431,10 @@ type NetInfo struct {
// WorkingUDP is whether UDP works. // WorkingUDP is whether UDP works.
WorkingUDP opt.Bool WorkingUDP opt.Bool
// HavePortMap is whether we have an existing portmap open
// (UPnP, PMP, or PCP).
HavePortMap bool `json:",omitempty"`
// UPnP is whether UPnP appears present on the LAN. // UPnP is whether UPnP appears present on the LAN.
// Empty means not checked. // Empty means not checked.
UPnP opt.Bool UPnP opt.Bool
@ -479,10 +483,14 @@ func (ni *NetInfo) String() string {
} }
func (ni *NetInfo) portMapSummary() string { func (ni *NetInfo) portMapSummary() string {
if ni.UPnP == "" && ni.PMP == "" && ni.PCP == "" { if !ni.HavePortMap && ni.UPnP == "" && ni.PMP == "" && ni.PCP == "" {
return "?" return "?"
} }
return conciseOptBool(ni.UPnP, "U") + conciseOptBool(ni.PMP, "M") + conciseOptBool(ni.PCP, "C") var prefix string
if ni.HavePortMap {
prefix = "active-"
}
return prefix + conciseOptBool(ni.UPnP, "U") + conciseOptBool(ni.PMP, "M") + conciseOptBool(ni.PCP, "C")
} }
func conciseOptBool(b opt.Bool, trueVal string) string { func conciseOptBool(b opt.Bool, trueVal string) string {
@ -512,6 +520,7 @@ func (ni *NetInfo) BasicallyEqual(ni2 *NetInfo) bool {
ni.HairPinning == ni2.HairPinning && ni.HairPinning == ni2.HairPinning &&
ni.WorkingIPv6 == ni2.WorkingIPv6 && ni.WorkingIPv6 == ni2.WorkingIPv6 &&
ni.WorkingUDP == ni2.WorkingUDP && ni.WorkingUDP == ni2.WorkingUDP &&
ni.HavePortMap == ni2.HavePortMap &&
ni.UPnP == ni2.UPnP && ni.UPnP == ni2.UPnP &&
ni.PMP == ni2.PMP && ni.PMP == ni2.PMP &&
ni.PCP == ni2.PCP && ni.PCP == ni2.PCP &&

@ -143,6 +143,7 @@ var _NetInfoNeedsRegeneration = NetInfo(struct {
HairPinning opt.Bool HairPinning opt.Bool
WorkingIPv6 opt.Bool WorkingIPv6 opt.Bool
WorkingUDP opt.Bool WorkingUDP opt.Bool
HavePortMap bool
UPnP opt.Bool UPnP opt.Bool
PMP opt.Bool PMP opt.Bool
PCP opt.Bool PCP opt.Bool

@ -375,6 +375,7 @@ func TestNetInfoFields(t *testing.T) {
"HairPinning", "HairPinning",
"WorkingIPv6", "WorkingIPv6",
"WorkingUDP", "WorkingUDP",
"HavePortMap",
"UPnP", "UPnP",
"PMP", "PMP",
"PCP", "PCP",

@ -628,6 +628,23 @@ func (c *Conn) setEndpoints(endpoints []string, reasons map[string]string) (chan
return true return true
} }
// setNetInfoHavePortMap updates NetInfo.HavePortMap to true.
func (c *Conn) setNetInfoHavePortMap() {
c.mu.Lock()
defer c.mu.Unlock()
if c.netInfoLast == nil {
// No NetInfo yet. Nothing to update.
return
}
if c.netInfoLast.HavePortMap {
// No change.
return
}
ni := c.netInfoLast.Clone()
ni.HavePortMap = true
c.callNetInfoCallbackLocked(ni)
}
func (c *Conn) updateNetInfo(ctx context.Context) (*netcheck.Report, error) { func (c *Conn) updateNetInfo(ctx context.Context) (*netcheck.Report, error) {
c.mu.Lock() c.mu.Lock()
dm := c.derpMap dm := c.derpMap
@ -658,6 +675,7 @@ func (c *Conn) updateNetInfo(ctx context.Context) (*netcheck.Report, error) {
UPnP: report.UPnP, UPnP: report.UPnP,
PMP: report.PMP, PMP: report.PMP,
PCP: report.PCP, PCP: report.PCP,
HavePortMap: c.portMapper.HaveMapping(),
} }
for rid, d := range report.RegionV4Latency { for rid, d := range report.RegionV4Latency {
ni.DERPLatency[fmt.Sprintf("%d-v4", rid)] = d.Seconds() ni.DERPLatency[fmt.Sprintf("%d-v4", rid)] = d.Seconds()
@ -752,6 +770,10 @@ func (c *Conn) callNetInfoCallback(ni *tailcfg.NetInfo) {
if ni.BasicallyEqual(c.netInfoLast) { if ni.BasicallyEqual(c.netInfoLast) {
return return
} }
c.callNetInfoCallbackLocked(ni)
}
func (c *Conn) callNetInfoCallbackLocked(ni *tailcfg.NetInfo) {
c.netInfoLast = ni c.netInfoLast = ni
if c.netInfoFunc != nil { if c.netInfoFunc != nil {
c.logf("[v1] magicsock: netInfo update: %+v", ni) c.logf("[v1] magicsock: netInfo update: %+v", ni)
@ -1016,6 +1038,7 @@ func (c *Conn) determineEndpoints(ctx context.Context) (ipPorts []string, reason
if ext, err := c.portMapper.CreateOrGetMapping(ctx); err == nil { if ext, err := c.portMapper.CreateOrGetMapping(ctx); err == nil {
addAddr(ext.String(), "portmap") addAddr(ext.String(), "portmap")
c.setNetInfoHavePortMap()
} else if !portmapper.IsNoMappingError(err) { } else if !portmapper.IsNoMappingError(err) {
c.logf("portmapper: %v", err) c.logf("portmapper: %v", err)
} }

Loading…
Cancel
Save