Compare commits

...

1 Commits

Author SHA1 Message Date
Brad Fitzpatrick
814375c127 control/controlclient: finish wiring up PingRequest TSMP support
Most of the code existed already but wasn't connected between two spots.

Updates tailscale/corp#754

Change-Id: I41c3386c4194bdcaabf4ce6b96eb6499ec0a513c
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-04-15 09:01:41 -07:00
2 changed files with 36 additions and 30 deletions

View File

@@ -850,7 +850,7 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netm
if pr := resp.PingRequest; pr != nil && c.isUniquePingRequest(pr) {
metricMapResponsePings.Add(1)
go answerPing(c.logf, c.httpc, pr)
go answerPing(c.logf, c.httpc, pr, c.pinger)
}
if u := resp.PopBrowserURL; u != "" && u != sess.lastPopBrowserURL {
sess.lastPopBrowserURL = u
@@ -1181,29 +1181,42 @@ func (c *Direct) isUniquePingRequest(pr *tailcfg.PingRequest) bool {
return true
}
func answerPing(logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest) {
func answerPing(logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest, pinger Pinger) {
if pr.URL == "" {
logf("invalid PingRequest with no URL")
return
}
if pr.Types == "" {
answerHeadPing(logf, c, pr)
return
}
for _, t := range strings.Split(pr.Types, ",") {
switch t {
case "TSMP":
go tsmpPing(logf, c, pr, pinger)
}
}
}
func answerHeadPing(logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest) {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "HEAD", pr.URL, nil)
if err != nil {
logf("http.NewRequestWithContext(%q): %v", pr.URL, err)
logf("answerHeadPing: NewRequestWithContext: %v", err)
return
}
if pr.Log {
logf("answerPing: sending ping to %v ...", pr.URL)
logf("answerHeadPing: sending HEAD ping to %v ...", pr.URL)
}
t0 := time.Now()
_, err = c.Do(req)
d := time.Since(t0).Round(time.Millisecond)
if err != nil {
logf("answerPing error: %v to %v (after %v)", err, pr.URL, d)
logf("answerHeadPing error: %v to %v (after %v)", err, pr.URL, d)
} else if pr.Log {
logf("answerPing complete to %v (after %v)", pr.URL, d)
logf("answerHeadPing complete to %v (after %v)", pr.URL, d)
}
}
@@ -1378,33 +1391,25 @@ func (c *Direct) DoNoiseRequest(req *http.Request) (*http.Response, error) {
// tsmpPing sends a Ping to pr.IP, and sends an http request back to pr.URL
// with ping response data.
func tsmpPing(logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest, pinger Pinger) error {
var err error
if pr.URL == "" {
return errors.New("invalid PingRequest with no URL")
func tsmpPing(logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest, pinger Pinger) {
if pr.URL == "" || pr.IP.IsZero() || pinger == nil {
return
}
if pr.IP.IsZero() {
return errors.New("PingRequest without IP")
}
if !strings.Contains(pr.Types, "TSMP") {
return fmt.Errorf("PingRequest with no TSMP in Types, got %q", pr.Types)
}
now := time.Now()
start := time.Now()
pinger.Ping(pr.IP, true, func(res *ipnstate.PingResult) {
// Currently does not check for error since we just return if it fails.
err = postPingResult(now, logf, c, pr, res)
postPingResult(start, logf, c, pr, res)
})
return err
}
func postPingResult(now time.Time, logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest, res *ipnstate.PingResult) error {
if res.Err != "" {
return errors.New(res.Err)
}
duration := time.Since(now)
func postPingResult(start time.Time, logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest, res *ipnstate.PingResult) error {
duration := time.Since(start).Round(time.Millisecond)
if pr.Log {
logf("TSMP ping to %v completed in %v seconds. pinger.Ping took %v seconds", pr.IP, res.LatencySeconds, duration.Seconds())
if res.Err == "" {
logf("TSMP ping to %v completed in %v. pinger.Ping took %v seconds", pr.IP, res.LatencySeconds, duration)
} else {
logf("TSMP ping to %v failed after %v: %v", pr.IP, duration, res.Err)
}
}
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
@@ -1414,7 +1419,7 @@ func postPingResult(now time.Time, logf logger.Logf, c *http.Client, pr *tailcfg
return err
}
// Send the results of the Ping, back to control URL.
req, err := http.NewRequestWithContext(ctx, "POST", pr.URL, bytes.NewBuffer(jsonPingRes))
req, err := http.NewRequestWithContext(ctx, "POST", pr.URL, bytes.NewReader(jsonPingRes))
if err != nil {
return fmt.Errorf("http.NewRequestWithContext(%q): %w", pr.URL, err)
}
@@ -1425,9 +1430,9 @@ func postPingResult(now time.Time, logf logger.Logf, c *http.Client, pr *tailcfg
_, err = c.Do(req)
d := time.Since(t0).Round(time.Millisecond)
if err != nil {
return fmt.Errorf("tsmpPing error: %w to %v (after %v)", err, pr.URL, d)
return fmt.Errorf("postPingResult error: %w to %v (after %v)", err, pr.URL, d)
} else if pr.Log {
logf("tsmpPing complete to %v (after %v)", pr.URL, d)
logf("postPingResult complete to %v (after %v)", pr.URL, d)
}
return nil
}

View File

@@ -67,7 +67,8 @@ type CapabilityVersion int
// 28: 2022-03-09: client can communicate over Noise.
// 29: 2022-03-21: MapResponse.PopBrowserURL
// 30: 2022-03-22: client can request id tokens.
const CurrentCapabilityVersion CapabilityVersion = 30
// 31: 2022-04-15: PingRequest TSMP support
const CurrentCapabilityVersion CapabilityVersion = 31
type StableID string