From 2b437c55cac08c9026101329c84049276fee3b05 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Thu, 25 Jul 2024 17:58:52 +0200 Subject: [PATCH 01/46] feat: Improve traceroute Adds a couple of features to the traceroute check: - address of every hop - dns name, if available, of the hops - latency for that hop There have also been major performance improvements: - All targets are now checked concurrently - every hop is checked concurrently So now, instead of waiting for the slowest hop of every target in series, we parallelized as much as possible. We should now only have to wait for the slowest target + dns resolution. In my testing (with a local setup), the time per run with a few target was cut down from a minute-ish to a few seconds. Signed-off-by: Niklas Treml --- go.mod | 2 +- go.sum | 4 +- pkg/checks/traceroute/check.go | 179 ++++++++++ .../{traceroute_test.go => check_test.go} | 56 ++- pkg/checks/traceroute/traceroute.go | 328 ++++++++++-------- 5 files changed, 387 insertions(+), 182 deletions(-) create mode 100644 pkg/checks/traceroute/check.go rename pkg/checks/traceroute/{traceroute_test.go => check_test.go} (66%) diff --git a/go.mod b/go.mod index 3530c1da..e0df5905 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/caas-team/sparrow go 1.22 require ( - github.com/aeden/traceroute v0.0.0-20210211061815-03f5f7cb7908 github.com/getkin/kin-openapi v0.120.0 github.com/go-chi/chi/v5 v5.0.14 github.com/google/go-cmp v0.6.0 @@ -11,6 +10,7 @@ require ( github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 + golang.org/x/net v0.23.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index a1db7cc1..c170a72e 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/aeden/traceroute v0.0.0-20210211061815-03f5f7cb7908 h1:6suDyKbvZ5r2G/gblQLV9Cdv7rdqNlUxsRXpLOF0rKM= -github.com/aeden/traceroute v0.0.0-20210211061815-03f5f7cb7908/go.mod h1:HPBB/4vaPt7NcN9l72/+IwsmDVQsa6AWM6ZDKJCLB9U= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -102,6 +100,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= diff --git a/pkg/checks/traceroute/check.go b/pkg/checks/traceroute/check.go new file mode 100644 index 00000000..8a795398 --- /dev/null +++ b/pkg/checks/traceroute/check.go @@ -0,0 +1,179 @@ +package traceroute + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/caas-team/sparrow/internal/logger" + "github.com/caas-team/sparrow/pkg/checks" + "github.com/getkin/kin-openapi/openapi3" + "github.com/prometheus/client_golang/prometheus" +) + +var _ checks.Check = (*Traceroute)(nil) + +const CheckName = "traceroute" + +type Target struct { + // The address of the target to traceroute to. Can be a DNS name or an IP address + Addr string `json:"addr" yaml:"addr" mapstructure:"addr"` + // The port to traceroute to + Port uint16 `json:"port" yaml:"port" mapstructure:"port"` +} + +func NewCheck() checks.Check { + return &Traceroute{ + CheckBase: checks.CheckBase{ + Mu: sync.Mutex{}, + DoneChan: make(chan struct{}), + }, + config: Config{}, + traceroute: TraceRoute, + } +} + +type Traceroute struct { + checks.CheckBase + config Config + traceroute tracerouteFactory +} + +type tracerouteFactory func(dest string, port, timeout, retries, maxHops int) ([]Hop, error) + +type result struct { + // The minimum number of hops required to reach the target + NumHops int + // The path taken to the destination + Hops []Hop +} + +// Run runs the check in a loop sending results to the provided channel +func (tr *Traceroute) Run(ctx context.Context, cResult chan checks.ResultDTO) error { + ctx, cancel := logger.NewContextWithLogger(ctx) + defer cancel() + log := logger.FromContext(ctx) + + log.Info("Starting traceroute check", "interval", tr.config.Interval.String()) + for { + select { + case <-ctx.Done(): + log.Error("Context canceled", "error", ctx.Err()) + return ctx.Err() + case <-tr.DoneChan: + return nil + case <-time.After(tr.config.Interval): + fmt.Println("Running traceroute") + res := tr.check(ctx) + + fmt.Println(res) + + cResult <- checks.ResultDTO{ + Name: tr.Name(), + Result: &checks.Result{ + Data: res, + Timestamp: time.Now(), + }, + } + log.Debug("Successfully finished traceroute check run") + } + } +} + +// GetConfig returns the current configuration of the check +func (tr *Traceroute) GetConfig() checks.Runtime { + tr.Mu.Lock() + defer tr.Mu.Unlock() + return &tr.config +} + +func (tr *Traceroute) check(ctx context.Context) map[string]result { + res := make(map[string]result) + log := logger.FromContext(ctx) + + type internalResult struct { + addr string + res result + } + + cResult := make(chan internalResult, len(tr.config.Targets)) + var wg sync.WaitGroup + + wg.Add(len(tr.config.Targets)) + for _, t := range tr.config.Targets { + go func(t Target) { + defer wg.Done() + l := log.With("target", t.Addr) + l.Debug("Running traceroute") + + start := time.Now() + trace, err := tr.traceroute(t.Addr, int(t.Port), int(tr.config.Timeout/time.Millisecond), tr.config.Retries, tr.config.MaxHops) + duration := time.Since(start) + if err != nil { + l.Error("Error running traceroute", "error", err) + } + + l.Debug("Ran traceroute", "result", trace, "duration", duration) + r := result{ + Hops: trace, + } + + for i, h := range trace { + if h.Reached { + r.NumHops = i + 1 + break + } + } + + cResult <- internalResult{addr: t.Addr, res: r} + }(t) + } + + wg.Wait() + close(cResult) + + for r := range cResult { + res[r.addr] = r.res + } + + return res +} + +// Shutdown is called once when the check is unregistered or sparrow shuts down +func (tr *Traceroute) Shutdown() { + tr.DoneChan <- struct{}{} + close(tr.DoneChan) +} + +// SetConfig is called once when the check is registered +// This is also called while the check is running, if the remote config is updated +// This should return an error if the config is invalid +func (tr *Traceroute) SetConfig(cfg checks.Runtime) error { + if cfg, ok := cfg.(*Config); ok { + tr.Mu.Lock() + defer tr.Mu.Unlock() + tr.config = *cfg + return nil + } + + return checks.ErrConfigMismatch{ + Expected: CheckName, + Current: cfg.For(), + } +} + +// Schema returns an openapi3.SchemaRef of the result type returned by the check +func (tr *Traceroute) Schema() (*openapi3.SchemaRef, error) { + return checks.OpenapiFromPerfData(map[string]result{}) +} + +// GetMetricCollectors allows the check to provide prometheus metric collectors +func (tr *Traceroute) GetMetricCollectors() []prometheus.Collector { + return []prometheus.Collector{} +} + +// Name returns the name of the check +func (tr *Traceroute) Name() string { + return CheckName +} diff --git a/pkg/checks/traceroute/traceroute_test.go b/pkg/checks/traceroute/check_test.go similarity index 66% rename from pkg/checks/traceroute/traceroute_test.go rename to pkg/checks/traceroute/check_test.go index 608e1c78..d0e7a152 100644 --- a/pkg/checks/traceroute/traceroute_test.go +++ b/pkg/checks/traceroute/check_test.go @@ -9,7 +9,6 @@ import ( "github.com/google/go-cmp/cmp" - "github.com/aeden/traceroute" "github.com/caas-team/sparrow/pkg/checks" ) @@ -25,12 +24,12 @@ func TestCheck(t *testing.T) { want: map[string]result{ "8.8.8.8": { NumHops: 5, - Hops: []hop{ - {Addr: "0.0.0.0", Latency: 0 * time.Second, Success: false}, - {Addr: "0.0.0.1", Latency: 1 * time.Second, Success: false}, - {Addr: "0.0.0.2", Latency: 2 * time.Second, Success: false}, - {Addr: "0.0.0.3", Latency: 3 * time.Second, Success: false}, - {Addr: "google-public-dns-a.google.com", Latency: 69 * time.Second, Success: true}, + Hops: []Hop{ + {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.0")}, Latency: 0 * time.Second, Reached: false}, + {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.1")}, Latency: 1 * time.Second, Reached: false}, + {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.2")}, Latency: 2 * time.Second, Reached: false}, + {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.3")}, Latency: 3 * time.Second, Reached: false}, + {Name: "google-public-dns-a.google.com", Latency: 69 * time.Second, Reached: true}, }, }, }, @@ -39,7 +38,7 @@ func TestCheck(t *testing.T) { name: "Traceroute internal error fails silently", c: newForTest(returnError(&net.DNSError{Err: "no such host", Name: "google.com", IsNotFound: true}), []string{"google.com"}), want: map[string]result{ - "google.com": {Hops: []hop{}}, + "google.com": {Hops: []Hop{}}, }, }, } @@ -73,36 +72,35 @@ func newForTest(f tracerouteFactory, targets []string) *Traceroute { // success produces a tracerouteFactory that returns a traceroute result with nHops hops func success(nHops int) tracerouteFactory { - return func(dest string, port, timeout, retries, maxHops int) (traceroute.TracerouteResult, error) { - hops := make([]traceroute.TracerouteHop, nHops) + return func(dest string, port, timeout, retries, maxHops int) ([]Hop, error) { + hops := make([]Hop, nHops) for i := 0; i < nHops-1; i++ { - hops[i] = traceroute.TracerouteHop{ - Success: false, - N: nHops, - Host: ipFromInt(i), - ElapsedTime: time.Duration(i) * time.Second, - TTL: i, + hops[i] = Hop{ + Latency: time.Second * time.Duration(i), + Addr: &net.TCPAddr{IP: net.ParseIP(ipFromInt(i))}, + Name: "", + Ttl: i + 1, + Reached: false, } } - hops[nHops-1] = traceroute.TracerouteHop{ - Success: true, - Address: [4]byte{8, 8, 8, 8}, - N: nHops, - Host: "google-public-dns-a.google.com", - ElapsedTime: 69 * time.Second, - TTL: nHops, + hops[nHops-1] = Hop{ + Latency: 69 * time.Second, + Addr: &net.TCPAddr{ + IP: net.ParseIP("123.0.0.123"), + Port: 53, + }, + Name: "google-public-dns-a.google.com", + Ttl: nHops, + Reached: true, } - return traceroute.TracerouteResult{ - DestinationAddress: hops[nHops-1].Address, - Hops: hops, - }, nil + return hops, nil } } func returnError(err error) tracerouteFactory { - return func(dest string, port, timeout, retries, maxHops int) (traceroute.TracerouteResult, error) { - return traceroute.TracerouteResult{}, err + return func(dest string, port, timeout, retries, maxHops int) ([]Hop, error) { + return []Hop{}, err } } diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 3cc64269..7be80d65 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -1,198 +1,226 @@ package traceroute import ( - "context" + "errors" + "fmt" + "math/rand" + "net" + "slices" "sync" + "syscall" "time" - "github.com/aeden/traceroute" - "github.com/caas-team/sparrow/internal/logger" - "github.com/caas-team/sparrow/pkg/checks" - "github.com/getkin/kin-openapi/openapi3" - "github.com/prometheus/client_golang/prometheus" + "golang.org/x/net/icmp" + "golang.org/x/net/ipv4" ) -var _ checks.Check = (*Traceroute)(nil) - -const CheckName = "traceroute" - -type Target struct { - // The address of the target to traceroute to. Can be a DNS name or an IP address - Addr string `json:"addr" yaml:"addr" mapstructure:"addr"` - // The port to traceroute to - Port uint16 `json:"port" yaml:"port" mapstructure:"port"` +// randomPort returns a random port in the interval [ 30_000, 40_000 [ +func randomPort() int { + return rand.Intn(10_000) + 30_000 } -func NewCheck() checks.Check { - return &Traceroute{ - CheckBase: checks.CheckBase{ - Mu: sync.Mutex{}, - DoneChan: make(chan struct{}), - }, - config: Config{}, - traceroute: newTraceroute, - } -} +func tcpHop(addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error) { + for { + port := randomPort() + // Dialer with control function to set IP_TTL + dialer := net.Dialer{ + LocalAddr: &net.TCPAddr{ + Port: port, + }, + Timeout: timeout, + Control: func(network, address string, c syscall.RawConn) error { + var opErr error + if err := c.Control(func(fd uintptr) { + opErr = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TTL, ttl) + }); err != nil { + return err + } + return opErr + }, + } -type Traceroute struct { - checks.CheckBase - config Config - traceroute tracerouteFactory + // Attempt to connect to the target host + conn, err := dialer.Dial("tcp", addr.String()) + if !errors.Is(err, syscall.Errno(syscall.EADDRINUSE)) { + return conn, port, err + } + } } -type tracerouteFactory func(dest string, port, timeout, retries, maxHops int) (traceroute.TracerouteResult, error) - -func newTraceroute(dest string, port, timeout, retries, maxHops int) (traceroute.TracerouteResult, error) { - opts := &traceroute.TracerouteOptions{} - opts.SetTimeoutMs(timeout) - opts.SetRetries(retries) - opts.SetMaxHops(maxHops) - opts.SetPort(port) - return traceroute.Traceroute(dest, opts) -} +// readIcmpMessage reads a packet from the provided icmp Connection. If the packet is 'Time Exceeded', +// it reads the address of the router that dropped created the icmp packet. It also reads the source port +// from the payload and finds the source port used by the previous tcp connection. If any error is returned, +// an icmp packet was either not received, or the received packet was not a time exceeded. +func readIcmpMessage(icmpListener *icmp.PacketConn, timeout time.Duration) (int, net.Addr, error) { + // Expected to fail due to TTL expiry, listen for ICMP response + icmpListener.SetReadDeadline(time.Now().Add(timeout)) + buffer := make([]byte, 1500) // Standard MTU size + n, routerAddr, err := icmpListener.ReadFrom(buffer) + if err != nil { + // we probably timed out so return + return 0, nil, fmt.Errorf("Failed to read from icmp connection: %w", err) + } -type result struct { - // The minimum number of hops required to reach the target - NumHops int - // The path taken to the destination - Hops []hop -} + // Parse the ICMP message + msg, err := icmp.ParseMessage(ipv4.ICMPTypeTimeExceeded.Protocol(), buffer[:n]) + if err != nil { + return 0, nil, err + } -type hop struct { - Addr string - Latency time.Duration - Success bool -} + // Ensure the message is an ICMP Time Exceeded message + if msg.Type != ipv4.ICMPTypeTimeExceeded { + return 0, nil, errors.New("Message is not 'Time Exceeded'") + } -// Run runs the check in a loop sending results to the provided channel -func (tr *Traceroute) Run(ctx context.Context, cResult chan checks.ResultDTO) error { - ctx, cancel := logger.NewContextWithLogger(ctx) - defer cancel() - log := logger.FromContext(ctx) + // The first 20 bytes of Data are the IP header, so the TCP segment starts at byte 20 + tcpSegment := msg.Body.(*icmp.TimeExceeded).Data[20:] - log.Info("Starting traceroute check", "interval", tr.config.Interval.String()) - for { - select { - case <-ctx.Done(): - log.Error("Context canceled", "error", ctx.Err()) - return ctx.Err() - case <-tr.DoneChan: - return nil - case <-time.After(tr.config.Interval): - res := tr.check(ctx) - - cResult <- checks.ResultDTO{ - Name: tr.Name(), - Result: &checks.Result{ - Data: res, - Timestamp: time.Now(), - }, - } - log.Debug("Successfully finished traceroute check run") - } - } -} + // Extract the source port from the TCP segment + destPort := int(tcpSegment[0])<<8 + int(tcpSegment[1]) -// GetConfig returns the current configuration of the check -func (tr *Traceroute) GetConfig() checks.Runtime { - tr.Mu.Lock() - defer tr.Mu.Unlock() - return &tr.config + return destPort, routerAddr, nil } +func TraceRoute(host string, port, timeout, retries, maxHops int) ([]Hop, error) { + // TraceRoute performs a traceroute to the specified host using TCP and listens for ICMP Time Exceeded messages using datagram-oriented ICMP. + // func TraceRoute(host string, port int, maxHops int, timeout time.Duration) ([]Hop, error) { + var hops []Hop -func (tr *Traceroute) check(ctx context.Context) map[string]result { - res := make(map[string]result) - log := logger.FromContext(ctx) + toDuration := time.Duration(timeout) * time.Second - type internalResult struct { - addr string - res result + addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port)) + if err != nil { + return nil, err } + results := make(chan Hop, maxHops) var wg sync.WaitGroup - cResult := make(chan internalResult, len(tr.config.Targets)) - for _, t := range tr.config.Targets { + for ttl := 1; ttl <= maxHops; ttl++ { wg.Add(1) - go func(t Target) { - l := log.With("target", t.Addr) + go func() { defer wg.Done() - l.Debug("Running traceroute") - start := time.Now() - trace, err := tr.traceroute(t.Addr, int(t.Port), int(tr.config.Timeout/time.Millisecond), tr.config.Retries, tr.config.MaxHops) - duration := time.Since(start) - if err != nil { - l.Error("Error running traceroute", "error", err) - } + traceroute(results, addr, ttl, toDuration) + }() + } - l.Debug("Ran traceroute", "result", trace, "duration", duration) + wg.Wait() + close(results) - r := result{ - NumHops: len(trace.Hops), - Hops: []hop{}, - } - - for _, h := range trace.Hops { - r.Hops = append(r.Hops, hop{ - Addr: h.Host, - Latency: h.ElapsedTime, - Success: h.Success, - }) - } - cResult <- internalResult{addr: t.Addr, res: r} - }(t) + for r := range results { + hops = append(hops, r) } - log.Debug("Waiting for traceroute checks to finish") + slices.SortFunc(hops, func(a, b Hop) int { + return a.Ttl - b.Ttl + }) - go func() { - wg.Wait() - close(cResult) - }() + PrintHops(hops) - log.Debug("All traceroute checks finished") + return hops, nil +} - for r := range cResult { - res[r.addr] = r.res +func ipFromAddr(remoteAddr net.Addr) net.IP { + switch addr := remoteAddr.(type) { + case *net.UDPAddr: + return addr.IP + case *net.TCPAddr: + return addr.IP + case *net.IPAddr: + return addr.IP } - - return res + return nil } -// Shutdown is called once when the check is unregistered or sparrow shuts down -func (tr *Traceroute) Shutdown() { - tr.DoneChan <- struct{}{} - close(tr.DoneChan) -} +func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) error { + icmpListener, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") + if err != nil { + return err + } + defer icmpListener.Close() + start := time.Now() + conn, clientPort, err := tcpHop(addr, ttl, timeout) + latency := time.Since(start) + if err == nil { + conn.Close() + + ipaddr := ipFromAddr(addr) + names, _ := net.LookupAddr(ipaddr.String()) // we don't care about this lookup failling + + name := "" + if len(names) >= 1 { + name = names[0] + } -// SetConfig is called once when the check is registered -// This is also called while the check is running, if the remote config is updated -// This should return an error if the config is invalid -func (tr *Traceroute) SetConfig(cfg checks.Runtime) error { - if cfg, ok := cfg.(*Config); ok { - tr.Mu.Lock() - defer tr.Mu.Unlock() - tr.config = *cfg + results <- Hop{ + Latency: latency, + Ttl: ttl, + Addr: addr, + Name: name, + Reached: true, + } return nil } - return checks.ErrConfigMismatch{ - Expected: CheckName, - Current: cfg.For(), + found := false + deadline := time.Now().Add(5 * time.Second) + + for time.Now().Unix() < deadline.Unix() && !found { + gotPort, addr, err := readIcmpMessage(icmpListener, timeout) + if err != nil { + results <- Hop{ + Latency: latency, + Ttl: ttl, + Reached: false, + } + return nil + } + + // Check if the destination port matches our dialer's source port + if gotPort == clientPort { + ipaddr := ipFromAddr(addr) + names, _ := net.LookupAddr(ipaddr.String()) // we don't really care if this lookup works, so ignore the error + + name := "" + if len(names) >= 1 { + name = names[0] + } + + results <- Hop{ + Latency: latency, + Ttl: ttl, + Addr: addr, + Reached: false, + Name: name, + } + found = true + break + } + } + if !found { + results <- Hop{ + Latency: latency, + Ttl: ttl, + Reached: false, + } } -} -// Schema returns an openapi3.SchemaRef of the result type returned by the check -func (tr *Traceroute) Schema() (*openapi3.SchemaRef, error) { - return checks.OpenapiFromPerfData[map[string]result](map[string]result{}) + return nil } -// GetMetricCollectors allows the check to provide prometheus metric collectors -func (tr *Traceroute) GetMetricCollectors() []prometheus.Collector { - return []prometheus.Collector{} +type Hop struct { + Latency time.Duration + Addr net.Addr + Name string + Ttl int + Reached bool } -// Name returns the name of the check -func (tr *Traceroute) Name() string { - return CheckName +func PrintHops(hops []Hop) { + for _, hop := range hops { + fmt.Printf("%d %s %s %v ", hop.Ttl, hop.Addr, hop.Name, hop.Latency) + if hop.Reached { + fmt.Print("( Reached )") + } + fmt.Println() + } } From 1c9b5e44e1d160c19262ba2eed0cb59d44a3a6d7 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Thu, 25 Jul 2024 18:15:23 +0200 Subject: [PATCH 02/46] chore: add test setup This is what I used to test traceroute locally. the tool is called kathara and it allows setting up simple or complex networks completely based on docker containers. I am in awe of how amazing this is Signed-off-by: Niklas Treml --- pkg/checks/traceroute/test-lab/.gitignore | 1 + .../traceroute/test-lab/as100r1.startup | 5 ++ .../test-lab/as100r1/etc/quagga/bgpd.conf | 41 +++++++++++ .../test-lab/as100r1/etc/quagga/daemons | 13 ++++ .../test-lab/as100r1/etc/quagga/ripd.conf | 9 +++ .../traceroute/test-lab/as100r2.startup | 4 ++ .../test-lab/as100r2/etc/quagga/daemons | 13 ++++ .../test-lab/as100r2/etc/quagga/ripd.conf | 10 +++ .../traceroute/test-lab/as100r3.startup | 4 ++ .../test-lab/as100r3/etc/quagga/daemons | 13 ++++ .../test-lab/as100r3/etc/quagga/ripd.conf | 10 +++ pkg/checks/traceroute/test-lab/as1r1.startup | 4 ++ .../test-lab/as1r1/etc/quagga/bgpd.conf | 36 ++++++++++ .../test-lab/as1r1/etc/quagga/daemons | 13 ++++ .../traceroute/test-lab/as200r1.startup | 4 ++ .../test-lab/as200r1/etc/quagga/bgpd.conf | 27 +++++++ .../test-lab/as200r1/etc/quagga/daemons | 13 ++++ pkg/checks/traceroute/test-lab/as20r1.startup | 5 ++ .../test-lab/as20r1/etc/quagga/bgpd.conf | 49 +++++++++++++ .../test-lab/as20r1/etc/quagga/daemons | 13 ++++ .../test-lab/as20r1/etc/quagga/ospfd.conf | 12 ++++ pkg/checks/traceroute/test-lab/as20r2.startup | 4 ++ .../test-lab/as20r2/etc/quagga/bgpd.conf | 34 +++++++++ .../test-lab/as20r2/etc/quagga/daemons | 13 ++++ .../test-lab/as20r2/etc/quagga/ospfd.conf | 12 ++++ pkg/checks/traceroute/test-lab/as20r3.startup | 3 + .../test-lab/as20r3/etc/quagga/bgpd.conf | 26 +++++++ .../test-lab/as20r3/etc/quagga/daemons | 13 ++++ .../test-lab/as20r3/etc/quagga/ospfd.conf | 12 ++++ pkg/checks/traceroute/test-lab/as30r1.startup | 5 ++ .../test-lab/as30r1/etc/quagga/bgpd.conf | 36 ++++++++++ .../test-lab/as30r1/etc/quagga/daemons | 13 ++++ pkg/checks/traceroute/test-lab/client.startup | 2 + .../test-lab/client/etc/resolv.conf | 1 + pkg/checks/traceroute/test-lab/itdns.startup | 3 + .../traceroute/test-lab/itdns/etc/bind/db.it | 13 ++++ .../test-lab/itdns/etc/bind/db.root | 2 + .../test-lab/itdns/etc/bind/named.conf | 11 +++ .../itdns/etc/bind/named.conf.options | 3 + pkg/checks/traceroute/test-lab/lab.conf | 70 +++++++++++++++++++ pkg/checks/traceroute/test-lab/ldns.startup | 3 + .../traceroute/test-lab/ldns/etc/bind/db.root | 2 + .../test-lab/ldns/etc/bind/named.conf | 6 ++ .../test-lab/ldns/etc/bind/named.conf.options | 5 ++ pkg/checks/traceroute/test-lab/r3dns.startup | 3 + .../test-lab/r3dns/etc/bind/db.it.uniroma3 | 11 +++ .../test-lab/r3dns/etc/bind/db.root | 2 + .../test-lab/r3dns/etc/bind/named.conf | 11 +++ .../r3dns/etc/bind/named.conf.options | 3 + .../traceroute/test-lab/rootdns.startup | 3 + .../test-lab/rootdns/etc/bind/db.root | 14 ++++ .../test-lab/rootdns/etc/bind/named.conf | 6 ++ .../rootdns/etc/bind/named.conf.options | 3 + .../traceroute/test-lab/webserver.startup | 3 + .../webserver/var/www/html/index.html | 14 ++++ .../test-lab/webserver/var/www/index.html | 14 ++++ pkg/checks/traceroute/traceroute.go | 1 + 57 files changed, 679 insertions(+) create mode 100644 pkg/checks/traceroute/test-lab/.gitignore create mode 100644 pkg/checks/traceroute/test-lab/as100r1.startup create mode 100644 pkg/checks/traceroute/test-lab/as100r1/etc/quagga/bgpd.conf create mode 100644 pkg/checks/traceroute/test-lab/as100r1/etc/quagga/daemons create mode 100644 pkg/checks/traceroute/test-lab/as100r1/etc/quagga/ripd.conf create mode 100644 pkg/checks/traceroute/test-lab/as100r2.startup create mode 100644 pkg/checks/traceroute/test-lab/as100r2/etc/quagga/daemons create mode 100644 pkg/checks/traceroute/test-lab/as100r2/etc/quagga/ripd.conf create mode 100644 pkg/checks/traceroute/test-lab/as100r3.startup create mode 100644 pkg/checks/traceroute/test-lab/as100r3/etc/quagga/daemons create mode 100644 pkg/checks/traceroute/test-lab/as100r3/etc/quagga/ripd.conf create mode 100644 pkg/checks/traceroute/test-lab/as1r1.startup create mode 100644 pkg/checks/traceroute/test-lab/as1r1/etc/quagga/bgpd.conf create mode 100644 pkg/checks/traceroute/test-lab/as1r1/etc/quagga/daemons create mode 100644 pkg/checks/traceroute/test-lab/as200r1.startup create mode 100644 pkg/checks/traceroute/test-lab/as200r1/etc/quagga/bgpd.conf create mode 100644 pkg/checks/traceroute/test-lab/as200r1/etc/quagga/daemons create mode 100644 pkg/checks/traceroute/test-lab/as20r1.startup create mode 100644 pkg/checks/traceroute/test-lab/as20r1/etc/quagga/bgpd.conf create mode 100644 pkg/checks/traceroute/test-lab/as20r1/etc/quagga/daemons create mode 100644 pkg/checks/traceroute/test-lab/as20r1/etc/quagga/ospfd.conf create mode 100644 pkg/checks/traceroute/test-lab/as20r2.startup create mode 100644 pkg/checks/traceroute/test-lab/as20r2/etc/quagga/bgpd.conf create mode 100644 pkg/checks/traceroute/test-lab/as20r2/etc/quagga/daemons create mode 100644 pkg/checks/traceroute/test-lab/as20r2/etc/quagga/ospfd.conf create mode 100644 pkg/checks/traceroute/test-lab/as20r3.startup create mode 100644 pkg/checks/traceroute/test-lab/as20r3/etc/quagga/bgpd.conf create mode 100644 pkg/checks/traceroute/test-lab/as20r3/etc/quagga/daemons create mode 100644 pkg/checks/traceroute/test-lab/as20r3/etc/quagga/ospfd.conf create mode 100644 pkg/checks/traceroute/test-lab/as30r1.startup create mode 100644 pkg/checks/traceroute/test-lab/as30r1/etc/quagga/bgpd.conf create mode 100644 pkg/checks/traceroute/test-lab/as30r1/etc/quagga/daemons create mode 100644 pkg/checks/traceroute/test-lab/client.startup create mode 100644 pkg/checks/traceroute/test-lab/client/etc/resolv.conf create mode 100644 pkg/checks/traceroute/test-lab/itdns.startup create mode 100644 pkg/checks/traceroute/test-lab/itdns/etc/bind/db.it create mode 100644 pkg/checks/traceroute/test-lab/itdns/etc/bind/db.root create mode 100644 pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf create mode 100644 pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf.options create mode 100644 pkg/checks/traceroute/test-lab/lab.conf create mode 100644 pkg/checks/traceroute/test-lab/ldns.startup create mode 100644 pkg/checks/traceroute/test-lab/ldns/etc/bind/db.root create mode 100644 pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf create mode 100644 pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf.options create mode 100644 pkg/checks/traceroute/test-lab/r3dns.startup create mode 100644 pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.it.uniroma3 create mode 100644 pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.root create mode 100644 pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf create mode 100644 pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf.options create mode 100644 pkg/checks/traceroute/test-lab/rootdns.startup create mode 100644 pkg/checks/traceroute/test-lab/rootdns/etc/bind/db.root create mode 100644 pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf create mode 100644 pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf.options create mode 100644 pkg/checks/traceroute/test-lab/webserver.startup create mode 100644 pkg/checks/traceroute/test-lab/webserver/var/www/html/index.html create mode 100644 pkg/checks/traceroute/test-lab/webserver/var/www/index.html diff --git a/pkg/checks/traceroute/test-lab/.gitignore b/pkg/checks/traceroute/test-lab/.gitignore new file mode 100644 index 00000000..d1d584b3 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/.gitignore @@ -0,0 +1 @@ +shared/ diff --git a/pkg/checks/traceroute/test-lab/as100r1.startup b/pkg/checks/traceroute/test-lab/as100r1.startup new file mode 100644 index 00000000..200b4239 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as100r1.startup @@ -0,0 +1,5 @@ +ip address add 11.0.0.1/30 dev eth0 +ip address add 11.0.0.5/30 dev eth1 +ip address add 100.1.0.1/30 dev eth2 +ip address add 100.1.0.5/30 dev eth3 +systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/bgpd.conf new file mode 100644 index 00000000..2c3a8fda --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/bgpd.conf @@ -0,0 +1,41 @@ +! +hostname bgpd +password zebra +enable password zebra +! +router bgp 100 +network 100.1.0.0/16 +! +neighbor 11.0.0.2 remote-as 20 +neighbor 11.0.0.2 description Router as20r2 (primary) +neighbor 11.0.0.2 prefix-list mineOutOnly out +neighbor 11.0.0.2 prefix-list defaultIn in +! +neighbor 11.0.0.6 remote-as 20 +neighbor 11.0.0.6 description Router as20r1 (backup) +neighbor 11.0.0.6 prefix-list mineOutOnly out +neighbor 11.0.0.6 route-map metricOut out +neighbor 11.0.0.6 prefix-list defaultIn in +neighbor 11.0.0.6 route-map localPrefIn in +! +ip prefix-list mineOutOnly permit 100.1.0.0/16 +ip prefix-list defaultIn permit 0.0.0.0/0 +! +route-map metricOut permit 10 +match ip address myAggregate +set metric 10 +! +route-map localPrefIn permit 10 +set local-preference 90 +! +access-list myAggregate permit 100.1.0.0/16 +! +log file /var/log/quagga/bgpd.log +! +debug bgp +debug bgp events +debug bgp filters +debug bgp fsm +debug bgp keepalives +debug bgp updates +! diff --git a/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/daemons new file mode 100644 index 00000000..4e3f16d6 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/daemons @@ -0,0 +1,13 @@ +# This file tells the zebra package +# which daemons to start. +# Entries are in the format: =(yes|no|priority) +# where 'yes' is equivalent to infinitely low priority, and +# lower numbers mean higher priority. Read +# /usr/doc/zebra/README.Debian for details. +# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd +zebra=yes +bgpd=yes +ospfd=no +ospf6d=no +ripd=yes +ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/ripd.conf b/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/ripd.conf new file mode 100644 index 00000000..57cda4d0 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/ripd.conf @@ -0,0 +1,9 @@ +! +hostname ripd +password zebra +! +router rip +redistribute bgp +network 100.1.0.0/16 +! +log file /var/log/quagga/ripd.log diff --git a/pkg/checks/traceroute/test-lab/as100r2.startup b/pkg/checks/traceroute/test-lab/as100r2.startup new file mode 100644 index 00000000..4d621abd --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as100r2.startup @@ -0,0 +1,4 @@ +ip address add 100.1.0.6/30 dev eth0 +ip address add 100.1.0.9/30 dev eth1 +ip address add 100.1.2.1/24 dev eth2 +systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as100r2/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as100r2/etc/quagga/daemons new file mode 100644 index 00000000..a5b998be --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as100r2/etc/quagga/daemons @@ -0,0 +1,13 @@ +# This file tells the zebra package +# which daemons to start. +# Entries are in the format: =(yes|no|priority) +# where 'yes' is equivalent to infinitely low priority, and +# lower numbers mean higher priority. Read +# /usr/doc/zebra/README.Debian for details. +# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd +zebra=yes +bgpd=no +ospfd=no +ospf6d=no +ripd=yes +ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as100r2/etc/quagga/ripd.conf b/pkg/checks/traceroute/test-lab/as100r2/etc/quagga/ripd.conf new file mode 100644 index 00000000..de74e422 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as100r2/etc/quagga/ripd.conf @@ -0,0 +1,10 @@ +! +hostname ripd +password zebra +! +router rip +network 100.1.0.0/16 +redistribute connected +! +log file /var/log/quagga/ripd.log +! diff --git a/pkg/checks/traceroute/test-lab/as100r3.startup b/pkg/checks/traceroute/test-lab/as100r3.startup new file mode 100644 index 00000000..df33dde3 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as100r3.startup @@ -0,0 +1,4 @@ +ip address add 100.1.0.2/30 dev eth0 +ip address add 100.1.0.10/30 dev eth1 +ip address add 100.1.3.1/24 dev eth2 +systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as100r3/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as100r3/etc/quagga/daemons new file mode 100644 index 00000000..a5b998be --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as100r3/etc/quagga/daemons @@ -0,0 +1,13 @@ +# This file tells the zebra package +# which daemons to start. +# Entries are in the format: =(yes|no|priority) +# where 'yes' is equivalent to infinitely low priority, and +# lower numbers mean higher priority. Read +# /usr/doc/zebra/README.Debian for details. +# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd +zebra=yes +bgpd=no +ospfd=no +ospf6d=no +ripd=yes +ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as100r3/etc/quagga/ripd.conf b/pkg/checks/traceroute/test-lab/as100r3/etc/quagga/ripd.conf new file mode 100644 index 00000000..de74e422 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as100r3/etc/quagga/ripd.conf @@ -0,0 +1,10 @@ +! +hostname ripd +password zebra +! +router rip +network 100.1.0.0/16 +redistribute connected +! +log file /var/log/quagga/ripd.log +! diff --git a/pkg/checks/traceroute/test-lab/as1r1.startup b/pkg/checks/traceroute/test-lab/as1r1.startup new file mode 100644 index 00000000..6194b450 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as1r1.startup @@ -0,0 +1,4 @@ +ip address add 11.0.0.26/30 dev eth0 +ip address add 11.0.0.22/30 dev eth1 +ip address add 1.1.0.1/16 dev eth2 +systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as1r1/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as1r1/etc/quagga/bgpd.conf new file mode 100644 index 00000000..f06eee2c --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as1r1/etc/quagga/bgpd.conf @@ -0,0 +1,36 @@ +! +hostname bgpd +password zebra +enable password zebra +! +router bgp 1 +network 11.0.0.20/30 +network 11.0.0.24/30 +network 11.0.0.28/30 +network 1.1.0.0/16 +network 0.0.0.0/0 +! +neighbor 11.0.0.21 remote-as 20 +neighbor 11.0.0.21 description Router as20r3 +neighbor 11.0.0.21 default-originate +neighbor 11.0.0.21 prefix-list defaultOut out +neighbor 11.0.0.21 prefix-list acceptAny in +! +neighbor 11.0.0.25 remote-as 30 +neighbor 11.0.0.25 description Router as30r1 +neighbor 11.0.0.25 default-originate +neighbor 11.0.0.25 prefix-list defaultOut out +neighbor 11.0.0.25 prefix-list acceptAny in +! +ip prefix-list defaultOut permit 0.0.0.0/0 +ip prefix-list acceptAny permit any +! +log file /var/log/quagga/bgpd.log +! +debug bgp +debug bgp events +debug bgp filters +debug bgp fsm +debug bgp keepalives +debug bgp updates +! diff --git a/pkg/checks/traceroute/test-lab/as1r1/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as1r1/etc/quagga/daemons new file mode 100644 index 00000000..0c469547 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as1r1/etc/quagga/daemons @@ -0,0 +1,13 @@ +# This file tells the zebra package +# which daemons to start. +# Entries are in the format: =(yes|no|priority) +# where 'yes' is equivalent to infinitely low priority, and +# lower numbers mean higher priority. Read +# /usr/doc/zebra/README.Debian for details. +# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd +zebra=yes +bgpd=yes +ospfd=no +ospf6d=no +ripd=no +ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as200r1.startup b/pkg/checks/traceroute/test-lab/as200r1.startup new file mode 100644 index 00000000..ddad67c6 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as200r1.startup @@ -0,0 +1,4 @@ +ip address add 11.0.0.33/30 dev eth0 +ip address add 200.2.0.1/16 dev eth1 +ip address add 11.0.0.9/30 dev eth2 +systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as200r1/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as200r1/etc/quagga/bgpd.conf new file mode 100644 index 00000000..1c1cf27e --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as200r1/etc/quagga/bgpd.conf @@ -0,0 +1,27 @@ +! +hostname bgpd +password zebra +enable password zebra +! +router bgp 200 +network 200.2.0.0/16 +! +neighbor 11.0.0.34 remote-as 20 +neighbor 11.0.0.34 description Router as20r1 +! +neighbor 11.0.0.10 remote-as 30 +neighbor 11.0.0.10 description Router as30r1 +neighbor 11.0.0.10 route-map localPrefIn in +! +route-map localPrefIn permit 10 +set local-preference 90 +! +log file /var/log/quagga/bgpd.log +! +debug bgp +debug bgp events +debug bgp filters +debug bgp fsm +debug bgp keepalives +debug bgp updates +! diff --git a/pkg/checks/traceroute/test-lab/as200r1/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as200r1/etc/quagga/daemons new file mode 100644 index 00000000..0c469547 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as200r1/etc/quagga/daemons @@ -0,0 +1,13 @@ +# This file tells the zebra package +# which daemons to start. +# Entries are in the format: =(yes|no|priority) +# where 'yes' is equivalent to infinitely low priority, and +# lower numbers mean higher priority. Read +# /usr/doc/zebra/README.Debian for details. +# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd +zebra=yes +bgpd=yes +ospfd=no +ospf6d=no +ripd=no +ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as20r1.startup b/pkg/checks/traceroute/test-lab/as20r1.startup new file mode 100644 index 00000000..975b59d7 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as20r1.startup @@ -0,0 +1,5 @@ +ip address add 11.0.0.34/30 dev eth0 +ip address add 11.0.0.6/30 dev eth1 +ip address add 20.1.1.1/24 dev eth2 +ip address add 11.0.0.17/30 dev eth3 +systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/bgpd.conf new file mode 100644 index 00000000..57d308e1 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/bgpd.conf @@ -0,0 +1,49 @@ +! +hostname bgpd +password zebra +enable password zebra +! +router bgp 20 +network 20.1.1.0/24 +network 11.0.0.4/30 +network 11.0.0.16/30 +network 11.0.0.32/30 +! +neighbor 11.0.0.33 remote-as 200 +neighbor 11.0.0.33 description Router as200r1 +neighbor 11.0.0.33 default-originate +neighbor 11.0.0.33 prefix-list customer200 in +neighbor 11.0.0.33 prefix-list defaultOut out +! +neighbor 11.0.0.5 remote-as 100 +neighbor 11.0.0.5 description Router as100r1 +neighbor 11.0.0.5 default-originate +neighbor 11.0.0.5 prefix-list customer100 in +neighbor 11.0.0.5 prefix-list defaultOut out +! +neighbor 20.1.1.2 remote-as 20 +neighbor 20.1.1.2 description Router as20r2 (iBGP) +! +neighbor 20.1.1.3 remote-as 20 +neighbor 20.1.1.3 description Router as20r3 (iBGP) +! +neighbor 11.0.0.18 remote-as 30 +neighbor 11.0.0.18 description Router as30r1 (eBGP) +neighbor 11.0.0.18 prefix-list meAndCustomers out +! +ip prefix-list customer100 permit 100.1.0.0/16 +ip prefix-list customer200 permit 200.2.0.0/16 +ip prefix-list defaultOut permit 0.0.0.0/0 +ip prefix-list meAndCustomers permit 20.1.1.0/24 +ip prefix-list meAndCustomers permit 100.1.0.0/16 +ip prefix-list meAndCustomers permit 200.2.0.0/16 +! +log file /var/log/quagga/bgpd.log +! +debug bgp +debug bgp events +debug bgp filters +debug bgp fsm +debug bgp keepalives +debug bgp updates +! diff --git a/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/daemons new file mode 100644 index 00000000..82dbc113 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/daemons @@ -0,0 +1,13 @@ +# This file tells the zebra package +# which daemons to start. +# Entries are in the format: =(yes|no|priority) +# where 'yes' is equivalent to infinitely low priority, and +# lower numbers mean higher priority. Read +# /usr/doc/zebra/README.Debian for details. +# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd +zebra=yes +bgpd=yes +ospfd=yes +ospf6d=no +ripd=no +ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/ospfd.conf b/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/ospfd.conf new file mode 100644 index 00000000..478567c8 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/ospfd.conf @@ -0,0 +1,12 @@ +! +hostname ospfd +password zebra +enable password zebra +! +router ospf +! Speak OSPF on all interfaces falling in 20.1.1.0/24 +network 20.1.1.0/24 area 0.0.0.0 +redistribute connected +! +log file /var/log/quagga/ospfd.log +! diff --git a/pkg/checks/traceroute/test-lab/as20r2.startup b/pkg/checks/traceroute/test-lab/as20r2.startup new file mode 100644 index 00000000..ae3f62cf --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as20r2.startup @@ -0,0 +1,4 @@ +ip address add 11.0.0.2/30 dev eth0 +ip address add 20.1.1.2/24 dev eth1 +ip address add 20.2.1.1/24 dev eth2 +systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/bgpd.conf new file mode 100644 index 00000000..23ef93d6 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/bgpd.conf @@ -0,0 +1,34 @@ +! +hostname bgpd +password zebra +enable password zebra +! +router bgp 20 +network 20.1.1.0/24 +network 20.2.1.0/24 +network 11.0.0.0/30 +! +neighbor 11.0.0.1 remote-as 100 +neighbor 11.0.0.1 description Router as100r1 +neighbor 11.0.0.1 default-originate +neighbor 11.0.0.1 prefix-list as100In in +neighbor 11.0.0.1 prefix-list defaultOut out +! +neighbor 20.1.1.1 remote-as 20 +neighbor 20.1.1.1 description Router as20r1 (iBGP) +! +neighbor 20.1.1.3 remote-as 20 +neighbor 20.1.1.3 description Router as20r3 (iBGP) +! +ip prefix-list as100In permit 100.1.0.0/16 +ip prefix-list defaultOut permit 0.0.0.0/0 +! +log file /var/log/quagga/bgpd.log +! +debug bgp +debug bgp events +debug bgp filters +debug bgp fsm +debug bgp keepalives +debug bgp updates +! diff --git a/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/daemons new file mode 100644 index 00000000..82dbc113 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/daemons @@ -0,0 +1,13 @@ +# This file tells the zebra package +# which daemons to start. +# Entries are in the format: =(yes|no|priority) +# where 'yes' is equivalent to infinitely low priority, and +# lower numbers mean higher priority. Read +# /usr/doc/zebra/README.Debian for details. +# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd +zebra=yes +bgpd=yes +ospfd=yes +ospf6d=no +ripd=no +ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/ospfd.conf b/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/ospfd.conf new file mode 100644 index 00000000..478567c8 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/ospfd.conf @@ -0,0 +1,12 @@ +! +hostname ospfd +password zebra +enable password zebra +! +router ospf +! Speak OSPF on all interfaces falling in 20.1.1.0/24 +network 20.1.1.0/24 area 0.0.0.0 +redistribute connected +! +log file /var/log/quagga/ospfd.log +! diff --git a/pkg/checks/traceroute/test-lab/as20r3.startup b/pkg/checks/traceroute/test-lab/as20r3.startup new file mode 100644 index 00000000..392e9823 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as20r3.startup @@ -0,0 +1,3 @@ +ip address add 11.0.0.21/30 dev eth0 +ip address add 20.1.1.3/24 dev eth1 +systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/bgpd.conf new file mode 100644 index 00000000..3696b2af --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/bgpd.conf @@ -0,0 +1,26 @@ +! +hostname bgpd +password zebra +enable password zebra +! +router bgp 20 +network 20.1.1.0/24 +! +neighbor 11.0.0.22 remote-as 1 +neighbor 11.0.0.22 description Router as1r1 (uplink) +! +neighbor 20.1.1.1 remote-as 20 +neighbor 20.1.1.1 description Router as20r1 (iBGP) +! +neighbor 20.1.1.2 remote-as 20 +neighbor 20.1.1.2 description Router as20r2 (iBGP) +! +log file /var/log/quagga/bgpd.log +! +debug bgp +debug bgp events +debug bgp filters +debug bgp fsm +debug bgp keepalives +debug bgp updates +! diff --git a/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/daemons new file mode 100644 index 00000000..82dbc113 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/daemons @@ -0,0 +1,13 @@ +# This file tells the zebra package +# which daemons to start. +# Entries are in the format: =(yes|no|priority) +# where 'yes' is equivalent to infinitely low priority, and +# lower numbers mean higher priority. Read +# /usr/doc/zebra/README.Debian for details. +# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd +zebra=yes +bgpd=yes +ospfd=yes +ospf6d=no +ripd=no +ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/ospfd.conf b/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/ospfd.conf new file mode 100644 index 00000000..478567c8 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/ospfd.conf @@ -0,0 +1,12 @@ +! +hostname ospfd +password zebra +enable password zebra +! +router ospf +! Speak OSPF on all interfaces falling in 20.1.1.0/24 +network 20.1.1.0/24 area 0.0.0.0 +redistribute connected +! +log file /var/log/quagga/ospfd.log +! diff --git a/pkg/checks/traceroute/test-lab/as30r1.startup b/pkg/checks/traceroute/test-lab/as30r1.startup new file mode 100644 index 00000000..6e9b29b4 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as30r1.startup @@ -0,0 +1,5 @@ +ip address add 11.0.0.10/30 dev eth0 +ip address add 30.3.3.1/24 dev eth1 +ip address add 11.0.0.25/30 dev eth2 +ip address add 11.0.0.18/30 dev eth3 +systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as30r1/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as30r1/etc/quagga/bgpd.conf new file mode 100644 index 00000000..50954ee5 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as30r1/etc/quagga/bgpd.conf @@ -0,0 +1,36 @@ +! +hostname bgpd +password zebra +enable password zebra +! +router bgp 30 +network 30.3.3.0/24 +network 11.0.0.8/30 +! +neighbor 11.0.0.9 remote-as 200 +neighbor 11.0.0.9 description Router as200r1 +neighbor 11.0.0.9 default-originate +neighbor 11.0.0.9 prefix-list customer200 in +neighbor 11.0.0.9 prefix-list defaultOut out +! +neighbor 11.0.0.26 remote-as 1 +neighbor 11.0.0.26 description Router as1r1 (eBGP) +! +neighbor 11.0.0.17 remote-as 20 +neighbor 11.0.0.17 description Router as20r1 (eBGP) +neighbor 11.0.0.17 prefix-list meAndCustomers out +! +ip prefix-list customer200 permit 200.2.0.0/16 +ip prefix-list defaultOut permit 0.0.0.0/0 +ip prefix-list meAndCustomers permit 30.3.3.0/24 +ip prefix-list meAndCustomers permit 200.2.0.0/16 +! +log file /var/log/quagga/bgpd.log +! +debug bgp +debug bgp events +debug bgp filters +debug bgp fsm +debug bgp keepalives +debug bgp updates +! diff --git a/pkg/checks/traceroute/test-lab/as30r1/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as30r1/etc/quagga/daemons new file mode 100644 index 00000000..0c469547 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/as30r1/etc/quagga/daemons @@ -0,0 +1,13 @@ +# This file tells the zebra package +# which daemons to start. +# Entries are in the format: =(yes|no|priority) +# where 'yes' is equivalent to infinitely low priority, and +# lower numbers mean higher priority. Read +# /usr/doc/zebra/README.Debian for details. +# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd +zebra=yes +bgpd=yes +ospfd=no +ospf6d=no +ripd=no +ripngd=no diff --git a/pkg/checks/traceroute/test-lab/client.startup b/pkg/checks/traceroute/test-lab/client.startup new file mode 100644 index 00000000..4aa5acf1 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/client.startup @@ -0,0 +1,2 @@ +ip address add 200.2.0.2/24 dev eth0 +ip route add default via 200.2.0.1 dev eth0 diff --git a/pkg/checks/traceroute/test-lab/client/etc/resolv.conf b/pkg/checks/traceroute/test-lab/client/etc/resolv.conf new file mode 100644 index 00000000..e2bb9fa4 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/client/etc/resolv.conf @@ -0,0 +1 @@ +nameserver 30.3.3.2 diff --git a/pkg/checks/traceroute/test-lab/itdns.startup b/pkg/checks/traceroute/test-lab/itdns.startup new file mode 100644 index 00000000..bfef7868 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/itdns.startup @@ -0,0 +1,3 @@ +ip address add 20.2.1.2/24 dev eth0 +ip route add default via 20.2.1.1 dev eth0 +systemctl start named diff --git a/pkg/checks/traceroute/test-lab/itdns/etc/bind/db.it b/pkg/checks/traceroute/test-lab/itdns/etc/bind/db.it new file mode 100644 index 00000000..4d76f656 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/itdns/etc/bind/db.it @@ -0,0 +1,13 @@ +$TTL 60000 +@ IN SOA dnsit.it. root.dnsit.it. ( + 2006031201 ; serial + 28800 ; refresh + 14400 ; retry + 3600000 ; expire + 0 ; negative cache ttl + ) +@ IN NS dnsit.it. +dnsit IN A 20.2.1.2 + +uniroma3 IN NS dnsr3.uniroma3.it. +dnsr3.uniroma3 IN A 100.1.3.2 diff --git a/pkg/checks/traceroute/test-lab/itdns/etc/bind/db.root b/pkg/checks/traceroute/test-lab/itdns/etc/bind/db.root new file mode 100644 index 00000000..b37e5a67 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/itdns/etc/bind/db.root @@ -0,0 +1,2 @@ +. IN NS ROOT-SERVER. +ROOT-SERVER. IN A 1.1.0.2 diff --git a/pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf b/pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf new file mode 100644 index 00000000..fae2bc49 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf @@ -0,0 +1,11 @@ +include "/etc/bind/named.conf.options"; + +zone "." { + type hint; + file "/etc/bind/db.root"; +}; + +zone "it" { + type master; + file "/etc/bind/db.it"; +}; diff --git a/pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf.options b/pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf.options new file mode 100644 index 00000000..b0311e27 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf.options @@ -0,0 +1,3 @@ +options { + directory "/var/cache/bind"; +}; diff --git a/pkg/checks/traceroute/test-lab/lab.conf b/pkg/checks/traceroute/test-lab/lab.conf new file mode 100644 index 00000000..24e6bc25 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/lab.conf @@ -0,0 +1,70 @@ +LAB_DESCRIPTION="A small Internet with DNS and a web server" +LAB_VERSION=1.0 +LAB_AUTHOR="M. Scazzariello, L. Ariemma, T. Caiazzi" +LAB_EMAIL=contact@kathara.org +LAB_WEB=https://www.kathara.org/ + +as1r1[0]="S" +as1r1[1]="U" +as1r1[2]="V" +as1r1[image]="kathara/quagga" + +as20r1[0]="A" +as20r1[1]="F" +as20r1[2]="C" +as20r1[3]="T" +as20r1[image]="kathara/quagga" + +as20r2[0]="E" +as20r2[1]="C" +as20r2[2]="W" +as20r2[image]="kathara/quagga" + +as20r3[0]="U" +as20r3[1]="C" +as20r3[image]="kathara/quagga" + +as30r1[0]="N" +as30r1[1]="R" +as30r1[2]="S" +as30r1[3]="T" +as30r1[image]="kathara/quagga" + +as100r1[0]="E" +as100r1[1]="F" +as100r1[2]="J" +as100r1[3]="D" +as100r1[image]="kathara/quagga" + +as100r2[0]="D" +as100r2[1]="H" +as100r2[2]="L" +as100r2[image]="kathara/quagga" + +as100r3[0]="J" +as100r3[1]="H" +as100r3[2]="K" +as100r3[image]="kathara/quagga" + +as200r1[0]="A" +as200r1[1]="B" +as200r1[2]="N" +as200r1[image]="kathara/quagga" + +webserver[0]="L" +webserver[image]="kathara/base" + +rootdns[0]="V" +rootdns[image]="kathara/base" + +itdns[0]="W" +itdns[image]="kathara/base" + +r3dns[0]="K" +r3dns[image]="kathara/base" + +ldns[0]="R" +ldns[image]="kathara/base" + +client[0]="B" +client[image]="kathara/base" diff --git a/pkg/checks/traceroute/test-lab/ldns.startup b/pkg/checks/traceroute/test-lab/ldns.startup new file mode 100644 index 00000000..725038b4 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/ldns.startup @@ -0,0 +1,3 @@ +ip address add 30.3.3.2/24 dev eth0 +ip route add default via 30.3.3.1 dev eth0 +systemctl start named diff --git a/pkg/checks/traceroute/test-lab/ldns/etc/bind/db.root b/pkg/checks/traceroute/test-lab/ldns/etc/bind/db.root new file mode 100644 index 00000000..4d78cbba --- /dev/null +++ b/pkg/checks/traceroute/test-lab/ldns/etc/bind/db.root @@ -0,0 +1,2 @@ +@ IN NS ROOT-SERVER. +ROOT-SERVER. IN A 1.1.0.2 diff --git a/pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf b/pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf new file mode 100644 index 00000000..d0b3f759 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf @@ -0,0 +1,6 @@ +include "/etc/bind/named.conf.options"; + +zone "." { + type hint; + file "/etc/bind/db.root"; +}; diff --git a/pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf.options b/pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf.options new file mode 100644 index 00000000..a9bdfbe7 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf.options @@ -0,0 +1,5 @@ +options { + directory "/var/cache/bind"; + allow-recursion { 200.2/16; }; + dnssec-validation no; +}; diff --git a/pkg/checks/traceroute/test-lab/r3dns.startup b/pkg/checks/traceroute/test-lab/r3dns.startup new file mode 100644 index 00000000..44844b84 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/r3dns.startup @@ -0,0 +1,3 @@ +ip address add 100.1.3.2/24 dev eth0 +ip route add default via 100.1.3.1 dev eth0 +systemctl start named diff --git a/pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.it.uniroma3 b/pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.it.uniroma3 new file mode 100644 index 00000000..ec3bcf04 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.it.uniroma3 @@ -0,0 +1,11 @@ +$TTL 60000 +@ IN SOA dnsr3.uniroma3.it. root.dnsr3.uniroma3.it. ( + 2006031201 ; serial + 28 ; refresh + 14 ; retry + 3600000 ; expire + 0 ; negative cache ttl + ) +@ IN NS dnsr3.uniroma3.it. +dnsr3 IN A 100.1.3.2 +www IN A 100.1.2.2 diff --git a/pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.root b/pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.root new file mode 100644 index 00000000..b37e5a67 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.root @@ -0,0 +1,2 @@ +. IN NS ROOT-SERVER. +ROOT-SERVER. IN A 1.1.0.2 diff --git a/pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf b/pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf new file mode 100644 index 00000000..3b51c888 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf @@ -0,0 +1,11 @@ +include "/etc/bind/named.conf.options"; + +zone "." { + type hint; + file "/etc/bind/db.root"; +}; + +zone "uniroma3.it" { + type master; + file "/etc/bind/db.it.uniroma3"; +}; diff --git a/pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf.options b/pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf.options new file mode 100644 index 00000000..b0311e27 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf.options @@ -0,0 +1,3 @@ +options { + directory "/var/cache/bind"; +}; diff --git a/pkg/checks/traceroute/test-lab/rootdns.startup b/pkg/checks/traceroute/test-lab/rootdns.startup new file mode 100644 index 00000000..83f04ab5 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/rootdns.startup @@ -0,0 +1,3 @@ +ip address add 1.1.0.2/16 dev eth0 +ip route add default via 1.1.0.1 dev eth0 +systemctl start named diff --git a/pkg/checks/traceroute/test-lab/rootdns/etc/bind/db.root b/pkg/checks/traceroute/test-lab/rootdns/etc/bind/db.root new file mode 100644 index 00000000..8e413ca9 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/rootdns/etc/bind/db.root @@ -0,0 +1,14 @@ +$TTL 60000 +@ IN SOA ROOT-SERVER. root.ROOT-SERVER. ( + 2006031201 ; serial + 28800 ; refresh + 14400 ; retry + 3600000 ; expire + 0 ; negative cache ttl + ) + +@ IN NS ROOT-SERVER. +ROOT-SERVER. IN A 1.1.0.2 + +it. IN NS dnsit.it. +dnsit.it. IN A 20.2.1.2 diff --git a/pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf b/pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf new file mode 100644 index 00000000..df43f708 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf @@ -0,0 +1,6 @@ +include "/etc/bind/named.conf.options"; + +zone "." { + type master; + file "/etc/bind/db.root"; +}; diff --git a/pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf.options b/pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf.options new file mode 100644 index 00000000..b0311e27 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf.options @@ -0,0 +1,3 @@ +options { + directory "/var/cache/bind"; +}; diff --git a/pkg/checks/traceroute/test-lab/webserver.startup b/pkg/checks/traceroute/test-lab/webserver.startup new file mode 100644 index 00000000..08fb9b09 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/webserver.startup @@ -0,0 +1,3 @@ +ip address add 100.1.2.2/24 dev eth0 +ip route add default via 100.1.2.1 dev eth0 +systemctl start apache2 diff --git a/pkg/checks/traceroute/test-lab/webserver/var/www/html/index.html b/pkg/checks/traceroute/test-lab/webserver/var/www/html/index.html new file mode 100644 index 00000000..5fa2e374 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/webserver/var/www/html/index.html @@ -0,0 +1,14 @@ + + + Hello! +
+            _   _  ____  __  __  _____   ___   ___ ___   ___  
+           | \ | |/ __ \|  \/  |/ ____| |__ \ / _ \__ \ / _ \ 
+           |  \| | |  | | \  / | (___      ) | | | | ) | | | |
+           | . ` | |  | | |\/| |\___ \    / /| | | |/ /| | | |
+           | |\  | |__| | |  | |____) |  / /_| |_| / /_| |_| |
+           |_| \_|\____/|_|  |_|_____/  |____|\___/____|\___/ 
+                                                              
+        
+ + diff --git a/pkg/checks/traceroute/test-lab/webserver/var/www/index.html b/pkg/checks/traceroute/test-lab/webserver/var/www/index.html new file mode 100644 index 00000000..5fa2e374 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/webserver/var/www/index.html @@ -0,0 +1,14 @@ + + + Hello! +
+            _   _  ____  __  __  _____   ___   ___ ___   ___  
+           | \ | |/ __ \|  \/  |/ ____| |__ \ / _ \__ \ / _ \ 
+           |  \| | |  | | \  / | (___      ) | | | | ) | | | |
+           | . ` | |  | | |\/| |\___ \    / /| | | |/ /| | | |
+           | |\  | |__| | |  | |____) |  / /_| |_| / /_| |_| |
+           |_| \_|\____/|_|  |_|_____/  |____|\___/____|\___/ 
+                                                              
+        
+ + diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 7be80d65..3cc539c4 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -80,6 +80,7 @@ func readIcmpMessage(icmpListener *icmp.PacketConn, timeout time.Duration) (int, return destPort, routerAddr, nil } + func TraceRoute(host string, port, timeout, retries, maxHops int) ([]Hop, error) { // TraceRoute performs a traceroute to the specified host using TCP and listens for ICMP Time Exceeded messages using datagram-oriented ICMP. // func TraceRoute(host string, port int, maxHops int, timeout time.Duration) ([]Hop, error) { From 9ad953521fd9414909ef20afbf3951b45fd56414 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Thu, 25 Jul 2024 18:30:04 +0200 Subject: [PATCH 03/46] fix: update unit test for new behaviour Signed-off-by: Niklas Treml --- pkg/checks/traceroute/check_test.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/pkg/checks/traceroute/check_test.go b/pkg/checks/traceroute/check_test.go index d0e7a152..000a2d96 100644 --- a/pkg/checks/traceroute/check_test.go +++ b/pkg/checks/traceroute/check_test.go @@ -25,11 +25,11 @@ func TestCheck(t *testing.T) { "8.8.8.8": { NumHops: 5, Hops: []Hop{ - {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.0")}, Latency: 0 * time.Second, Reached: false}, - {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.1")}, Latency: 1 * time.Second, Reached: false}, - {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.2")}, Latency: 2 * time.Second, Reached: false}, - {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.3")}, Latency: 3 * time.Second, Reached: false}, - {Name: "google-public-dns-a.google.com", Latency: 69 * time.Second, Reached: true}, + {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.0")}, Latency: 0 * time.Second, Reached: false, Ttl: 1}, + {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.1")}, Latency: 1 * time.Second, Reached: false, Ttl: 2}, + {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.2")}, Latency: 2 * time.Second, Reached: false, Ttl: 3}, + {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.3")}, Latency: 3 * time.Second, Reached: false, Ttl: 4}, + {Addr: &net.TCPAddr{IP: net.ParseIP("123.0.0.123"), Port: 53}, Name: "google-public-dns-a.google.com", Latency: 69 * time.Second, Reached: true, Ttl: 5}, }, }, }, @@ -44,12 +44,14 @@ func TestCheck(t *testing.T) { } for _, c := range cases { - res := c.c.check(context.Background()) + t.Run(c.name, func(t *testing.T) { + res := c.c.check(context.Background()) - if !cmp.Equal(res, c.want) { - diff := cmp.Diff(res, c.want) - t.Errorf("unexpected result: +want -got\n%s", diff) - } + if !cmp.Equal(res, c.want) { + diff := cmp.Diff(res, c.want) + t.Errorf("unexpected result: +want -got\n%s", diff) + } + }) } } From 4ccae9a204a063a949e88dddaa0cde18003a36b7 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 08:47:44 +0200 Subject: [PATCH 04/46] feat: implement retry logic Signed-off-by: Niklas Treml --- pkg/checks/traceroute/check.go | 5 +++-- pkg/checks/traceroute/check_test.go | 5 +++-- pkg/checks/traceroute/config.go | 5 +++-- pkg/checks/traceroute/traceroute.go | 25 ++++++++++++++++++------- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/pkg/checks/traceroute/check.go b/pkg/checks/traceroute/check.go index 8a795398..5761e38f 100644 --- a/pkg/checks/traceroute/check.go +++ b/pkg/checks/traceroute/check.go @@ -6,6 +6,7 @@ import ( "sync" "time" + "github.com/caas-team/sparrow/internal/helper" "github.com/caas-team/sparrow/internal/logger" "github.com/caas-team/sparrow/pkg/checks" "github.com/getkin/kin-openapi/openapi3" @@ -40,7 +41,7 @@ type Traceroute struct { traceroute tracerouteFactory } -type tracerouteFactory func(dest string, port, timeout, retries, maxHops int) ([]Hop, error) +type tracerouteFactory func(dest string, port, timeout, maxHops int, rc helper.RetryConfig) ([]Hop, error) type result struct { // The minimum number of hops required to reach the target @@ -108,7 +109,7 @@ func (tr *Traceroute) check(ctx context.Context) map[string]result { l.Debug("Running traceroute") start := time.Now() - trace, err := tr.traceroute(t.Addr, int(t.Port), int(tr.config.Timeout/time.Millisecond), tr.config.Retries, tr.config.MaxHops) + trace, err := tr.traceroute(t.Addr, int(t.Port), int(tr.config.Timeout/time.Millisecond), tr.config.MaxHops, tr.config.Retry) duration := time.Since(start) if err != nil { l.Error("Error running traceroute", "error", err) diff --git a/pkg/checks/traceroute/check_test.go b/pkg/checks/traceroute/check_test.go index 000a2d96..c1469211 100644 --- a/pkg/checks/traceroute/check_test.go +++ b/pkg/checks/traceroute/check_test.go @@ -9,6 +9,7 @@ import ( "github.com/google/go-cmp/cmp" + "github.com/caas-team/sparrow/internal/helper" "github.com/caas-team/sparrow/pkg/checks" ) @@ -74,7 +75,7 @@ func newForTest(f tracerouteFactory, targets []string) *Traceroute { // success produces a tracerouteFactory that returns a traceroute result with nHops hops func success(nHops int) tracerouteFactory { - return func(dest string, port, timeout, retries, maxHops int) ([]Hop, error) { + return func(dest string, port, timeout, maxHops int, _ helper.RetryConfig) ([]Hop, error) { hops := make([]Hop, nHops) for i := 0; i < nHops-1; i++ { hops[i] = Hop{ @@ -101,7 +102,7 @@ func success(nHops int) tracerouteFactory { } func returnError(err error) tracerouteFactory { - return func(dest string, port, timeout, retries, maxHops int) ([]Hop, error) { + return func(string, int, int, int, helper.RetryConfig) ([]Hop, error) { return []Hop{}, err } } diff --git a/pkg/checks/traceroute/config.go b/pkg/checks/traceroute/config.go index 5400370e..592a9e6a 100644 --- a/pkg/checks/traceroute/config.go +++ b/pkg/checks/traceroute/config.go @@ -6,6 +6,7 @@ import ( "net/url" "time" + "github.com/caas-team/sparrow/internal/helper" "github.com/caas-team/sparrow/pkg/checks" ) @@ -13,8 +14,8 @@ import ( type Config struct { // Targets is a list of targets to traceroute to Targets []Target `json:"targets" yaml:"targets" mapstructure:"targets"` - // Retries is the number of times to retry the traceroute for a target, if it fails - Retries int `json:"retries" yaml:"retries" mapstructure:"retries"` + // Retry defines if and how to retry a target + Retry helper.RetryConfig `json:"retry" yaml:"retry" mapstructure:"retry"` // MaxHops is the maximum number of hops to try before giving up MaxHops int `json:"maxHops" yaml:"maxHops" mapstructure:"maxHops"` // Interval is the time to wait between check iterations diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 3cc539c4..902efe7c 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -1,6 +1,7 @@ package traceroute import ( + "context" "errors" "fmt" "math/rand" @@ -10,6 +11,7 @@ import ( "syscall" "time" + "github.com/caas-team/sparrow/internal/helper" "golang.org/x/net/icmp" "golang.org/x/net/ipv4" ) @@ -81,7 +83,7 @@ func readIcmpMessage(icmpListener *icmp.PacketConn, timeout time.Duration) (int, return destPort, routerAddr, nil } -func TraceRoute(host string, port, timeout, retries, maxHops int) ([]Hop, error) { +func TraceRoute(host string, port, timeout, maxHops int, rc helper.RetryConfig) ([]Hop, error) { // TraceRoute performs a traceroute to the specified host using TCP and listens for ICMP Time Exceeded messages using datagram-oriented ICMP. // func TraceRoute(host string, port int, maxHops int, timeout time.Duration) ([]Hop, error) { var hops []Hop @@ -100,7 +102,16 @@ func TraceRoute(host string, port, timeout, retries, maxHops int) ([]Hop, error) wg.Add(1) go func() { defer wg.Done() - traceroute(results, addr, ttl, toDuration) + helper.Retry(func(ctx context.Context) error { + reached, err := traceroute(results, addr, ttl, toDuration, rc) + if err != nil { + return err + } + if !reached { + return errors.New("failed to reach target, please retry") + } + return nil + }, rc) }() } @@ -132,10 +143,10 @@ func ipFromAddr(remoteAddr net.Addr) net.IP { return nil } -func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) error { +func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration, rc helper.RetryConfig) (bool, error) { icmpListener, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") if err != nil { - return err + return false, err } defer icmpListener.Close() start := time.Now() @@ -159,7 +170,7 @@ func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) Name: name, Reached: true, } - return nil + return true, nil } found := false @@ -173,7 +184,7 @@ func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) Ttl: ttl, Reached: false, } - return nil + return false, nil } // Check if the destination port matches our dialer's source port @@ -205,7 +216,7 @@ func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) } } - return nil + return false, nil } type Hop struct { From 476f570fa1582bfd108e5fd0b12e8c59cb0d9fc2 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 09:30:04 +0200 Subject: [PATCH 05/46] feat: show all attempted hops in api output Signed-off-by: Niklas Treml --- pkg/checks/traceroute/check.go | 15 ++++---- pkg/checks/traceroute/check_test.go | 56 +++++++++++++++-------------- pkg/checks/traceroute/traceroute.go | 33 +++++++++-------- 3 files changed, 55 insertions(+), 49 deletions(-) diff --git a/pkg/checks/traceroute/check.go b/pkg/checks/traceroute/check.go index 5761e38f..cbb4c05e 100644 --- a/pkg/checks/traceroute/check.go +++ b/pkg/checks/traceroute/check.go @@ -41,13 +41,13 @@ type Traceroute struct { traceroute tracerouteFactory } -type tracerouteFactory func(dest string, port, timeout, maxHops int, rc helper.RetryConfig) ([]Hop, error) +type tracerouteFactory func(dest string, port, timeout, maxHops int, rc helper.RetryConfig) (map[int][]Hop, error) type result struct { // The minimum number of hops required to reach the target NumHops int // The path taken to the destination - Hops []Hop + Hops map[int][]Hop } // Run runs the check in a loop sending results to the provided channel @@ -120,10 +120,13 @@ func (tr *Traceroute) check(ctx context.Context) map[string]result { Hops: trace, } - for i, h := range trace { - if h.Reached { - r.NumHops = i + 1 - break + reached: + for i, hops := range trace { + for _, hop := range hops { + if hop.Reached { + r.NumHops = i + break reached + } } } diff --git a/pkg/checks/traceroute/check_test.go b/pkg/checks/traceroute/check_test.go index c1469211..ae5858c9 100644 --- a/pkg/checks/traceroute/check_test.go +++ b/pkg/checks/traceroute/check_test.go @@ -25,12 +25,12 @@ func TestCheck(t *testing.T) { want: map[string]result{ "8.8.8.8": { NumHops: 5, - Hops: []Hop{ - {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.0")}, Latency: 0 * time.Second, Reached: false, Ttl: 1}, - {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.1")}, Latency: 1 * time.Second, Reached: false, Ttl: 2}, - {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.2")}, Latency: 2 * time.Second, Reached: false, Ttl: 3}, - {Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.3")}, Latency: 3 * time.Second, Reached: false, Ttl: 4}, - {Addr: &net.TCPAddr{IP: net.ParseIP("123.0.0.123"), Port: 53}, Name: "google-public-dns-a.google.com", Latency: 69 * time.Second, Reached: true, Ttl: 5}, + Hops: map[int][]Hop{ + 1: {{Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.1")}, Latency: 1 * time.Second, Reached: false, Ttl: 1}}, + 2: {{Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.2")}, Latency: 2 * time.Second, Reached: false, Ttl: 2}}, + 3: {{Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.3")}, Latency: 3 * time.Second, Reached: false, Ttl: 3}}, + 4: {{Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.4")}, Latency: 4 * time.Second, Reached: false, Ttl: 4}}, + 5: {{Addr: &net.TCPAddr{IP: net.ParseIP("123.0.0.123"), Port: 53}, Name: "google-public-dns-a.google.com", Latency: 69 * time.Second, Reached: true, Ttl: 5}}, }, }, }, @@ -39,7 +39,7 @@ func TestCheck(t *testing.T) { name: "Traceroute internal error fails silently", c: newForTest(returnError(&net.DNSError{Err: "no such host", Name: "google.com", IsNotFound: true}), []string{"google.com"}), want: map[string]result{ - "google.com": {Hops: []Hop{}}, + "google.com": {Hops: map[int][]Hop{}}, }, }, } @@ -75,26 +75,30 @@ func newForTest(f tracerouteFactory, targets []string) *Traceroute { // success produces a tracerouteFactory that returns a traceroute result with nHops hops func success(nHops int) tracerouteFactory { - return func(dest string, port, timeout, maxHops int, _ helper.RetryConfig) ([]Hop, error) { - hops := make([]Hop, nHops) - for i := 0; i < nHops-1; i++ { - hops[i] = Hop{ - Latency: time.Second * time.Duration(i), - Addr: &net.TCPAddr{IP: net.ParseIP(ipFromInt(i))}, - Name: "", - Ttl: i + 1, - Reached: false, + return func(dest string, port, timeout, maxHops int, _ helper.RetryConfig) (map[int][]Hop, error) { + hops := make(map[int][]Hop) + for i := 1; i < nHops; i++ { + hops[i] = []Hop{ + { + Latency: time.Second * time.Duration(i), + Addr: &net.TCPAddr{IP: net.ParseIP(ipFromInt(i))}, + Name: "", + Ttl: i, + Reached: false, + }, } } - hops[nHops-1] = Hop{ - Latency: 69 * time.Second, - Addr: &net.TCPAddr{ - IP: net.ParseIP("123.0.0.123"), - Port: 53, + hops[nHops] = []Hop{ + { + Latency: 69 * time.Second, + Addr: &net.TCPAddr{ + IP: net.ParseIP("123.0.0.123"), + Port: 53, + }, + Name: "google-public-dns-a.google.com", + Ttl: nHops, + Reached: true, }, - Name: "google-public-dns-a.google.com", - Ttl: nHops, - Reached: true, } return hops, nil @@ -102,8 +106,8 @@ func success(nHops int) tracerouteFactory { } func returnError(err error) tracerouteFactory { - return func(string, int, int, int, helper.RetryConfig) ([]Hop, error) { - return []Hop{}, err + return func(string, int, int, int, helper.RetryConfig) (map[int][]Hop, error) { + return map[int][]Hop{}, err } } diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 902efe7c..daaef1ed 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -6,7 +6,6 @@ import ( "fmt" "math/rand" "net" - "slices" "sync" "syscall" "time" @@ -83,10 +82,11 @@ func readIcmpMessage(icmpListener *icmp.PacketConn, timeout time.Duration) (int, return destPort, routerAddr, nil } -func TraceRoute(host string, port, timeout, maxHops int, rc helper.RetryConfig) ([]Hop, error) { - // TraceRoute performs a traceroute to the specified host using TCP and listens for ICMP Time Exceeded messages using datagram-oriented ICMP. - // func TraceRoute(host string, port int, maxHops int, timeout time.Duration) ([]Hop, error) { - var hops []Hop +// TraceRoute performs a traceroute to the specified host using TCP and listens for ICMP Time Exceeded messages using ICMP. +func TraceRoute(host string, port, timeout, maxHops int, rc helper.RetryConfig) (map[int][]Hop, error) { + // this could also be a 2d array, but I feel like using an int map here makes the json easier to understand + // as it explicitly shows a mapping of ttl->hops + var hops map[int][]Hop toDuration := time.Duration(timeout) * time.Second @@ -119,14 +119,11 @@ func TraceRoute(host string, port, timeout, maxHops int, rc helper.RetryConfig) close(results) for r := range results { - hops = append(hops, r) + hops[r.Ttl] = append(hops[r.Ttl], r) } - slices.SortFunc(hops, func(a, b Hop) int { - return a.Ttl - b.Ttl - }) - - PrintHops(hops) + // TODO: log this on debug level + printHops(hops) return hops, nil } @@ -227,12 +224,14 @@ type Hop struct { Reached bool } -func PrintHops(hops []Hop) { - for _, hop := range hops { - fmt.Printf("%d %s %s %v ", hop.Ttl, hop.Addr, hop.Name, hop.Latency) - if hop.Reached { - fmt.Print("( Reached )") +func printHops(mapHops map[int][]Hop) { + for ttl, hops := range mapHops { + for _, hop := range hops { + fmt.Printf("%d %s %s %v ", ttl, hop.Addr, hop.Name, hop.Latency) + if hop.Reached { + fmt.Print("( Reached )") + } + fmt.Println() } - fmt.Println() } } From b347c9bbf827b2d3832158a6ef2c754b8da495de Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 09:46:33 +0200 Subject: [PATCH 06/46] feat: logging Signed-off-by: Niklas Treml --- pkg/checks/traceroute/check.go | 4 ++-- pkg/checks/traceroute/check_test.go | 4 ++-- pkg/checks/traceroute/traceroute.go | 36 ++++++++++++++++++----------- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/pkg/checks/traceroute/check.go b/pkg/checks/traceroute/check.go index cbb4c05e..b955ceec 100644 --- a/pkg/checks/traceroute/check.go +++ b/pkg/checks/traceroute/check.go @@ -41,7 +41,7 @@ type Traceroute struct { traceroute tracerouteFactory } -type tracerouteFactory func(dest string, port, timeout, maxHops int, rc helper.RetryConfig) (map[int][]Hop, error) +type tracerouteFactory func(ctx context.Context, dest string, port, timeout, maxHops int, rc helper.RetryConfig) (map[int][]Hop, error) type result struct { // The minimum number of hops required to reach the target @@ -109,7 +109,7 @@ func (tr *Traceroute) check(ctx context.Context) map[string]result { l.Debug("Running traceroute") start := time.Now() - trace, err := tr.traceroute(t.Addr, int(t.Port), int(tr.config.Timeout/time.Millisecond), tr.config.MaxHops, tr.config.Retry) + trace, err := tr.traceroute(ctx, t.Addr, int(t.Port), int(tr.config.Timeout/time.Millisecond), tr.config.MaxHops, tr.config.Retry) duration := time.Since(start) if err != nil { l.Error("Error running traceroute", "error", err) diff --git a/pkg/checks/traceroute/check_test.go b/pkg/checks/traceroute/check_test.go index ae5858c9..fd15e13c 100644 --- a/pkg/checks/traceroute/check_test.go +++ b/pkg/checks/traceroute/check_test.go @@ -75,7 +75,7 @@ func newForTest(f tracerouteFactory, targets []string) *Traceroute { // success produces a tracerouteFactory that returns a traceroute result with nHops hops func success(nHops int) tracerouteFactory { - return func(dest string, port, timeout, maxHops int, _ helper.RetryConfig) (map[int][]Hop, error) { + return func(ctx context.Context, dest string, port, timeout, maxHops int, _ helper.RetryConfig) (map[int][]Hop, error) { hops := make(map[int][]Hop) for i := 1; i < nHops; i++ { hops[i] = []Hop{ @@ -106,7 +106,7 @@ func success(nHops int) tracerouteFactory { } func returnError(err error) tracerouteFactory { - return func(string, int, int, int, helper.RetryConfig) (map[int][]Hop, error) { + return func(context.Context, string, int, int, int, helper.RetryConfig) (map[int][]Hop, error) { return map[int][]Hop{}, err } } diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index daaef1ed..e5e70477 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -11,6 +11,7 @@ import ( "time" "github.com/caas-team/sparrow/internal/helper" + "github.com/caas-team/sparrow/internal/logger" "golang.org/x/net/icmp" "golang.org/x/net/ipv4" ) @@ -83,15 +84,17 @@ func readIcmpMessage(icmpListener *icmp.PacketConn, timeout time.Duration) (int, } // TraceRoute performs a traceroute to the specified host using TCP and listens for ICMP Time Exceeded messages using ICMP. -func TraceRoute(host string, port, timeout, maxHops int, rc helper.RetryConfig) (map[int][]Hop, error) { +func TraceRoute(ctx context.Context, host string, port, timeout, maxHops int, rc helper.RetryConfig) (map[int][]Hop, error) { // this could also be a 2d array, but I feel like using an int map here makes the json easier to understand // as it explicitly shows a mapping of ttl->hops - var hops map[int][]Hop + hops := make(map[int][]Hop) + log := logger.FromContext(ctx).With("target", host) - toDuration := time.Duration(timeout) * time.Second + timeoutDuration := time.Duration(timeout) * time.Second addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port)) if err != nil { + log.Error("failed to resolve target name", "err", err.Error()) return nil, err } @@ -102,16 +105,21 @@ func TraceRoute(host string, port, timeout, maxHops int, rc helper.RetryConfig) wg.Add(1) go func() { defer wg.Done() - helper.Retry(func(ctx context.Context) error { - reached, err := traceroute(results, addr, ttl, toDuration, rc) + err := helper.Retry(func(ctx context.Context) error { + reached, err := traceroute(results, addr, ttl, timeoutDuration) if err != nil { + log.Error("traceroute failed", "err", err.Error(), "ttl", ttl) return err } if !reached { - return errors.New("failed to reach target, please retry") + log.Debug("failed to reach target, retrying", "ttl", ttl) + return errors.New("failed to reach target") } return nil }, rc) + if err != nil { + log.Error("traceroute could not reach target", "ttl", ttl) + } }() } @@ -122,8 +130,7 @@ func TraceRoute(host string, port, timeout, maxHops int, rc helper.RetryConfig) hops[r.Ttl] = append(hops[r.Ttl], r) } - // TODO: log this on debug level - printHops(hops) + log.Debug("finished trace", "hops", printHops(hops)) return hops, nil } @@ -140,7 +147,7 @@ func ipFromAddr(remoteAddr net.Addr) net.IP { return nil } -func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration, rc helper.RetryConfig) (bool, error) { +func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) (bool, error) { icmpListener, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") if err != nil { return false, err @@ -224,14 +231,17 @@ type Hop struct { Reached bool } -func printHops(mapHops map[int][]Hop) { +func printHops(mapHops map[int][]Hop) string { + out := "" for ttl, hops := range mapHops { for _, hop := range hops { - fmt.Printf("%d %s %s %v ", ttl, hop.Addr, hop.Name, hop.Latency) + out += fmt.Sprintf("%d %s %s %v ", ttl, hop.Addr, hop.Name, hop.Latency) if hop.Reached { - fmt.Print("( Reached )") + out += "( Reached )" } - fmt.Println() + out += "\n" } } + + return out } From ced17bdecdbe9ee514299ced4016990edc959d8b Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 11:06:55 +0200 Subject: [PATCH 07/46] feat: check permissions for icmp Signed-off-by: Niklas Treml --- pkg/checks/traceroute/traceroute.go | 36 ++++++++++++++++-------- pkg/checks/traceroute/traceroute_test.go | 16 +++++++++++ 2 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 pkg/checks/traceroute/traceroute_test.go diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index e5e70477..938fe9a8 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -116,7 +116,7 @@ func TraceRoute(ctx context.Context, host string, port, timeout, maxHops int, rc return errors.New("failed to reach target") } return nil - }, rc) + }, rc)(ctx) if err != nil { log.Error("traceroute could not reach target", "ttl", ttl) } @@ -148,11 +148,21 @@ func ipFromAddr(remoteAddr net.Addr) net.IP { } func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) (bool, error) { + canIcmp := true icmpListener, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") if err != nil { - return false, err + if !errors.Is(err, syscall.EPERM) { + return false, err + } + fmt.Println("no permission to create icmp sockets. continuing without") + canIcmp = false } - defer icmpListener.Close() + + defer func() { + if canIcmp { + icmpListener.Close() + } + }() start := time.Now() conn, clientPort, err := tcpHop(addr, ttl, timeout) latency := time.Since(start) @@ -181,18 +191,22 @@ func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) deadline := time.Now().Add(5 * time.Second) for time.Now().Unix() < deadline.Unix() && !found { - gotPort, addr, err := readIcmpMessage(icmpListener, timeout) - if err != nil { - results <- Hop{ - Latency: latency, - Ttl: ttl, - Reached: false, + gotPort := -1 + var addr net.Addr + if canIcmp { + gotPort, addr, err = readIcmpMessage(icmpListener, timeout) + if err != nil { + results <- Hop{ + Latency: latency, + Ttl: ttl, + Reached: false, + } + return false, nil } - return false, nil } // Check if the destination port matches our dialer's source port - if gotPort == clientPort { + if canIcmp && gotPort == clientPort { ipaddr := ipFromAddr(addr) names, _ := net.LookupAddr(ipaddr.String()) // we don't really care if this lookup works, so ignore the error diff --git a/pkg/checks/traceroute/traceroute_test.go b/pkg/checks/traceroute/traceroute_test.go new file mode 100644 index 00000000..c4c5c4ad --- /dev/null +++ b/pkg/checks/traceroute/traceroute_test.go @@ -0,0 +1,16 @@ +package traceroute + +import ( + "errors" + "syscall" + "testing" + + "golang.org/x/net/icmp" +) + +func TestTR(t *testing.T) { + _, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") + if !errors.Is(err, syscall.EPERM) { + t.Errorf("err is not eperm") + } +} From 01b76b682eea174a5351b50df0930c215d38874d Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 11:18:01 +0200 Subject: [PATCH 08/46] fix: calm down linter Signed-off-by: Niklas Treml --- pkg/checks/traceroute/traceroute.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 938fe9a8..1cdf823c 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -18,7 +18,7 @@ import ( // randomPort returns a random port in the interval [ 30_000, 40_000 [ func randomPort() int { - return rand.Intn(10_000) + 30_000 + return rand.Intn(10_000) + 30_000 //nolint:gosec,mnd // math.rand is fine here, we're not doing encryption } func tcpHop(addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error) { @@ -30,7 +30,7 @@ func tcpHop(addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error Port: port, }, Timeout: timeout, - Control: func(network, address string, c syscall.RawConn) error { + Control: func(_, _ string, c syscall.RawConn) error { var opErr error if err := c.Control(func(fd uintptr) { opErr = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TTL, ttl) @@ -43,7 +43,7 @@ func tcpHop(addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error // Attempt to connect to the target host conn, err := dialer.Dial("tcp", addr.String()) - if !errors.Is(err, syscall.Errno(syscall.EADDRINUSE)) { + if !errors.Is(err, syscall.EADDRINUSE) { return conn, port, err } } @@ -55,12 +55,14 @@ func tcpHop(addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error // an icmp packet was either not received, or the received packet was not a time exceeded. func readIcmpMessage(icmpListener *icmp.PacketConn, timeout time.Duration) (int, net.Addr, error) { // Expected to fail due to TTL expiry, listen for ICMP response - icmpListener.SetReadDeadline(time.Now().Add(timeout)) - buffer := make([]byte, 1500) // Standard MTU size + if err := icmpListener.SetReadDeadline(time.Now().Add(timeout)); err != nil { + return 0, nil, fmt.Errorf("failed to set icmp read deadline: %w", err) + } + buffer := make([]byte, 1500) //nolint:mnd // Standard MTU size n, routerAddr, err := icmpListener.ReadFrom(buffer) if err != nil { // we probably timed out so return - return 0, nil, fmt.Errorf("Failed to read from icmp connection: %w", err) + return 0, nil, fmt.Errorf("failed to read from icmp connection: %w", err) } // Parse the ICMP message @@ -71,7 +73,7 @@ func readIcmpMessage(icmpListener *icmp.PacketConn, timeout time.Duration) (int, // Ensure the message is an ICMP Time Exceeded message if msg.Type != ipv4.ICMPTypeTimeExceeded { - return 0, nil, errors.New("Message is not 'Time Exceeded'") + return 0, nil, errors.New("message is not 'Time Exceeded'") } // The first 20 bytes of Data are the IP header, so the TCP segment starts at byte 20 @@ -105,7 +107,7 @@ func TraceRoute(ctx context.Context, host string, port, timeout, maxHops int, rc wg.Add(1) go func() { defer wg.Done() - err := helper.Retry(func(ctx context.Context) error { + err := helper.Retry(func(_ context.Context) error { reached, err := traceroute(results, addr, ttl, timeoutDuration) if err != nil { log.Error("traceroute failed", "err", err.Error(), "ttl", ttl) @@ -188,7 +190,7 @@ func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) } found := false - deadline := time.Now().Add(5 * time.Second) + deadline := time.Now().Add(timeout) for time.Now().Unix() < deadline.Unix() && !found { gotPort := -1 From 84e92c7e266e7f95d362518385f2e699cca6e0ce Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 11:26:09 +0200 Subject: [PATCH 09/46] refactor: tracerouteConfig struct for factory Signed-off-by: Niklas Treml --- pkg/checks/traceroute/check.go | 17 +++++++++++++++-- pkg/checks/traceroute/check_test.go | 8 +++----- pkg/checks/traceroute/traceroute.go | 14 +++++++------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/pkg/checks/traceroute/check.go b/pkg/checks/traceroute/check.go index b955ceec..d552e922 100644 --- a/pkg/checks/traceroute/check.go +++ b/pkg/checks/traceroute/check.go @@ -41,7 +41,14 @@ type Traceroute struct { traceroute tracerouteFactory } -type tracerouteFactory func(ctx context.Context, dest string, port, timeout, maxHops int, rc helper.RetryConfig) (map[int][]Hop, error) +type tracerouteConfig struct { + Dest string + Port int + Timeout int + MaxHops int + Rc helper.RetryConfig +} +type tracerouteFactory func(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error) type result struct { // The minimum number of hops required to reach the target @@ -109,7 +116,13 @@ func (tr *Traceroute) check(ctx context.Context) map[string]result { l.Debug("Running traceroute") start := time.Now() - trace, err := tr.traceroute(ctx, t.Addr, int(t.Port), int(tr.config.Timeout/time.Millisecond), tr.config.MaxHops, tr.config.Retry) + trace, err := tr.traceroute(ctx, tracerouteConfig{ + Dest: t.Addr, + Port: int(t.Port), + Timeout: int(tr.config.Timeout / time.Millisecond), + MaxHops: tr.config.MaxHops, + Rc: tr.config.Retry, + }) duration := time.Since(start) if err != nil { l.Error("Error running traceroute", "error", err) diff --git a/pkg/checks/traceroute/check_test.go b/pkg/checks/traceroute/check_test.go index fd15e13c..297b2636 100644 --- a/pkg/checks/traceroute/check_test.go +++ b/pkg/checks/traceroute/check_test.go @@ -7,10 +7,8 @@ import ( "testing" "time" - "github.com/google/go-cmp/cmp" - - "github.com/caas-team/sparrow/internal/helper" "github.com/caas-team/sparrow/pkg/checks" + "github.com/google/go-cmp/cmp" ) func TestCheck(t *testing.T) { @@ -75,7 +73,7 @@ func newForTest(f tracerouteFactory, targets []string) *Traceroute { // success produces a tracerouteFactory that returns a traceroute result with nHops hops func success(nHops int) tracerouteFactory { - return func(ctx context.Context, dest string, port, timeout, maxHops int, _ helper.RetryConfig) (map[int][]Hop, error) { + return func(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error) { hops := make(map[int][]Hop) for i := 1; i < nHops; i++ { hops[i] = []Hop{ @@ -106,7 +104,7 @@ func success(nHops int) tracerouteFactory { } func returnError(err error) tracerouteFactory { - return func(context.Context, string, int, int, int, helper.RetryConfig) (map[int][]Hop, error) { + return func(_ context.Context, _ tracerouteConfig) (map[int][]Hop, error) { return map[int][]Hop{}, err } } diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 1cdf823c..25b09549 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -86,24 +86,24 @@ func readIcmpMessage(icmpListener *icmp.PacketConn, timeout time.Duration) (int, } // TraceRoute performs a traceroute to the specified host using TCP and listens for ICMP Time Exceeded messages using ICMP. -func TraceRoute(ctx context.Context, host string, port, timeout, maxHops int, rc helper.RetryConfig) (map[int][]Hop, error) { +func TraceRoute(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error) { // this could also be a 2d array, but I feel like using an int map here makes the json easier to understand // as it explicitly shows a mapping of ttl->hops hops := make(map[int][]Hop) - log := logger.FromContext(ctx).With("target", host) + log := logger.FromContext(ctx).With("target", cfg.Dest) - timeoutDuration := time.Duration(timeout) * time.Second + timeoutDuration := time.Duration(cfg.Timeout) * time.Second - addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port)) + addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", cfg.Dest, cfg.Port)) if err != nil { log.Error("failed to resolve target name", "err", err.Error()) return nil, err } - results := make(chan Hop, maxHops) + results := make(chan Hop, cfg.MaxHops) var wg sync.WaitGroup - for ttl := 1; ttl <= maxHops; ttl++ { + for ttl := 1; ttl <= cfg.MaxHops; ttl++ { wg.Add(1) go func() { defer wg.Done() @@ -118,7 +118,7 @@ func TraceRoute(ctx context.Context, host string, port, timeout, maxHops int, rc return errors.New("failed to reach target") } return nil - }, rc)(ctx) + }, cfg.Rc)(ctx) if err != nil { log.Error("traceroute could not reach target", "ttl", ttl) } From 9297a1fcf9cf923467717f1bc04b558075444b11 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 11:55:31 +0200 Subject: [PATCH 10/46] fix: unbuffered channel caused sparrow to hang on shut down when traceroute waas enabled Signed-off-by: Niklas Treml --- pkg/checks/traceroute/check.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/checks/traceroute/check.go b/pkg/checks/traceroute/check.go index d552e922..16c1649e 100644 --- a/pkg/checks/traceroute/check.go +++ b/pkg/checks/traceroute/check.go @@ -28,7 +28,7 @@ func NewCheck() checks.Check { return &Traceroute{ CheckBase: checks.CheckBase{ Mu: sync.Mutex{}, - DoneChan: make(chan struct{}), + DoneChan: make(chan struct{}, 1), }, config: Config{}, traceroute: TraceRoute, From 8e450e2b93f2fae739d69c35d1463399007795b0 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 13:59:30 +0200 Subject: [PATCH 11/46] feat: prometheus metrics Signed-off-by: Niklas Treml --- pkg/checks/traceroute/check.go | 28 +++++++++--------- pkg/checks/traceroute/check_test.go | 2 +- pkg/checks/traceroute/metrics.go | 46 +++++++++++++++++++++++++++++ pkg/checks/traceroute/traceroute.go | 1 - 4 files changed, 61 insertions(+), 16 deletions(-) create mode 100644 pkg/checks/traceroute/metrics.go diff --git a/pkg/checks/traceroute/check.go b/pkg/checks/traceroute/check.go index 16c1649e..ff73ad03 100644 --- a/pkg/checks/traceroute/check.go +++ b/pkg/checks/traceroute/check.go @@ -2,7 +2,7 @@ package traceroute import ( "context" - "fmt" + "math" "sync" "time" @@ -32,6 +32,7 @@ func NewCheck() checks.Check { }, config: Config{}, traceroute: TraceRoute, + metrics: newMetrics(), } } @@ -39,6 +40,7 @@ type Traceroute struct { checks.CheckBase config Config traceroute tracerouteFactory + metrics metrics } type tracerouteConfig struct { @@ -52,7 +54,7 @@ type tracerouteFactory func(ctx context.Context, cfg tracerouteConfig) (map[int] type result struct { // The minimum number of hops required to reach the target - NumHops int + MinHops int // The path taken to the destination Hops map[int][]Hop } @@ -72,11 +74,8 @@ func (tr *Traceroute) Run(ctx context.Context, cResult chan checks.ResultDTO) er case <-tr.DoneChan: return nil case <-time.After(tr.config.Interval): - fmt.Println("Running traceroute") res := tr.check(ctx) - - fmt.Println(res) - + tr.metrics.MinHops(res) cResult <- checks.ResultDTO{ Name: tr.Name(), Result: &checks.Result{ @@ -123,22 +122,23 @@ func (tr *Traceroute) check(ctx context.Context) map[string]result { MaxHops: tr.config.MaxHops, Rc: tr.config.Retry, }) - duration := time.Since(start) + elapsed := time.Since(start) if err != nil { l.Error("Error running traceroute", "error", err) } - l.Debug("Ran traceroute", "result", trace, "duration", duration) + tr.metrics.CheckDuration(t.Addr, elapsed) + + l.Debug("Ran traceroute", "result", trace, "duration", elapsed) r := result{ - Hops: trace, + Hops: trace, + MinHops: math.MaxInt, } - reached: for i, hops := range trace { for _, hop := range hops { - if hop.Reached { - r.NumHops = i - break reached + if hop.Reached && hop.Ttl < r.MinHops { + r.MinHops = i } } } @@ -187,7 +187,7 @@ func (tr *Traceroute) Schema() (*openapi3.SchemaRef, error) { // GetMetricCollectors allows the check to provide prometheus metric collectors func (tr *Traceroute) GetMetricCollectors() []prometheus.Collector { - return []prometheus.Collector{} + return tr.metrics.List() } // Name returns the name of the check diff --git a/pkg/checks/traceroute/check_test.go b/pkg/checks/traceroute/check_test.go index 297b2636..f1cdb8c4 100644 --- a/pkg/checks/traceroute/check_test.go +++ b/pkg/checks/traceroute/check_test.go @@ -22,7 +22,7 @@ func TestCheck(t *testing.T) { c: newForTest(success(5), []string{"8.8.8.8"}), want: map[string]result{ "8.8.8.8": { - NumHops: 5, + MinHops: 5, Hops: map[int][]Hop{ 1: {{Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.1")}, Latency: 1 * time.Second, Reached: false, Ttl: 1}}, 2: {{Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.2")}, Latency: 2 * time.Second, Reached: false, Ttl: 2}}, diff --git a/pkg/checks/traceroute/metrics.go b/pkg/checks/traceroute/metrics.go new file mode 100644 index 00000000..7b87f628 --- /dev/null +++ b/pkg/checks/traceroute/metrics.go @@ -0,0 +1,46 @@ +package traceroute + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" +) + +const ( + labelTarget = "target" +) + +type metrics struct { + minHops *prometheus.GaugeVec + checkDuration *prometheus.GaugeVec +} + +func (m metrics) List() []prometheus.Collector { + return []prometheus.Collector{ + m.minHops, + m.checkDuration, + } +} + +func (m metrics) MinHops(data map[string]result) { + for target, hops := range data { + m.minHops.With(prometheus.Labels{labelTarget: target}).Set(float64(hops.MinHops)) + } +} + +func (m metrics) CheckDuration(target string, n time.Duration) { + m.checkDuration.With(prometheus.Labels{labelTarget: target}).Set(float64(n.Milliseconds())) +} + +func newMetrics() metrics { + return metrics{ + minHops: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: "sparrow_traceroute", + Name: "minimum_hops", + }, []string{labelTarget}), + checkDuration: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: "sparrow_traceroute", + Name: "check_duration_ms", + }, []string{labelTarget}), + } +} diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 25b09549..84d28f47 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -156,7 +156,6 @@ func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) if !errors.Is(err, syscall.EPERM) { return false, err } - fmt.Println("no permission to create icmp sockets. continuing without") canIcmp = false } From b238797faaf4b3f278bda0be7315f4bb55e2eff1 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 15:29:23 +0200 Subject: [PATCH 12/46] testing: simplify test setup Signed-off-by: Niklas Treml --- .../traceroute/test-lab/as100r1.startup | 5 -- .../test-lab/as100r1/etc/quagga/bgpd.conf | 41 ---------- .../test-lab/as100r1/etc/quagga/daemons | 13 --- .../test-lab/as100r1/etc/quagga/ripd.conf | 9 --- .../traceroute/test-lab/as100r2.startup | 4 - .../test-lab/as100r2/etc/quagga/daemons | 13 --- .../test-lab/as100r2/etc/quagga/ripd.conf | 10 --- .../traceroute/test-lab/as100r3.startup | 4 - .../test-lab/as100r3/etc/quagga/daemons | 13 --- .../test-lab/as100r3/etc/quagga/ripd.conf | 10 --- pkg/checks/traceroute/test-lab/as1r1.startup | 4 - .../test-lab/as1r1/etc/quagga/bgpd.conf | 36 --------- .../test-lab/as1r1/etc/quagga/daemons | 13 --- .../traceroute/test-lab/as200r1.startup | 4 - .../test-lab/as200r1/etc/quagga/bgpd.conf | 27 ------- .../test-lab/as200r1/etc/quagga/daemons | 13 --- pkg/checks/traceroute/test-lab/as20r1.startup | 5 -- .../test-lab/as20r1/etc/quagga/bgpd.conf | 49 ------------ .../test-lab/as20r1/etc/quagga/daemons | 13 --- .../test-lab/as20r1/etc/quagga/ospfd.conf | 12 --- pkg/checks/traceroute/test-lab/as20r2.startup | 4 - .../test-lab/as20r2/etc/quagga/bgpd.conf | 34 -------- .../test-lab/as20r2/etc/quagga/daemons | 13 --- .../test-lab/as20r2/etc/quagga/ospfd.conf | 12 --- pkg/checks/traceroute/test-lab/as20r3.startup | 3 - .../test-lab/as20r3/etc/quagga/bgpd.conf | 26 ------ .../test-lab/as20r3/etc/quagga/daemons | 13 --- .../test-lab/as20r3/etc/quagga/ospfd.conf | 12 --- pkg/checks/traceroute/test-lab/as30r1.startup | 5 -- .../test-lab/as30r1/etc/quagga/bgpd.conf | 36 --------- .../test-lab/as30r1/etc/quagga/daemons | 13 --- pkg/checks/traceroute/test-lab/client.startup | 2 - .../test-lab/client/etc/resolv.conf | 1 - pkg/checks/traceroute/test-lab/itdns.startup | 3 - .../traceroute/test-lab/itdns/etc/bind/db.it | 13 --- .../test-lab/itdns/etc/bind/db.root | 2 - .../test-lab/itdns/etc/bind/named.conf | 11 --- .../itdns/etc/bind/named.conf.options | 3 - pkg/checks/traceroute/test-lab/lab.conf | 79 ++++--------------- pkg/checks/traceroute/test-lab/ldns.startup | 3 - .../traceroute/test-lab/ldns/etc/bind/db.root | 2 - .../test-lab/ldns/etc/bind/named.conf | 6 -- .../test-lab/ldns/etc/bind/named.conf.options | 5 -- pkg/checks/traceroute/test-lab/pc1.startup | 2 + pkg/checks/traceroute/test-lab/pc2.startup | 3 + pkg/checks/traceroute/test-lab/r1.startup | 3 + pkg/checks/traceroute/test-lab/r2.startup | 3 + pkg/checks/traceroute/test-lab/r3dns.startup | 3 - .../test-lab/r3dns/etc/bind/db.it.uniroma3 | 11 --- .../test-lab/r3dns/etc/bind/db.root | 2 - .../test-lab/r3dns/etc/bind/named.conf | 11 --- .../r3dns/etc/bind/named.conf.options | 3 - .../traceroute/test-lab/rootdns.startup | 3 - .../test-lab/rootdns/etc/bind/db.root | 14 ---- .../test-lab/rootdns/etc/bind/named.conf | 6 -- .../rootdns/etc/bind/named.conf.options | 3 - .../traceroute/test-lab/webserver.startup | 3 - .../webserver/var/www/html/index.html | 14 ---- .../test-lab/webserver/var/www/index.html | 14 ---- 59 files changed, 25 insertions(+), 672 deletions(-) delete mode 100644 pkg/checks/traceroute/test-lab/as100r1.startup delete mode 100644 pkg/checks/traceroute/test-lab/as100r1/etc/quagga/bgpd.conf delete mode 100644 pkg/checks/traceroute/test-lab/as100r1/etc/quagga/daemons delete mode 100644 pkg/checks/traceroute/test-lab/as100r1/etc/quagga/ripd.conf delete mode 100644 pkg/checks/traceroute/test-lab/as100r2.startup delete mode 100644 pkg/checks/traceroute/test-lab/as100r2/etc/quagga/daemons delete mode 100644 pkg/checks/traceroute/test-lab/as100r2/etc/quagga/ripd.conf delete mode 100644 pkg/checks/traceroute/test-lab/as100r3.startup delete mode 100644 pkg/checks/traceroute/test-lab/as100r3/etc/quagga/daemons delete mode 100644 pkg/checks/traceroute/test-lab/as100r3/etc/quagga/ripd.conf delete mode 100644 pkg/checks/traceroute/test-lab/as1r1.startup delete mode 100644 pkg/checks/traceroute/test-lab/as1r1/etc/quagga/bgpd.conf delete mode 100644 pkg/checks/traceroute/test-lab/as1r1/etc/quagga/daemons delete mode 100644 pkg/checks/traceroute/test-lab/as200r1.startup delete mode 100644 pkg/checks/traceroute/test-lab/as200r1/etc/quagga/bgpd.conf delete mode 100644 pkg/checks/traceroute/test-lab/as200r1/etc/quagga/daemons delete mode 100644 pkg/checks/traceroute/test-lab/as20r1.startup delete mode 100644 pkg/checks/traceroute/test-lab/as20r1/etc/quagga/bgpd.conf delete mode 100644 pkg/checks/traceroute/test-lab/as20r1/etc/quagga/daemons delete mode 100644 pkg/checks/traceroute/test-lab/as20r1/etc/quagga/ospfd.conf delete mode 100644 pkg/checks/traceroute/test-lab/as20r2.startup delete mode 100644 pkg/checks/traceroute/test-lab/as20r2/etc/quagga/bgpd.conf delete mode 100644 pkg/checks/traceroute/test-lab/as20r2/etc/quagga/daemons delete mode 100644 pkg/checks/traceroute/test-lab/as20r2/etc/quagga/ospfd.conf delete mode 100644 pkg/checks/traceroute/test-lab/as20r3.startup delete mode 100644 pkg/checks/traceroute/test-lab/as20r3/etc/quagga/bgpd.conf delete mode 100644 pkg/checks/traceroute/test-lab/as20r3/etc/quagga/daemons delete mode 100644 pkg/checks/traceroute/test-lab/as20r3/etc/quagga/ospfd.conf delete mode 100644 pkg/checks/traceroute/test-lab/as30r1.startup delete mode 100644 pkg/checks/traceroute/test-lab/as30r1/etc/quagga/bgpd.conf delete mode 100644 pkg/checks/traceroute/test-lab/as30r1/etc/quagga/daemons delete mode 100644 pkg/checks/traceroute/test-lab/client.startup delete mode 100644 pkg/checks/traceroute/test-lab/client/etc/resolv.conf delete mode 100644 pkg/checks/traceroute/test-lab/itdns.startup delete mode 100644 pkg/checks/traceroute/test-lab/itdns/etc/bind/db.it delete mode 100644 pkg/checks/traceroute/test-lab/itdns/etc/bind/db.root delete mode 100644 pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf delete mode 100644 pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf.options delete mode 100644 pkg/checks/traceroute/test-lab/ldns.startup delete mode 100644 pkg/checks/traceroute/test-lab/ldns/etc/bind/db.root delete mode 100644 pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf delete mode 100644 pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf.options create mode 100644 pkg/checks/traceroute/test-lab/pc1.startup create mode 100644 pkg/checks/traceroute/test-lab/pc2.startup create mode 100644 pkg/checks/traceroute/test-lab/r1.startup create mode 100644 pkg/checks/traceroute/test-lab/r2.startup delete mode 100644 pkg/checks/traceroute/test-lab/r3dns.startup delete mode 100644 pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.it.uniroma3 delete mode 100644 pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.root delete mode 100644 pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf delete mode 100644 pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf.options delete mode 100644 pkg/checks/traceroute/test-lab/rootdns.startup delete mode 100644 pkg/checks/traceroute/test-lab/rootdns/etc/bind/db.root delete mode 100644 pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf delete mode 100644 pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf.options delete mode 100644 pkg/checks/traceroute/test-lab/webserver.startup delete mode 100644 pkg/checks/traceroute/test-lab/webserver/var/www/html/index.html delete mode 100644 pkg/checks/traceroute/test-lab/webserver/var/www/index.html diff --git a/pkg/checks/traceroute/test-lab/as100r1.startup b/pkg/checks/traceroute/test-lab/as100r1.startup deleted file mode 100644 index 200b4239..00000000 --- a/pkg/checks/traceroute/test-lab/as100r1.startup +++ /dev/null @@ -1,5 +0,0 @@ -ip address add 11.0.0.1/30 dev eth0 -ip address add 11.0.0.5/30 dev eth1 -ip address add 100.1.0.1/30 dev eth2 -ip address add 100.1.0.5/30 dev eth3 -systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/bgpd.conf deleted file mode 100644 index 2c3a8fda..00000000 --- a/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/bgpd.conf +++ /dev/null @@ -1,41 +0,0 @@ -! -hostname bgpd -password zebra -enable password zebra -! -router bgp 100 -network 100.1.0.0/16 -! -neighbor 11.0.0.2 remote-as 20 -neighbor 11.0.0.2 description Router as20r2 (primary) -neighbor 11.0.0.2 prefix-list mineOutOnly out -neighbor 11.0.0.2 prefix-list defaultIn in -! -neighbor 11.0.0.6 remote-as 20 -neighbor 11.0.0.6 description Router as20r1 (backup) -neighbor 11.0.0.6 prefix-list mineOutOnly out -neighbor 11.0.0.6 route-map metricOut out -neighbor 11.0.0.6 prefix-list defaultIn in -neighbor 11.0.0.6 route-map localPrefIn in -! -ip prefix-list mineOutOnly permit 100.1.0.0/16 -ip prefix-list defaultIn permit 0.0.0.0/0 -! -route-map metricOut permit 10 -match ip address myAggregate -set metric 10 -! -route-map localPrefIn permit 10 -set local-preference 90 -! -access-list myAggregate permit 100.1.0.0/16 -! -log file /var/log/quagga/bgpd.log -! -debug bgp -debug bgp events -debug bgp filters -debug bgp fsm -debug bgp keepalives -debug bgp updates -! diff --git a/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/daemons deleted file mode 100644 index 4e3f16d6..00000000 --- a/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/daemons +++ /dev/null @@ -1,13 +0,0 @@ -# This file tells the zebra package -# which daemons to start. -# Entries are in the format: =(yes|no|priority) -# where 'yes' is equivalent to infinitely low priority, and -# lower numbers mean higher priority. Read -# /usr/doc/zebra/README.Debian for details. -# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd -zebra=yes -bgpd=yes -ospfd=no -ospf6d=no -ripd=yes -ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/ripd.conf b/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/ripd.conf deleted file mode 100644 index 57cda4d0..00000000 --- a/pkg/checks/traceroute/test-lab/as100r1/etc/quagga/ripd.conf +++ /dev/null @@ -1,9 +0,0 @@ -! -hostname ripd -password zebra -! -router rip -redistribute bgp -network 100.1.0.0/16 -! -log file /var/log/quagga/ripd.log diff --git a/pkg/checks/traceroute/test-lab/as100r2.startup b/pkg/checks/traceroute/test-lab/as100r2.startup deleted file mode 100644 index 4d621abd..00000000 --- a/pkg/checks/traceroute/test-lab/as100r2.startup +++ /dev/null @@ -1,4 +0,0 @@ -ip address add 100.1.0.6/30 dev eth0 -ip address add 100.1.0.9/30 dev eth1 -ip address add 100.1.2.1/24 dev eth2 -systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as100r2/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as100r2/etc/quagga/daemons deleted file mode 100644 index a5b998be..00000000 --- a/pkg/checks/traceroute/test-lab/as100r2/etc/quagga/daemons +++ /dev/null @@ -1,13 +0,0 @@ -# This file tells the zebra package -# which daemons to start. -# Entries are in the format: =(yes|no|priority) -# where 'yes' is equivalent to infinitely low priority, and -# lower numbers mean higher priority. Read -# /usr/doc/zebra/README.Debian for details. -# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd -zebra=yes -bgpd=no -ospfd=no -ospf6d=no -ripd=yes -ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as100r2/etc/quagga/ripd.conf b/pkg/checks/traceroute/test-lab/as100r2/etc/quagga/ripd.conf deleted file mode 100644 index de74e422..00000000 --- a/pkg/checks/traceroute/test-lab/as100r2/etc/quagga/ripd.conf +++ /dev/null @@ -1,10 +0,0 @@ -! -hostname ripd -password zebra -! -router rip -network 100.1.0.0/16 -redistribute connected -! -log file /var/log/quagga/ripd.log -! diff --git a/pkg/checks/traceroute/test-lab/as100r3.startup b/pkg/checks/traceroute/test-lab/as100r3.startup deleted file mode 100644 index df33dde3..00000000 --- a/pkg/checks/traceroute/test-lab/as100r3.startup +++ /dev/null @@ -1,4 +0,0 @@ -ip address add 100.1.0.2/30 dev eth0 -ip address add 100.1.0.10/30 dev eth1 -ip address add 100.1.3.1/24 dev eth2 -systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as100r3/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as100r3/etc/quagga/daemons deleted file mode 100644 index a5b998be..00000000 --- a/pkg/checks/traceroute/test-lab/as100r3/etc/quagga/daemons +++ /dev/null @@ -1,13 +0,0 @@ -# This file tells the zebra package -# which daemons to start. -# Entries are in the format: =(yes|no|priority) -# where 'yes' is equivalent to infinitely low priority, and -# lower numbers mean higher priority. Read -# /usr/doc/zebra/README.Debian for details. -# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd -zebra=yes -bgpd=no -ospfd=no -ospf6d=no -ripd=yes -ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as100r3/etc/quagga/ripd.conf b/pkg/checks/traceroute/test-lab/as100r3/etc/quagga/ripd.conf deleted file mode 100644 index de74e422..00000000 --- a/pkg/checks/traceroute/test-lab/as100r3/etc/quagga/ripd.conf +++ /dev/null @@ -1,10 +0,0 @@ -! -hostname ripd -password zebra -! -router rip -network 100.1.0.0/16 -redistribute connected -! -log file /var/log/quagga/ripd.log -! diff --git a/pkg/checks/traceroute/test-lab/as1r1.startup b/pkg/checks/traceroute/test-lab/as1r1.startup deleted file mode 100644 index 6194b450..00000000 --- a/pkg/checks/traceroute/test-lab/as1r1.startup +++ /dev/null @@ -1,4 +0,0 @@ -ip address add 11.0.0.26/30 dev eth0 -ip address add 11.0.0.22/30 dev eth1 -ip address add 1.1.0.1/16 dev eth2 -systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as1r1/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as1r1/etc/quagga/bgpd.conf deleted file mode 100644 index f06eee2c..00000000 --- a/pkg/checks/traceroute/test-lab/as1r1/etc/quagga/bgpd.conf +++ /dev/null @@ -1,36 +0,0 @@ -! -hostname bgpd -password zebra -enable password zebra -! -router bgp 1 -network 11.0.0.20/30 -network 11.0.0.24/30 -network 11.0.0.28/30 -network 1.1.0.0/16 -network 0.0.0.0/0 -! -neighbor 11.0.0.21 remote-as 20 -neighbor 11.0.0.21 description Router as20r3 -neighbor 11.0.0.21 default-originate -neighbor 11.0.0.21 prefix-list defaultOut out -neighbor 11.0.0.21 prefix-list acceptAny in -! -neighbor 11.0.0.25 remote-as 30 -neighbor 11.0.0.25 description Router as30r1 -neighbor 11.0.0.25 default-originate -neighbor 11.0.0.25 prefix-list defaultOut out -neighbor 11.0.0.25 prefix-list acceptAny in -! -ip prefix-list defaultOut permit 0.0.0.0/0 -ip prefix-list acceptAny permit any -! -log file /var/log/quagga/bgpd.log -! -debug bgp -debug bgp events -debug bgp filters -debug bgp fsm -debug bgp keepalives -debug bgp updates -! diff --git a/pkg/checks/traceroute/test-lab/as1r1/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as1r1/etc/quagga/daemons deleted file mode 100644 index 0c469547..00000000 --- a/pkg/checks/traceroute/test-lab/as1r1/etc/quagga/daemons +++ /dev/null @@ -1,13 +0,0 @@ -# This file tells the zebra package -# which daemons to start. -# Entries are in the format: =(yes|no|priority) -# where 'yes' is equivalent to infinitely low priority, and -# lower numbers mean higher priority. Read -# /usr/doc/zebra/README.Debian for details. -# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd -zebra=yes -bgpd=yes -ospfd=no -ospf6d=no -ripd=no -ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as200r1.startup b/pkg/checks/traceroute/test-lab/as200r1.startup deleted file mode 100644 index ddad67c6..00000000 --- a/pkg/checks/traceroute/test-lab/as200r1.startup +++ /dev/null @@ -1,4 +0,0 @@ -ip address add 11.0.0.33/30 dev eth0 -ip address add 200.2.0.1/16 dev eth1 -ip address add 11.0.0.9/30 dev eth2 -systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as200r1/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as200r1/etc/quagga/bgpd.conf deleted file mode 100644 index 1c1cf27e..00000000 --- a/pkg/checks/traceroute/test-lab/as200r1/etc/quagga/bgpd.conf +++ /dev/null @@ -1,27 +0,0 @@ -! -hostname bgpd -password zebra -enable password zebra -! -router bgp 200 -network 200.2.0.0/16 -! -neighbor 11.0.0.34 remote-as 20 -neighbor 11.0.0.34 description Router as20r1 -! -neighbor 11.0.0.10 remote-as 30 -neighbor 11.0.0.10 description Router as30r1 -neighbor 11.0.0.10 route-map localPrefIn in -! -route-map localPrefIn permit 10 -set local-preference 90 -! -log file /var/log/quagga/bgpd.log -! -debug bgp -debug bgp events -debug bgp filters -debug bgp fsm -debug bgp keepalives -debug bgp updates -! diff --git a/pkg/checks/traceroute/test-lab/as200r1/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as200r1/etc/quagga/daemons deleted file mode 100644 index 0c469547..00000000 --- a/pkg/checks/traceroute/test-lab/as200r1/etc/quagga/daemons +++ /dev/null @@ -1,13 +0,0 @@ -# This file tells the zebra package -# which daemons to start. -# Entries are in the format: =(yes|no|priority) -# where 'yes' is equivalent to infinitely low priority, and -# lower numbers mean higher priority. Read -# /usr/doc/zebra/README.Debian for details. -# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd -zebra=yes -bgpd=yes -ospfd=no -ospf6d=no -ripd=no -ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as20r1.startup b/pkg/checks/traceroute/test-lab/as20r1.startup deleted file mode 100644 index 975b59d7..00000000 --- a/pkg/checks/traceroute/test-lab/as20r1.startup +++ /dev/null @@ -1,5 +0,0 @@ -ip address add 11.0.0.34/30 dev eth0 -ip address add 11.0.0.6/30 dev eth1 -ip address add 20.1.1.1/24 dev eth2 -ip address add 11.0.0.17/30 dev eth3 -systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/bgpd.conf deleted file mode 100644 index 57d308e1..00000000 --- a/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/bgpd.conf +++ /dev/null @@ -1,49 +0,0 @@ -! -hostname bgpd -password zebra -enable password zebra -! -router bgp 20 -network 20.1.1.0/24 -network 11.0.0.4/30 -network 11.0.0.16/30 -network 11.0.0.32/30 -! -neighbor 11.0.0.33 remote-as 200 -neighbor 11.0.0.33 description Router as200r1 -neighbor 11.0.0.33 default-originate -neighbor 11.0.0.33 prefix-list customer200 in -neighbor 11.0.0.33 prefix-list defaultOut out -! -neighbor 11.0.0.5 remote-as 100 -neighbor 11.0.0.5 description Router as100r1 -neighbor 11.0.0.5 default-originate -neighbor 11.0.0.5 prefix-list customer100 in -neighbor 11.0.0.5 prefix-list defaultOut out -! -neighbor 20.1.1.2 remote-as 20 -neighbor 20.1.1.2 description Router as20r2 (iBGP) -! -neighbor 20.1.1.3 remote-as 20 -neighbor 20.1.1.3 description Router as20r3 (iBGP) -! -neighbor 11.0.0.18 remote-as 30 -neighbor 11.0.0.18 description Router as30r1 (eBGP) -neighbor 11.0.0.18 prefix-list meAndCustomers out -! -ip prefix-list customer100 permit 100.1.0.0/16 -ip prefix-list customer200 permit 200.2.0.0/16 -ip prefix-list defaultOut permit 0.0.0.0/0 -ip prefix-list meAndCustomers permit 20.1.1.0/24 -ip prefix-list meAndCustomers permit 100.1.0.0/16 -ip prefix-list meAndCustomers permit 200.2.0.0/16 -! -log file /var/log/quagga/bgpd.log -! -debug bgp -debug bgp events -debug bgp filters -debug bgp fsm -debug bgp keepalives -debug bgp updates -! diff --git a/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/daemons deleted file mode 100644 index 82dbc113..00000000 --- a/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/daemons +++ /dev/null @@ -1,13 +0,0 @@ -# This file tells the zebra package -# which daemons to start. -# Entries are in the format: =(yes|no|priority) -# where 'yes' is equivalent to infinitely low priority, and -# lower numbers mean higher priority. Read -# /usr/doc/zebra/README.Debian for details. -# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd -zebra=yes -bgpd=yes -ospfd=yes -ospf6d=no -ripd=no -ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/ospfd.conf b/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/ospfd.conf deleted file mode 100644 index 478567c8..00000000 --- a/pkg/checks/traceroute/test-lab/as20r1/etc/quagga/ospfd.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -hostname ospfd -password zebra -enable password zebra -! -router ospf -! Speak OSPF on all interfaces falling in 20.1.1.0/24 -network 20.1.1.0/24 area 0.0.0.0 -redistribute connected -! -log file /var/log/quagga/ospfd.log -! diff --git a/pkg/checks/traceroute/test-lab/as20r2.startup b/pkg/checks/traceroute/test-lab/as20r2.startup deleted file mode 100644 index ae3f62cf..00000000 --- a/pkg/checks/traceroute/test-lab/as20r2.startup +++ /dev/null @@ -1,4 +0,0 @@ -ip address add 11.0.0.2/30 dev eth0 -ip address add 20.1.1.2/24 dev eth1 -ip address add 20.2.1.1/24 dev eth2 -systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/bgpd.conf deleted file mode 100644 index 23ef93d6..00000000 --- a/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/bgpd.conf +++ /dev/null @@ -1,34 +0,0 @@ -! -hostname bgpd -password zebra -enable password zebra -! -router bgp 20 -network 20.1.1.0/24 -network 20.2.1.0/24 -network 11.0.0.0/30 -! -neighbor 11.0.0.1 remote-as 100 -neighbor 11.0.0.1 description Router as100r1 -neighbor 11.0.0.1 default-originate -neighbor 11.0.0.1 prefix-list as100In in -neighbor 11.0.0.1 prefix-list defaultOut out -! -neighbor 20.1.1.1 remote-as 20 -neighbor 20.1.1.1 description Router as20r1 (iBGP) -! -neighbor 20.1.1.3 remote-as 20 -neighbor 20.1.1.3 description Router as20r3 (iBGP) -! -ip prefix-list as100In permit 100.1.0.0/16 -ip prefix-list defaultOut permit 0.0.0.0/0 -! -log file /var/log/quagga/bgpd.log -! -debug bgp -debug bgp events -debug bgp filters -debug bgp fsm -debug bgp keepalives -debug bgp updates -! diff --git a/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/daemons deleted file mode 100644 index 82dbc113..00000000 --- a/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/daemons +++ /dev/null @@ -1,13 +0,0 @@ -# This file tells the zebra package -# which daemons to start. -# Entries are in the format: =(yes|no|priority) -# where 'yes' is equivalent to infinitely low priority, and -# lower numbers mean higher priority. Read -# /usr/doc/zebra/README.Debian for details. -# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd -zebra=yes -bgpd=yes -ospfd=yes -ospf6d=no -ripd=no -ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/ospfd.conf b/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/ospfd.conf deleted file mode 100644 index 478567c8..00000000 --- a/pkg/checks/traceroute/test-lab/as20r2/etc/quagga/ospfd.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -hostname ospfd -password zebra -enable password zebra -! -router ospf -! Speak OSPF on all interfaces falling in 20.1.1.0/24 -network 20.1.1.0/24 area 0.0.0.0 -redistribute connected -! -log file /var/log/quagga/ospfd.log -! diff --git a/pkg/checks/traceroute/test-lab/as20r3.startup b/pkg/checks/traceroute/test-lab/as20r3.startup deleted file mode 100644 index 392e9823..00000000 --- a/pkg/checks/traceroute/test-lab/as20r3.startup +++ /dev/null @@ -1,3 +0,0 @@ -ip address add 11.0.0.21/30 dev eth0 -ip address add 20.1.1.3/24 dev eth1 -systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/bgpd.conf deleted file mode 100644 index 3696b2af..00000000 --- a/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/bgpd.conf +++ /dev/null @@ -1,26 +0,0 @@ -! -hostname bgpd -password zebra -enable password zebra -! -router bgp 20 -network 20.1.1.0/24 -! -neighbor 11.0.0.22 remote-as 1 -neighbor 11.0.0.22 description Router as1r1 (uplink) -! -neighbor 20.1.1.1 remote-as 20 -neighbor 20.1.1.1 description Router as20r1 (iBGP) -! -neighbor 20.1.1.2 remote-as 20 -neighbor 20.1.1.2 description Router as20r2 (iBGP) -! -log file /var/log/quagga/bgpd.log -! -debug bgp -debug bgp events -debug bgp filters -debug bgp fsm -debug bgp keepalives -debug bgp updates -! diff --git a/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/daemons deleted file mode 100644 index 82dbc113..00000000 --- a/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/daemons +++ /dev/null @@ -1,13 +0,0 @@ -# This file tells the zebra package -# which daemons to start. -# Entries are in the format: =(yes|no|priority) -# where 'yes' is equivalent to infinitely low priority, and -# lower numbers mean higher priority. Read -# /usr/doc/zebra/README.Debian for details. -# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd -zebra=yes -bgpd=yes -ospfd=yes -ospf6d=no -ripd=no -ripngd=no diff --git a/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/ospfd.conf b/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/ospfd.conf deleted file mode 100644 index 478567c8..00000000 --- a/pkg/checks/traceroute/test-lab/as20r3/etc/quagga/ospfd.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -hostname ospfd -password zebra -enable password zebra -! -router ospf -! Speak OSPF on all interfaces falling in 20.1.1.0/24 -network 20.1.1.0/24 area 0.0.0.0 -redistribute connected -! -log file /var/log/quagga/ospfd.log -! diff --git a/pkg/checks/traceroute/test-lab/as30r1.startup b/pkg/checks/traceroute/test-lab/as30r1.startup deleted file mode 100644 index 6e9b29b4..00000000 --- a/pkg/checks/traceroute/test-lab/as30r1.startup +++ /dev/null @@ -1,5 +0,0 @@ -ip address add 11.0.0.10/30 dev eth0 -ip address add 30.3.3.1/24 dev eth1 -ip address add 11.0.0.25/30 dev eth2 -ip address add 11.0.0.18/30 dev eth3 -systemctl start quagga diff --git a/pkg/checks/traceroute/test-lab/as30r1/etc/quagga/bgpd.conf b/pkg/checks/traceroute/test-lab/as30r1/etc/quagga/bgpd.conf deleted file mode 100644 index 50954ee5..00000000 --- a/pkg/checks/traceroute/test-lab/as30r1/etc/quagga/bgpd.conf +++ /dev/null @@ -1,36 +0,0 @@ -! -hostname bgpd -password zebra -enable password zebra -! -router bgp 30 -network 30.3.3.0/24 -network 11.0.0.8/30 -! -neighbor 11.0.0.9 remote-as 200 -neighbor 11.0.0.9 description Router as200r1 -neighbor 11.0.0.9 default-originate -neighbor 11.0.0.9 prefix-list customer200 in -neighbor 11.0.0.9 prefix-list defaultOut out -! -neighbor 11.0.0.26 remote-as 1 -neighbor 11.0.0.26 description Router as1r1 (eBGP) -! -neighbor 11.0.0.17 remote-as 20 -neighbor 11.0.0.17 description Router as20r1 (eBGP) -neighbor 11.0.0.17 prefix-list meAndCustomers out -! -ip prefix-list customer200 permit 200.2.0.0/16 -ip prefix-list defaultOut permit 0.0.0.0/0 -ip prefix-list meAndCustomers permit 30.3.3.0/24 -ip prefix-list meAndCustomers permit 200.2.0.0/16 -! -log file /var/log/quagga/bgpd.log -! -debug bgp -debug bgp events -debug bgp filters -debug bgp fsm -debug bgp keepalives -debug bgp updates -! diff --git a/pkg/checks/traceroute/test-lab/as30r1/etc/quagga/daemons b/pkg/checks/traceroute/test-lab/as30r1/etc/quagga/daemons deleted file mode 100644 index 0c469547..00000000 --- a/pkg/checks/traceroute/test-lab/as30r1/etc/quagga/daemons +++ /dev/null @@ -1,13 +0,0 @@ -# This file tells the zebra package -# which daemons to start. -# Entries are in the format: =(yes|no|priority) -# where 'yes' is equivalent to infinitely low priority, and -# lower numbers mean higher priority. Read -# /usr/doc/zebra/README.Debian for details. -# Daemons are: bgpd zebra ospfd ospf6d ripd ripngd -zebra=yes -bgpd=yes -ospfd=no -ospf6d=no -ripd=no -ripngd=no diff --git a/pkg/checks/traceroute/test-lab/client.startup b/pkg/checks/traceroute/test-lab/client.startup deleted file mode 100644 index 4aa5acf1..00000000 --- a/pkg/checks/traceroute/test-lab/client.startup +++ /dev/null @@ -1,2 +0,0 @@ -ip address add 200.2.0.2/24 dev eth0 -ip route add default via 200.2.0.1 dev eth0 diff --git a/pkg/checks/traceroute/test-lab/client/etc/resolv.conf b/pkg/checks/traceroute/test-lab/client/etc/resolv.conf deleted file mode 100644 index e2bb9fa4..00000000 --- a/pkg/checks/traceroute/test-lab/client/etc/resolv.conf +++ /dev/null @@ -1 +0,0 @@ -nameserver 30.3.3.2 diff --git a/pkg/checks/traceroute/test-lab/itdns.startup b/pkg/checks/traceroute/test-lab/itdns.startup deleted file mode 100644 index bfef7868..00000000 --- a/pkg/checks/traceroute/test-lab/itdns.startup +++ /dev/null @@ -1,3 +0,0 @@ -ip address add 20.2.1.2/24 dev eth0 -ip route add default via 20.2.1.1 dev eth0 -systemctl start named diff --git a/pkg/checks/traceroute/test-lab/itdns/etc/bind/db.it b/pkg/checks/traceroute/test-lab/itdns/etc/bind/db.it deleted file mode 100644 index 4d76f656..00000000 --- a/pkg/checks/traceroute/test-lab/itdns/etc/bind/db.it +++ /dev/null @@ -1,13 +0,0 @@ -$TTL 60000 -@ IN SOA dnsit.it. root.dnsit.it. ( - 2006031201 ; serial - 28800 ; refresh - 14400 ; retry - 3600000 ; expire - 0 ; negative cache ttl - ) -@ IN NS dnsit.it. -dnsit IN A 20.2.1.2 - -uniroma3 IN NS dnsr3.uniroma3.it. -dnsr3.uniroma3 IN A 100.1.3.2 diff --git a/pkg/checks/traceroute/test-lab/itdns/etc/bind/db.root b/pkg/checks/traceroute/test-lab/itdns/etc/bind/db.root deleted file mode 100644 index b37e5a67..00000000 --- a/pkg/checks/traceroute/test-lab/itdns/etc/bind/db.root +++ /dev/null @@ -1,2 +0,0 @@ -. IN NS ROOT-SERVER. -ROOT-SERVER. IN A 1.1.0.2 diff --git a/pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf b/pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf deleted file mode 100644 index fae2bc49..00000000 --- a/pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf +++ /dev/null @@ -1,11 +0,0 @@ -include "/etc/bind/named.conf.options"; - -zone "." { - type hint; - file "/etc/bind/db.root"; -}; - -zone "it" { - type master; - file "/etc/bind/db.it"; -}; diff --git a/pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf.options b/pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf.options deleted file mode 100644 index b0311e27..00000000 --- a/pkg/checks/traceroute/test-lab/itdns/etc/bind/named.conf.options +++ /dev/null @@ -1,3 +0,0 @@ -options { - directory "/var/cache/bind"; -}; diff --git a/pkg/checks/traceroute/test-lab/lab.conf b/pkg/checks/traceroute/test-lab/lab.conf index 24e6bc25..9836e8cf 100644 --- a/pkg/checks/traceroute/test-lab/lab.conf +++ b/pkg/checks/traceroute/test-lab/lab.conf @@ -1,70 +1,19 @@ -LAB_DESCRIPTION="A small Internet with DNS and a web server" -LAB_VERSION=1.0 -LAB_AUTHOR="M. Scazzariello, L. Ariemma, T. Caiazzi" +LAB_DESCRIPTION="A simple example showing how to configure static routes" +LAB_VERSION=2.0 +LAB_AUTHOR="T. Caiazzi, G. Di Battista, M. Patrignani, M. Pizzonia, F. Ricci, M. Rimondini" LAB_EMAIL=contact@kathara.org -LAB_WEB=https://www.kathara.org/ +LAB_WEB=http://www.kathara.org/ -as1r1[0]="S" -as1r1[1]="U" -as1r1[2]="V" -as1r1[image]="kathara/quagga" +r1[0]="A" +r1[1]="B" +r1[image]="kathara/base" -as20r1[0]="A" -as20r1[1]="F" -as20r1[2]="C" -as20r1[3]="T" -as20r1[image]="kathara/quagga" +r2[0]="C" +r2[1]="B" +r2[image]="kathara/base" -as20r2[0]="E" -as20r2[1]="C" -as20r2[2]="W" -as20r2[image]="kathara/quagga" +pc1[0]="A" +pc1[image]="kathara/base" -as20r3[0]="U" -as20r3[1]="C" -as20r3[image]="kathara/quagga" - -as30r1[0]="N" -as30r1[1]="R" -as30r1[2]="S" -as30r1[3]="T" -as30r1[image]="kathara/quagga" - -as100r1[0]="E" -as100r1[1]="F" -as100r1[2]="J" -as100r1[3]="D" -as100r1[image]="kathara/quagga" - -as100r2[0]="D" -as100r2[1]="H" -as100r2[2]="L" -as100r2[image]="kathara/quagga" - -as100r3[0]="J" -as100r3[1]="H" -as100r3[2]="K" -as100r3[image]="kathara/quagga" - -as200r1[0]="A" -as200r1[1]="B" -as200r1[2]="N" -as200r1[image]="kathara/quagga" - -webserver[0]="L" -webserver[image]="kathara/base" - -rootdns[0]="V" -rootdns[image]="kathara/base" - -itdns[0]="W" -itdns[image]="kathara/base" - -r3dns[0]="K" -r3dns[image]="kathara/base" - -ldns[0]="R" -ldns[image]="kathara/base" - -client[0]="B" -client[image]="kathara/base" +pc2[0]="C" +pc2[image]="kathara/base" diff --git a/pkg/checks/traceroute/test-lab/ldns.startup b/pkg/checks/traceroute/test-lab/ldns.startup deleted file mode 100644 index 725038b4..00000000 --- a/pkg/checks/traceroute/test-lab/ldns.startup +++ /dev/null @@ -1,3 +0,0 @@ -ip address add 30.3.3.2/24 dev eth0 -ip route add default via 30.3.3.1 dev eth0 -systemctl start named diff --git a/pkg/checks/traceroute/test-lab/ldns/etc/bind/db.root b/pkg/checks/traceroute/test-lab/ldns/etc/bind/db.root deleted file mode 100644 index 4d78cbba..00000000 --- a/pkg/checks/traceroute/test-lab/ldns/etc/bind/db.root +++ /dev/null @@ -1,2 +0,0 @@ -@ IN NS ROOT-SERVER. -ROOT-SERVER. IN A 1.1.0.2 diff --git a/pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf b/pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf deleted file mode 100644 index d0b3f759..00000000 --- a/pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf +++ /dev/null @@ -1,6 +0,0 @@ -include "/etc/bind/named.conf.options"; - -zone "." { - type hint; - file "/etc/bind/db.root"; -}; diff --git a/pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf.options b/pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf.options deleted file mode 100644 index a9bdfbe7..00000000 --- a/pkg/checks/traceroute/test-lab/ldns/etc/bind/named.conf.options +++ /dev/null @@ -1,5 +0,0 @@ -options { - directory "/var/cache/bind"; - allow-recursion { 200.2/16; }; - dnssec-validation no; -}; diff --git a/pkg/checks/traceroute/test-lab/pc1.startup b/pkg/checks/traceroute/test-lab/pc1.startup new file mode 100644 index 00000000..46d9b5d0 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/pc1.startup @@ -0,0 +1,2 @@ +ip address add 195.11.14.5/24 dev eth0 +ip route add default via 195.11.14.1 dev eth0 diff --git a/pkg/checks/traceroute/test-lab/pc2.startup b/pkg/checks/traceroute/test-lab/pc2.startup new file mode 100644 index 00000000..c73ca7e4 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/pc2.startup @@ -0,0 +1,3 @@ +ip address add 200.1.1.7/24 dev eth0 +ip route add default via 200.1.1.1 dev eth0 +systemctl start apache2 diff --git a/pkg/checks/traceroute/test-lab/r1.startup b/pkg/checks/traceroute/test-lab/r1.startup new file mode 100644 index 00000000..bb6bb5e5 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/r1.startup @@ -0,0 +1,3 @@ +ip address add 195.11.14.1/24 dev eth0 +ip address add 100.0.0.9/30 dev eth1 +ip route add 200.1.1.0/24 via 100.0.0.10 dev eth1 diff --git a/pkg/checks/traceroute/test-lab/r2.startup b/pkg/checks/traceroute/test-lab/r2.startup new file mode 100644 index 00000000..54b4254e --- /dev/null +++ b/pkg/checks/traceroute/test-lab/r2.startup @@ -0,0 +1,3 @@ +ip address add 200.1.1.1/24 dev eth0 +ip address add 100.0.0.10/30 dev eth1 +ip route add 195.11.14.0/24 via 100.0.0.9 dev eth1 diff --git a/pkg/checks/traceroute/test-lab/r3dns.startup b/pkg/checks/traceroute/test-lab/r3dns.startup deleted file mode 100644 index 44844b84..00000000 --- a/pkg/checks/traceroute/test-lab/r3dns.startup +++ /dev/null @@ -1,3 +0,0 @@ -ip address add 100.1.3.2/24 dev eth0 -ip route add default via 100.1.3.1 dev eth0 -systemctl start named diff --git a/pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.it.uniroma3 b/pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.it.uniroma3 deleted file mode 100644 index ec3bcf04..00000000 --- a/pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.it.uniroma3 +++ /dev/null @@ -1,11 +0,0 @@ -$TTL 60000 -@ IN SOA dnsr3.uniroma3.it. root.dnsr3.uniroma3.it. ( - 2006031201 ; serial - 28 ; refresh - 14 ; retry - 3600000 ; expire - 0 ; negative cache ttl - ) -@ IN NS dnsr3.uniroma3.it. -dnsr3 IN A 100.1.3.2 -www IN A 100.1.2.2 diff --git a/pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.root b/pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.root deleted file mode 100644 index b37e5a67..00000000 --- a/pkg/checks/traceroute/test-lab/r3dns/etc/bind/db.root +++ /dev/null @@ -1,2 +0,0 @@ -. IN NS ROOT-SERVER. -ROOT-SERVER. IN A 1.1.0.2 diff --git a/pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf b/pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf deleted file mode 100644 index 3b51c888..00000000 --- a/pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf +++ /dev/null @@ -1,11 +0,0 @@ -include "/etc/bind/named.conf.options"; - -zone "." { - type hint; - file "/etc/bind/db.root"; -}; - -zone "uniroma3.it" { - type master; - file "/etc/bind/db.it.uniroma3"; -}; diff --git a/pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf.options b/pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf.options deleted file mode 100644 index b0311e27..00000000 --- a/pkg/checks/traceroute/test-lab/r3dns/etc/bind/named.conf.options +++ /dev/null @@ -1,3 +0,0 @@ -options { - directory "/var/cache/bind"; -}; diff --git a/pkg/checks/traceroute/test-lab/rootdns.startup b/pkg/checks/traceroute/test-lab/rootdns.startup deleted file mode 100644 index 83f04ab5..00000000 --- a/pkg/checks/traceroute/test-lab/rootdns.startup +++ /dev/null @@ -1,3 +0,0 @@ -ip address add 1.1.0.2/16 dev eth0 -ip route add default via 1.1.0.1 dev eth0 -systemctl start named diff --git a/pkg/checks/traceroute/test-lab/rootdns/etc/bind/db.root b/pkg/checks/traceroute/test-lab/rootdns/etc/bind/db.root deleted file mode 100644 index 8e413ca9..00000000 --- a/pkg/checks/traceroute/test-lab/rootdns/etc/bind/db.root +++ /dev/null @@ -1,14 +0,0 @@ -$TTL 60000 -@ IN SOA ROOT-SERVER. root.ROOT-SERVER. ( - 2006031201 ; serial - 28800 ; refresh - 14400 ; retry - 3600000 ; expire - 0 ; negative cache ttl - ) - -@ IN NS ROOT-SERVER. -ROOT-SERVER. IN A 1.1.0.2 - -it. IN NS dnsit.it. -dnsit.it. IN A 20.2.1.2 diff --git a/pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf b/pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf deleted file mode 100644 index df43f708..00000000 --- a/pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf +++ /dev/null @@ -1,6 +0,0 @@ -include "/etc/bind/named.conf.options"; - -zone "." { - type master; - file "/etc/bind/db.root"; -}; diff --git a/pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf.options b/pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf.options deleted file mode 100644 index b0311e27..00000000 --- a/pkg/checks/traceroute/test-lab/rootdns/etc/bind/named.conf.options +++ /dev/null @@ -1,3 +0,0 @@ -options { - directory "/var/cache/bind"; -}; diff --git a/pkg/checks/traceroute/test-lab/webserver.startup b/pkg/checks/traceroute/test-lab/webserver.startup deleted file mode 100644 index 08fb9b09..00000000 --- a/pkg/checks/traceroute/test-lab/webserver.startup +++ /dev/null @@ -1,3 +0,0 @@ -ip address add 100.1.2.2/24 dev eth0 -ip route add default via 100.1.2.1 dev eth0 -systemctl start apache2 diff --git a/pkg/checks/traceroute/test-lab/webserver/var/www/html/index.html b/pkg/checks/traceroute/test-lab/webserver/var/www/html/index.html deleted file mode 100644 index 5fa2e374..00000000 --- a/pkg/checks/traceroute/test-lab/webserver/var/www/html/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - Hello! -
-            _   _  ____  __  __  _____   ___   ___ ___   ___  
-           | \ | |/ __ \|  \/  |/ ____| |__ \ / _ \__ \ / _ \ 
-           |  \| | |  | | \  / | (___      ) | | | | ) | | | |
-           | . ` | |  | | |\/| |\___ \    / /| | | |/ /| | | |
-           | |\  | |__| | |  | |____) |  / /_| |_| / /_| |_| |
-           |_| \_|\____/|_|  |_|_____/  |____|\___/____|\___/ 
-                                                              
-        
- - diff --git a/pkg/checks/traceroute/test-lab/webserver/var/www/index.html b/pkg/checks/traceroute/test-lab/webserver/var/www/index.html deleted file mode 100644 index 5fa2e374..00000000 --- a/pkg/checks/traceroute/test-lab/webserver/var/www/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - Hello! -
-            _   _  ____  __  __  _____   ___   ___ ___   ___  
-           | \ | |/ __ \|  \/  |/ ____| |__ \ / _ \__ \ / _ \ 
-           |  \| | |  | | \  / | (___      ) | | | | ) | | | |
-           | . ` | |  | | |\/| |\___ \    / /| | | |/ /| | | |
-           | |\  | |__| | |  | |____) |  / /_| |_| / /_| |_| |
-           |_| \_|\____/|_|  |_|_____/  |____|\___/____|\___/ 
-                                                              
-        
- - From 9aa6a8b1d9f3b4911d4a0048cb99f435eb911e37 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 15:59:46 +0200 Subject: [PATCH 13/46] docs: update README.md Signed-off-by: Niklas Treml --- README.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bf4a8ae0..bffaeb30 100644 --- a/README.md +++ b/README.md @@ -498,7 +498,7 @@ dns: interval: 5s timeout: 3s retries: 3 - maxHops: 8 + maxHops: 30 targets: - addr: 8.8.8.8 port: 53 @@ -506,15 +506,83 @@ dns: port: 80 ``` -#### Required Capabilities +#### Optional Capabilities -To use this check, sparrow needs to be run with the `CAP_NET_RAW` capability or elevated privileges to be able to send raw packets. -Using the `CAP_NET_RAW` capability is recommended over running sparrow as sudo. +Sparrow does not need any extra permissions to run this check. However, some data, like the ip address +of the hop that dropped a packet, will not be available. To enable this functionality, there are two options: +- run sparrow as root: +```bash +sudo sparrow run --config config.yaml +``` + +- allow sparrow to create raw sockets, by assignging the `CAP_NET_RAW` capability to the sparrow binary: ```bash sudo setcap 'cap_net_raw=ep' sparrow ``` +#### Traceroute Prometheus Metrics + + +- `sparrow_traceroute_check_duration_ms{target="google.com"} 43150` + - Type: Gauge + - Description: How long the last traceroute took for this target in total +- `sparrow_traceroute_minimum_hops{target="google.com"} 14` + - Type: Gauge + - Description: The minimum number of hops required to reach a target + +#### Traceroute API Metrics +The traceroute check exposes additional data through its rest API that isn't available in prometheus. +This data give a more detailed breakdown of the trace and can be found at `/v1/metrics/traceroute` and is +meant to be a json representation of traditional traceroute output: +```bash +$ traceroute -T -q 1 100.1.2.2 + 1 200.2.0.1 (200.2.0.1) 2 ms + 2 11.0.0.34 (11.0.0.34) 5 ms + ... +``` +Is roughly equal to this: +```json +{ + "data": { + "100.1.2.2": { + "MinHops": 1, + "Hops": { + "1": [ + { + "Latency": 2, + "Addr": { + "IP": "200.2.0.1", + "Port": 80, + "Zone": "" + }, + "Name": "", + "Ttl": 1, + "Reached": false + } + ], + "2": [ + { + "Latency": 5, + "Addr": { + "IP": "11.0.0.34", + "Port": 80, + "Zone": "" + }, + "Name": "", + "Ttl": 2, + "Reached": false + } + ] + ... + } + }, + }, + "timestamp": "2024-07-26T15:49:39.60760766+02:00" +} + +``` + ## API The `sparrow` exposes an API for accessing the results of various checks. Each check registers its own endpoint From e4964186195ad33503a3c7408e6b15c1413a8dde Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 16:05:46 +0200 Subject: [PATCH 14/46] docs: fix incorrect retry docs Signed-off-by: Niklas Treml --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bffaeb30..bb6df3f0 100644 --- a/README.md +++ b/README.md @@ -483,7 +483,8 @@ dns: | ---------------- | ----------------- | ---------------------------------------------------------------------------- | | `interval` | `duration` | Interval to perform the Traceroute check. | | `timeout` | `duration` | Timeout for every hop. | -| `retries` | `integer` | Number of times to retry the traceroute for a target, if it fails. | +| `retry.count` | `integer` | Number of retries for the latency check. | +| `retry.delay` | `duration` | Initial delay between retries for the latency check. | | `maxHops` | `integer` | Maximum number of hops to try before giving up. | | `targets` | `list of objects` | List of targets to traceroute to. | | `targets[].addr` | `string` | The address of the target to traceroute to. Can be an IP address or DNS name | @@ -497,7 +498,9 @@ dns: traceroute: interval: 5s timeout: 3s - retries: 3 + retry: + count: 3 + delay: 1s maxHops: 30 targets: - addr: 8.8.8.8 From d44fecad2d7ad5aca6369741a1760d52e7f14d9e Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 16:35:38 +0200 Subject: [PATCH 15/46] docs: how to debug traceroute Signed-off-by: Niklas Treml --- pkg/checks/traceroute/test-lab/how-to-test.md | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 pkg/checks/traceroute/test-lab/how-to-test.md diff --git a/pkg/checks/traceroute/test-lab/how-to-test.md b/pkg/checks/traceroute/test-lab/how-to-test.md new file mode 100644 index 00000000..e5b88035 --- /dev/null +++ b/pkg/checks/traceroute/test-lab/how-to-test.md @@ -0,0 +1,126 @@ +# How to test the traceroute check + +## What is this +Kathara is a container-based network emulation tool. The files in this folder configure a small test network using kathara. +In this case we use kathara to locally simulate a network with a webserver, a client and multiple network hops between them. +## Requirements +- install [ kathara ](https://github.com/KatharaFramework/Kathara) +- install wireshark (optional) + +## How to + +1. Start kathara network +In this folder run: +```bash +kathara lstart +``` + +This starts the test-lab ([ topology ](https://github.com/KatharaFramework/Kathara-Labs/blob/main/main-labs/basic-topics/static-routing/004-kathara-lab_static-routing.pdf)) + +2. Connect to the client system +In a separate terminal run: +```bash +kathara connect pc1 +``` + + +3. (optional) Explore the network +Aside from you, there are two routers and a webserver in this lab. +Tracerouting to the webserver shows us, that we need to go through the two routers to reach the webserver: +```bash +export WEBSERVER=200.1.1.7 +root@pc1:/# traceroute $WEBSERVER +traceroute to 200.1.1.7 (200.1.1.7), 30 hops max, 60 byte packets + 1 195.11.14.1 (195.11.14.1) 0.972 ms 1.093 ms 1.095 ms + 2 100.0.0.10 (100.0.0.10) 1.543 ms 1.712 ms 1.838 ms + 3 200.1.1.7 (200.1.1.7) 2.232 ms 2.310 ms 2.394 ms +``` + +We can also look at the server website: +```bash +root@pc1:/# curl $WEBSERVER +``` +This should return the default apache website. + +4. Run sparrow + +To run sparrow we first need to build and move the sparrow binary into the container. Luckily, kathara mounts a shared folder to all systems in the lab. +We can use this folder to run sparrow in the containers without having to build our own image! + +```bash +go build -o sparrow . && mv sparrow pkg/checks/traceroute/test-lab/shared/ +``` + +Back in the client container: +```bash +root@pc1:/# cd /shared +root@pc1:/shared# ./sparrow -h +Sparrow is an infrastructure monitoring agent that is able to perform different checks. +The check results are exposed via an API. + +Usage: + sparrow [command] + +Available Commands: + completion Generate the autocompletion script for the specified shell + help Help about any command + run Run sparrow + +Flags: + --config string config file (default is $HOME/.sparrow.yaml) + -h, --help help for sparrow + +Use "sparrow [command] --help" for more information about a command. +``` +Now we just have to create a config for sparrow to use and we're ready to develop. For testing traceroute I used this config: +```yaml +root@pc1:/shared# cat config.yaml +name: sparrow.dev +loader: + type: file + interval: 30s + file: + path: ./config.yaml +traceroute: + interval: 5s + timeout: 3s + retries: 3 + maxHops: 8 + targets: + - addr: 200.1.1.7 + port: 80 +``` + + +Now just run sparrow in the shared folder: + +```bash +root@pc1:/shared# ./sparrow run --config config.yaml +``` + +5. Other tools +The container image has a bunch of utilities for debugging network issues. If you're debugging low level issues, where you need to inspect +specific network packets you can use tcpdump directly, which is preinstalled: +```bash +root@pc1:/# tcpdump +tcpdump: verbose output suppressed, use -v[v]... for full protocol decode +listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes +14:30:40.022157 IP 195.11.14.5 > 200.1.1.7: ICMP echo request, id 66, seq 1, length 64 +14:30:40.023392 IP 200.1.1.7 > 195.11.14.5: ICMP echo reply, id 66, seq 1, length 64 +^C +2 packets captured +2 packets received by filter +0 packets dropped by kernel +``` + +Or dump to a file which you can the inspect with wireshark: + +```bash +# capture in kathara client to shared folder +root@pc1:/# tcpdump -w /shared/dump.pcap +# open dumped capture in wireshark on your host system +wireshark -r dump.pcap +``` + + +Happy Debugging! From 474a84575860178db9fd1c8d7363926194334ed7 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 16:40:44 +0200 Subject: [PATCH 16/46] docs: add clean up section Signed-off-by: Niklas Treml --- pkg/checks/traceroute/test-lab/how-to-test.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pkg/checks/traceroute/test-lab/how-to-test.md b/pkg/checks/traceroute/test-lab/how-to-test.md index e5b88035..3693bb6a 100644 --- a/pkg/checks/traceroute/test-lab/how-to-test.md +++ b/pkg/checks/traceroute/test-lab/how-to-test.md @@ -14,6 +14,10 @@ In this folder run: ```bash kathara lstart ``` +To prevent kathara from creating a terminal window for every container: +```bash +kathara lstart --noterminals +``` This starts the test-lab ([ topology ](https://github.com/KatharaFramework/Kathara-Labs/blob/main/main-labs/basic-topics/static-routing/004-kathara-lab_static-routing.pdf)) @@ -124,3 +128,9 @@ wireshark -r dump.pcap Happy Debugging! + +6. Cleaning up +Cleanup is simple: +```bash +kathara lclean +``` From d977b6bfeb2fd4d59b82708a3f90c14aec33e496 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 16:46:53 +0200 Subject: [PATCH 17/46] fix: initialize metrics in test Signed-off-by: Niklas Treml --- pkg/checks/traceroute/check_test.go | 1 + pkg/checks/traceroute/traceroute_test.go | 16 ---------------- 2 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 pkg/checks/traceroute/traceroute_test.go diff --git a/pkg/checks/traceroute/check_test.go b/pkg/checks/traceroute/check_test.go index f1cdb8c4..5f687979 100644 --- a/pkg/checks/traceroute/check_test.go +++ b/pkg/checks/traceroute/check_test.go @@ -64,6 +64,7 @@ func newForTest(f tracerouteFactory, targets []string) *Traceroute { Targets: t, }, traceroute: f, + metrics: newMetrics(), CheckBase: checks.CheckBase{ Mu: sync.Mutex{}, DoneChan: make(chan struct{}), diff --git a/pkg/checks/traceroute/traceroute_test.go b/pkg/checks/traceroute/traceroute_test.go deleted file mode 100644 index c4c5c4ad..00000000 --- a/pkg/checks/traceroute/traceroute_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package traceroute - -import ( - "errors" - "syscall" - "testing" - - "golang.org/x/net/icmp" -) - -func TestTR(t *testing.T) { - _, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") - if !errors.Is(err, syscall.EPERM) { - t.Errorf("err is not eperm") - } -} From 8f69f808bf1e32ae19726d38d239e6493b8dcaec Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 16:50:57 +0200 Subject: [PATCH 18/46] fix: ignore some linter things Signed-off-by: Niklas Treml --- pkg/checks/traceroute/traceroute.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 84d28f47..9e3c7175 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -18,7 +18,7 @@ import ( // randomPort returns a random port in the interval [ 30_000, 40_000 [ func randomPort() int { - return rand.Intn(10_000) + 30_000 //nolint:gosec,mnd // math.rand is fine here, we're not doing encryption + return rand.Intn(10_000) + 30_000 //nolint:gosec,mnd // #nosec G404 // math.rand is fine here, we're not doing encryption } func tcpHop(addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error) { @@ -161,14 +161,14 @@ func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) defer func() { if canIcmp { - icmpListener.Close() + icmpListener.Close() // #nosec G104 } }() start := time.Now() conn, clientPort, err := tcpHop(addr, ttl, timeout) latency := time.Since(start) if err == nil { - conn.Close() + conn.Close() // #nosec G104 ipaddr := ipFromAddr(addr) names, _ := net.LookupAddr(ipaddr.String()) // we don't care about this lookup failling From 4dae4b95f107996c22a1098b0ee3f363daddff35 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 17:01:24 +0200 Subject: [PATCH 19/46] fix: linters are my friends Signed-off-by: Niklas Treml --- pkg/checks/traceroute/traceroute.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 9e3c7175..f2580aad 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -17,8 +17,10 @@ import ( ) // randomPort returns a random port in the interval [ 30_000, 40_000 [ +// +//nolint:all func randomPort() int { - return rand.Intn(10_000) + 30_000 //nolint:gosec,mnd // #nosec G404 // math.rand is fine here, we're not doing encryption + return rand.Intn(10_000) + 30_000 // #nosec G404 // math.rand is fine here, we're not doing encryption } func tcpHop(addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error) { From 906521cb0e5853120597ad4c75daf9da5ef19477 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Fri, 26 Jul 2024 17:10:37 +0200 Subject: [PATCH 20/46] fix: minHops now equals maxHops if no hop was able to connect Signed-off-by: Niklas Treml --- pkg/checks/traceroute/check.go | 3 +-- pkg/checks/traceroute/check_test.go | 9 +++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/checks/traceroute/check.go b/pkg/checks/traceroute/check.go index ff73ad03..fb412ca6 100644 --- a/pkg/checks/traceroute/check.go +++ b/pkg/checks/traceroute/check.go @@ -2,7 +2,6 @@ package traceroute import ( "context" - "math" "sync" "time" @@ -132,7 +131,7 @@ func (tr *Traceroute) check(ctx context.Context) map[string]result { l.Debug("Ran traceroute", "result", trace, "duration", elapsed) r := result{ Hops: trace, - MinHops: math.MaxInt, + MinHops: tr.config.MaxHops, } for i, hops := range trace { diff --git a/pkg/checks/traceroute/check_test.go b/pkg/checks/traceroute/check_test.go index 5f687979..7299ac98 100644 --- a/pkg/checks/traceroute/check_test.go +++ b/pkg/checks/traceroute/check_test.go @@ -19,7 +19,7 @@ func TestCheck(t *testing.T) { }{ { name: "Success 5 hops", - c: newForTest(success(5), []string{"8.8.8.8"}), + c: newForTest(success(5), 10, []string{"8.8.8.8"}), want: map[string]result{ "8.8.8.8": { MinHops: 5, @@ -35,9 +35,9 @@ func TestCheck(t *testing.T) { }, { name: "Traceroute internal error fails silently", - c: newForTest(returnError(&net.DNSError{Err: "no such host", Name: "google.com", IsNotFound: true}), []string{"google.com"}), + c: newForTest(returnError(&net.DNSError{Err: "no such host", Name: "google.com", IsNotFound: true}), 10, []string{"google.com"}), want: map[string]result{ - "google.com": {Hops: map[int][]Hop{}}, + "google.com": {MinHops: 10, Hops: map[int][]Hop{}}, }, }, } @@ -54,7 +54,7 @@ func TestCheck(t *testing.T) { } } -func newForTest(f tracerouteFactory, targets []string) *Traceroute { +func newForTest(f tracerouteFactory, maxHops int, targets []string) *Traceroute { t := make([]Target, len(targets)) for i, target := range targets { t[i] = Target{Addr: target} @@ -62,6 +62,7 @@ func newForTest(f tracerouteFactory, targets []string) *Traceroute { return &Traceroute{ config: Config{ Targets: t, + MaxHops: maxHops, }, traceroute: f, metrics: newMetrics(), From 20c714c704c67931d8bfa8c58fc8ee7356efdb9f Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Tue, 30 Jul 2024 08:25:44 +0200 Subject: [PATCH 21/46] refactor: rename variables to make code more understandable Signed-off-by: Niklas Treml --- pkg/checks/traceroute/check.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/checks/traceroute/check.go b/pkg/checks/traceroute/check.go index fb412ca6..586065d3 100644 --- a/pkg/checks/traceroute/check.go +++ b/pkg/checks/traceroute/check.go @@ -129,20 +129,20 @@ func (tr *Traceroute) check(ctx context.Context) map[string]result { tr.metrics.CheckDuration(t.Addr, elapsed) l.Debug("Ran traceroute", "result", trace, "duration", elapsed) - r := result{ + res := result{ Hops: trace, MinHops: tr.config.MaxHops, } - for i, hops := range trace { - for _, hop := range hops { - if hop.Reached && hop.Ttl < r.MinHops { - r.MinHops = i + for ttl, hop := range trace { + for _, attempt := range hop { + if attempt.Reached && attempt.Ttl < res.MinHops { + res.MinHops = ttl } } } - cResult <- internalResult{addr: t.Addr, res: r} + cResult <- internalResult{addr: t.Addr, res: res} }(t) } From 7de61ba8e418a207868c988a15b2324aad422f95 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Tue, 30 Jul 2024 10:15:27 +0200 Subject: [PATCH 22/46] docs: better comment for hops map --- pkg/checks/traceroute/traceroute.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index f2580aad..8fb73ea2 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -89,8 +89,7 @@ func readIcmpMessage(icmpListener *icmp.PacketConn, timeout time.Duration) (int, // TraceRoute performs a traceroute to the specified host using TCP and listens for ICMP Time Exceeded messages using ICMP. func TraceRoute(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error) { - // this could also be a 2d array, but I feel like using an int map here makes the json easier to understand - // as it explicitly shows a mapping of ttl->hops + // maps ttl -> attempted hops for that ttl hops := make(map[int][]Hop) log := logger.FromContext(ctx).With("target", cfg.Dest) From cecea62f9e90886ae0161583470e1b11f2efed40 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Tue, 30 Jul 2024 10:35:59 +0200 Subject: [PATCH 23/46] fix: correct channel buffer size Signed-off-by: Niklas Treml --- pkg/checks/traceroute/traceroute.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 8fb73ea2..96913570 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -101,12 +101,15 @@ func TraceRoute(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error return nil, err } - results := make(chan Hop, cfg.MaxHops) + // if we don't add the +1, this causes issues, when the user does not want to retry, + // since the channels size would be zero, blocking all threads from sending + queueSize := cfg.MaxHops * (1 + cfg.Rc.Count) + results := make(chan Hop, queueSize) var wg sync.WaitGroup for ttl := 1; ttl <= cfg.MaxHops; ttl++ { wg.Add(1) - go func() { + go func(ttl int) { defer wg.Done() err := helper.Retry(func(_ context.Context) error { reached, err := traceroute(results, addr, ttl, timeoutDuration) @@ -123,7 +126,7 @@ func TraceRoute(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error if err != nil { log.Error("traceroute could not reach target", "ttl", ttl) } - }() + }(ttl) } wg.Wait() From bb2e5acbaf61f901841805b05aebc2563ed99f9b Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Tue, 30 Jul 2024 11:19:31 +0200 Subject: [PATCH 24/46] refactor: remove channel from traceroute and simplify arguments Signed-off-by: Niklas Treml --- pkg/checks/traceroute/traceroute.go | 68 +++++++++++++++-------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 96913570..75a7a16f 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -112,12 +112,15 @@ func TraceRoute(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error go func(ttl int) { defer wg.Done() err := helper.Retry(func(_ context.Context) error { - reached, err := traceroute(results, addr, ttl, timeoutDuration) + hop, err := traceroute(addr, ttl, timeoutDuration) + if hop != nil { + results <- *hop + } if err != nil { log.Error("traceroute failed", "err", err.Error(), "ttl", ttl) return err } - if !reached { + if !hop.Reached { log.Debug("failed to reach target, retrying", "ttl", ttl) return errors.New("failed to reach target") } @@ -153,12 +156,14 @@ func ipFromAddr(remoteAddr net.Addr) net.IP { return nil } -func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) (bool, error) { +// traceroute performs a traceroute to the given address with the specified TTL and timeout. +// It returns a Hop struct containing the latency, TTL, address, and other details of the hop. +func traceroute(addr net.Addr, ttl int, timeout time.Duration) (*Hop, error) { canIcmp := true icmpListener, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") if err != nil { if !errors.Is(err, syscall.EPERM) { - return false, err + return nil, err } canIcmp = false } @@ -182,36 +187,38 @@ func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) name = names[0] } - results <- Hop{ + return &Hop{ Latency: latency, Ttl: ttl, Addr: addr, Name: name, Reached: true, - } - return true, nil + }, nil } - found := false deadline := time.Now().Add(timeout) - for time.Now().Unix() < deadline.Unix() && !found { - gotPort := -1 + if !canIcmp { + return &Hop{ + Latency: latency, + Ttl: ttl, + Reached: false, + }, nil + } + + for time.Now().Unix() < deadline.Unix() { var addr net.Addr - if canIcmp { - gotPort, addr, err = readIcmpMessage(icmpListener, timeout) - if err != nil { - results <- Hop{ - Latency: latency, - Ttl: ttl, - Reached: false, - } - return false, nil - } + gotPort, addr, err := readIcmpMessage(icmpListener, timeout) + if err != nil { + return &Hop{ + Latency: latency, + Ttl: ttl, + Reached: false, + }, nil } // Check if the destination port matches our dialer's source port - if canIcmp && gotPort == clientPort { + if gotPort == clientPort { ipaddr := ipFromAddr(addr) names, _ := net.LookupAddr(ipaddr.String()) // we don't really care if this lookup works, so ignore the error @@ -220,26 +227,21 @@ func traceroute(results chan Hop, addr net.Addr, ttl int, timeout time.Duration) name = names[0] } - results <- Hop{ + return &Hop{ Latency: latency, Ttl: ttl, Addr: addr, Reached: false, Name: name, - } - found = true - break - } - } - if !found { - results <- Hop{ - Latency: latency, - Ttl: ttl, - Reached: false, + }, nil } } - return false, nil + return &Hop{ + Latency: latency, + Ttl: ttl, + Reached: false, + }, nil } type Hop struct { From d1379dcd6b2891b7beb06904e6a9275e01261987 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Tue, 30 Jul 2024 11:39:54 +0200 Subject: [PATCH 25/46] refactor: split up traceroute function Signed-off-by: Niklas Treml --- pkg/checks/traceroute/traceroute.go | 110 ++++++++++++++++------------ 1 file changed, 62 insertions(+), 48 deletions(-) diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 75a7a16f..42e63f14 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -159,45 +159,19 @@ func ipFromAddr(remoteAddr net.Addr) net.IP { // traceroute performs a traceroute to the given address with the specified TTL and timeout. // It returns a Hop struct containing the latency, TTL, address, and other details of the hop. func traceroute(addr net.Addr, ttl int, timeout time.Duration) (*Hop, error) { - canIcmp := true - icmpListener, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") + canIcmp, icmpListener, err := setupIcmpListener() if err != nil { - if !errors.Is(err, syscall.EPERM) { - return nil, err - } - canIcmp = false + return nil, err } + defer closeIcmpListener(canIcmp, icmpListener) - defer func() { - if canIcmp { - icmpListener.Close() // #nosec G104 - } - }() start := time.Now() conn, clientPort, err := tcpHop(addr, ttl, timeout) latency := time.Since(start) if err == nil { - conn.Close() // #nosec G104 - - ipaddr := ipFromAddr(addr) - names, _ := net.LookupAddr(ipaddr.String()) // we don't care about this lookup failling - - name := "" - if len(names) >= 1 { - name = names[0] - } - - return &Hop{ - Latency: latency, - Ttl: ttl, - Addr: addr, - Name: name, - Reached: true, - }, nil + return handleTcpSuccess(conn, addr, ttl, latency), nil } - deadline := time.Now().Add(timeout) - if !canIcmp { return &Hop{ Latency: latency, @@ -206,15 +180,59 @@ func traceroute(addr net.Addr, ttl int, timeout time.Duration) (*Hop, error) { }, nil } + h := handleIcmpResponse(icmpListener, clientPort, ttl, timeout) + h.Latency = latency + return &h, nil +} + +func setupIcmpListener() (bool, *icmp.PacketConn, error) { + icmpListener, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") + if err != nil { + if !errors.Is(err, syscall.EPERM) { + return false, nil, err + } + return false, nil, nil + } + return true, icmpListener, nil +} + +func closeIcmpListener(canIcmp bool, icmpListener *icmp.PacketConn) { + if canIcmp && icmpListener != nil { + icmpListener.Close() // #nosec G104 + } +} + +func handleTcpSuccess(conn net.Conn, addr net.Addr, ttl int, latency time.Duration) *Hop { + conn.Close() // #nosec G104 + + ipaddr := ipFromAddr(addr) + names, _ := net.LookupAddr(ipaddr.String()) // we don't care about this lookup failing + + name := "" + if len(names) >= 1 { + name = names[0] + } + + return &Hop{ + Latency: latency, + Ttl: ttl, + Addr: addr, + Name: name, + Reached: true, + } +} + +// handleIcmpResponse attempts to read a time exceeded packet that matches clientPort until timeout is reached +// if an error occurs while reading from the socket, handleIcmpResponse will silently fail and return a hop with hop.Reached=false +func handleIcmpResponse(icmpListener *icmp.PacketConn, clientPort, ttl int, timeout time.Duration) Hop { + deadline := time.Now().Add(timeout) + for time.Now().Unix() < deadline.Unix() { - var addr net.Addr gotPort, addr, err := readIcmpMessage(icmpListener, timeout) if err != nil { - return &Hop{ - Latency: latency, - Ttl: ttl, - Reached: false, - }, nil + return Hop{ + Ttl: ttl, + } } // Check if the destination port matches our dialer's source port @@ -227,21 +245,17 @@ func traceroute(addr net.Addr, ttl int, timeout time.Duration) (*Hop, error) { name = names[0] } - return &Hop{ - Latency: latency, - Ttl: ttl, - Addr: addr, - Reached: false, - Name: name, - }, nil + return Hop{ + Ttl: ttl, + Addr: addr, + Name: name, + } } } - return &Hop{ - Latency: latency, - Ttl: ttl, - Reached: false, - }, nil + return Hop{ + Ttl: ttl, + } } type Hop struct { From 5d1cea960d382479021a1c5ab3f9f5d6897fbf0d Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Wed, 31 Jul 2024 08:06:56 +0200 Subject: [PATCH 26/46] fix: caps in json. All json output now starts with lowercase as god intended Signed-off-by: Niklas Treml --- pkg/checks/traceroute/check.go | 4 +- pkg/checks/traceroute/check_test.go | 16 +++---- pkg/checks/traceroute/traceroute.go | 73 ++++++++++++++++++++++------- 3 files changed, 66 insertions(+), 27 deletions(-) diff --git a/pkg/checks/traceroute/check.go b/pkg/checks/traceroute/check.go index 586065d3..87604873 100644 --- a/pkg/checks/traceroute/check.go +++ b/pkg/checks/traceroute/check.go @@ -53,9 +53,9 @@ type tracerouteFactory func(ctx context.Context, cfg tracerouteConfig) (map[int] type result struct { // The minimum number of hops required to reach the target - MinHops int + MinHops int `json:"min_hops" yaml:"min_hops" mapstructure:"min_hops"` // The path taken to the destination - Hops map[int][]Hop + Hops map[int][]Hop `json:"hops" yaml:"hops" mapstructure:"hops"` } // Run runs the check in a loop sending results to the provided channel diff --git a/pkg/checks/traceroute/check_test.go b/pkg/checks/traceroute/check_test.go index 7299ac98..1afafd8e 100644 --- a/pkg/checks/traceroute/check_test.go +++ b/pkg/checks/traceroute/check_test.go @@ -24,11 +24,11 @@ func TestCheck(t *testing.T) { "8.8.8.8": { MinHops: 5, Hops: map[int][]Hop{ - 1: {{Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.1")}, Latency: 1 * time.Second, Reached: false, Ttl: 1}}, - 2: {{Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.2")}, Latency: 2 * time.Second, Reached: false, Ttl: 2}}, - 3: {{Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.3")}, Latency: 3 * time.Second, Reached: false, Ttl: 3}}, - 4: {{Addr: &net.TCPAddr{IP: net.ParseIP("0.0.0.4")}, Latency: 4 * time.Second, Reached: false, Ttl: 4}}, - 5: {{Addr: &net.TCPAddr{IP: net.ParseIP("123.0.0.123"), Port: 53}, Name: "google-public-dns-a.google.com", Latency: 69 * time.Second, Reached: true, Ttl: 5}}, + 1: {{Addr: HopAddress{IP: "0.0.0.1"}, Latency: 1 * time.Second, Reached: false, Ttl: 1}}, + 2: {{Addr: HopAddress{IP: "0.0.0.2"}, Latency: 2 * time.Second, Reached: false, Ttl: 2}}, + 3: {{Addr: HopAddress{IP: "0.0.0.3"}, Latency: 3 * time.Second, Reached: false, Ttl: 3}}, + 4: {{Addr: HopAddress{IP: "0.0.0.4"}, Latency: 4 * time.Second, Reached: false, Ttl: 4}}, + 5: {{Addr: HopAddress{IP: "123.0.0.123", Port: 53}, Name: "google-public-dns-a.google.com", Latency: 69 * time.Second, Reached: true, Ttl: 5}}, }, }, }, @@ -81,7 +81,7 @@ func success(nHops int) tracerouteFactory { hops[i] = []Hop{ { Latency: time.Second * time.Duration(i), - Addr: &net.TCPAddr{IP: net.ParseIP(ipFromInt(i))}, + Addr: HopAddress{IP: ipFromInt(i)}, Name: "", Ttl: i, Reached: false, @@ -91,8 +91,8 @@ func success(nHops int) tracerouteFactory { hops[nHops] = []Hop{ { Latency: 69 * time.Second, - Addr: &net.TCPAddr{ - IP: net.ParseIP("123.0.0.123"), + Addr: HopAddress{ + IP: "123.0.0.123", Port: 53, }, Name: "google-public-dns-a.google.com", diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 42e63f14..9ad9e6b5 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -6,6 +6,7 @@ import ( "fmt" "math/rand" "net" + "slices" "sync" "syscall" "time" @@ -127,7 +128,7 @@ func TraceRoute(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error return nil }, cfg.Rc)(ctx) if err != nil { - log.Error("traceroute could not reach target", "ttl", ttl) + log.Debug("traceroute could not reach target", "ttl", ttl) } }(ttl) } @@ -139,7 +140,7 @@ func TraceRoute(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error hops[r.Ttl] = append(hops[r.Ttl], r) } - log.Debug("finished trace", "hops", printHops(hops)) + printHops(ctx, hops) return hops, nil } @@ -202,6 +203,27 @@ func closeIcmpListener(canIcmp bool, icmpListener *icmp.PacketConn) { } } +func newHopAddress(addr net.Addr) HopAddress { + switch addr := addr.(type) { + case *net.UDPAddr: + return HopAddress{ + IP: addr.IP.String(), + Port: addr.Port, + } + case *net.TCPAddr: + return HopAddress{ + IP: addr.IP.String(), + Port: addr.Port, + } + case *net.IPAddr: + return HopAddress{ + IP: addr.IP.String(), + } + default: + return HopAddress{} + } +} + func handleTcpSuccess(conn net.Conn, addr net.Addr, ttl int, latency time.Duration) *Hop { conn.Close() // #nosec G104 @@ -216,7 +238,7 @@ func handleTcpSuccess(conn net.Conn, addr net.Addr, ttl int, latency time.Durati return &Hop{ Latency: latency, Ttl: ttl, - Addr: addr, + Addr: newHopAddress(addr), Name: name, Reached: true, } @@ -247,7 +269,7 @@ func handleIcmpResponse(icmpListener *icmp.PacketConn, clientPort, ttl int, time return Hop{ Ttl: ttl, - Addr: addr, + Addr: newHopAddress(addr), Name: name, } } @@ -259,24 +281,41 @@ func handleIcmpResponse(icmpListener *icmp.PacketConn, clientPort, ttl int, time } type Hop struct { - Latency time.Duration - Addr net.Addr - Name string - Ttl int - Reached bool + Latency time.Duration `json:"latency" yaml:"latency" mapstructure:"latency"` + Addr HopAddress `json:"addr" yaml:"addr" mapstructure:"addr"` + Name string `json:"name" yaml:"name" mapstructure:"name"` + Ttl int `json:"ttl" yaml:"ttl" mapstructure:"ttl"` + Reached bool `json:"reached" yaml:"reached" mapstructure:"reached"` } -func printHops(mapHops map[int][]Hop) string { - out := "" - for ttl, hops := range mapHops { - for _, hop := range hops { - out += fmt.Sprintf("%d %s %s %v ", ttl, hop.Addr, hop.Name, hop.Latency) +type HopAddress struct { + IP string `json:"ip" yaml:"ip" mapstructure:"ip"` + Port int `json:"port" yaml:"port" mapstructure:"port"` +} + +func (a HopAddress) String() string { + if a.Port != 0 { + return fmt.Sprintf("%s:%d", a.IP, a.Port) + } + return a.IP +} + +func printHops(ctx context.Context, mapHops map[int][]Hop) { + log := logger.FromContext(ctx) + + keys := []int{} + for k := range mapHops { + keys = append(keys, k) + } + slices.Sort(keys) + + for _, key := range keys { + for _, hop := range mapHops[key] { + out := fmt.Sprintf("%d %s %s %v ", key, hop.Addr.String(), hop.Name, hop.Latency) if hop.Reached { out += "( Reached )" } - out += "\n" + log.Debug(out) } } - - return out } From 42c7123e32f97471212f509b6f80a3cf0361abd8 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Wed, 31 Jul 2024 08:31:19 +0200 Subject: [PATCH 27/46] tests: add some testcases Signed-off-by: Niklas Treml --- pkg/checks/traceroute/traceroute_test.go | 81 ++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 pkg/checks/traceroute/traceroute_test.go diff --git a/pkg/checks/traceroute/traceroute_test.go b/pkg/checks/traceroute/traceroute_test.go new file mode 100644 index 00000000..26197640 --- /dev/null +++ b/pkg/checks/traceroute/traceroute_test.go @@ -0,0 +1,81 @@ +package traceroute + +import ( + "net" + "reflect" + "testing" +) + +func TestHopAddress_String(t *testing.T) { + type fields struct { + IP string + Port int + } + tests := []struct { + name string + fields fields + want string + }{ + {name: "No Port", fields: fields{IP: "100.1.1.7"}, want: "100.1.1.7"}, + {name: "With Port", fields: fields{IP: "100.1.1.7", Port: 80}, want: "100.1.1.7:80"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := HopAddress{ + IP: tt.fields.IP, + Port: tt.fields.Port, + } + if got := a.String(); got != tt.want { + t.Errorf("HopAddress.String() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_newHopAddress(t *testing.T) { + type args struct { + addr net.Addr + } + tests := []struct { + name string + args args + want HopAddress + }{ + { + name: "Works with TCP", + args: args{ + addr: &net.TCPAddr{IP: net.ParseIP("100.1.1.7"), Port: 80}, + }, + want: HopAddress{ + IP: "100.1.1.7", + Port: 80, + }, + }, + { + name: "Works with UDP", + args: args{ + addr: &net.UDPAddr{IP: net.ParseIP("100.1.1.7"), Port: 80}, + }, + want: HopAddress{ + IP: "100.1.1.7", + Port: 80, + }, + }, + { + name: "Works with IP", + args: args{ + addr: &net.IPAddr{IP: net.ParseIP("100.1.1.7")}, + }, + want: HopAddress{ + IP: "100.1.1.7", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := newHopAddress(tt.args.addr); !reflect.DeepEqual(got, tt.want) { + t.Errorf("newHopAddress() = %v, want %v", got, tt.want) + } + }) + } +} From 9e163bbbcd607651a54937c2ae8c943437af012e Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Wed, 31 Jul 2024 10:39:00 +0200 Subject: [PATCH 28/46] feat(ci): e2e tests for traceroute --- .github/workflows/e2e_checks.yml | 32 +++++++++++++ e2e/traceroute/lab.conf | 19 ++++++++ e2e/traceroute/pc1.startup | 2 + e2e/traceroute/pc2.startup | 3 ++ e2e/traceroute/r1.startup | 3 ++ e2e/traceroute/r2.startup | 3 ++ e2e/traceroute/shared/config.yaml | 25 +++++++++++ e2e/traceroute/shared/get_api.sh | 2 + e2e/traceroute/test.sh | 74 +++++++++++++++++++++++++++++++ scripts/run_e2e_tests.sh | 16 +++++++ 10 files changed, 179 insertions(+) create mode 100644 .github/workflows/e2e_checks.yml create mode 100644 e2e/traceroute/lab.conf create mode 100644 e2e/traceroute/pc1.startup create mode 100644 e2e/traceroute/pc2.startup create mode 100644 e2e/traceroute/r1.startup create mode 100644 e2e/traceroute/r2.startup create mode 100644 e2e/traceroute/shared/config.yaml create mode 100644 e2e/traceroute/shared/get_api.sh create mode 100755 e2e/traceroute/test.sh create mode 100755 scripts/run_e2e_tests.sh diff --git a/.github/workflows/e2e_checks.yml b/.github/workflows/e2e_checks.yml new file mode 100644 index 00000000..1ffebe76 --- /dev/null +++ b/.github/workflows/e2e_checks.yml @@ -0,0 +1,32 @@ +name: E2E - Test checks + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + test_e2e: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y python3 python3-pip jq + pip3 install kathara + + - name: Build binary for e2e + uses: goreleaser/goreleaser-action@v5 + with: + version: latest + args: build --single-target --clean --config .goreleaser-ci.yaml + + - name: Run e2e tests + run: | + ./scripts/run_e2e_tests.sh diff --git a/e2e/traceroute/lab.conf b/e2e/traceroute/lab.conf new file mode 100644 index 00000000..9836e8cf --- /dev/null +++ b/e2e/traceroute/lab.conf @@ -0,0 +1,19 @@ +LAB_DESCRIPTION="A simple example showing how to configure static routes" +LAB_VERSION=2.0 +LAB_AUTHOR="T. Caiazzi, G. Di Battista, M. Patrignani, M. Pizzonia, F. Ricci, M. Rimondini" +LAB_EMAIL=contact@kathara.org +LAB_WEB=http://www.kathara.org/ + +r1[0]="A" +r1[1]="B" +r1[image]="kathara/base" + +r2[0]="C" +r2[1]="B" +r2[image]="kathara/base" + +pc1[0]="A" +pc1[image]="kathara/base" + +pc2[0]="C" +pc2[image]="kathara/base" diff --git a/e2e/traceroute/pc1.startup b/e2e/traceroute/pc1.startup new file mode 100644 index 00000000..46d9b5d0 --- /dev/null +++ b/e2e/traceroute/pc1.startup @@ -0,0 +1,2 @@ +ip address add 195.11.14.5/24 dev eth0 +ip route add default via 195.11.14.1 dev eth0 diff --git a/e2e/traceroute/pc2.startup b/e2e/traceroute/pc2.startup new file mode 100644 index 00000000..c73ca7e4 --- /dev/null +++ b/e2e/traceroute/pc2.startup @@ -0,0 +1,3 @@ +ip address add 200.1.1.7/24 dev eth0 +ip route add default via 200.1.1.1 dev eth0 +systemctl start apache2 diff --git a/e2e/traceroute/r1.startup b/e2e/traceroute/r1.startup new file mode 100644 index 00000000..bb6bb5e5 --- /dev/null +++ b/e2e/traceroute/r1.startup @@ -0,0 +1,3 @@ +ip address add 195.11.14.1/24 dev eth0 +ip address add 100.0.0.9/30 dev eth1 +ip route add 200.1.1.0/24 via 100.0.0.10 dev eth1 diff --git a/e2e/traceroute/r2.startup b/e2e/traceroute/r2.startup new file mode 100644 index 00000000..54b4254e --- /dev/null +++ b/e2e/traceroute/r2.startup @@ -0,0 +1,3 @@ +ip address add 200.1.1.1/24 dev eth0 +ip address add 100.0.0.10/30 dev eth1 +ip route add 195.11.14.0/24 via 100.0.0.9 dev eth1 diff --git a/e2e/traceroute/shared/config.yaml b/e2e/traceroute/shared/config.yaml new file mode 100644 index 00000000..0d9d815b --- /dev/null +++ b/e2e/traceroute/shared/config.yaml @@ -0,0 +1,25 @@ +# DNS sparrow is exposed on +name: sparrow.caas-t21.telekom.de + +# Selects and configures a loader to continuously fetch the checks' configuration at runtime +loader: + # Defines which loader to use. Options: "file | http" + type: file + # The interval in which sparrow tries to fetch a new configuration + # If this isn't set or set to 0, the loader will only retrieve the configuration once + interval: 30s + + # Config specific to the file loader + # The file loader is not intended for production use + file: + # Location of the file in the local filesystem + path: /shared/config.yaml + +traceroute: + interval: 5s + timeout: 3s + retries: 3 + maxHops: 3 + targets: + - addr: 200.1.1.7 + port: 80 diff --git a/e2e/traceroute/shared/get_api.sh b/e2e/traceroute/shared/get_api.sh new file mode 100644 index 00000000..c1abf290 --- /dev/null +++ b/e2e/traceroute/shared/get_api.sh @@ -0,0 +1,2 @@ +curl -s localhost:8080/v1/metrics/traceroute > /shared/api.json +curl -s localhost:8080/metrics > /shared/prometheus.txt \ No newline at end of file diff --git a/e2e/traceroute/test.sh b/e2e/traceroute/test.sh new file mode 100755 index 00000000..59caf669 --- /dev/null +++ b/e2e/traceroute/test.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +EXIT_CODE=0 + +function cleanup() +{ + kathara lclean + yes | rm ./shared/api.json ./shared/prometheus.txt ./shared/sparrow + exit $EXIT_CODE +} + +function error() { + echo "[ ERROR ]: $@" + EXIT_CODE=1 +} + +function info() { + echo "[ INFO ]: $@" +} + +function success() { + echo "[ SUCCESS ]: $@" +} + +function check_prometheus_output() { + if grep -q 'sparrow_traceroute_minimum_hops{target="200.1.1.7"} 3' ./shared/prometheus.txt; then + success "The specific Prometheus output is present." + else + error "The specific Prometheus output is not present." + fi +} + +function check_api_output() { + if jq -e ' + .data["200.1.1.7"].hops | + .["1"][0].addr.ip == "195.11.14.1" and + .["1"][0].reached == false and + .["1"][0].ttl == 1 and + .["2"][0].addr.ip == "100.0.0.10" and + .["2"][0].reached == false and + .["2"][0].ttl == 2 and + .["3"][0].addr.ip == "200.1.1.7" and + .["3"][0].reached == true and + .["3"][0].ttl == 3 and + .["3"][0].addr.port == 80' ./shared/api.json > /dev/null; then + success "The API output matches the expected hops and conditions." + else + error "The API output does not match the expected hops and conditions." + cat ./shared/api.json + fi +} + +trap cleanup EXIT + +# Start the KatharĂ¡ lab +kathara lstart + + +# Copy the binary into the shared folder +info "Using $SPARROW_BIN" +cp $SPARROW_BIN ./shared/sparrow + +# Start Sparrow on pc1 +kathara exec pc1 "/shared/sparrow run --config /shared/config.yaml" & + +# Wait for 10 seconds to ensure Sparrow is up and running +sleep 10 + +# Curl the API of Sparrow +kathara exec pc1 "bash /shared/get_api.sh" + +check_prometheus_output + +check_api_output diff --git a/scripts/run_e2e_tests.sh b/scripts/run_e2e_tests.sh new file mode 100755 index 00000000..a8276da4 --- /dev/null +++ b/scripts/run_e2e_tests.sh @@ -0,0 +1,16 @@ +root=$(pwd) +export SPARROW_BIN=$(realpath ./dist/sparrow_linux_amd64_v1/sparrow) + +EXIT_CODE=0 + +for i in $(ls e2e); do + echo "Running test e2e/$i" + cd e2e/$i + ./test.sh || { + EXIT_CODE=$? + echo "E2E test e2e/$i failed" + } + cd $root +done + +exit $EXIT_CODE \ No newline at end of file From b88ca551dfd295acc5c701ae84733c064366c7e4 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Wed, 31 Jul 2024 10:40:30 +0200 Subject: [PATCH 29/46] fix(ci): snapshot Signed-off-by: Niklas Treml --- .github/workflows/e2e_checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e_checks.yml b/.github/workflows/e2e_checks.yml index 1ffebe76..b4610241 100644 --- a/.github/workflows/e2e_checks.yml +++ b/.github/workflows/e2e_checks.yml @@ -25,7 +25,7 @@ jobs: uses: goreleaser/goreleaser-action@v5 with: version: latest - args: build --single-target --clean --config .goreleaser-ci.yaml + args: build --single-target --clean --snapshot --config .goreleaser-ci.yaml - name: Run e2e tests run: | From 501890af3e8ed9dd0ba7ff4c3b4a7d64f1a3784b Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Wed, 31 Jul 2024 10:48:02 +0200 Subject: [PATCH 30/46] fix(ci): install kathara to path Signed-off-by: Niklas Treml --- .github/workflows/e2e_checks.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e_checks.yml b/.github/workflows/e2e_checks.yml index b4610241..34bfcb13 100644 --- a/.github/workflows/e2e_checks.yml +++ b/.github/workflows/e2e_checks.yml @@ -17,9 +17,9 @@ jobs: - name: Install dependencies run: | + sudo add-apt-repository ppa:katharaframework/kathara sudo apt-get update - sudo apt-get install -y python3 python3-pip jq - pip3 install kathara + sudo apt-get install -y python3 python3-pip jq kathara - name: Build binary for e2e uses: goreleaser/goreleaser-action@v5 From bdfac86af67694234b0f182722f11f7a004a2729 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Wed, 31 Jul 2024 11:09:48 +0200 Subject: [PATCH 31/46] feat(ci): retry ci Signed-off-by: Niklas Treml --- scripts/run_e2e_tests.sh | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/scripts/run_e2e_tests.sh b/scripts/run_e2e_tests.sh index a8276da4..f8387baf 100755 --- a/scripts/run_e2e_tests.sh +++ b/scripts/run_e2e_tests.sh @@ -3,14 +3,21 @@ export SPARROW_BIN=$(realpath ./dist/sparrow_linux_amd64_v1/sparrow) EXIT_CODE=0 +MAX_RETRY=3 + for i in $(ls e2e); do - echo "Running test e2e/$i" - cd e2e/$i - ./test.sh || { - EXIT_CODE=$? - echo "E2E test e2e/$i failed" - } - cd $root + for ATTEMPT in $(seq 1 $MAX_RETRY ); do + echo "[$ATTEMPT/$MAX_RETRY] Running test e2e/$i" + cd e2e/$i + ./test.sh + TEST_EXIT_CODE=$? + cd $root + if [ $TEST_EXIT_CODE -eq 0 ]; then + break + elif [ $ATTEMPT -eq $MAX_RETRY ]; then + EXIT_CODE=1 + fi + done done exit $EXIT_CODE \ No newline at end of file From 872bf5a98face47119748b94edbf07c5787053ce Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Wed, 31 Jul 2024 11:56:02 +0200 Subject: [PATCH 32/46] feat(ci): kathara config --- .github/workflows/e2e_checks.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/workflows/e2e_checks.yml b/.github/workflows/e2e_checks.yml index 34bfcb13..cc5a8cd2 100644 --- a/.github/workflows/e2e_checks.yml +++ b/.github/workflows/e2e_checks.yml @@ -20,6 +20,28 @@ jobs: sudo add-apt-repository ppa:katharaframework/kathara sudo apt-get update sudo apt-get install -y python3 python3-pip jq kathara + - name: Setup kathara + run: | + echo '{ + "image": "kathara/base", + "manager_type": "docker", + "terminal": "/usr/bin/xterm", + "open_terminals": false, + "device_shell": "/bin/bash", + "net_prefix": "kathara", + "device_prefix": "kathara", + "debug_level": "INFO", + "print_startup_log": true, + "enable_ipv6": false, + "last_checked": 1721834897.2415252, + "hosthome_mount": false, + "shared_mount": true, + "image_update_policy": "Prompt", + "shared_cds": 1, + "remote_url": null, + "cert_path": null, + "network_plugin": "kathara/katharanp_vde" + }' > ~/.config/kathara.conf - name: Build binary for e2e uses: goreleaser/goreleaser-action@v5 From 92ce5f90313aac42b5a943eef132d7a988c48851 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Wed, 31 Jul 2024 13:46:43 +0200 Subject: [PATCH 33/46] fix: flaky e2e test due to wrong socket reading logic Signed-off-by: Niklas Treml --- pkg/checks/traceroute/traceroute.go | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 9ad9e6b5..21e34ff6 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -56,7 +56,8 @@ func tcpHop(addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error // it reads the address of the router that dropped created the icmp packet. It also reads the source port // from the payload and finds the source port used by the previous tcp connection. If any error is returned, // an icmp packet was either not received, or the received packet was not a time exceeded. -func readIcmpMessage(icmpListener *icmp.PacketConn, timeout time.Duration) (int, net.Addr, error) { +func readIcmpMessage(ctx context.Context, icmpListener *icmp.PacketConn, timeout time.Duration) (int, net.Addr, error) { + log := logger.FromContext(ctx) // Expected to fail due to TTL expiry, listen for ICMP response if err := icmpListener.SetReadDeadline(time.Now().Add(timeout)); err != nil { return 0, nil, fmt.Errorf("failed to set icmp read deadline: %w", err) @@ -76,6 +77,7 @@ func readIcmpMessage(icmpListener *icmp.PacketConn, timeout time.Duration) (int, // Ensure the message is an ICMP Time Exceeded message if msg.Type != ipv4.ICMPTypeTimeExceeded { + log.Debug("message is not 'Time Exceeded'", "type", msg.Type.Protocol()) return 0, nil, errors.New("message is not 'Time Exceeded'") } @@ -113,7 +115,7 @@ func TraceRoute(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error go func(ttl int) { defer wg.Done() err := helper.Retry(func(_ context.Context) error { - hop, err := traceroute(addr, ttl, timeoutDuration) + hop, err := traceroute(ctx, addr, ttl, timeoutDuration) if hop != nil { results <- *hop } @@ -159,9 +161,11 @@ func ipFromAddr(remoteAddr net.Addr) net.IP { // traceroute performs a traceroute to the given address with the specified TTL and timeout. // It returns a Hop struct containing the latency, TTL, address, and other details of the hop. -func traceroute(addr net.Addr, ttl int, timeout time.Duration) (*Hop, error) { +func traceroute(ctx context.Context, addr net.Addr, ttl int, timeout time.Duration) (*Hop, error) { + log := logger.FromContext(ctx) canIcmp, icmpListener, err := setupIcmpListener() if err != nil { + log.Error("Failed to open ICMP socket", "err", err.Error(), "ttl", ttl) return nil, err } defer closeIcmpListener(canIcmp, icmpListener) @@ -174,6 +178,7 @@ func traceroute(addr net.Addr, ttl int, timeout time.Duration) (*Hop, error) { } if !canIcmp { + log.Debug("No permission for icmp socket", "ttl", ttl) return &Hop{ Latency: latency, Ttl: ttl, @@ -181,7 +186,7 @@ func traceroute(addr net.Addr, ttl int, timeout time.Duration) (*Hop, error) { }, nil } - h := handleIcmpResponse(icmpListener, clientPort, ttl, timeout) + h := handleIcmpResponse(ctx, icmpListener, clientPort, ttl, timeout) h.Latency = latency return &h, nil } @@ -246,15 +251,16 @@ func handleTcpSuccess(conn net.Conn, addr net.Addr, ttl int, latency time.Durati // handleIcmpResponse attempts to read a time exceeded packet that matches clientPort until timeout is reached // if an error occurs while reading from the socket, handleIcmpResponse will silently fail and return a hop with hop.Reached=false -func handleIcmpResponse(icmpListener *icmp.PacketConn, clientPort, ttl int, timeout time.Duration) Hop { +func handleIcmpResponse(ctx context.Context, icmpListener *icmp.PacketConn, clientPort, ttl int, timeout time.Duration) Hop { + log := logger.FromContext(ctx) deadline := time.Now().Add(timeout) for time.Now().Unix() < deadline.Unix() { - gotPort, addr, err := readIcmpMessage(icmpListener, timeout) + log.Debug("Reading ICMP message", "ttl", ttl) + gotPort, addr, err := readIcmpMessage(ctx, icmpListener, timeout) if err != nil { - return Hop{ - Ttl: ttl, - } + log.Debug("Failed to read ICMP message", "err", err.Error(), "ttl", ttl) + continue } // Check if the destination port matches our dialer's source port @@ -275,6 +281,7 @@ func handleIcmpResponse(icmpListener *icmp.PacketConn, clientPort, ttl int, time } } + log.Debug("Deadline reached", "ttl", ttl) return Hop{ Ttl: ttl, } From 5bf2d7ab3e3d430e1151ae993cfe8256480d7d7e Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Wed, 31 Jul 2024 14:39:11 +0200 Subject: [PATCH 34/46] chore: add dist to .gitignore Signed-off-by: Niklas Treml --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d41d1df3..22485668 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ gen # Temporary directory .tmp/* +dist From fe4f631c83c678a6c29dc26a7c072364ee3ee8ec Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Mon, 5 Aug 2024 09:15:11 +0200 Subject: [PATCH 35/46] feat: debug logs in ci Signed-off-by: Niklas Treml --- .github/workflows/e2e_checks.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e_checks.yml b/.github/workflows/e2e_checks.yml index cc5a8cd2..0f64ae72 100644 --- a/.github/workflows/e2e_checks.yml +++ b/.github/workflows/e2e_checks.yml @@ -10,7 +10,9 @@ permissions: jobs: test_e2e: runs-on: ubuntu-latest - + env: + LOG_LEVEL: DEBUG + LOG_FORMAT: TEXT steps: - name: Checkout repository uses: actions/checkout@v4 From 4434492835a954cf00ac936ebc1c49bebc842dd5 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Mon, 5 Aug 2024 09:18:29 +0200 Subject: [PATCH 36/46] chore: rename setupIcmpListener Signed-off-by: Niklas Treml --- pkg/checks/traceroute/traceroute.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 21e34ff6..2a0ef0f5 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -163,7 +163,7 @@ func ipFromAddr(remoteAddr net.Addr) net.IP { // It returns a Hop struct containing the latency, TTL, address, and other details of the hop. func traceroute(ctx context.Context, addr net.Addr, ttl int, timeout time.Duration) (*Hop, error) { log := logger.FromContext(ctx) - canIcmp, icmpListener, err := setupIcmpListener() + canIcmp, icmpListener, err := newIcmpListener() if err != nil { log.Error("Failed to open ICMP socket", "err", err.Error(), "ttl", ttl) return nil, err @@ -191,7 +191,7 @@ func traceroute(ctx context.Context, addr net.Addr, ttl int, timeout time.Durati return &h, nil } -func setupIcmpListener() (bool, *icmp.PacketConn, error) { +func newIcmpListener() (bool, *icmp.PacketConn, error) { icmpListener, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") if err != nil { if !errors.Is(err, syscall.EPERM) { From 247730b641e6bf0562fa886cb50e2b23fdc977b7 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Mon, 5 Aug 2024 09:21:33 +0200 Subject: [PATCH 37/46] refactor: constants Signed-off-by: Niklas Treml --- pkg/checks/traceroute/traceroute.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 2a0ef0f5..83d47246 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -17,6 +17,11 @@ import ( "golang.org/x/net/ipv4" ) +const ( + IPv4HeaderSize = 20 + mtuSize = 1500 // Standard MTU size +) + // randomPort returns a random port in the interval [ 30_000, 40_000 [ // //nolint:all @@ -62,7 +67,7 @@ func readIcmpMessage(ctx context.Context, icmpListener *icmp.PacketConn, timeout if err := icmpListener.SetReadDeadline(time.Now().Add(timeout)); err != nil { return 0, nil, fmt.Errorf("failed to set icmp read deadline: %w", err) } - buffer := make([]byte, 1500) //nolint:mnd // Standard MTU size + buffer := make([]byte, mtuSize) n, routerAddr, err := icmpListener.ReadFrom(buffer) if err != nil { // we probably timed out so return @@ -82,7 +87,7 @@ func readIcmpMessage(ctx context.Context, icmpListener *icmp.PacketConn, timeout } // The first 20 bytes of Data are the IP header, so the TCP segment starts at byte 20 - tcpSegment := msg.Body.(*icmp.TimeExceeded).Data[20:] + tcpSegment := msg.Body.(*icmp.TimeExceeded).Data[IPv4HeaderSize:] // Extract the source port from the TCP segment destPort := int(tcpSegment[0])<<8 + int(tcpSegment[1]) From aa347ef7d5b8fd73efe2f375696b69abfb35b34c Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Mon, 5 Aug 2024 09:28:44 +0200 Subject: [PATCH 38/46] feat: unix package Signed-off-by: Niklas Treml --- .github/workflows/e2e_checks.yml | 5 ++++- README.md | 2 +- go.mod | 2 +- pkg/checks/traceroute/traceroute.go | 8 +++++--- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/e2e_checks.yml b/.github/workflows/e2e_checks.yml index 0f64ae72..5865c052 100644 --- a/.github/workflows/e2e_checks.yml +++ b/.github/workflows/e2e_checks.yml @@ -16,12 +16,15 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' - name: Install dependencies run: | sudo add-apt-repository ppa:katharaframework/kathara sudo apt-get update - sudo apt-get install -y python3 python3-pip jq kathara + sudo apt-get install -y jq kathara - name: Setup kathara run: | echo '{ diff --git a/README.md b/README.md index bb6df3f0..bb63a609 100644 --- a/README.md +++ b/README.md @@ -519,7 +519,7 @@ of the hop that dropped a packet, will not be available. To enable this function sudo sparrow run --config config.yaml ``` -- allow sparrow to create raw sockets, by assignging the `CAP_NET_RAW` capability to the sparrow binary: +- allow sparrow to create raw sockets, by assigning the `CAP_NET_RAW` capability to the sparrow binary: ```bash sudo setcap 'cap_net_raw=ep' sparrow ``` diff --git a/go.mod b/go.mod index e0df5905..160c6768 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ require ( github.com/subosito/gotenv v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/sys v0.20.0 // indirect + golang.org/x/sys v0.20.0 golang.org/x/text v0.15.0 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 83d47246..4be9239a 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -11,6 +11,8 @@ import ( "syscall" "time" + "golang.org/x/sys/unix" + "github.com/caas-team/sparrow/internal/helper" "github.com/caas-team/sparrow/internal/logger" "golang.org/x/net/icmp" @@ -41,7 +43,7 @@ func tcpHop(addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error Control: func(_, _ string, c syscall.RawConn) error { var opErr error if err := c.Control(func(fd uintptr) { - opErr = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TTL, ttl) + opErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_TTL, ttl) }); err != nil { return err } @@ -51,7 +53,7 @@ func tcpHop(addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error // Attempt to connect to the target host conn, err := dialer.Dial("tcp", addr.String()) - if !errors.Is(err, syscall.EADDRINUSE) { + if !errors.Is(err, unix.EADDRINUSE) { return conn, port, err } } @@ -199,7 +201,7 @@ func traceroute(ctx context.Context, addr net.Addr, ttl int, timeout time.Durati func newIcmpListener() (bool, *icmp.PacketConn, error) { icmpListener, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") if err != nil { - if !errors.Is(err, syscall.EPERM) { + if !errors.Is(err, unix.EPERM) { return false, nil, err } return false, nil, nil From ba281eeed20d2923c17d9053d10d2ddc48b65de3 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Mon, 5 Aug 2024 09:34:51 +0200 Subject: [PATCH 39/46] feat: ipv6 Signed-off-by: Niklas Treml --- pkg/checks/traceroute/traceroute.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 4be9239a..3c39b42b 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -17,6 +17,7 @@ import ( "github.com/caas-team/sparrow/internal/logger" "golang.org/x/net/icmp" "golang.org/x/net/ipv4" + "golang.org/x/net/ipv6" ) const ( @@ -83,7 +84,7 @@ func readIcmpMessage(ctx context.Context, icmpListener *icmp.PacketConn, timeout } // Ensure the message is an ICMP Time Exceeded message - if msg.Type != ipv4.ICMPTypeTimeExceeded { + if msg.Type != ipv4.ICMPTypeTimeExceeded && msg.Type != ipv6.ICMPTypeTimeExceeded { log.Debug("message is not 'Time Exceeded'", "type", msg.Type.Protocol()) return 0, nil, errors.New("message is not 'Time Exceeded'") } From 63292f0e113b7c046da11bfe79fd6704c90774a4 Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Mon, 5 Aug 2024 09:47:22 +0200 Subject: [PATCH 40/46] refactor: retry context Signed-off-by: Niklas Treml --- pkg/checks/traceroute/traceroute.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 3c39b42b..ee1c9e93 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -122,7 +122,7 @@ func TraceRoute(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error wg.Add(1) go func(ttl int) { defer wg.Done() - err := helper.Retry(func(_ context.Context) error { + err := helper.Retry(func(ctx context.Context) error { hop, err := traceroute(ctx, addr, ttl, timeoutDuration) if hop != nil { results <- *hop From 6c5f24abbb83d64c8eefcd79588314290f503a0d Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Mon, 5 Aug 2024 10:01:48 +0200 Subject: [PATCH 41/46] fix: correct log level in e2e tests Signed-off-by: Niklas Treml --- .github/workflows/e2e_checks.yml | 3 --- e2e/traceroute/lab.conf | 2 ++ pkg/checks/traceroute/test-lab/lab.conf | 2 ++ pkg/checks/traceroute/traceroute.go | 6 +++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/e2e_checks.yml b/.github/workflows/e2e_checks.yml index 5865c052..866b3c9e 100644 --- a/.github/workflows/e2e_checks.yml +++ b/.github/workflows/e2e_checks.yml @@ -10,9 +10,6 @@ permissions: jobs: test_e2e: runs-on: ubuntu-latest - env: - LOG_LEVEL: DEBUG - LOG_FORMAT: TEXT steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/e2e/traceroute/lab.conf b/e2e/traceroute/lab.conf index 9836e8cf..6219303a 100644 --- a/e2e/traceroute/lab.conf +++ b/e2e/traceroute/lab.conf @@ -14,6 +14,8 @@ r2[image]="kathara/base" pc1[0]="A" pc1[image]="kathara/base" +pc1[env]="LOG_LEVEL=DEBUG" +pc1[env]="LOG_FORMAT=TEXT" pc2[0]="C" pc2[image]="kathara/base" diff --git a/pkg/checks/traceroute/test-lab/lab.conf b/pkg/checks/traceroute/test-lab/lab.conf index 9836e8cf..6219303a 100644 --- a/pkg/checks/traceroute/test-lab/lab.conf +++ b/pkg/checks/traceroute/test-lab/lab.conf @@ -14,6 +14,8 @@ r2[image]="kathara/base" pc1[0]="A" pc1[image]="kathara/base" +pc1[env]="LOG_LEVEL=DEBUG" +pc1[env]="LOG_FORMAT=TEXT" pc2[0]="C" pc2[image]="kathara/base" diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index ee1c9e93..83b737f9 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -32,7 +32,7 @@ func randomPort() int { return rand.Intn(10_000) + 30_000 // #nosec G404 // math.rand is fine here, we're not doing encryption } -func tcpHop(addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error) { +func tcpHop(ctx context.Context, addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error) { for { port := randomPort() // Dialer with control function to set IP_TTL @@ -53,7 +53,7 @@ func tcpHop(addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error } // Attempt to connect to the target host - conn, err := dialer.Dial("tcp", addr.String()) + conn, err := dialer.DialContext(ctx, "tcp", addr.String()) if !errors.Is(err, unix.EADDRINUSE) { return conn, port, err } @@ -179,7 +179,7 @@ func traceroute(ctx context.Context, addr net.Addr, ttl int, timeout time.Durati defer closeIcmpListener(canIcmp, icmpListener) start := time.Now() - conn, clientPort, err := tcpHop(addr, ttl, timeout) + conn, clientPort, err := tcpHop(ctx, addr, ttl, timeout) latency := time.Since(start) if err == nil { return handleTcpSuccess(conn, addr, ttl, latency), nil From b58d300dddcb0b197bbfec91ef6c02cb0c1800ee Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Mon, 5 Aug 2024 10:07:58 +0200 Subject: [PATCH 42/46] fix(ci): only run e2e test once on pr Signed-off-by: Niklas Treml --- .github/workflows/e2e_checks.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e_checks.yml b/.github/workflows/e2e_checks.yml index 866b3c9e..47335bbc 100644 --- a/.github/workflows/e2e_checks.yml +++ b/.github/workflows/e2e_checks.yml @@ -2,6 +2,8 @@ name: E2E - Test checks on: push: + branches: + - main pull_request: permissions: @@ -13,9 +15,9 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v5 with: - python-version: '3.12' + python-version: "3.12" - name: Install dependencies run: | From 61c0564df4be0c086cb0321bca45795cba7a670d Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Mon, 5 Aug 2024 13:50:14 +0200 Subject: [PATCH 43/46] feat(ci): only run on push events to prevent duplicate pipelines Signed-off-by: Niklas Treml --- .github/workflows/ci.yml | 1 - .github/workflows/e2e_checks.yml | 3 --- .github/workflows/end2end.yml | 1 - .github/workflows/pre-commit.yml | 3 ++- .github/workflows/test_sast.yml | 3 +-- .github/workflows/test_unit.yml | 1 - 6 files changed, 3 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b2d2c48b..1ca3d7c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,6 @@ name: Continuous Integration on: push: - pull_request: permissions: contents: write diff --git a/.github/workflows/e2e_checks.yml b/.github/workflows/e2e_checks.yml index 47335bbc..4ccc805e 100644 --- a/.github/workflows/e2e_checks.yml +++ b/.github/workflows/e2e_checks.yml @@ -2,9 +2,6 @@ name: E2E - Test checks on: push: - branches: - - main - pull_request: permissions: contents: read diff --git a/.github/workflows/end2end.yml b/.github/workflows/end2end.yml index 2632131a..38ecbf12 100644 --- a/.github/workflows/end2end.yml +++ b/.github/workflows/end2end.yml @@ -4,7 +4,6 @@ name: End2End Testing on: push: - pull_request: jobs: end2end: diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 29def31a..75561863 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -1,6 +1,7 @@ name: pre-commit.ci -on: [push, pull_request] +on: + push: jobs: pre-commit: diff --git a/.github/workflows/test_sast.yml b/.github/workflows/test_sast.yml index 2ed4eeba..811828f3 100644 --- a/.github/workflows/test_sast.yml +++ b/.github/workflows/test_sast.yml @@ -2,7 +2,6 @@ name: Test - SAST on: push: - pull_request: permissions: contents: read @@ -21,4 +20,4 @@ jobs: - name: Run Gosec Security Scanner uses: securego/gosec@master with: - args: ./... \ No newline at end of file + args: ./... diff --git a/.github/workflows/test_unit.yml b/.github/workflows/test_unit.yml index dc8679e4..5a77885f 100644 --- a/.github/workflows/test_unit.yml +++ b/.github/workflows/test_unit.yml @@ -2,7 +2,6 @@ name: Test - Unit on: push: - pull_request: permissions: contents: read From 0a23dee9661f1cb52cae00944bdc1211096c75ad Mon Sep 17 00:00:00 2001 From: lvlcn-t <75443136+lvlcn-t@users.noreply.github.com> Date: Mon, 5 Aug 2024 21:36:34 +0200 Subject: [PATCH 44/46] chore: lint markdown files --- README.md | 41 +++++++----- pkg/checks/traceroute/test-lab/how-to-test.md | 65 +++++++++++++------ 2 files changed, 70 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index bb63a609..1c86be28 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,9 @@ - [DNS Metrics](#dns-metrics) - [Check: Traceroute](#check-traceroute) - [Example configuration](#example-configuration-3) - - [Required Capabilities](#required-capabilities) + - [Optional Capabilities](#optional-capabilities) + - [Traceroute Prometheus Metrics](#traceroute-prometheus-metrics) + - [Traceroute API Metrics](#traceroute-api-metrics) - [API](#api) - [Metrics](#metrics) - [Code of Conduct](#code-of-conduct) @@ -409,7 +411,7 @@ latency: - `sparrow_latency_duration_seconds` - Type: Gauge - - Description: Latency with status information of targets. This metric is DEPRECATED. Use `sparrow_latency_seconds`. + - Description: Latency with status information of targets. This metric is DEPRECATED. Use `sparrow_latency_seconds`. - Labelled with `target` and `status` - `sparrow_latency_seconds` @@ -511,40 +513,45 @@ dns: #### Optional Capabilities -Sparrow does not need any extra permissions to run this check. However, some data, like the ip address +Sparrow does not need any extra permissions to run this check. However, some data, like the ip address of the hop that dropped a packet, will not be available. To enable this functionality, there are two options: -- run sparrow as root: -```bash -sudo sparrow run --config config.yaml -``` +- Run sparrow as root: -- allow sparrow to create raw sockets, by assigning the `CAP_NET_RAW` capability to the sparrow binary: -```bash -sudo setcap 'cap_net_raw=ep' sparrow -``` + ```bash + sudo sparrow run --config config.yaml + ``` -#### Traceroute Prometheus Metrics +- Allow sparrow to create raw sockets, by assigning the `CAP_NET_RAW` capability to the sparrow binary: + + ```bash + sudo setcap 'cap_net_raw=ep' sparrow + ``` +#### Traceroute Prometheus Metrics - `sparrow_traceroute_check_duration_ms{target="google.com"} 43150` - - Type: Gauge - - Description: How long the last traceroute took for this target in total + - Type: Gauge + - Description: How long the last traceroute took for this target in total - `sparrow_traceroute_minimum_hops{target="google.com"} 14` - - Type: Gauge - - Description: The minimum number of hops required to reach a target + - Type: Gauge + - Description: The minimum number of hops required to reach a target #### Traceroute API Metrics + The traceroute check exposes additional data through its rest API that isn't available in prometheus. -This data give a more detailed breakdown of the trace and can be found at `/v1/metrics/traceroute` and is +This data give a more detailed breakdown of the trace and can be found at `/v1/metrics/traceroute` and is meant to be a json representation of traditional traceroute output: + ```bash $ traceroute -T -q 1 100.1.2.2 1 200.2.0.1 (200.2.0.1) 2 ms 2 11.0.0.34 (11.0.0.34) 5 ms ... ``` + Is roughly equal to this: + ```json { "data": { diff --git a/pkg/checks/traceroute/test-lab/how-to-test.md b/pkg/checks/traceroute/test-lab/how-to-test.md index 3693bb6a..1bd1947a 100644 --- a/pkg/checks/traceroute/test-lab/how-to-test.md +++ b/pkg/checks/traceroute/test-lab/how-to-test.md @@ -1,61 +1,84 @@ -# How to test the traceroute check +# How to test the traceroute check + +- [About this tool](#about-this-tool) +- [Requirements](#requirements) +- [How to](#how-to) + - [1. Start kathara network](#1-start-kathara-network) + - [2. Connect to the client system](#2-connect-to-the-client-system) + - [3. (optional) Explore the network](#3-optional-explore-the-network) + - [4. Run sparrow](#4-run-sparrow) + - [5. Other tools](#5-other-tools) + - [6. Cleaning up](#6-cleaning-up) + +## About this tool -## What is this Kathara is a container-based network emulation tool. The files in this folder configure a small test network using kathara. In this case we use kathara to locally simulate a network with a webserver, a client and multiple network hops between them. + ## Requirements -- install [ kathara ](https://github.com/KatharaFramework/Kathara) -- install wireshark (optional) + +- Install [kathara](https://github.com/KatharaFramework/Kathara) +- Install wireshark (optional) ## How to -1. Start kathara network +### 1. Start kathara network + In this folder run: + ```bash kathara lstart ``` + To prevent kathara from creating a terminal window for every container: + ```bash kathara lstart --noterminals ``` -This starts the test-lab ([ topology ](https://github.com/KatharaFramework/Kathara-Labs/blob/main/main-labs/basic-topics/static-routing/004-kathara-lab_static-routing.pdf)) +This starts the test-lab ([topology](https://github.com/KatharaFramework/Kathara-Labs/blob/main/main-labs/basic-topics/static-routing/004-kathara-lab_static-routing.pdf)) + +### 2. Connect to the client system -2. Connect to the client system In a separate terminal run: + ```bash kathara connect pc1 ``` +### 3. (optional) Explore the network -3. (optional) Explore the network Aside from you, there are two routers and a webserver in this lab. Tracerouting to the webserver shows us, that we need to go through the two routers to reach the webserver: + ```bash export WEBSERVER=200.1.1.7 root@pc1:/# traceroute $WEBSERVER traceroute to 200.1.1.7 (200.1.1.7), 30 hops max, 60 byte packets - 1 195.11.14.1 (195.11.14.1) 0.972 ms 1.093 ms 1.095 ms - 2 100.0.0.10 (100.0.0.10) 1.543 ms 1.712 ms 1.838 ms - 3 200.1.1.7 (200.1.1.7) 2.232 ms 2.310 ms 2.394 ms +1 195.11.14.1 (195.11.14.1) 0.972 ms 1.093 ms 1.095 ms +2 100.0.0.10 (100.0.0.10) 1.543 ms 1.712 ms 1.838 ms +3 200.1.1.7 (200.1.1.7) 2.232 ms 2.310 ms 2.394 ms ``` We can also look at the server website: + ```bash root@pc1:/# curl $WEBSERVER ``` + This should return the default apache website. -4. Run sparrow +### 4. Run sparrow -To run sparrow we first need to build and move the sparrow binary into the container. Luckily, kathara mounts a shared folder to all systems in the lab. -We can use this folder to run sparrow in the containers without having to build our own image! +To run sparrow we first need to build and move the sparrow binary into the container. Luckily, kathara mounts a shared folder to all systems in the lab. +We can use this folder to run sparrow in the containers without having to build our own image! ```bash go build -o sparrow . && mv sparrow pkg/checks/traceroute/test-lab/shared/ ``` Back in the client container: + ```bash root@pc1:/# cd /shared root@pc1:/shared# ./sparrow -h @@ -76,7 +99,9 @@ Flags: Use "sparrow [command] --help" for more information about a command. ``` + Now we just have to create a config for sparrow to use and we're ready to develop. For testing traceroute I used this config: + ```yaml root@pc1:/shared# cat config.yaml name: sparrow.dev @@ -95,16 +120,17 @@ traceroute: port: 80 ``` - Now just run sparrow in the shared folder: ```bash root@pc1:/shared# ./sparrow run --config config.yaml ``` -5. Other tools -The container image has a bunch of utilities for debugging network issues. If you're debugging low level issues, where you need to inspect +### 5. Other tools + +The container image has a bunch of utilities for debugging network issues. If you're debugging low level issues, where you need to inspect specific network packets you can use tcpdump directly, which is preinstalled: + ```bash root@pc1:/# tcpdump tcpdump: verbose output suppressed, use -v[v]... for full protocol decode @@ -126,11 +152,12 @@ root@pc1:/# tcpdump -w /shared/dump.pcap wireshark -r dump.pcap ``` - Happy Debugging! -6. Cleaning up +### 6. Cleaning up + Cleanup is simple: + ```bash kathara lclean ``` From e137d6af0be7fd2775a8d929acb13eb84d5940a3 Mon Sep 17 00:00:00 2001 From: lvlcn-t <75443136+lvlcn-t@users.noreply.github.com> Date: Mon, 5 Aug 2024 22:12:49 +0200 Subject: [PATCH 45/46] fix: handle IPv6 icmpv6 time exceeded --- README.md | 2 +- pkg/checks/traceroute/check.go | 4 ++-- pkg/checks/traceroute/traceroute.go | 37 +++++++++++++++++------------ 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 1c86be28..3c8b2b00 100644 --- a/README.md +++ b/README.md @@ -497,7 +497,7 @@ dns: ```yaml - traceroute: +traceroute: interval: 5s timeout: 3s retry: diff --git a/pkg/checks/traceroute/check.go b/pkg/checks/traceroute/check.go index 87604873..078e0aa3 100644 --- a/pkg/checks/traceroute/check.go +++ b/pkg/checks/traceroute/check.go @@ -45,7 +45,7 @@ type Traceroute struct { type tracerouteConfig struct { Dest string Port int - Timeout int + Timeout time.Duration MaxHops int Rc helper.RetryConfig } @@ -117,7 +117,7 @@ func (tr *Traceroute) check(ctx context.Context) map[string]result { trace, err := tr.traceroute(ctx, tracerouteConfig{ Dest: t.Addr, Port: int(t.Port), - Timeout: int(tr.config.Timeout / time.Millisecond), + Timeout: tr.config.Timeout, MaxHops: tr.config.MaxHops, Rc: tr.config.Retry, }) diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 83b737f9..589d3c70 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -4,7 +4,7 @@ import ( "context" "errors" "fmt" - "math/rand" + "math/rand/v2" "net" "slices" "sync" @@ -21,15 +21,21 @@ import ( ) const ( + // IPv4HeaderSize is the size of an IPv4 header in bytes IPv4HeaderSize = 20 - mtuSize = 1500 // Standard MTU size + // IPv6HeaderSize is the size of an IPv6 header in bytes + IPv6HeaderSize = 40 + // mtuSize is the maximum transmission unit size + mtuSize = 1500 + // basePort is the starting port for the TCP connection + basePort = 30000 + // portRange is the range of ports to generate a random port from + portRange = 10000 ) -// randomPort returns a random port in the interval [ 30_000, 40_000 [ -// -//nolint:all +// randomPort returns a random port in the interval [30_000, 40_000) func randomPort() int { - return rand.Intn(10_000) + 30_000 // #nosec G404 // math.rand is fine here, we're not doing encryption + return rand.N(portRange) + basePort // #nosec G404 // math.rand is fine here, we're not doing encryption } func tcpHop(ctx context.Context, addr net.Addr, ttl int, timeout time.Duration) (net.Conn, int, error) { @@ -73,7 +79,7 @@ func readIcmpMessage(ctx context.Context, icmpListener *icmp.PacketConn, timeout buffer := make([]byte, mtuSize) n, routerAddr, err := icmpListener.ReadFrom(buffer) if err != nil { - // we probably timed out so return + // This is probably a timeout, so we can return an error return 0, nil, fmt.Errorf("failed to read from icmp connection: %w", err) } @@ -83,15 +89,18 @@ func readIcmpMessage(ctx context.Context, icmpListener *icmp.PacketConn, timeout return 0, nil, err } - // Ensure the message is an ICMP Time Exceeded message - if msg.Type != ipv4.ICMPTypeTimeExceeded && msg.Type != ipv6.ICMPTypeTimeExceeded { + // Extract the TCP segment from the ICMP message + var tcpSegment []byte + switch msg.Type { + case ipv4.ICMPTypeTimeExceeded: + tcpSegment = msg.Body.(*icmp.TimeExceeded).Data[IPv4HeaderSize:] + case ipv6.ICMPTypeTimeExceeded: + tcpSegment = msg.Body.(*icmp.TimeExceeded).Data[IPv6HeaderSize:] + default: log.Debug("message is not 'Time Exceeded'", "type", msg.Type.Protocol()) return 0, nil, errors.New("message is not 'Time Exceeded'") } - // The first 20 bytes of Data are the IP header, so the TCP segment starts at byte 20 - tcpSegment := msg.Body.(*icmp.TimeExceeded).Data[IPv4HeaderSize:] - // Extract the source port from the TCP segment destPort := int(tcpSegment[0])<<8 + int(tcpSegment[1]) @@ -104,8 +113,6 @@ func TraceRoute(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error hops := make(map[int][]Hop) log := logger.FromContext(ctx).With("target", cfg.Dest) - timeoutDuration := time.Duration(cfg.Timeout) * time.Second - addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", cfg.Dest, cfg.Port)) if err != nil { log.Error("failed to resolve target name", "err", err.Error()) @@ -123,7 +130,7 @@ func TraceRoute(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error go func(ttl int) { defer wg.Done() err := helper.Retry(func(ctx context.Context) error { - hop, err := traceroute(ctx, addr, ttl, timeoutDuration) + hop, err := traceroute(ctx, addr, ttl, cfg.Timeout) if hop != nil { results <- *hop } From 6c8385718a6d03237db91e435dd5a65942ceca3e Mon Sep 17 00:00:00 2001 From: Niklas Treml Date: Tue, 6 Aug 2024 11:45:49 +0200 Subject: [PATCH 46/46] refactor: inject more metadata into logs Signed-off-by: Niklas Treml --- pkg/checks/traceroute/check.go | 14 ++++++++++---- pkg/checks/traceroute/traceroute.go | 20 +++++++++++--------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/pkg/checks/traceroute/check.go b/pkg/checks/traceroute/check.go index 078e0aa3..ab6e22d4 100644 --- a/pkg/checks/traceroute/check.go +++ b/pkg/checks/traceroute/check.go @@ -20,7 +20,7 @@ type Target struct { // The address of the target to traceroute to. Can be a DNS name or an IP address Addr string `json:"addr" yaml:"addr" mapstructure:"addr"` // The port to traceroute to - Port uint16 `json:"port" yaml:"port" mapstructure:"port"` + Port int `json:"port" yaml:"port" mapstructure:"port"` } func NewCheck() checks.Check { @@ -106,6 +106,8 @@ func (tr *Traceroute) check(ctx context.Context) map[string]result { cResult := make(chan internalResult, len(tr.config.Targets)) var wg sync.WaitGroup + start := time.Now() + wg.Add(len(tr.config.Targets)) for _, t := range tr.config.Targets { go func(t Target) { @@ -113,15 +115,15 @@ func (tr *Traceroute) check(ctx context.Context) map[string]result { l := log.With("target", t.Addr) l.Debug("Running traceroute") - start := time.Now() + targetstart := time.Now() trace, err := tr.traceroute(ctx, tracerouteConfig{ Dest: t.Addr, - Port: int(t.Port), + Port: t.Port, Timeout: tr.config.Timeout, MaxHops: tr.config.MaxHops, Rc: tr.config.Retry, }) - elapsed := time.Since(start) + elapsed := time.Since(targetstart) if err != nil { l.Error("Error running traceroute", "error", err) } @@ -153,6 +155,10 @@ func (tr *Traceroute) check(ctx context.Context) map[string]result { res[r.addr] = r.res } + elapsed := time.Since(start) + + log.Info("Finished traceroute check", "duration", elapsed) + return res } diff --git a/pkg/checks/traceroute/traceroute.go b/pkg/checks/traceroute/traceroute.go index 589d3c70..f0d2fbc4 100644 --- a/pkg/checks/traceroute/traceroute.go +++ b/pkg/checks/traceroute/traceroute.go @@ -129,23 +129,25 @@ func TraceRoute(ctx context.Context, cfg tracerouteConfig) (map[int][]Hop, error wg.Add(1) go func(ttl int) { defer wg.Done() + l := log.With("ttl", ttl) + logctx := logger.IntoContext(ctx, l) err := helper.Retry(func(ctx context.Context) error { hop, err := traceroute(ctx, addr, ttl, cfg.Timeout) if hop != nil { results <- *hop } if err != nil { - log.Error("traceroute failed", "err", err.Error(), "ttl", ttl) + l.Error("traceroute failed", "err", err.Error()) return err } if !hop.Reached { - log.Debug("failed to reach target, retrying", "ttl", ttl) + l.Debug("failed to reach target, retrying") return errors.New("failed to reach target") } return nil - }, cfg.Rc)(ctx) + }, cfg.Rc)(logctx) if err != nil { - log.Debug("traceroute could not reach target", "ttl", ttl) + l.Debug("traceroute could not reach target") } }(ttl) } @@ -180,7 +182,7 @@ func traceroute(ctx context.Context, addr net.Addr, ttl int, timeout time.Durati log := logger.FromContext(ctx) canIcmp, icmpListener, err := newIcmpListener() if err != nil { - log.Error("Failed to open ICMP socket", "err", err.Error(), "ttl", ttl) + log.Error("Failed to open ICMP socket", "err", err.Error()) return nil, err } defer closeIcmpListener(canIcmp, icmpListener) @@ -193,7 +195,7 @@ func traceroute(ctx context.Context, addr net.Addr, ttl int, timeout time.Durati } if !canIcmp { - log.Debug("No permission for icmp socket", "ttl", ttl) + log.Debug("No permission for icmp socket") return &Hop{ Latency: latency, Ttl: ttl, @@ -271,10 +273,10 @@ func handleIcmpResponse(ctx context.Context, icmpListener *icmp.PacketConn, clie deadline := time.Now().Add(timeout) for time.Now().Unix() < deadline.Unix() { - log.Debug("Reading ICMP message", "ttl", ttl) + log.Debug("Reading ICMP message") gotPort, addr, err := readIcmpMessage(ctx, icmpListener, timeout) if err != nil { - log.Debug("Failed to read ICMP message", "err", err.Error(), "ttl", ttl) + log.Debug("Failed to read ICMP message", "err", err.Error()) continue } @@ -296,7 +298,7 @@ func handleIcmpResponse(ctx context.Context, icmpListener *icmp.PacketConn, clie } } - log.Debug("Deadline reached", "ttl", ttl) + log.Debug("Deadline reached") return Hop{ Ttl: ttl, }