Multi network integration tests (#2464)
This commit is contained in:
parent
707438f25e
commit
603f3ad490
29 changed files with 2385 additions and 1449 deletions
|
@ -3,8 +3,12 @@ package util
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"tailscale.com/util/cmpver"
|
||||
)
|
||||
|
@ -46,3 +50,126 @@ func ParseLoginURLFromCLILogin(output string) (*url.URL, error) {
|
|||
|
||||
return loginURL, nil
|
||||
}
|
||||
|
||||
type TraceroutePath struct {
|
||||
// Hop is the current jump in the total traceroute.
|
||||
Hop int
|
||||
|
||||
// Hostname is the resolved hostname or IP address identifying the jump
|
||||
Hostname string
|
||||
|
||||
// IP is the IP address of the jump
|
||||
IP netip.Addr
|
||||
|
||||
// Latencies is a list of the latencies for this jump
|
||||
Latencies []time.Duration
|
||||
}
|
||||
|
||||
type Traceroute struct {
|
||||
// Hostname is the resolved hostname or IP address identifying the target
|
||||
Hostname string
|
||||
|
||||
// IP is the IP address of the target
|
||||
IP netip.Addr
|
||||
|
||||
// Route is the path taken to reach the target if successful. The list is ordered by the path taken.
|
||||
Route []TraceroutePath
|
||||
|
||||
// Success indicates if the traceroute was successful.
|
||||
Success bool
|
||||
|
||||
// Err contains an error if the traceroute was not successful.
|
||||
Err error
|
||||
}
|
||||
|
||||
// ParseTraceroute parses the output of the traceroute command and returns a Traceroute struct
|
||||
func ParseTraceroute(output string) (Traceroute, error) {
|
||||
lines := strings.Split(strings.TrimSpace(output), "\n")
|
||||
if len(lines) < 1 {
|
||||
return Traceroute{}, errors.New("empty traceroute output")
|
||||
}
|
||||
|
||||
// Parse the header line
|
||||
headerRegex := regexp.MustCompile(`traceroute to ([^ ]+) \(([^)]+)\)`)
|
||||
headerMatches := headerRegex.FindStringSubmatch(lines[0])
|
||||
if len(headerMatches) != 3 {
|
||||
return Traceroute{}, fmt.Errorf("parsing traceroute header: %s", lines[0])
|
||||
}
|
||||
|
||||
hostname := headerMatches[1]
|
||||
ipStr := headerMatches[2]
|
||||
ip, err := netip.ParseAddr(ipStr)
|
||||
if err != nil {
|
||||
return Traceroute{}, fmt.Errorf("parsing IP address %s: %w", ipStr, err)
|
||||
}
|
||||
|
||||
result := Traceroute{
|
||||
Hostname: hostname,
|
||||
IP: ip,
|
||||
Route: []TraceroutePath{},
|
||||
Success: false,
|
||||
}
|
||||
|
||||
// Parse each hop line
|
||||
hopRegex := regexp.MustCompile(`^\s*(\d+)\s+(?:([^ ]+) \(([^)]+)\)|(\*))(?:\s+(\d+\.\d+) ms)?(?:\s+(\d+\.\d+) ms)?(?:\s+(\d+\.\d+) ms)?`)
|
||||
|
||||
for i := 1; i < len(lines); i++ {
|
||||
matches := hopRegex.FindStringSubmatch(lines[i])
|
||||
if len(matches) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
hop, err := strconv.Atoi(matches[1])
|
||||
if err != nil {
|
||||
return Traceroute{}, fmt.Errorf("parsing hop number: %w", err)
|
||||
}
|
||||
|
||||
var hopHostname string
|
||||
var hopIP netip.Addr
|
||||
var latencies []time.Duration
|
||||
|
||||
// Handle hostname and IP
|
||||
if matches[2] != "" && matches[3] != "" {
|
||||
hopHostname = matches[2]
|
||||
hopIP, err = netip.ParseAddr(matches[3])
|
||||
if err != nil {
|
||||
return Traceroute{}, fmt.Errorf("parsing hop IP address %s: %w", matches[3], err)
|
||||
}
|
||||
} else if matches[4] == "*" {
|
||||
hopHostname = "*"
|
||||
// No IP for timeouts
|
||||
}
|
||||
|
||||
// Parse latencies
|
||||
for j := 5; j <= 7; j++ {
|
||||
if matches[j] != "" {
|
||||
ms, err := strconv.ParseFloat(matches[j], 64)
|
||||
if err != nil {
|
||||
return Traceroute{}, fmt.Errorf("parsing latency: %w", err)
|
||||
}
|
||||
latencies = append(latencies, time.Duration(ms*float64(time.Millisecond)))
|
||||
}
|
||||
}
|
||||
|
||||
path := TraceroutePath{
|
||||
Hop: hop,
|
||||
Hostname: hopHostname,
|
||||
IP: hopIP,
|
||||
Latencies: latencies,
|
||||
}
|
||||
|
||||
result.Route = append(result.Route, path)
|
||||
|
||||
// Check if we've reached the target
|
||||
if hopIP == ip {
|
||||
result.Success = true
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't reach the target, it's unsuccessful
|
||||
if !result.Success {
|
||||
result.Err = errors.New("traceroute did not reach target")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue