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