@ -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,8 +272,18 @@ 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 {
var dm * tailcfg . DERPMap
if d . derpMapURL == "local" {
var err error
dm , err = tsLocalClient . CurrentDERPMap ( ctx )
if err != nil {
return err
}
} else {
req , err := http . NewRequestWithContext ( ctx , "GET" , d . derpMapURL , nil )
req , err := http . NewRequestWithContext ( ctx , "GET" , d . derpMapURL , nil )
if err != nil {
if err != nil {
return nil
return nil
@ -290,10 +304,11 @@ func (d *derpProber) updateMap(ctx context.Context) error {
if res . StatusCode != 200 {
if res . StatusCode != 200 {
return fmt . Errorf ( "fetching %s: %s" , d . derpMapURL , res . Status )
return fmt . Errorf ( "fetching %s: %s" , d . derpMapURL , res . Status )
}
}
dm : = new ( tailcfg . DERPMap )
dm = new ( tailcfg . DERPMap )
if err := json . NewDecoder ( res . Body ) . Decode ( dm ) ; err != nil {
if err := json . NewDecoder ( res . Body ) . Decode ( dm ) ; err != nil {
return fmt . Errorf ( "decoding %s JSON: %v" , d . derpMapURL , err )
return fmt . Errorf ( "decoding %s JSON: %v" , d . derpMapURL , err )
}
}
}
d . Lock ( )
d . Lock ( )
defer d . Unlock ( )
defer d . Unlock ( )