ipn, ipn/ipnlocal: add Foreground field to ServeConfig

This PR adds a new field to the ServeConfig which maps
WatchIPNBus session ids to foreground serve configs.

The PR also adds a DeleteForegroundSession method to ensure the config
gets cleaned up on sessions ending.

Note this field is not currently used but will be in follow up work.

Updates #8489

Signed-off-by: Marwan Sulaiman <marwan@tailscale.com>
This commit is contained in:
Marwan Sulaiman 2023-09-05 14:33:18 -04:00 committed by Marwan Sulaiman
parent cb3b281e98
commit 45eeef244e
5 changed files with 41 additions and 0 deletions

View File

@ -76,6 +76,12 @@ func (src *ServeConfig) Clone() *ServeConfig {
}
}
dst.AllowFunnel = maps.Clone(src.AllowFunnel)
if dst.Foreground != nil {
dst.Foreground = map[string]*ServeConfig{}
for k, v := range src.Foreground {
dst.Foreground[k] = v.Clone()
}
}
return dst
}
@ -84,6 +90,7 @@ func (src *ServeConfig) Clone() *ServeConfig {
TCP map[uint16]*TCPPortHandler
Web map[HostPort]*WebServerConfig
AllowFunnel map[HostPort]bool
Foreground map[string]*ServeConfig
}{})
// Clone makes a deep copy of TCPPortHandler.

View File

@ -177,11 +177,18 @@ func (v ServeConfigView) AllowFunnel() views.Map[HostPort, bool] {
return views.MapOf(v.ж.AllowFunnel)
}
func (v ServeConfigView) Foreground() views.MapFn[string, *ServeConfig, ServeConfigView] {
return views.MapFnOf(v.ж.Foreground, func(t *ServeConfig) ServeConfigView {
return t.View()
})
}
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
var _ServeConfigViewNeedsRegeneration = ServeConfig(struct {
TCP map[uint16]*TCPPortHandler
Web map[HostPort]*WebServerConfig
AllowFunnel map[HostPort]bool
Foreground map[string]*ServeConfig
}{})
// View returns a readonly view of TCPPortHandler.

View File

@ -2014,6 +2014,8 @@ func (b *LocalBackend) WatchNotifications(ctx context.Context, mask ipn.NotifyWa
go b.pollRequestEngineStatus(ctx)
}
defer b.DeleteForegroundSession(sessionID) // TODO(marwan-at-work): check err
for {
select {
case <-ctx.Done():

View File

@ -218,7 +218,10 @@ func (b *LocalBackend) updateServeTCPPortNetMapAddrListenersLocked(ports []uint1
func (b *LocalBackend) SetServeConfig(config *ipn.ServeConfig) error {
b.mu.Lock()
defer b.mu.Unlock()
return b.setServeConfigLocked(config)
}
func (b *LocalBackend) setServeConfigLocked(config *ipn.ServeConfig) error {
prefs := b.pm.CurrentPrefs()
if config.IsFunnelOn() && prefs.ShieldsUp() {
return errors.New("Unable to turn on Funnel while shields-up is enabled")
@ -258,6 +261,20 @@ func (b *LocalBackend) ServeConfig() ipn.ServeConfigView {
return b.serveConfig
}
// DeleteForegroundSession deletes a ServeConfig's foreground session
// in the LocalBackend if it exists. It also ensures check, delete, and
// set operations happen within the same mutex lock to avoid any races.
func (b *LocalBackend) DeleteForegroundSession(sessionID string) error {
b.mu.Lock()
defer b.mu.Unlock()
if !b.serveConfig.Valid() || !b.serveConfig.Foreground().Has(sessionID) {
return nil
}
sc := b.serveConfig.AsStruct()
delete(sc.Foreground, sessionID)
return b.setServeConfigLocked(sc)
}
// StreamServe opens a stream to write any incoming connections made
// to the given HostPort out to the listening io.Writer.
//

View File

@ -37,6 +37,14 @@ type ServeConfig struct {
// AllowFunnel is the set of SNI:port values for which funnel
// traffic is allowed, from trusted ingress peers.
AllowFunnel map[HostPort]bool `json:",omitempty"`
// Foreground is a map of an IPN Bus session id to a
// foreground serve config. Note that only TCP and Web
// are used inside the Foreground map.
//
// TODO(marwan-at-work): this is not currently
// used. Remove the TODO in the follow up PR.
Foreground map[string]*ServeConfig `json:",omitempty"`
}
// HostPort is an SNI name and port number, joined by a colon.