Skip to content

Commit

Permalink
Feat/traceroute (#113)
Browse files Browse the repository at this point in the history
* feat: boilerplate

* feat: register udptraceroute

* chore: fix nits

* fix: unit tests breaking

* Merge from main

* refactor: validation logic

* review: implement changes requested by @lvlcn-t

* review: implement changes requested by @puffitos

* chore: add target to logger

* chore: remove testcase type

Signed-off-by: Niklas Treml <treml.niklas@gmail.com>

* chore: rename shadowed variable

Signed-off-by: Niklas Treml <treml.niklas@gmail.com>

* fix: validate ip correctly

Signed-off-by: Niklas Treml <treml.niklas@gmail.com>

* docs: add docs for config

Signed-off-by: Niklas Treml <treml.niklas@gmail.com>

* chore: log error instead of err

Signed-off-by: Niklas Treml <treml.niklas@gmail.com>

* docs: update readme to include traceroute

Signed-off-by: Niklas Treml <treml.niklas@gmail.com>

* docs: capabilities

Signed-off-by: Niklas Treml <treml.niklas@gmail.com>

* docs: document target

* chore: remove duplicate debug log

Signed-off-by: Niklas Treml <treml.niklas@gmail.com>

---------

Signed-off-by: Niklas Treml <treml.niklas@gmail.com>
  • Loading branch information
niklastreml committed Mar 1, 2024
1 parent 1d5f0ed commit ec1fc82
Show file tree
Hide file tree
Showing 10 changed files with 487 additions and 9 deletions.
9 changes: 9 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Connect to server",
"type": "go",
"request": "attach",
"mode": "remote",
"remotePath": "${workspaceFolder}",
"port": 2345,
"host": "127.0.0.1"
},
{
"name": "Launch Package",
"type": "go",
Expand Down
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ The following checks are available:
3. [DNS check](#check-dns) - `dns`: The `sparrow` is able to perform DNS resolution checks to monitor domain name system
performance and reliability. The check has the ability to target specific domains or IPs for monitoring.

4. [Traceroute Check](#check-traceroute) - `traceroute`: The `sparrow` is able to perform traceroute checks to monitor
the network path to a target. The check has the ability to target specific domains or IPs for monitoring.

Each check is designed to provide comprehensive insights into the various aspects of network and service health,
ensuring robust monitoring and quick detection of potential issues.

Expand Down Expand Up @@ -432,6 +435,41 @@ dns:
- Description: Histogram of response times for DNS checks
- Labelled with `target`

### Check: Traceroute

| Field | Type | Description |
| ----------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `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. |
| `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 |
| `targets[].port` | `uint16` | The port of the target to traceroute to. Default is 80 |

#### Example configuration

```yaml
traceroute:
interval: 5s
timeout: 3s
retries: 3
maxHops: 8
targets:
- addr: 8.8.8.8
port: 53
- addr: www.google.com
port: 80
```

#### Required 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

```bash
sudo setcap 'cap_net_raw=ep' sparrow
```

## API

The `sparrow` exposes an API for accessing the results of various checks. Each check registers its own endpoint
Expand Down
8 changes: 7 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ require (
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/aeden/traceroute v0.0.0-20210211061815-03f5f7cb7908
github.com/google/go-cmp v0.6.0
)

require github.com/mitchellh/mapstructure v1.5.0 // indirect

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
Expand All @@ -28,7 +35,6 @@ require (
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
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.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
Expand Down Expand Up @@ -27,8 +29,8 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
Expand Down
25 changes: 22 additions & 3 deletions pkg/checks/runtime/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,17 @@ import (
"github.com/caas-team/sparrow/pkg/checks/dns"
"github.com/caas-team/sparrow/pkg/checks/health"
"github.com/caas-team/sparrow/pkg/checks/latency"
"github.com/caas-team/sparrow/pkg/checks/traceroute"
)

// Config holds the runtime configuration
// for the various checks
// the sparrow supports
type Config struct {
Health *health.Config `yaml:"health" json:"health"`
Latency *latency.Config `yaml:"latency" json:"latency"`
Dns *dns.Config `yaml:"dns" json:"dns"`
Health *health.Config `yaml:"health" json:"health"`
Latency *latency.Config `yaml:"latency" json:"latency"`
Dns *dns.Config `yaml:"dns" json:"dns"`
Traceroute *traceroute.Config `yaml:"traceroute" json:"traceroute"`
}

// Empty returns true if no checks are configured
Expand Down Expand Up @@ -63,6 +65,9 @@ func (c Config) Iter() []checks.Runtime {
if c.Dns != nil {
configs = append(configs, c.Dns)
}
if c.Traceroute != nil {
configs = append(configs, c.Traceroute)
}
return configs
}

Expand All @@ -78,6 +83,9 @@ func (c Config) size() int {
if c.HasDNSCheck() {
size++
}
if c.HasTracerouteCheck() {
size++
}
return size
}

Expand All @@ -96,6 +104,11 @@ func (c Config) HasDNSCheck() bool {
return c.Dns != nil
}

// HasTracerouteCheck returns true if the check has a traceroute check configured
func (c Config) HasTracerouteCheck() bool {
return c.Traceroute != nil
}

// HasCheck returns true if the check has a check with the given name configured
func (c Config) HasCheck(name string) bool {
switch name {
Expand All @@ -105,6 +118,8 @@ func (c Config) HasCheck(name string) bool {
return c.HasLatencyCheck()
case dns.CheckName:
return c.HasDNSCheck()
case traceroute.CheckName:
return c.HasTracerouteCheck()
default:
return false
}
Expand All @@ -125,6 +140,10 @@ func (c Config) For(name string) checks.Runtime {
if c.HasDNSCheck() {
return c.Dns
}
case traceroute.CheckName:
if c.HasTracerouteCheck() {
return c.Traceroute
}
}
return nil
}
51 changes: 51 additions & 0 deletions pkg/checks/traceroute/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package traceroute

import (
"fmt"
"net"
"net/url"
"time"

"github.com/caas-team/sparrow/pkg/checks"
)

// Config is the configuration for the traceroute check
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"`
// 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
Interval time.Duration `json:"interval" yaml:"interval" mapstructure:"interval"`
// Timeout is the maximum time to wait for a response from a hop
Timeout time.Duration `json:"timeout" yaml:"timeout" mapstructure:"timeout"`
}

func (c *Config) For() string {
return CheckName
}

func (c *Config) Validate() error {
if c.Timeout <= 0 {
return checks.ErrInvalidConfig{CheckName: CheckName, Field: "traceroute.timeout", Reason: "must be greater than 0"}
}
if c.Interval <= 0 {
return checks.ErrInvalidConfig{CheckName: CheckName, Field: "traceroute.interval", Reason: "must be greater than 0"}
}

for i, t := range c.Targets {
ip := net.ParseIP(t.Addr)

if ip != nil {
continue
}

_, err := url.Parse(t.Addr)
if err != nil && ip == nil {
return checks.ErrInvalidConfig{CheckName: CheckName, Field: fmt.Sprintf("traceroute.targets[%d].addr", i), Reason: "invalid url or ip"}
}
}
return nil
}
Loading

0 comments on commit ec1fc82

Please sign in to comment.