diff --git a/control/controlclient/direct.go b/control/controlclient/direct.go index 612ccbfc6..d0d65080a 100644 --- a/control/controlclient/direct.go +++ b/control/controlclient/direct.go @@ -751,22 +751,23 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*Netw c.mu.Unlock() nm := &NetworkMap{ - NodeKey: tailcfg.NodeKey(persist.PrivateNodeKey.Public()), - PrivateKey: persist.PrivateNodeKey, - MachineKey: machinePubKey, - Expiry: resp.Node.KeyExpiry, - Name: resp.Node.Name, - Addresses: resp.Node.Addresses, - Peers: resp.Peers, - LocalPort: localPort, - User: resp.Node.User, - UserProfiles: make(map[tailcfg.UserID]tailcfg.UserProfile), - Domain: resp.Domain, - DNS: resp.DNSConfig, - Hostinfo: resp.Node.Hostinfo, - PacketFilter: lastParsedPacketFilter, - DERPMap: lastDERPMap, - Debug: resp.Debug, + NodeKey: tailcfg.NodeKey(persist.PrivateNodeKey.Public()), + PrivateKey: persist.PrivateNodeKey, + MachineKey: machinePubKey, + Expiry: resp.Node.KeyExpiry, + Name: resp.Node.Name, + Addresses: resp.Node.Addresses, + Peers: resp.Peers, + LocalPort: localPort, + User: resp.Node.User, + UserProfiles: make(map[tailcfg.UserID]tailcfg.UserProfile), + Domain: resp.Domain, + DNS: resp.DNSConfig, + Hostinfo: resp.Node.Hostinfo, + PacketFilter: lastParsedPacketFilter, + CollectServices: resp.CollectServices, + DERPMap: lastDERPMap, + Debug: resp.Debug, } addUserProfile := func(userID tailcfg.UserID) { if _, dup := nm.UserProfiles[userID]; dup { diff --git a/control/controlclient/netmap.go b/control/controlclient/netmap.go index ab4caa83c..a79a5c780 100644 --- a/control/controlclient/netmap.go +++ b/control/controlclient/netmap.go @@ -39,6 +39,12 @@ type NetworkMap struct { Hostinfo tailcfg.Hostinfo PacketFilter []filter.Match + // CollectServices reports whether this node's Tailnet has + // requested that info about services be included in HostInfo. + // If set, Hostinfo.ShieldsUp blocks services collection; that + // takes precedence over this field. + CollectServices bool + // DERPMap is the last DERP server map received. It's reused // between updates and should not be modified. DERPMap *tailcfg.DERPMap diff --git a/ipn/local.go b/ipn/local.go index b3abdf9d1..ba2733b16 100644 --- a/ipn/local.go +++ b/ipn/local.go @@ -1015,16 +1015,18 @@ func (b *LocalBackend) parseWgStatusLocked(s *wgengine.Status) (ret EngineStatus return ret } -// shieldsAreUp returns whether user preferences currently request -// "shields up" mode, which disallows all inbound connections. -func (b *LocalBackend) shieldsAreUp() bool { +// shouldUploadServices reports whether this node should include services +// in Hostinfo. When the user preferences currently request "shields up" +// mode, all inbound connections are refused, so services are not reported. +// Otherwise, shouldUploadServices respects NetMap.CollectServices. +func (b *LocalBackend) shouldUploadServices() bool { b.mu.Lock() defer b.mu.Unlock() - if b.prefs == nil { - return true // default to safest setting + if b.prefs == nil || b.netMap == nil { + return false // default to safest setting } - return b.prefs.ShieldsUp + return !b.prefs.ShieldsUp && b.netMap.CollectServices } func (b *LocalBackend) SetCurrentUserID(uid string) { @@ -1124,9 +1126,7 @@ func (b *LocalBackend) SetPrefs(newp *Prefs) { // painstakingly constructing it in twelvety other places. func (b *LocalBackend) doSetHostinfoFilterServices(hi *tailcfg.Hostinfo) { hi2 := *hi - if b.shieldsAreUp() { - // No local services are available, since ShieldsUp will block - // them all. + if !b.shouldUploadServices() { hi2.Services = []tailcfg.Service{} } diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index 86ab028ef..df1cfcd60 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -665,6 +665,10 @@ type MapResponse struct { // forms are coming later. Domain string + // CollectServices reports whether this node's Tailnet has + // requested that info about services be included in HostInfo. + CollectServices bool `json:",omitempty"` + // PacketFilter are the firewall rules. // // For MapRequest.Version >= 6, a nil value means the most