Skip to content

Commit

Permalink
feat(scheme): set ping's privilege mode automatically
Browse files Browse the repository at this point in the history
  • Loading branch information
macrat committed Dec 17, 2022
1 parent 4842137 commit e84581e
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 78 deletions.
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,6 @@ Send ICMP echo request (a.k.a. ping command) and check if the target is connecte
Ayd sends 3 packets in 1 second and expects all packets to return.
These parameter can changed by `AYD_PING_PACKETS` and `AYD_PING_PERIOD` environment variable.

In Linux or MacOS, Ayd use non-privileged ICMP in default. So, you can use ping even if rootless.
But this way is not work on some platforms for instance docker container.
Please set `yes` to `AYD_PRIVILEGED` environment variable to use privileged ICMP.

You can specify IPv4 or IPv6 with `ping4:` or `ping6:` scheme.

Ping will timeout in 30 seconds after sent all packets and report as failure.
Expand Down
43 changes: 10 additions & 33 deletions internal/scheme/ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,39 +98,13 @@ func newAutoPinger() *autoPingerStruct {
}
}

func getAydPrivilegedEnv() bool {
switch strings.ToLower(os.Getenv("AYD_PRIVILEGED")) {
case "", "0", "no", "false":
return false
}
return true
}

func makePingers() (v4, v6 *pinger.Pinger) {
v4 = pinger.NewIPv4()
v6 = pinger.NewIPv6()

if getAydPrivilegedEnv() {
v4.SetPrivileged(true)
v6.SetPrivileged(true)
}

return v4, v6
}

func (p *autoPingerStruct) start() (teardown func(), err error) {
p.v4, p.v6 = makePingers()
p.v4 = pinger.NewIPv4()
p.v6 = pinger.NewIPv6()

ctx, stop := context.WithCancel(context.Background())

if err := p.v4.Start(ctx); err != nil {
stop()
p.v4 = nil
p.v6 = nil
return nil, err
}

if err := p.v6.Start(ctx); err != nil {
if err := p.startPingers(ctx); err != nil {
stop()
p.v4 = nil
p.v6 = nil
Expand Down Expand Up @@ -212,11 +186,14 @@ var (

// checkPingPermission tries to prepare pinger for check if it has permission.
func checkPingPermission() error {
ctx, stop := context.WithCancel(context.Background())
defer stop()
stop, err := autoPinger.start()

p, _ := makePingers()
return p.Start(ctx)
if err != nil {
return err
}

stop()
return nil
}

// PingProbe is a Prober implementation for SNMP echo request aka ping.
Expand Down
41 changes: 0 additions & 41 deletions internal/scheme/ping_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package scheme_test

import (
"context"
"errors"
"os"
"runtime"
"strings"
"testing"
Expand Down Expand Up @@ -102,45 +100,6 @@ func TestPingProbe_Probe(t *testing.T) {
})
}

func TestPingProbe(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("unprivileged mode is not supported on windows")
}

privileged := os.Getenv("AYD_PRIVILEGED")
t.Cleanup(func() {
os.Setenv("AYD_PRIVILEGED", privileged)
})

tests := []struct {
Env string
Fail bool
}{
{"1", true},
{"0", false},
{"yes", true},
{"no", false},
{"true", true},
{"false", false},
{"TRUE", true},
{"False", false},
}

for _, tt := range tests {
t.Run("AYD_PRIVILEGED="+tt.Env, func(t *testing.T) {
os.Setenv("AYD_PRIVILEGED", tt.Env)
_, err := scheme.NewPingProbe(&api.URL{Scheme: "ping", Opaque: "localhost"})

if tt.Fail && !errors.Is(err, scheme.ErrFailedToPreparePing) {
t.Errorf("expected permission error but got %v", err)
}
if !tt.Fail && err != nil {
t.Errorf("expected nil but got error: %s", err)
}
})
}
}

func BenchmarkPingProbe(b *testing.B) {
p := testutil.NewProber(b, "ping:localhost")

Expand Down
22 changes: 22 additions & 0 deletions internal/scheme/ping_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//go:build linux || darwin
// +build linux darwin

package scheme

import (
"context"
)

func (p *autoPingerStruct) startPingers(ctx context.Context) error {
if err := p.v4.Start(ctx); err == nil {
return p.v6.Start(ctx)
}

p.v4.SetPrivileged(true)
p.v4.SetPrivileged(false)

if err := p.v4.Start(ctx); err != nil {
return err
}
return p.v6.Start(ctx)
}
15 changes: 15 additions & 0 deletions internal/scheme/ping_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//go:build windows
// +build windows

package scheme

import (
"context"
)

func (p *autoPingerStruct) startPingers(ctx context.Context) error {
if err := p.v4.Start(ctx); err != nil {
return err
}
return p.v6.Start(ctx)
}

0 comments on commit e84581e

Please sign in to comment.