control/controlclient, ipn/ipnlocal, tailcfg: add MapResponse.PopBrowserURL

Updates #3802

Change-Id: I89481fc5782a0cc8084354706f8f28d94f197325
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/4257/head
Brad Fitzpatrick 3 years ago committed by Brad Fitzpatrick
parent 3ea6ddbb5f
commit f3b13604b3

@ -69,6 +69,7 @@ type Direct struct {
keepSharerAndUserSplit bool keepSharerAndUserSplit bool
skipIPForwardingCheck bool skipIPForwardingCheck bool
pinger Pinger pinger Pinger
popBrowser func(url string) // or nil
mu sync.Mutex // mutex guards the following fields mu sync.Mutex // mutex guards the following fields
serverKey key.MachinePublic // original ("legacy") nacl crypto_box-based public key serverKey key.MachinePublic // original ("legacy") nacl crypto_box-based public key
@ -100,9 +101,10 @@ type Options struct {
NewDecompressor func() (Decompressor, error) NewDecompressor func() (Decompressor, error)
KeepAlive bool KeepAlive bool
Logf logger.Logf Logf logger.Logf
HTTPTestClient *http.Client // optional HTTP client to use (for tests only) HTTPTestClient *http.Client // optional HTTP client to use (for tests only)
DebugFlags []string // debug settings to send to control DebugFlags []string // debug settings to send to control
LinkMonitor *monitor.Mon // optional link monitor LinkMonitor *monitor.Mon // optional link monitor
PopBrowserURL func(url string) // optional func to open browser
// KeepSharerAndUserSplit controls whether the client // KeepSharerAndUserSplit controls whether the client
// understands Node.Sharer. If false, the Sharer is mapped to the User. // understands Node.Sharer. If false, the Sharer is mapped to the User.
@ -198,6 +200,7 @@ func NewDirect(opts Options) (*Direct, error) {
linkMon: opts.LinkMonitor, linkMon: opts.LinkMonitor,
skipIPForwardingCheck: opts.SkipIPForwardingCheck, skipIPForwardingCheck: opts.SkipIPForwardingCheck,
pinger: opts.Pinger, pinger: opts.Pinger,
popBrowser: opts.PopBrowserURL,
} }
if opts.Hostinfo == nil { if opts.Hostinfo == nil {
c.SetHostinfo(hostinfo.New()) c.SetHostinfo(hostinfo.New())
@ -849,7 +852,15 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netm
metricMapResponsePings.Add(1) metricMapResponsePings.Add(1)
go answerPing(c.logf, c.httpc, pr) go answerPing(c.logf, c.httpc, pr)
} }
if u := resp.PopBrowserURL; u != "" && u != sess.lastPopBrowserURL {
sess.lastPopBrowserURL = u
if c.popBrowser != nil {
c.logf("netmap: control says to open URL %v; opening...", u)
c.popBrowser(u)
} else {
c.logf("netmap: control says to open URL %v; no popBrowser func", u)
}
}
if resp.ControlTime != nil && !resp.ControlTime.IsZero() { if resp.ControlTime != nil && !resp.ControlTime.IsZero() {
c.logf.JSON(1, "controltime", resp.ControlTime.UTC()) c.logf.JSON(1, "controltime", resp.ControlTime.UTC())
} }
@ -858,6 +869,7 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netm
} else { } else {
vlogf("netmap: got new map") vlogf("netmap: got new map")
} }
select { select {
case timeoutReset <- struct{}{}: case timeoutReset <- struct{}{}:
vlogf("netmap: sent timer reset") vlogf("netmap: sent timer reset")

@ -44,6 +44,7 @@ type mapSession struct {
previousPeers []*tailcfg.Node // for delta-purposes previousPeers []*tailcfg.Node // for delta-purposes
lastDomain string lastDomain string
lastHealth []string lastHealth []string
lastPopBrowserURL string
// netMapBuilding is non-nil during a netmapForResponse call, // netMapBuilding is non-nil during a netmapForResponse call,
// containing the value to be returned, once fully populated. // containing the value to be returned, once fully populated.

@ -973,6 +973,7 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
DebugFlags: debugFlags, DebugFlags: debugFlags,
LinkMonitor: b.e.GetLinkMonitor(), LinkMonitor: b.e.GetLinkMonitor(),
Pinger: b.e, Pinger: b.e,
PopBrowserURL: b.tellClientToBrowseToURL,
// Don't warn about broken Linux IP forwarding when // Don't warn about broken Linux IP forwarding when
// netstack is being used. // netstack is being used.
@ -1370,12 +1371,18 @@ func (b *LocalBackend) popBrowserAuthNow() {
b.blockEngineUpdates(true) b.blockEngineUpdates(true)
b.stopEngineAndWait() b.stopEngineAndWait()
b.send(ipn.Notify{BrowseToURL: &url}) b.tellClientToBrowseToURL(url)
if b.State() == ipn.Running { if b.State() == ipn.Running {
b.enterState(ipn.Starting) b.enterState(ipn.Starting)
} }
} }
func (b *LocalBackend) tellClientToBrowseToURL(url string) {
if url != "" {
b.send(ipn.Notify{BrowseToURL: &url})
}
}
// For testing lazy machine key generation. // For testing lazy machine key generation.
var panicOnMachineKeyGeneration = envknob.Bool("TS_DEBUG_PANIC_MACHINE_KEY") var panicOnMachineKeyGeneration = envknob.Bool("TS_DEBUG_PANIC_MACHINE_KEY")

@ -65,7 +65,8 @@ type CapabilityVersion int
// 26: 2022-01-12: (nothing, just bumping for 1.20.0) // 26: 2022-01-12: (nothing, just bumping for 1.20.0)
// 27: 2022-02-18: start of SSHPolicy being respected // 27: 2022-02-18: start of SSHPolicy being respected
// 28: 2022-03-09: client can communicate over Noise. // 28: 2022-03-09: client can communicate over Noise.
const CurrentCapabilityVersion CapabilityVersion = 28 // 29: 2022-03-09: MapResponse.PopBrowserURL
const CurrentCapabilityVersion CapabilityVersion = 29
type StableID string type StableID string
@ -1221,7 +1222,7 @@ type PingRequest struct {
type MapResponse struct { type MapResponse struct {
// KeepAlive, if set, represents an empty message just to keep // KeepAlive, if set, represents an empty message just to keep
// the connection alive. When true, all other fields except // the connection alive. When true, all other fields except
// PingRequest are ignored. // PingRequest, ControlTime, and PopBrowserURL are ignored.
KeepAlive bool `json:",omitempty"` KeepAlive bool `json:",omitempty"`
// PingRequest, if non-empty, is a request to the client to // PingRequest, if non-empty, is a request to the client to
@ -1231,6 +1232,11 @@ type MapResponse struct {
// KeepAlive true or false). // KeepAlive true or false).
PingRequest *PingRequest `json:",omitempty"` PingRequest *PingRequest `json:",omitempty"`
// PopBrowserURL, if non-empty, is a URL for the client to
// open to complete an action. The client should dup suppress
// identical URLs and only open it once for the same URL.
PopBrowserURL string
// Networking // Networking
// Node describes the node making the map request. // Node describes the node making the map request.

Loading…
Cancel
Save