From 6595e624a5a302756c53057f4fd5dcb47cae0e85 Mon Sep 17 00:00:00 2001 From: cyclinder Date: Thu, 13 Jun 2024 17:27:09 +0800 Subject: [PATCH] coordinator: Use arping to detect the gateway if reachable Signed-off-by: cyclinder --- cmd/coordinator/cmd/cni_types.go | 4 +- cmd/coordinator/cmd/command_add.go | 23 +- docs/concepts/coordinator-zh_CN.md | 2 +- docs/concepts/coordinator.md | 2 +- go.mod | 1 - go.sum | 2 - pkg/constant/errors.go | 12 +- pkg/networking/gwconnection/connection.go | 180 +++- pkg/networking/networking/route.go | 10 +- .../pro-bing/.editorconfig | 16 - .../prometheus-community/pro-bing/.gitignore | 2 - .../pro-bing/.golangci.yml | 10 - .../pro-bing/.goreleaser.yaml | 46 - .../pro-bing/CODE_OF_CONDUCT.md | 3 - .../pro-bing/CONTRIBUTING.md | 44 - .../prometheus-community/pro-bing/LICENSE | 22 - .../pro-bing/MAINTAINERS.md | 4 - .../prometheus-community/pro-bing/Makefile | 32 - .../prometheus-community/pro-bing/README.md | 144 --- .../prometheus-community/pro-bing/SECURITY.md | 6 - .../prometheus-community/pro-bing/logger.go | 53 - .../pro-bing/packetconn.go | 105 -- .../prometheus-community/pro-bing/ping.go | 913 ------------------ .../pro-bing/utils_linux.go | 122 --- .../pro-bing/utils_other.go | 47 - .../pro-bing/utils_windows.go | 58 -- vendor/modules.txt | 3 - 27 files changed, 191 insertions(+), 1675 deletions(-) delete mode 100644 vendor/github.com/prometheus-community/pro-bing/.editorconfig delete mode 100644 vendor/github.com/prometheus-community/pro-bing/.gitignore delete mode 100644 vendor/github.com/prometheus-community/pro-bing/.golangci.yml delete mode 100644 vendor/github.com/prometheus-community/pro-bing/.goreleaser.yaml delete mode 100644 vendor/github.com/prometheus-community/pro-bing/CODE_OF_CONDUCT.md delete mode 100644 vendor/github.com/prometheus-community/pro-bing/CONTRIBUTING.md delete mode 100644 vendor/github.com/prometheus-community/pro-bing/LICENSE delete mode 100644 vendor/github.com/prometheus-community/pro-bing/MAINTAINERS.md delete mode 100644 vendor/github.com/prometheus-community/pro-bing/Makefile delete mode 100644 vendor/github.com/prometheus-community/pro-bing/README.md delete mode 100644 vendor/github.com/prometheus-community/pro-bing/SECURITY.md delete mode 100644 vendor/github.com/prometheus-community/pro-bing/logger.go delete mode 100644 vendor/github.com/prometheus-community/pro-bing/packetconn.go delete mode 100644 vendor/github.com/prometheus-community/pro-bing/ping.go delete mode 100644 vendor/github.com/prometheus-community/pro-bing/utils_linux.go delete mode 100644 vendor/github.com/prometheus-community/pro-bing/utils_other.go delete mode 100644 vendor/github.com/prometheus-community/pro-bing/utils_windows.go diff --git a/cmd/coordinator/cmd/cni_types.go b/cmd/coordinator/cmd/cni_types.go index 08c2c67909..bd84af3c4e 100644 --- a/cmd/coordinator/cmd/cni_types.go +++ b/cmd/coordinator/cmd/cni_types.go @@ -256,7 +256,7 @@ func ValidateDelectOptions(config *DetectOptions) (*DetectOptions, error) { if config == nil { return &DetectOptions{ Interval: "1s", - TimeOut: "1s", + TimeOut: "3s", Retry: 3, }, nil } @@ -270,7 +270,7 @@ func ValidateDelectOptions(config *DetectOptions) (*DetectOptions, error) { } if config.TimeOut == "" { - config.TimeOut = "1s" + config.TimeOut = "3s" } _, err := time.ParseDuration(config.Interval) diff --git a/cmd/coordinator/cmd/command_add.go b/cmd/coordinator/cmd/command_add.go index cffd4bfa90..697799d114 100644 --- a/cmd/coordinator/cmd/command_add.go +++ b/cmd/coordinator/cmd/command_add.go @@ -5,6 +5,7 @@ package cmd import ( "fmt" + "net" "time" "github.com/containernetworking/cni/pkg/skel" @@ -77,7 +78,7 @@ func CmdAdd(args *skel.CmdArgs) (err error) { ) logger.Info(fmt.Sprintf("start to implement ADD command in %v mode", conf.Mode)) logger.Debug(fmt.Sprintf("api configuration: %+v", *coordinatorConfig)) - logger.Debug(fmt.Sprintf("final configuration: %+v", *conf)) + logger.Debug("final configuration", zap.Any("conf", conf)) // parse prevResult prevResult, err := current.GetResult(conf.PrevResult) @@ -183,22 +184,28 @@ func CmdAdd(args *skel.CmdArgs) (err error) { if conf.DetectGateway != nil && *conf.DetectGateway { logger.Debug("Try to detect gateway") - var gws []string + var gws []net.IP err = c.netns.Do(func(netNS ns.NetNS) error { gws, err = networking.GetDefaultGatewayByName(c.currentInterface, c.ipFamily) if err != nil { logger.Error("failed to GetDefaultGatewayByName", zap.Error(err)) return fmt.Errorf("failed to GetDefaultGatewayByName: %v", err) } + logger.Debug("Get GetDefaultGatewayByName", zap.Any("Gws", gws)) - logger.Debug("Get GetDefaultGatewayByName", zap.Strings("Gws", gws)) - + p, err := gwconnection.New(conf.DetectOptions.Retry, conf.DetectOptions.Interval, conf.DetectOptions.TimeOut, c.currentInterface, logger) + if err != nil { + return fmt.Errorf("failed to init the gateway client: %v", err) + } + p.ParseAddrFromPreresult(prevResult.IPs) for _, gw := range gws { - p, err := gwconnection.NewPinger(conf.DetectOptions.Retry, conf.DetectOptions.Interval, conf.DetectOptions.TimeOut, gw, logger) - if err != nil { - return fmt.Errorf("failed to run NewPinger: %v", err) + if gw.To4() != nil { + p.V4Gw = gw + errg.Go(c.hostNs, c.netns, p.ArpingOverIface) + } else { + p.V6Gw = gw + errg.Go(c.hostNs, c.netns, p.NDPingOverIface) } - errg.Go(c.hostNs, c.netns, p.DetectGateway) } return nil diff --git a/docs/concepts/coordinator-zh_CN.md b/docs/concepts/coordinator-zh_CN.md index 7e10b56b87..eb9f1f51d2 100644 --- a/docs/concepts/coordinator-zh_CN.md +++ b/docs/concepts/coordinator-zh_CN.md @@ -77,7 +77,7 @@ spec: ## 支持检测 Pod 的网关是否可达(alpha) 在 Underlay 网络下,Pod 访问外部需要通过网关转发。如果网关不可达,那么在外界看来,这个 Pod 实际是失联的。有时候我们希望创建 Pod 时,其网关是可达的。 我们可借助 `coordinator` 检测 Pod 的网关是否可达, -支持检测 IPv4 和 IPv6 的网关地址。我们通过发送 ICMP 报文,探测网关地址是否可达。如果网关不可达,将会阻止 Pod 创建: +支持检测 IPv4 和 IPv6 的网关地址。我们通过发送 ARP 探测报文,探测网关地址是否可达。如果网关不可达,将会阻止 Pod 创建: 我们可以通过 Spidermultusconfig 配置它: diff --git a/docs/concepts/coordinator.md b/docs/concepts/coordinator.md index 362f3206ff..7834701c28 100644 --- a/docs/concepts/coordinator.md +++ b/docs/concepts/coordinator.md @@ -75,7 +75,7 @@ spec: ## Detect Pod gateway reachability(alpha) Under the underlay network, pod access to the outside needs to be forwarded through the gateway. If the gateway is unreachable, then the pod is actually lost. Sometimes we want to create a pod with a gateway reachable. We can use the 'coordinator' to check if the pod's gateway is reachable. -Gateway addresses for IPv4 and IPv6 can be detected. We send an ICMP packet to check whether the gateway address is reachable. If the gateway is unreachable, pods will be prevented from creating: +Gateway addresses for IPv4 and IPv6 can be detected. We send an ARP probe packet to check whether the gateway address is reachable. If the gateway is unreachable, pods will be prevented from creating: We can configure it via Spidermultusconfig: diff --git a/go.mod b/go.mod index 259faeb252..3043a4034c 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,6 @@ require ( github.com/onsi/ginkgo/v2 v2.13.0 github.com/onsi/gomega v1.29.0 github.com/openkruise/kruise-api v1.3.0 - github.com/prometheus-community/pro-bing v0.2.0 github.com/prometheus/client_golang v1.17.0 github.com/sasha-s/go-deadlock v0.3.1 github.com/spf13/cobra v1.7.0 diff --git a/go.sum b/go.sum index 9457289e8c..cbee90bd11 100644 --- a/go.sum +++ b/go.sum @@ -507,8 +507,6 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/projectcalico/api v0.0.0-20220722155641-439a754a988b h1:dW+UhJMzusDO6hqVGuCYeDxXWAzc7HnA9CsPN+uHPnA= github.com/projectcalico/api v0.0.0-20220722155641-439a754a988b/go.mod h1:Avoy1rTN1GfeisnHGf3WhQNqR+BuGOcwfNFsdWX6OHE= -github.com/prometheus-community/pro-bing v0.2.0 h1:hyK7yPFndU3LCDwEQJwPQUCjNkp1DGP/VxyzrWfXZUU= -github.com/prometheus-community/pro-bing v0.2.0/go.mod h1:20arNb2S8rNG3EtmjHyZZU92cfbhQx7oCHZ9sulAV+I= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= diff --git a/pkg/constant/errors.go b/pkg/constant/errors.go index f08bf50407..bcaa351922 100644 --- a/pkg/constant/errors.go +++ b/pkg/constant/errors.go @@ -8,10 +8,14 @@ import ( ) var ( - ErrWrongInput = errors.New("wrong input") - ErrNoAvailablePool = errors.New("no IPPool available") - ErrRetriesExhausted = errors.New("exhaust all retries") - ErrIPUsedOut = errors.New("all IP addresses used out") + ErrWrongInput = errors.New("wrong input") + ErrNoAvailablePool = errors.New("no IPPool available") + ErrRetriesExhausted = errors.New("exhaust all retries") + ErrIPUsedOut = errors.New("all IP addresses used out") + ErrIPConflict = errors.New("ip conflict") + ErrGatewayUnreachable = errors.New("unreachable") + ErrForbidReleasingStatefulWorkload = errors.New("forbid releasing IPs for stateful workload ") + ErrForbidReleasingStatelessWorkload = errors.New("forbid releasing IPs for stateless workload") ) var ErrMissingRequiredParam = errors.New("must be specified") diff --git a/pkg/networking/gwconnection/connection.go b/pkg/networking/gwconnection/connection.go index f071f6a451..2dbe097fcb 100644 --- a/pkg/networking/gwconnection/connection.go +++ b/pkg/networking/gwconnection/connection.go @@ -5,48 +5,186 @@ package gwconnection import ( "fmt" + "net" + "net/netip" "time" "go.uber.org/zap" - ping "github.com/prometheus-community/pro-bing" + types100 "github.com/containernetworking/cni/pkg/types/100" + "github.com/mdlayher/arp" + _ "github.com/mdlayher/ethernet" + "github.com/mdlayher/ndp" + "github.com/spidernet-io/spiderpool/pkg/constant" ) -type Pinger struct { - logger *zap.Logger - pinger *ping.Pinger +type DetectGateway struct { + retries int + iface string + interval time.Duration + timeout time.Duration + v4Addr, v6Addr, V4Gw, V6Gw net.IP + logger *zap.Logger } -func NewPinger(count int, interval, timeout, gw string, logger *zap.Logger) (*Pinger, error) { - pinger := ping.New(gw) - pinger.Count = count +func New(retries int, interval, timeout, iface string, logger *zap.Logger) (*DetectGateway, error) { + var err error + dg := &DetectGateway{ + retries: retries, + iface: iface, + } - intervalDuration, err := time.ParseDuration(interval) + dg.interval, err = time.ParseDuration(interval) if err != nil { return nil, err } - pinger.Interval = intervalDuration - timeoutDuration, err := time.ParseDuration(timeout) + dg.timeout, err = time.ParseDuration(timeout) if err != nil { return nil, err } - pinger.Timeout = timeoutDuration - pinger.SetPrivileged(true) + dg.logger = logger + + return dg, nil +} - return &Pinger{logger, pinger}, nil +func (dg *DetectGateway) ParseAddrFromPreresult(ipconfigs []*types100.IPConfig) { + for _, ipconfig := range ipconfigs { + if ipconfig.Address.IP.To4() != nil { + dg.v4Addr = ipconfig.Address.IP + } else { + dg.v6Addr = ipconfig.Address.IP + } + } } -func (p *Pinger) DetectGateway() error { - if err := p.pinger.Run(); err != nil { - return fmt.Errorf("failed to run DetectGateway: %v", err) +// PingOverIface sends an arp ping over interface 'iface' to 'dstIP' +func (dg *DetectGateway) ArpingOverIface() error { + ifi, err := net.InterfaceByName(dg.iface) + if err != nil { + return err } - stats := p.pinger.Statistics() - if stats.PacketLoss > 0 { - return fmt.Errorf("gateway %s is unreachable", p.pinger.Addr()) + client, err := arp.Dial(ifi) + if err != nil { + return err + } + defer client.Close() + + gwNetIP := netip.MustParseAddr(dg.V4Gw.String()) + var gwHwAddr net.HardwareAddr + for i := 0; i < dg.retries; i++ { + + err = client.SetReadDeadline(time.Now().Add(dg.timeout)) + if err != nil { + dg.logger.Sugar().Errorf("[RetryNum: %v]failed to set ReadDeadline: %v", i+1, err) + time.Sleep(dg.interval) + continue + } + + dg.logger.Sugar().Debugf("[RetryNum: %v]try to arping the gateway", i+1) + gwHwAddr, err = client.Resolve(gwNetIP) + if err != nil { + dg.logger.Sugar().Errorf("[RetryNum: %v]failed to resolve: %v", i+1, err) + time.Sleep(dg.interval) + continue + } + + if gwHwAddr != nil { + dg.logger.Sugar().Infof("Gateway %s is reachable, gateway is located at %v", gwNetIP, gwHwAddr.String()) + return nil + } + time.Sleep(dg.interval) + } + + if neterr, ok := err.(net.Error); ok && neterr.Timeout() { + dg.logger.Sugar().Errorf("gateway %s is %v, reason: %v", dg.V4Gw.String(), err) + return fmt.Errorf("gateway %s is %v", dg.V4Gw.String(), constant.ErrGatewayUnreachable) + } + + return fmt.Errorf("failed to checking the gateway %s if is reachable: %w", dg.V4Gw.String(), err) +} + +func (dg *DetectGateway) NDPingOverIface() error { + ifi, err := net.InterfaceByName(dg.iface) + if err != nil { + return err + } + + client, _, err := ndp.Listen(ifi, ndp.LinkLocal) + if err != nil { + return err } + defer client.Close() - p.logger.Sugar().Debugf("gateway %s is reachable", p.pinger.Addr()) - return nil + msg := &ndp.NeighborSolicitation{ + TargetAddress: netip.MustParseAddr(dg.V6Gw.String()), + Options: []ndp.Option{ + &ndp.LinkLayerAddress{ + Direction: ndp.Source, + Addr: ifi.HardwareAddr, + }, + }, + } + + ticker := time.NewTicker(dg.interval) + defer ticker.Stop() + + var gwHwAddr string + for i := 0; i < dg.retries && gwHwAddr == ""; i++ { + <-ticker.C + gwHwAddr, err = dg.sendReceive(client, msg) + if err != nil { + dg.logger.Sugar().Errorf("[retry number: %v]error detect if gateway is reachable: %v", i+1, err) + } else if gwHwAddr != "" { + dg.logger.Sugar().Infof("gateway %s is reachable, it's located at %s", dg.V6Gw.String(), gwHwAddr) + return nil + } + } + + if neterr, ok := err.(net.Error); ok && neterr.Timeout() { + dg.logger.Sugar().Errorf("gateway %s is unreachable, reason: %v", dg.V6Gw.String(), err) + return fmt.Errorf("gateway %s is %w", dg.V6Gw.String(), constant.ErrGatewayUnreachable) + } + return fmt.Errorf("error detect the gateway %s if is reachable: %v", dg.V6Gw.String(), err) +} + +func (dg *DetectGateway) sendReceive(client *ndp.Conn, m ndp.Message) (string, error) { + gwNetIP := netip.MustParseAddr(dg.V6Gw.String()) + // Always multicast the message to the target's solicited-node multicast + // group as if we have no knowledge of its MAC address. + snm, err := ndp.SolicitedNodeMulticast(gwNetIP) + if err != nil { + dg.logger.Error("[NDP]failed to determine solicited-node multicast address", zap.Error(err)) + return "", fmt.Errorf("failed to determine solicited-node multicast address: %v", err) + } + + // we send a gratuitous neighbor solicitation to checking if ip is conflict + err = client.WriteTo(m, nil, snm) + if err != nil { + dg.logger.Error("[NDP]failed to send message", zap.Error(err)) + return "", fmt.Errorf("failed to send message: %v", err) + } + + if err := client.SetReadDeadline(time.Now().Add(dg.timeout)); err != nil { + dg.logger.Error("[NDP]failed to set deadline", zap.Error(err)) + return "", fmt.Errorf("failed to set deadline: %v", err) + } + + msg, _, _, err := client.ReadFrom() + if err != nil { + return "", err + } + + gwAddr := netip.MustParseAddr(dg.V6Gw.String()) + na, ok := msg.(*ndp.NeighborAdvertisement) + if ok && na.TargetAddress.Compare(gwAddr) == 0 && len(na.Options) == 1 { + dg.logger.Debug("Detect gateway: found the response", zap.String("TargetAddress", na.TargetAddress.String())) + // found ndp reply what we want + option, ok := na.Options[0].(*ndp.LinkLayerAddress) + if ok { + return option.Addr.String(), nil + } + } + return "", nil } diff --git a/pkg/networking/networking/route.go b/pkg/networking/networking/route.go index d839028875..26689667c9 100644 --- a/pkg/networking/networking/route.go +++ b/pkg/networking/networking/route.go @@ -31,7 +31,7 @@ func GetRoutesByName(iface string, ipfamily int) (routes []netlink.Route, err er return netlink.RouteList(link, ipfamily) } -func GetDefaultGatewayByName(iface string, ipfamily int) ([]string, error) { +func GetDefaultGatewayByName(iface string, ipfamily int) ([]net.IP, error) { routes, err := GetRoutesByName("", ipfamily) if err != nil { return nil, err @@ -42,17 +42,17 @@ func GetDefaultGatewayByName(iface string, ipfamily int) ([]string, error) { return nil, err } - gws := make([]string, 0) + gws := make([]net.IP, 0) for _, route := range routes { if route.LinkIndex == link.Attrs().Index { - if route.Dst == nil || route.Dst.IP.Equal(net.IPv4zero) { - gws = append(gws, route.Gw.String()) + if route.Dst == nil || route.Dst.IP.Equal(net.IPv4zero) || route.Dst.IP.Equal(net.IPv6zero) { + gws = append(gws, route.Gw) } } else { if len(route.MultiPath) > 0 { for _, r := range route.MultiPath { if r.LinkIndex == link.Attrs().Index { - gws = append(gws, r.Gw.String()) + gws = append(gws, r.Gw) break } } diff --git a/vendor/github.com/prometheus-community/pro-bing/.editorconfig b/vendor/github.com/prometheus-community/pro-bing/.editorconfig deleted file mode 100644 index 57abfdc270..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -# https://editorconfig.org - -root = true - -[*] -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true -charset = utf-8 -indent_style = space - -[Makefile] -indent_style = tab - -[*.go] -indent_style = tab diff --git a/vendor/github.com/prometheus-community/pro-bing/.gitignore b/vendor/github.com/prometheus-community/pro-bing/.gitignore deleted file mode 100644 index f527a0e07d..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/ping -/dist diff --git a/vendor/github.com/prometheus-community/pro-bing/.golangci.yml b/vendor/github.com/prometheus-community/pro-bing/.golangci.yml deleted file mode 100644 index f49404377b..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/.golangci.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -linters: - enable: - - revive - -issues: - exclude-rules: - - path: _test.go - linters: - - errcheck diff --git a/vendor/github.com/prometheus-community/pro-bing/.goreleaser.yaml b/vendor/github.com/prometheus-community/pro-bing/.goreleaser.yaml deleted file mode 100644 index 3c5cc0ac30..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/.goreleaser.yaml +++ /dev/null @@ -1,46 +0,0 @@ -project_name: ping -before: - hooks: - - go mod download -builds: -- binary: ping - dir: cmd/ping - goarch: - - amd64 - - arm - - arm64 - goarm: - - 6 - - 7 - goos: - - darwin - - freebsd - - linux - - windows -archives: -- files: - - LICENSE - - README.md - format_overrides: - - goos: windows - format: zip - wrap_in_directory: true -# TODO: Decide if we want packages (name conflcits with /bin/ping?) -# nfpms: -# homepage: https://github.com/go-ping/ping -# maintainer: 'Go Ping Maintainers ' -# description: Ping written in Go. -# license: MIT -# formats: -# - deb -# - rpm -checksum: - name_template: 'checksums.txt' -snapshot: - name_template: "{{ .Tag }}-{{ .ShortCommit }}" -changelog: - sort: asc - filters: - exclude: - - '^docs:' - - '^test:' diff --git a/vendor/github.com/prometheus-community/pro-bing/CODE_OF_CONDUCT.md b/vendor/github.com/prometheus-community/pro-bing/CODE_OF_CONDUCT.md deleted file mode 100644 index d325872bdf..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,3 +0,0 @@ -# Prometheus Community Code of Conduct - -Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md). diff --git a/vendor/github.com/prometheus-community/pro-bing/CONTRIBUTING.md b/vendor/github.com/prometheus-community/pro-bing/CONTRIBUTING.md deleted file mode 100644 index a0bdadacc5..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/CONTRIBUTING.md +++ /dev/null @@ -1,44 +0,0 @@ -# Contributing - -First off, thanks for taking the time to contribute! - -Remember that this is open source software so please consider the other people who will read your code. -Make it look nice for them, document your logic in comments and add or update the unit test cases. - -This library is used by various other projects, companies and individuals in live production environments so please discuss any breaking changes with us before making them. -Feel free to join us in the [#pro-bing](https://gophers.slack.com/archives/C019J5E26U8/p1673599762771949) channel of the [Gophers Slack](https://invite.slack.golangbridge.org/). - -## Pull Requests - -[Fork the repo on GitHub](https://github.com/prometheus-community/pro-bing/fork) and clone it to your local machine. - -```bash -git clone https://github.com/YOUR_USERNAME/pro-bing.git && cd pro-bing -``` - -Here is a guide on [how to configure a remote repository](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/configuring-a-remote-for-a-fork). - -Check out a new branch, make changes, run tests, commit & sign-off, then push branch to your fork. - -```bash -$ git checkout -b -# edit files -$ make style vet test -$ git add -$ git commit -s -$ git push -``` - -Open a [new pull request](https://github.com/prometheus-community/pro-bing/compare) in the main `prometheus-community/pro-bing` repository. -Please describe the purpose of your PR and remember link it to any related issues. - -*We may ask you to rebase your feature branch or squash the commits in order to keep the history clean.* - -## Development Guides - -- Run `make style vet test` before committing your changes. -- Document your logic in code comments. -- Add tests for bug fixes and new features. -- Use UNIX-style (LF) line endings. -- End every file with a single blank line. -- Use the UTF-8 character set. diff --git a/vendor/github.com/prometheus-community/pro-bing/LICENSE b/vendor/github.com/prometheus-community/pro-bing/LICENSE deleted file mode 100644 index 6812e8c57e..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright 2022 The Prometheus Authors -Copyright 2016 Cameron Sparr and contributors. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/prometheus-community/pro-bing/MAINTAINERS.md b/vendor/github.com/prometheus-community/pro-bing/MAINTAINERS.md deleted file mode 100644 index d3021ab42e..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/MAINTAINERS.md +++ /dev/null @@ -1,4 +0,0 @@ -# Maintainers - -* Ben Kochie @SuperQ -* Matthias Loibl @metalmatze diff --git a/vendor/github.com/prometheus-community/pro-bing/Makefile b/vendor/github.com/prometheus-community/pro-bing/Makefile deleted file mode 100644 index d4b4bce799..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -GO ?= go -GOFMT ?= $(GO)fmt -GOOPTS ?= -GO111MODULE := -pkgs = ./... - -all: style vet build test - -.PHONY: build -build: - @echo ">> building ping" - GO111MODULE=$(GO111MODULE) $(GO) build $(GOOPTS) ./cmd/ping - -.PHONY: style -style: - @echo ">> checking code style" - @fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \ - if [ -n "$${fmtRes}" ]; then \ - echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \ - echo "Please ensure you are using $$($(GO) version) for formatting code."; \ - exit 1; \ - fi - -.PHONY: test -test: - @echo ">> running all tests" - GO111MODULE=$(GO111MODULE) $(GO) test -race -cover $(GOOPTS) $(pkgs) - -.PHONY: vet -vet: - @echo ">> vetting code" - GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs) diff --git a/vendor/github.com/prometheus-community/pro-bing/README.md b/vendor/github.com/prometheus-community/pro-bing/README.md deleted file mode 100644 index 2568a802cb..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/README.md +++ /dev/null @@ -1,144 +0,0 @@ -# pro-bing -[![PkgGoDev](https://pkg.go.dev/badge/github.com/prometheus-community/pro-bing)](https://pkg.go.dev/github.com/prometheus-community/pro-bing) -[![Circle CI](https://circleci.com/gh/prometheus-community/pro-bing.svg?style=svg)](https://circleci.com/gh/prometheus-community/pro-bing) - -A simple but powerful ICMP echo (ping) library for Go, inspired by -[go-ping](https://github.com/go-ping/ping) & [go-fastping](https://github.com/tatsushid/go-fastping). - -Here is a very simple example that sends and receives three packets: - -```go -pinger, err := probing.NewPinger("www.google.com") -if err != nil { - panic(err) -} -pinger.Count = 3 -err = pinger.Run() // Blocks until finished. -if err != nil { - panic(err) -} -stats := pinger.Statistics() // get send/receive/duplicate/rtt stats -``` - -Here is an example that emulates the traditional UNIX ping command: - -```go -pinger, err := probing.NewPinger("www.google.com") -if err != nil { - panic(err) -} - -// Listen for Ctrl-C. -c := make(chan os.Signal, 1) -signal.Notify(c, os.Interrupt) -go func() { - for _ = range c { - pinger.Stop() - } -}() - -pinger.OnRecv = func(pkt *probing.Packet) { - fmt.Printf("%d bytes from %s: icmp_seq=%d time=%v\n", - pkt.Nbytes, pkt.IPAddr, pkt.Seq, pkt.Rtt) -} - -pinger.OnDuplicateRecv = func(pkt *probing.Packet) { - fmt.Printf("%d bytes from %s: icmp_seq=%d time=%v ttl=%v (DUP!)\n", - pkt.Nbytes, pkt.IPAddr, pkt.Seq, pkt.Rtt, pkt.Ttl) -} - -pinger.OnFinish = func(stats *ping.Statistics) { - fmt.Printf("\n--- %s ping statistics ---\n", stats.Addr) - fmt.Printf("%d packets transmitted, %d packets received, %v%% packet loss\n", - stats.PacketsSent, stats.PacketsRecv, stats.PacketLoss) - fmt.Printf("round-trip min/avg/max/stddev = %v/%v/%v/%v\n", - stats.MinRtt, stats.AvgRtt, stats.MaxRtt, stats.StdDevRtt) -} - -fmt.Printf("PING %s (%s):\n", pinger.Addr(), pinger.IPAddr()) -err = pinger.Run() -if err != nil { - panic(err) -} -``` - -It sends ICMP Echo Request packet(s) and waits for an Echo Reply in -response. If it receives a response, it calls the `OnRecv` callback -unless a packet with that sequence number has already been received, -in which case it calls the `OnDuplicateRecv` callback. When it's -finished, it calls the `OnFinish` callback. - -For a full ping example, see -[cmd/ping/ping.go](https://github.com/prometheus-community/pro-bing/blob/master/cmd/ping/ping.go). - -## Installation - -``` -go get -u github.com/prometheus-community/pro-bing -``` - -To install the native Go ping executable: - -```bash -go get -u github.com/prometheus-community/pro-bing/... -$GOPATH/bin/ping -``` - -## Supported Operating Systems - -### Linux -This library attempts to send an "unprivileged" ping via UDP. On Linux, -this must be enabled with the following sysctl command: - -``` -sudo sysctl -w net.ipv4.ping_group_range="0 2147483647" -``` - -If you do not wish to do this, you can call `pinger.SetPrivileged(true)` -in your code and then use setcap on your binary to allow it to bind to -raw sockets (or just run it as root): - -``` -setcap cap_net_raw=+ep /path/to/your/compiled/binary -``` - -See [this blog](https://sturmflut.github.io/linux/ubuntu/2015/01/17/unprivileged-icmp-sockets-on-linux/) -and the Go [x/net/icmp](https://godoc.org/golang.org/x/net/icmp) package -for more details. - -This library supports setting the `SO_MARK` socket option which is equivalent to the `-m mark` -flag in standard ping binaries on linux. Setting this option requires the `CAP_NET_ADMIN` capability -(via `setcap` or elevated privileges). You can set a mark (ex: 100) with `pinger.SetMark(100)` in your code. - -Setting the "Don't Fragment" bit is supported under Linux which is equivalent to `ping -Mdo`. -You can enable this with `pinger.SetDoNotFragment(true)`. - -### Windows - -You must use `pinger.SetPrivileged(true)`, otherwise you will receive -the following error: - -``` -socket: The requested protocol has not been configured into the system, or no implementation for it exists. -``` - -Despite the method name, this should work without the need to elevate -privileges and has been tested on Windows 10. Please note that accessing -packet TTL values is not supported due to limitations in the Go -x/net/ipv4 and x/net/ipv6 packages. - -### Plan 9 from Bell Labs - -There is no support for Plan 9. This is because the entire `x/net/ipv4` -and `x/net/ipv6` packages are not implemented by the Go programming -language. - -## Maintainers and Getting Help: - -This repo was originally in the personal account of -[sparrc](https://github.com/sparrc), but is now maintained by the -[Prometheus Community](https://prometheus.io/community). - -## Contributing - -Refer to [CONTRIBUTING.md](https://github.com/prometheus-community/pro-bing/blob/master/CONTRIBUTING.md) diff --git a/vendor/github.com/prometheus-community/pro-bing/SECURITY.md b/vendor/github.com/prometheus-community/pro-bing/SECURITY.md deleted file mode 100644 index fed02d85c7..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/SECURITY.md +++ /dev/null @@ -1,6 +0,0 @@ -# Reporting a security issue - -The Prometheus security policy, including how to report vulnerabilities, can be -found here: - - diff --git a/vendor/github.com/prometheus-community/pro-bing/logger.go b/vendor/github.com/prometheus-community/pro-bing/logger.go deleted file mode 100644 index 709b480c8c..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/logger.go +++ /dev/null @@ -1,53 +0,0 @@ -package probing - -import "log" - -type Logger interface { - Fatalf(format string, v ...interface{}) - Errorf(format string, v ...interface{}) - Warnf(format string, v ...interface{}) - Infof(format string, v ...interface{}) - Debugf(format string, v ...interface{}) -} - -type StdLogger struct { - Logger *log.Logger -} - -func (l StdLogger) Fatalf(format string, v ...interface{}) { - l.Logger.Printf("FATAL: "+format, v...) -} - -func (l StdLogger) Errorf(format string, v ...interface{}) { - l.Logger.Printf("ERROR: "+format, v...) -} - -func (l StdLogger) Warnf(format string, v ...interface{}) { - l.Logger.Printf("WARN: "+format, v...) -} - -func (l StdLogger) Infof(format string, v ...interface{}) { - l.Logger.Printf("INFO: "+format, v...) -} - -func (l StdLogger) Debugf(format string, v ...interface{}) { - l.Logger.Printf("DEBUG: "+format, v...) -} - -type NoopLogger struct { -} - -func (l NoopLogger) Fatalf(format string, v ...interface{}) { -} - -func (l NoopLogger) Errorf(format string, v ...interface{}) { -} - -func (l NoopLogger) Warnf(format string, v ...interface{}) { -} - -func (l NoopLogger) Infof(format string, v ...interface{}) { -} - -func (l NoopLogger) Debugf(format string, v ...interface{}) { -} diff --git a/vendor/github.com/prometheus-community/pro-bing/packetconn.go b/vendor/github.com/prometheus-community/pro-bing/packetconn.go deleted file mode 100644 index ec5c7ac576..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/packetconn.go +++ /dev/null @@ -1,105 +0,0 @@ -package probing - -import ( - "net" - "runtime" - "time" - - "golang.org/x/net/icmp" - "golang.org/x/net/ipv4" - "golang.org/x/net/ipv6" -) - -type packetConn interface { - Close() error - ICMPRequestType() icmp.Type - ReadFrom(b []byte) (n int, ttl int, src net.Addr, err error) - SetFlagTTL() error - SetReadDeadline(t time.Time) error - WriteTo(b []byte, dst net.Addr) (int, error) - SetTTL(ttl int) - SetMark(m uint) error - SetDoNotFragment() error -} - -type icmpConn struct { - c *icmp.PacketConn - ttl int -} - -func (c *icmpConn) Close() error { - return c.c.Close() -} - -func (c *icmpConn) SetTTL(ttl int) { - c.ttl = ttl -} - -func (c *icmpConn) SetReadDeadline(t time.Time) error { - return c.c.SetReadDeadline(t) -} - -func (c *icmpConn) WriteTo(b []byte, dst net.Addr) (int, error) { - if c.c.IPv6PacketConn() != nil { - if err := c.c.IPv6PacketConn().SetHopLimit(c.ttl); err != nil { - return 0, err - } - } - if c.c.IPv4PacketConn() != nil { - if err := c.c.IPv4PacketConn().SetTTL(c.ttl); err != nil { - return 0, err - } - } - - return c.c.WriteTo(b, dst) -} - -type icmpv4Conn struct { - icmpConn -} - -func (c *icmpv4Conn) SetFlagTTL() error { - err := c.c.IPv4PacketConn().SetControlMessage(ipv4.FlagTTL, true) - if runtime.GOOS == "windows" { - return nil - } - return err -} - -func (c *icmpv4Conn) ReadFrom(b []byte) (int, int, net.Addr, error) { - ttl := -1 - n, cm, src, err := c.c.IPv4PacketConn().ReadFrom(b) - if cm != nil { - ttl = cm.TTL - } - return n, ttl, src, err -} - -func (c icmpv4Conn) ICMPRequestType() icmp.Type { - return ipv4.ICMPTypeEcho -} - -type icmpV6Conn struct { - icmpConn -} - -func (c *icmpV6Conn) SetFlagTTL() error { - err := c.c.IPv6PacketConn().SetControlMessage(ipv6.FlagHopLimit, true) - if runtime.GOOS == "windows" { - return nil - } - return err -} - -func (c *icmpV6Conn) ReadFrom(b []byte) (int, int, net.Addr, error) { - ttl := -1 - n, cm, src, err := c.c.IPv6PacketConn().ReadFrom(b) - if cm != nil { - ttl = cm.HopLimit - } - return n, ttl, src, err -} - -func (c icmpV6Conn) ICMPRequestType() icmp.Type { - return ipv6.ICMPTypeEchoRequest -} diff --git a/vendor/github.com/prometheus-community/pro-bing/ping.go b/vendor/github.com/prometheus-community/pro-bing/ping.go deleted file mode 100644 index 2859bed725..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/ping.go +++ /dev/null @@ -1,913 +0,0 @@ -// Package probing is a simple but powerful ICMP echo (ping) library. -// -// Here is a very simple example that sends and receives three packets: -// -// pinger, err := probing.NewPinger("www.google.com") -// if err != nil { -// panic(err) -// } -// pinger.Count = 3 -// err = pinger.Run() // blocks until finished -// if err != nil { -// panic(err) -// } -// stats := pinger.Statistics() // get send/receive/rtt stats -// -// Here is an example that emulates the traditional UNIX ping command: -// -// pinger, err := probing.NewPinger("www.google.com") -// if err != nil { -// panic(err) -// } -// // Listen for Ctrl-C. -// c := make(chan os.Signal, 1) -// signal.Notify(c, os.Interrupt) -// go func() { -// for _ = range c { -// pinger.Stop() -// } -// }() -// pinger.OnRecv = func(pkt *probing.Packet) { -// fmt.Printf("%d bytes from %s: icmp_seq=%d time=%v\n", -// pkt.Nbytes, pkt.IPAddr, pkt.Seq, pkt.Rtt) -// } -// pinger.OnFinish = func(stats *probing.Statistics) { -// fmt.Printf("\n--- %s ping statistics ---\n", stats.Addr) -// fmt.Printf("%d packets transmitted, %d packets received, %v%% packet loss\n", -// stats.PacketsSent, stats.PacketsRecv, stats.PacketLoss) -// fmt.Printf("round-trip min/avg/max/stddev = %v/%v/%v/%v\n", -// stats.MinRtt, stats.AvgRtt, stats.MaxRtt, stats.StdDevRtt) -// } -// fmt.Printf("PING %s (%s):\n", pinger.Addr(), pinger.IPAddr()) -// err = pinger.Run() -// if err != nil { -// panic(err) -// } -// -// It sends ICMP Echo Request packet(s) and waits for an Echo Reply in response. -// If it receives a response, it calls the OnRecv callback. When it's finished, -// it calls the OnFinish callback. -// -// For a full ping example, see "cmd/ping/ping.go". -package probing - -import ( - "bytes" - "context" - "errors" - "fmt" - "log" - "math" - "math/rand" - "net" - "runtime" - "sync" - "sync/atomic" - "syscall" - "time" - - "github.com/google/uuid" - "golang.org/x/net/icmp" - "golang.org/x/net/ipv4" - "golang.org/x/net/ipv6" - "golang.org/x/sync/errgroup" -) - -const ( - timeSliceLength = 8 - trackerLength = len(uuid.UUID{}) - protocolICMP = 1 - protocolIPv6ICMP = 58 -) - -var ( - ipv4Proto = map[string]string{"icmp": "ip4:icmp", "udp": "udp4"} - ipv6Proto = map[string]string{"icmp": "ip6:ipv6-icmp", "udp": "udp6"} - - ErrMarkNotSupported = errors.New("setting SO_MARK socket option is not supported on this platform") - ErrDFNotSupported = errors.New("setting do-not-fragment bit is not supported on this platform") -) - -// New returns a new Pinger struct pointer. -func New(addr string) *Pinger { - r := rand.New(rand.NewSource(getSeed())) - firstUUID := uuid.New() - var firstSequence = map[uuid.UUID]map[int]struct{}{} - firstSequence[firstUUID] = make(map[int]struct{}) - return &Pinger{ - Count: -1, - Interval: time.Second, - RecordRtts: true, - Size: timeSliceLength + trackerLength, - Timeout: time.Duration(math.MaxInt64), - - addr: addr, - done: make(chan interface{}), - id: r.Intn(math.MaxUint16), - trackerUUIDs: []uuid.UUID{firstUUID}, - ipaddr: nil, - ipv4: false, - network: "ip", - protocol: "udp", - awaitingSequences: firstSequence, - TTL: 64, - logger: StdLogger{Logger: log.New(log.Writer(), log.Prefix(), log.Flags())}, - } -} - -// NewPinger returns a new Pinger and resolves the address. -func NewPinger(addr string) (*Pinger, error) { - p := New(addr) - return p, p.Resolve() -} - -// Pinger represents a packet sender/receiver. -type Pinger struct { - // Interval is the wait time between each packet send. Default is 1s. - Interval time.Duration - - // Timeout specifies a timeout before ping exits, regardless of how many - // packets have been received. - Timeout time.Duration - - // Count tells pinger to stop after sending (and receiving) Count echo - // packets. If this option is not specified, pinger will operate until - // interrupted. - Count int - - // Debug runs in debug mode - Debug bool - - // Number of packets sent - PacketsSent int - - // Number of packets received - PacketsRecv int - - // Number of duplicate packets received - PacketsRecvDuplicates int - - // Round trip time statistics - minRtt time.Duration - maxRtt time.Duration - avgRtt time.Duration - stdDevRtt time.Duration - stddevm2 time.Duration - statsMu sync.RWMutex - - // If true, keep a record of rtts of all received packets. - // Set to false to avoid memory bloat for long running pings. - RecordRtts bool - - // rtts is all of the Rtts - rtts []time.Duration - - // OnSetup is called when Pinger has finished setting up the listening socket - OnSetup func() - - // OnSend is called when Pinger sends a packet - OnSend func(*Packet) - - // OnRecv is called when Pinger receives and processes a packet - OnRecv func(*Packet) - - // OnFinish is called when Pinger exits - OnFinish func(*Statistics) - - // OnDuplicateRecv is called when a packet is received that has already been received. - OnDuplicateRecv func(*Packet) - - // OnSendError is called when an error occurs while Pinger attempts to send a packet - OnSendError func(*Packet, error) - - // OnRecvError is called when an error occurs while Pinger attempts to receive a packet - OnRecvError func(error) - - // Size of packet being sent - Size int - - // Tracker: Used to uniquely identify packets - Deprecated - Tracker uint64 - - // Source is the source IP address - Source string - - // Channel and mutex used to communicate when the Pinger should stop between goroutines. - done chan interface{} - lock sync.Mutex - - ipaddr *net.IPAddr - addr string - - // mark is a SO_MARK (fwmark) set on outgoing icmp packets - mark uint - - // df when true sets the do-not-fragment bit in the outer IP or IPv6 header - df bool - - // trackerUUIDs is the list of UUIDs being used for sending packets. - trackerUUIDs []uuid.UUID - - ipv4 bool - id int - sequence int - // awaitingSequences are in-flight sequence numbers we keep track of to help remove duplicate receipts - awaitingSequences map[uuid.UUID]map[int]struct{} - // network is one of "ip", "ip4", or "ip6". - network string - // protocol is "icmp" or "udp". - protocol string - - logger Logger - - TTL int -} - -type packet struct { - bytes []byte - nbytes int - ttl int -} - -// Packet represents a received and processed ICMP echo packet. -type Packet struct { - // Rtt is the round-trip time it took to ping. - Rtt time.Duration - - // IPAddr is the address of the host being pinged. - IPAddr *net.IPAddr - - // Addr is the string address of the host being pinged. - Addr string - - // NBytes is the number of bytes in the message. - Nbytes int - - // Seq is the ICMP sequence number. - Seq int - - // TTL is the Time To Live on the packet. - TTL int - - // ID is the ICMP identifier. - ID int -} - -// Statistics represent the stats of a currently running or finished -// pinger operation. -type Statistics struct { - // PacketsRecv is the number of packets received. - PacketsRecv int - - // PacketsSent is the number of packets sent. - PacketsSent int - - // PacketsRecvDuplicates is the number of duplicate responses there were to a sent packet. - PacketsRecvDuplicates int - - // PacketLoss is the percentage of packets lost. - PacketLoss float64 - - // IPAddr is the address of the host being pinged. - IPAddr *net.IPAddr - - // Addr is the string address of the host being pinged. - Addr string - - // Rtts is all of the round-trip times sent via this pinger. - Rtts []time.Duration - - // MinRtt is the minimum round-trip time sent via this pinger. - MinRtt time.Duration - - // MaxRtt is the maximum round-trip time sent via this pinger. - MaxRtt time.Duration - - // AvgRtt is the average round-trip time sent via this pinger. - AvgRtt time.Duration - - // StdDevRtt is the standard deviation of the round-trip times sent via - // this pinger. - StdDevRtt time.Duration -} - -func (p *Pinger) updateStatistics(pkt *Packet) { - p.statsMu.Lock() - defer p.statsMu.Unlock() - - p.PacketsRecv++ - if p.RecordRtts { - p.rtts = append(p.rtts, pkt.Rtt) - } - - if p.PacketsRecv == 1 || pkt.Rtt < p.minRtt { - p.minRtt = pkt.Rtt - } - - if pkt.Rtt > p.maxRtt { - p.maxRtt = pkt.Rtt - } - - pktCount := time.Duration(p.PacketsRecv) - // welford's online method for stddev - // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm - delta := pkt.Rtt - p.avgRtt - p.avgRtt += delta / pktCount - delta2 := pkt.Rtt - p.avgRtt - p.stddevm2 += delta * delta2 - - p.stdDevRtt = time.Duration(math.Sqrt(float64(p.stddevm2 / pktCount))) -} - -// SetIPAddr sets the ip address of the target host. -func (p *Pinger) SetIPAddr(ipaddr *net.IPAddr) { - p.ipv4 = isIPv4(ipaddr.IP) - - p.ipaddr = ipaddr - p.addr = ipaddr.String() -} - -// IPAddr returns the ip address of the target host. -func (p *Pinger) IPAddr() *net.IPAddr { - return p.ipaddr -} - -// Resolve does the DNS lookup for the Pinger address and sets IP protocol. -func (p *Pinger) Resolve() error { - if len(p.addr) == 0 { - return errors.New("addr cannot be empty") - } - ipaddr, err := net.ResolveIPAddr(p.network, p.addr) - if err != nil { - return err - } - - p.ipv4 = isIPv4(ipaddr.IP) - - p.ipaddr = ipaddr - - return nil -} - -// SetAddr resolves and sets the ip address of the target host, addr can be a -// DNS name like "www.google.com" or IP like "127.0.0.1". -func (p *Pinger) SetAddr(addr string) error { - oldAddr := p.addr - p.addr = addr - err := p.Resolve() - if err != nil { - p.addr = oldAddr - return err - } - return nil -} - -// Addr returns the string ip address of the target host. -func (p *Pinger) Addr() string { - return p.addr -} - -// SetNetwork allows configuration of DNS resolution. -// * "ip" will automatically select IPv4 or IPv6. -// * "ip4" will select IPv4. -// * "ip6" will select IPv6. -func (p *Pinger) SetNetwork(n string) { - switch n { - case "ip4": - p.network = "ip4" - case "ip6": - p.network = "ip6" - default: - p.network = "ip" - } -} - -// SetPrivileged sets the type of ping pinger will send. -// false means pinger will send an "unprivileged" UDP ping. -// true means pinger will send a "privileged" raw ICMP ping. -// NOTE: setting to true requires that it be run with super-user privileges. -func (p *Pinger) SetPrivileged(privileged bool) { - if privileged { - p.protocol = "icmp" - } else { - p.protocol = "udp" - } -} - -// Privileged returns whether pinger is running in privileged mode. -func (p *Pinger) Privileged() bool { - return p.protocol == "icmp" -} - -// SetLogger sets the logger to be used to log events from the pinger. -func (p *Pinger) SetLogger(logger Logger) { - p.logger = logger -} - -// SetID sets the ICMP identifier. -func (p *Pinger) SetID(id int) { - p.id = id -} - -// ID returns the ICMP identifier. -func (p *Pinger) ID() int { - return p.id -} - -// SetMark sets a mark intended to be set on outgoing ICMP packets. -func (p *Pinger) SetMark(m uint) { - p.mark = m -} - -// Mark returns the mark to be set on outgoing ICMP packets. -func (p *Pinger) Mark() uint { - return p.mark -} - -// SetDoNotFragment sets the do-not-fragment bit in the outer IP header to the desired value. -func (p *Pinger) SetDoNotFragment(df bool) { - p.df = df -} - -// Run runs the pinger. This is a blocking function that will exit when it's -// done. If Count or Interval are not specified, it will run continuously until -// it is interrupted. -func (p *Pinger) Run() error { - return p.RunWithContext(context.Background()) -} - -// RunWithContext runs the pinger with a context. This is a blocking function that will exit when it's -// done or if the context is canceled. If Count or Interval are not specified, it will run continuously until -// it is interrupted. -func (p *Pinger) RunWithContext(ctx context.Context) error { - var conn packetConn - var err error - if p.Size < timeSliceLength+trackerLength { - return fmt.Errorf("size %d is less than minimum required size %d", p.Size, timeSliceLength+trackerLength) - } - if p.ipaddr == nil { - err = p.Resolve() - } - if err != nil { - return err - } - if conn, err = p.listen(); err != nil { - return err - } - defer conn.Close() - - if p.mark != 0 { - if err := conn.SetMark(p.mark); err != nil { - return fmt.Errorf("error setting mark: %v", err) - } - } - - if p.df { - if err := conn.SetDoNotFragment(); err != nil { - return fmt.Errorf("error setting do-not-fragment: %v", err) - } - } - - conn.SetTTL(p.TTL) - return p.run(ctx, conn) -} - -func (p *Pinger) run(ctx context.Context, conn packetConn) error { - if err := conn.SetFlagTTL(); err != nil { - return err - } - defer p.finish() - - recv := make(chan *packet, 5) - defer close(recv) - - if p.OnSetup != nil { - p.OnSetup() - } - - g, ctx := errgroup.WithContext(ctx) - - g.Go(func() error { - select { - case <-ctx.Done(): - p.Stop() - case <-p.done: - } - return nil - }) - - g.Go(func() error { - defer p.Stop() - return p.recvICMP(conn, recv) - }) - - g.Go(func() error { - defer p.Stop() - return p.runLoop(conn, recv) - }) - - return g.Wait() -} - -func (p *Pinger) runLoop( - conn packetConn, - recvCh <-chan *packet, -) error { - logger := p.logger - if logger == nil { - logger = NoopLogger{} - } - - timeout := time.NewTicker(p.Timeout) - interval := time.NewTicker(p.Interval) - defer func() { - interval.Stop() - timeout.Stop() - }() - - if err := p.sendICMP(conn); err != nil { - return err - } - - for { - select { - case <-p.done: - return nil - - case <-timeout.C: - return nil - - case r := <-recvCh: - err := p.processPacket(r) - if err != nil { - // FIXME: this logs as FATAL but continues - logger.Fatalf("processing received packet: %s", err) - } - - case <-interval.C: - if p.Count > 0 && p.PacketsSent >= p.Count { - interval.Stop() - continue - } - err := p.sendICMP(conn) - if err != nil { - // FIXME: this logs as FATAL but continues - logger.Fatalf("sending packet: %s", err) - } - } - if p.Count > 0 && p.PacketsRecv >= p.Count { - return nil - } - } -} - -func (p *Pinger) Stop() { - p.lock.Lock() - defer p.lock.Unlock() - - open := true - select { - case _, open = <-p.done: - default: - } - - if open { - close(p.done) - } -} - -func (p *Pinger) finish() { - if p.OnFinish != nil { - p.OnFinish(p.Statistics()) - } -} - -// Statistics returns the statistics of the pinger. This can be run while the -// pinger is running or after it is finished. OnFinish calls this function to -// get it's finished statistics. -func (p *Pinger) Statistics() *Statistics { - p.statsMu.RLock() - defer p.statsMu.RUnlock() - sent := p.PacketsSent - loss := float64(sent-p.PacketsRecv) / float64(sent) * 100 - s := Statistics{ - PacketsSent: sent, - PacketsRecv: p.PacketsRecv, - PacketsRecvDuplicates: p.PacketsRecvDuplicates, - PacketLoss: loss, - Rtts: p.rtts, - Addr: p.addr, - IPAddr: p.ipaddr, - MaxRtt: p.maxRtt, - MinRtt: p.minRtt, - AvgRtt: p.avgRtt, - StdDevRtt: p.stdDevRtt, - } - return &s -} - -type expBackoff struct { - baseDelay time.Duration - maxExp int64 - c int64 -} - -func (b *expBackoff) Get() time.Duration { - if b.c < b.maxExp { - b.c++ - } - - return b.baseDelay * time.Duration(rand.Int63n(1< 0 { - t = append(t, bytes.Repeat([]byte{1}, remainSize)...) - } - - body := &icmp.Echo{ - ID: p.id, - Seq: p.sequence, - Data: t, - } - - msg := &icmp.Message{ - Type: conn.ICMPRequestType(), - Code: 0, - Body: body, - } - - msgBytes, err := msg.Marshal(nil) - if err != nil { - return err - } - - for { - if _, err := conn.WriteTo(msgBytes, dst); err != nil { - if p.OnSendError != nil { - outPkt := &Packet{ - Nbytes: len(msgBytes), - IPAddr: p.ipaddr, - Addr: p.addr, - Seq: p.sequence, - ID: p.id, - } - p.OnSendError(outPkt, err) - } - if neterr, ok := err.(*net.OpError); ok { - if neterr.Err == syscall.ENOBUFS { - continue - } - } - return err - } - if p.OnSend != nil { - outPkt := &Packet{ - Nbytes: len(msgBytes), - IPAddr: p.ipaddr, - Addr: p.addr, - Seq: p.sequence, - ID: p.id, - } - p.OnSend(outPkt) - } - // mark this sequence as in-flight - p.awaitingSequences[currentUUID][p.sequence] = struct{}{} - p.PacketsSent++ - p.sequence++ - if p.sequence > 65535 { - newUUID := uuid.New() - p.trackerUUIDs = append(p.trackerUUIDs, newUUID) - p.awaitingSequences[newUUID] = make(map[int]struct{}) - p.sequence = 0 - } - break - } - - return nil -} - -func (p *Pinger) listen() (packetConn, error) { - var ( - conn packetConn - err error - ) - - if p.ipv4 { - var c icmpv4Conn - c.c, err = icmp.ListenPacket(ipv4Proto[p.protocol], p.Source) - conn = &c - } else { - var c icmpV6Conn - c.c, err = icmp.ListenPacket(ipv6Proto[p.protocol], p.Source) - conn = &c - } - - if err != nil { - p.Stop() - return nil, err - } - return conn, nil -} - -func bytesToTime(b []byte) time.Time { - var nsec int64 - for i := uint8(0); i < 8; i++ { - nsec += int64(b[i]) << ((7 - i) * 8) - } - return time.Unix(nsec/1000000000, nsec%1000000000) -} - -func isIPv4(ip net.IP) bool { - return len(ip.To4()) == net.IPv4len -} - -func timeToBytes(t time.Time) []byte { - nsec := t.UnixNano() - b := make([]byte, 8) - for i := uint8(0); i < 8; i++ { - b[i] = byte((nsec >> ((7 - i) * 8)) & 0xff) - } - return b -} - -var seed = time.Now().UnixNano() - -// getSeed returns a goroutine-safe unique seed -func getSeed() int64 { - return atomic.AddInt64(&seed, 1) -} - -// stripIPv4Header strips IPv4 header bytes if present -// https://github.com/golang/go/commit/3b5be4522a21df8ce52a06a0c4ba005c89a8590f -func stripIPv4Header(n int, b []byte) int { - if len(b) < 20 { - return n - } - l := int(b[0]&0x0f) << 2 - if 20 > l || l > len(b) { - return n - } - if b[0]>>4 != 4 { - return n - } - copy(b, b[l:]) - return n - l -} diff --git a/vendor/github.com/prometheus-community/pro-bing/utils_linux.go b/vendor/github.com/prometheus-community/pro-bing/utils_linux.go deleted file mode 100644 index 63b97a090e..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/utils_linux.go +++ /dev/null @@ -1,122 +0,0 @@ -//go:build linux -// +build linux - -package probing - -import ( - "errors" - "os" - "reflect" - "syscall" - - "golang.org/x/net/icmp" -) - -// Returns the length of an ICMP message. -func (p *Pinger) getMessageLength() int { - return p.Size + 8 -} - -// Attempts to match the ID of an ICMP packet. -func (p *Pinger) matchID(ID int) bool { - // On Linux we can only match ID if we are privileged. - if p.protocol == "icmp" { - return ID == p.id - } - return true -} - -// SetMark sets the SO_MARK socket option on outgoing ICMP packets. -// Setting this option requires CAP_NET_ADMIN. -func (c *icmpConn) SetMark(mark uint) error { - fd, err := getFD(c.c) - if err != nil { - return err - } - return os.NewSyscallError( - "setsockopt", - syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(mark)), - ) -} - -// SetMark sets the SO_MARK socket option on outgoing ICMP packets. -// Setting this option requires CAP_NET_ADMIN. -func (c *icmpv4Conn) SetMark(mark uint) error { - fd, err := getFD(c.icmpConn.c) - if err != nil { - return err - } - return os.NewSyscallError( - "setsockopt", - syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(mark)), - ) -} - -// SetMark sets the SO_MARK socket option on outgoing ICMP packets. -// Setting this option requires CAP_NET_ADMIN. -func (c *icmpV6Conn) SetMark(mark uint) error { - fd, err := getFD(c.icmpConn.c) - if err != nil { - return err - } - return os.NewSyscallError( - "setsockopt", - syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(mark)), - ) -} - -// SetDoNotFragment sets the do-not-fragment bit in the IP header of outgoing ICMP packets. -func (c *icmpConn) SetDoNotFragment() error { - fd, err := getFD(c.c) - if err != nil { - return err - } - return os.NewSyscallError( - "setsockopt", - syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_DO), - ) -} - -// SetDoNotFragment sets the do-not-fragment bit in the IP header of outgoing ICMP packets. -func (c *icmpv4Conn) SetDoNotFragment() error { - fd, err := getFD(c.icmpConn.c) - if err != nil { - return err - } - return os.NewSyscallError( - "setsockopt", - syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_DO), - ) -} - -// SetDoNotFragment sets the do-not-fragment bit in the IPv6 header of outgoing ICMPv6 packets. -func (c *icmpV6Conn) SetDoNotFragment() error { - fd, err := getFD(c.icmpConn.c) - if err != nil { - return err - } - return os.NewSyscallError( - "setsockopt", - syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_MTU_DISCOVER, syscall.IP_PMTUDISC_DO), - ) -} - -// getFD gets the system file descriptor for an icmp.PacketConn -func getFD(c *icmp.PacketConn) (uintptr, error) { - v := reflect.ValueOf(c).Elem().FieldByName("c").Elem() - if v.Elem().Kind() != reflect.Struct { - return 0, errors.New("invalid type") - } - - fd := v.Elem().FieldByName("conn").FieldByName("fd") - if fd.Elem().Kind() != reflect.Struct { - return 0, errors.New("invalid type") - } - - pfd := fd.Elem().FieldByName("pfd") - if pfd.Kind() != reflect.Struct { - return 0, errors.New("invalid type") - } - - return uintptr(pfd.FieldByName("Sysfd").Int()), nil -} diff --git a/vendor/github.com/prometheus-community/pro-bing/utils_other.go b/vendor/github.com/prometheus-community/pro-bing/utils_other.go deleted file mode 100644 index 7c52de058b..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/utils_other.go +++ /dev/null @@ -1,47 +0,0 @@ -//go:build !linux && !windows -// +build !linux,!windows - -package probing - -// Returns the length of an ICMP message. -func (p *Pinger) getMessageLength() int { - return p.Size + 8 -} - -// Attempts to match the ID of an ICMP packet. -func (p *Pinger) matchID(ID int) bool { - return ID == p.id -} - -// SetMark sets the SO_MARK socket option on outgoing ICMP packets. -// Setting this option requires CAP_NET_ADMIN. -func (c *icmpConn) SetMark(mark uint) error { - return ErrMarkNotSupported -} - -// SetMark sets the SO_MARK socket option on outgoing ICMP packets. -// Setting this option requires CAP_NET_ADMIN. -func (c *icmpv4Conn) SetMark(mark uint) error { - return ErrMarkNotSupported -} - -// SetMark sets the SO_MARK socket option on outgoing ICMP packets. -// Setting this option requires CAP_NET_ADMIN. -func (c *icmpV6Conn) SetMark(mark uint) error { - return ErrMarkNotSupported -} - -// SetDoNotFragment sets the do-not-fragment bit in the IP header of outgoing ICMP packets. -func (c *icmpConn) SetDoNotFragment() error { - return ErrDFNotSupported -} - -// SetDoNotFragment sets the do-not-fragment bit in the IP header of outgoing ICMP packets. -func (c *icmpv4Conn) SetDoNotFragment() error { - return ErrDFNotSupported -} - -// SetDoNotFragment sets the do-not-fragment bit in the IPv6 header of outgoing ICMPv6 packets. -func (c *icmpV6Conn) SetDoNotFragment() error { - return ErrDFNotSupported -} diff --git a/vendor/github.com/prometheus-community/pro-bing/utils_windows.go b/vendor/github.com/prometheus-community/pro-bing/utils_windows.go deleted file mode 100644 index ed2eae4a47..0000000000 --- a/vendor/github.com/prometheus-community/pro-bing/utils_windows.go +++ /dev/null @@ -1,58 +0,0 @@ -//go:build windows -// +build windows - -package probing - -import ( - "golang.org/x/net/ipv4" - "golang.org/x/net/ipv6" -) - -// Returns the length of an ICMP message, plus the IP packet header. -func (p *Pinger) getMessageLength() int { - if p.ipv4 { - return p.Size + 8 + ipv4.HeaderLen - } - return p.Size + 8 + ipv6.HeaderLen -} - -// Attempts to match the ID of an ICMP packet. -func (p *Pinger) matchID(ID int) bool { - if ID != p.id { - return false - } - return true -} - -// SetMark sets the SO_MARK socket option on outgoing ICMP packets. -// Setting this option requires CAP_NET_ADMIN. -func (c *icmpConn) SetMark(mark uint) error { - return ErrMarkNotSupported -} - -// SetMark sets the SO_MARK socket option on outgoing ICMP packets. -// Setting this option requires CAP_NET_ADMIN. -func (c *icmpv4Conn) SetMark(mark uint) error { - return ErrMarkNotSupported -} - -// SetMark sets the SO_MARK socket option on outgoing ICMP packets. -// Setting this option requires CAP_NET_ADMIN. -func (c *icmpV6Conn) SetMark(mark uint) error { - return ErrMarkNotSupported -} - -// SetDoNotFragment sets the do-not-fragment bit in the IP header of outgoing ICMP packets. -func (c *icmpConn) SetDoNotFragment() error { - return ErrDFNotSupported -} - -// SetDoNotFragment sets the do-not-fragment bit in the IP header of outgoing ICMP packets. -func (c *icmpv4Conn) SetDoNotFragment() error { - return ErrDFNotSupported -} - -// SetDoNotFragment sets the do-not-fragment bit in the IPv6 header of outgoing ICMPv6 packets. -func (c *icmpV6Conn) SetDoNotFragment() error { - return ErrDFNotSupported -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 7130779390..dca2c865bc 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -486,9 +486,6 @@ github.com/power-devops/perfstat # github.com/projectcalico/api v0.0.0-20220722155641-439a754a988b ## explicit; go 1.16 github.com/projectcalico/api/pkg/lib/numorstring -# github.com/prometheus-community/pro-bing v0.2.0 -## explicit; go 1.19 -github.com/prometheus-community/pro-bing # github.com/prometheus/client_golang v1.17.0 ## explicit; go 1.19 github.com/prometheus/client_golang/prometheus