cmd/derpprobe: support 'local' derpmap to get derp map via LocalAPI

To make it easier for people to monitor their custom DERP fleet.

Updates tailscale/corp#20654

Change-Id: Id8af22936a6d893cc7b6186d298ab794a2672524
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
icio/tsweb-nested-stdhandler
Brad Fitzpatrick 3 weeks ago committed by Brad Fitzpatrick
parent 6e106712f6
commit 8a11a43c28

@ -20,7 +20,7 @@ import (
) )
var ( var (
derpMapURL = flag.String("derp-map", "https://login.tailscale.com/derpmap/default", "URL to DERP map (https:// or file://)") derpMapURL = flag.String("derp-map", "https://login.tailscale.com/derpmap/default", "URL to DERP map (https:// or file://) or 'local' to use the local tailscaled's DERP map")
versionFlag = flag.Bool("version", false, "print version and exit") versionFlag = flag.Bool("version", false, "print version and exit")
listen = flag.String("listen", ":8030", "HTTP listen address") listen = flag.String("listen", ":8030", "HTTP listen address")
probeOnce = flag.Bool("once", false, "probe once and print results, then exit; ignores the listen flag") probeOnce = flag.Bool("once", false, "probe once and print results, then exit; ignores the listen flag")

@ -21,6 +21,7 @@ import (
"time" "time"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"tailscale.com/client/tailscale"
"tailscale.com/derp" "tailscale.com/derp"
"tailscale.com/derp/derphttp" "tailscale.com/derp/derphttp"
"tailscale.com/net/netmon" "tailscale.com/net/netmon"
@ -35,7 +36,7 @@ import (
// based on the current DERPMap. // based on the current DERPMap.
type derpProber struct { type derpProber struct {
p *Prober p *Prober
derpMapURL string derpMapURL string // or "local"
udpInterval time.Duration udpInterval time.Duration
meshInterval time.Duration meshInterval time.Duration
tlsInterval time.Duration tlsInterval time.Duration
@ -97,6 +98,9 @@ func WithTLSProbing(interval time.Duration) DERPOpt {
} }
// DERP creates a new derpProber. // DERP creates a new derpProber.
//
// If derpMapURL is "local", the DERPMap is fetched via
// the local machine's tailscaled.
func DERP(p *Prober, derpMapURL string, opts ...DERPOpt) (*derpProber, error) { func DERP(p *Prober, derpMapURL string, opts ...DERPOpt) (*derpProber, error) {
d := &derpProber{ d := &derpProber{
p: p, p: p,
@ -268,31 +272,42 @@ func (d *derpProber) getNodePair(n1, n2 string) (ret1, ret2 *tailcfg.DERPNode, _
return ret1, ret2, nil return ret1, ret2, nil
} }
var tsLocalClient tailscale.LocalClient
// updateMap refreshes the locally-cached DERP map. // updateMap refreshes the locally-cached DERP map.
func (d *derpProber) updateMap(ctx context.Context) error { func (d *derpProber) updateMap(ctx context.Context) error {
req, err := http.NewRequestWithContext(ctx, "GET", d.derpMapURL, nil) var dm *tailcfg.DERPMap
if err != nil { if d.derpMapURL == "local" {
return nil var err error
} dm, err = tsLocalClient.CurrentDERPMap(ctx)
res, err := httpOrFileClient.Do(req) if err != nil {
if err != nil { return err
d.Lock() }
defer d.Unlock() } else {
if d.lastDERPMap != nil && time.Since(d.lastDERPMapAt) < 10*time.Minute { req, err := http.NewRequestWithContext(ctx, "GET", d.derpMapURL, nil)
log.Printf("Error while fetching DERP map, using cached one: %s", err) if err != nil {
// Assume that control is restarting and use
// the same one for a bit.
return nil return nil
} }
return err res, err := httpOrFileClient.Do(req)
} if err != nil {
defer res.Body.Close() d.Lock()
if res.StatusCode != 200 { defer d.Unlock()
return fmt.Errorf("fetching %s: %s", d.derpMapURL, res.Status) if d.lastDERPMap != nil && time.Since(d.lastDERPMapAt) < 10*time.Minute {
} log.Printf("Error while fetching DERP map, using cached one: %s", err)
dm := new(tailcfg.DERPMap) // Assume that control is restarting and use
if err := json.NewDecoder(res.Body).Decode(dm); err != nil { // the same one for a bit.
return fmt.Errorf("decoding %s JSON: %v", d.derpMapURL, err) return nil
}
return err
}
defer res.Body.Close()
if res.StatusCode != 200 {
return fmt.Errorf("fetching %s: %s", d.derpMapURL, res.Status)
}
dm = new(tailcfg.DERPMap)
if err := json.NewDecoder(res.Body).Decode(dm); err != nil {
return fmt.Errorf("decoding %s JSON: %v", d.derpMapURL, err)
}
} }
d.Lock() d.Lock()

Loading…
Cancel
Save