Update dependencies
This commit is contained in:
16
vendor/github.com/prometheus-community/pro-bing/.editorconfig
generated
vendored
Normal file
16
vendor/github.com/prometheus-community/pro-bing/.editorconfig
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# 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
|
||||
2
vendor/github.com/prometheus-community/pro-bing/.gitignore
generated
vendored
Normal file
2
vendor/github.com/prometheus-community/pro-bing/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/ping
|
||||
/dist
|
||||
19
vendor/github.com/prometheus-community/pro-bing/.golangci.yml
generated
vendored
Normal file
19
vendor/github.com/prometheus-community/pro-bing/.golangci.yml
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
linters:
|
||||
enable:
|
||||
- misspell
|
||||
- revive
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
- path: _test.go
|
||||
linters:
|
||||
- errcheck
|
||||
|
||||
linters-settings:
|
||||
revive:
|
||||
rules:
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-parameter
|
||||
- name: unused-parameter
|
||||
severity: warning
|
||||
disabled: true
|
||||
46
vendor/github.com/prometheus-community/pro-bing/.goreleaser.yaml
generated
vendored
Normal file
46
vendor/github.com/prometheus-community/pro-bing/.goreleaser.yaml
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
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 <go-ping@example.com>'
|
||||
# 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:'
|
||||
3
vendor/github.com/prometheus-community/pro-bing/CODE_OF_CONDUCT.md
generated
vendored
Normal file
3
vendor/github.com/prometheus-community/pro-bing/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Prometheus Community Code of Conduct
|
||||
|
||||
Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md).
|
||||
44
vendor/github.com/prometheus-community/pro-bing/CONTRIBUTING.md
generated
vendored
Normal file
44
vendor/github.com/prometheus-community/pro-bing/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# 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 <BRANCH_NAME>
|
||||
# edit files
|
||||
$ make style vet test
|
||||
$ git add <CHANGED_FILES>
|
||||
$ git commit -s
|
||||
$ git push <FORK> <BRANCH_NAME>
|
||||
```
|
||||
|
||||
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.
|
||||
22
vendor/github.com/prometheus-community/pro-bing/LICENSE
generated
vendored
Normal file
22
vendor/github.com/prometheus-community/pro-bing/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
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.
|
||||
4
vendor/github.com/prometheus-community/pro-bing/MAINTAINERS.md
generated
vendored
Normal file
4
vendor/github.com/prometheus-community/pro-bing/MAINTAINERS.md
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# Maintainers
|
||||
|
||||
* Ben Kochie <superq@gmail.com> @SuperQ
|
||||
* Matthias Loibl <mail@matthiasloibl.com> @metalmatze
|
||||
32
vendor/github.com/prometheus-community/pro-bing/Makefile
generated
vendored
Normal file
32
vendor/github.com/prometheus-community/pro-bing/Makefile
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
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)
|
||||
191
vendor/github.com/prometheus-community/pro-bing/README.md
generated
vendored
Normal file
191
vendor/github.com/prometheus-community/pro-bing/README.md
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
# pro-bing
|
||||
[](https://pkg.go.dev/github.com/prometheus-community/pro-bing)
|
||||
[](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 *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
|
||||
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.
|
||||
|
||||
## HTTP
|
||||
|
||||
This library also provides support for HTTP probing.
|
||||
Here is a trivial example:
|
||||
|
||||
```go
|
||||
httpCaller := probing.NewHttpCaller("https://www.google.com",
|
||||
probing.WithHTTPCallerCallFrequency(time.Second),
|
||||
probing.WithHTTPCallerOnResp(func(suite *probing.TraceSuite, info *probing.HTTPCallInfo) {
|
||||
fmt.Printf("got resp, status code: %d, latency: %s\n",
|
||||
info.StatusCode,
|
||||
suite.GetGeneralEnd().Sub(suite.GetGeneralStart()),
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
// Listen for Ctrl-C.
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
go func() {
|
||||
<-c
|
||||
httpCaller.Stop()
|
||||
}()
|
||||
httpCaller.Run()
|
||||
```
|
||||
|
||||
Library provides a rich list of options available for a probing. You can check the full list of available
|
||||
options in a generated doc.
|
||||
|
||||
### Callbacks
|
||||
|
||||
HTTPCaller uses `net/http/httptrace` pkg to provide an API to track specific request event, e.g. tls handshake start.
|
||||
It is highly recommended to check the httptrace library [doc](https://pkg.go.dev/net/http/httptrace) to understand
|
||||
the purpose of provided callbacks. Nevertheless, httptrace callbacks are concurrent-unsafe, our implementation provides
|
||||
a concurrent-safe API. In addition to that, each callback contains a TraceSuite object which provides an Extra field
|
||||
which you can use to propagate your data across them and a number of timer fields, which are set prior to the execution of a
|
||||
corresponding callback.
|
||||
|
||||
### Target RPS & performance
|
||||
|
||||
Library provides two options, allowing to manipulate your call load: `callFrequency` & `maxConcurrentCalls`.
|
||||
In case you set `callFrequency` to a value X, but it can't be achieved during the execution - you will need to
|
||||
try increasing a number of `maxConcurrentCalls`. Moreover, your callbacks might directly influence an execution
|
||||
performance.
|
||||
|
||||
For a full documentation, please refer to the generated [doc](https://pkg.go.dev/github.com/prometheus-community/pro-bing).
|
||||
|
||||
## 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)
|
||||
6
vendor/github.com/prometheus-community/pro-bing/SECURITY.md
generated
vendored
Normal file
6
vendor/github.com/prometheus-community/pro-bing/SECURITY.md
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# Reporting a security issue
|
||||
|
||||
The Prometheus security policy, including how to report vulnerabilities, can be
|
||||
found here:
|
||||
|
||||
<https://prometheus.io/docs/operating/security/>
|
||||
619
vendor/github.com/prometheus-community/pro-bing/http.go
generated
vendored
Normal file
619
vendor/github.com/prometheus-community/pro-bing/http.go
generated
vendored
Normal file
@@ -0,0 +1,619 @@
|
||||
package probing
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptrace"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultHTTPCallFrequency = time.Second
|
||||
defaultHTTPMaxConcurrentCalls = 1
|
||||
defaultHTTPMethod = http.MethodGet
|
||||
defaultTimeout = time.Second * 10
|
||||
)
|
||||
|
||||
type httpCallerOptions struct {
|
||||
client *http.Client
|
||||
|
||||
callFrequency time.Duration
|
||||
maxConcurrentCalls int
|
||||
|
||||
host string
|
||||
headers http.Header
|
||||
method string
|
||||
body []byte
|
||||
timeout time.Duration
|
||||
|
||||
isValidResponse func(response *http.Response, body []byte) bool
|
||||
|
||||
onDNSStart func(suite *TraceSuite, info httptrace.DNSStartInfo)
|
||||
onDNSDone func(suite *TraceSuite, info httptrace.DNSDoneInfo)
|
||||
onConnStart func(suite *TraceSuite, network, addr string)
|
||||
onConnDone func(suite *TraceSuite, network, addr string, err error)
|
||||
onTLSStart func(suite *TraceSuite)
|
||||
onTLSDone func(suite *TraceSuite, state tls.ConnectionState, err error)
|
||||
onWroteHeaders func(suite *TraceSuite)
|
||||
onFirstByteReceived func(suite *TraceSuite)
|
||||
onReq func(suite *TraceSuite)
|
||||
onResp func(suite *TraceSuite, info *HTTPCallInfo)
|
||||
|
||||
logger Logger
|
||||
}
|
||||
|
||||
// HTTPCallerOption represents a function type for a functional parameter passed to a NewHttpCaller constructor.
|
||||
type HTTPCallerOption func(options *httpCallerOptions)
|
||||
|
||||
// WithHTTPCallerClient is a functional parameter for a HTTPCaller which specifies a http.Client.
|
||||
func WithHTTPCallerClient(client *http.Client) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.client = client
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerCallFrequency is a functional parameter for a HTTPCaller which specifies a call frequency.
|
||||
// If this option is not provided the default one will be used. You can check default value in const
|
||||
// defaultHTTPCallFrequency.
|
||||
func WithHTTPCallerCallFrequency(frequency time.Duration) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.callFrequency = frequency
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerMaxConcurrentCalls is a functional parameter for a HTTPCaller which specifies a number of
|
||||
// maximum concurrent calls. If this option is not provided the default one will be used. You can check default value in const
|
||||
// defaultHTTPMaxConcurrentCalls.
|
||||
func WithHTTPCallerMaxConcurrentCalls(max int) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.maxConcurrentCalls = max
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerHeaders is a functional parameter for a HTTPCaller which specifies headers that should be
|
||||
// set in request.
|
||||
// To override a Host header use a WithHTTPCallerHost method.
|
||||
func WithHTTPCallerHeaders(headers http.Header) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.headers = headers
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerMethod is a functional parameter for a HTTPCaller which specifies a method that should be
|
||||
// set in request. If this option is not provided the default one will be used. You can check default value in const
|
||||
// defaultHTTPMethod.
|
||||
func WithHTTPCallerMethod(method string) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.method = method
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerHost is a functional parameter for a HTTPCaller which allowed to override a host header.
|
||||
func WithHTTPCallerHost(host string) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.host = host
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerBody is a functional parameter for a HTTPCaller which specifies a body that should be set
|
||||
// in request.
|
||||
func WithHTTPCallerBody(body []byte) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.body = body
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerTimeout is a functional parameter for a HTTPCaller which specifies request timeout.
|
||||
// If this option is not provided the default one will be used. You can check default value in const defaultTimeout.
|
||||
func WithHTTPCallerTimeout(timeout time.Duration) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.timeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerIsValidResponse is a functional parameter for a HTTPCaller which specifies a function that
|
||||
// will be used to assess whether a response is valid. If not specified, all responses will be treated as valid.
|
||||
// You can read more explanation about this parameter in HTTPCaller annotation.
|
||||
func WithHTTPCallerIsValidResponse(isValid func(response *http.Response, body []byte) bool) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.isValidResponse = isValid
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerOnDNSStart is a functional parameter for a HTTPCaller which specifies a callback that will be
|
||||
// called when dns resolving starts. You can read more explanation about this parameter in HTTPCaller annotation.
|
||||
func WithHTTPCallerOnDNSStart(onDNSStart func(suite *TraceSuite, info httptrace.DNSStartInfo)) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.onDNSStart = onDNSStart
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerOnDNSDone is a functional parameter for a HTTPCaller which specifies a callback that will be
|
||||
// called when dns resolving ended. You can read more explanation about this parameter in HTTPCaller annotation.
|
||||
func WithHTTPCallerOnDNSDone(onDNSDone func(suite *TraceSuite, info httptrace.DNSDoneInfo)) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.onDNSDone = onDNSDone
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerOnConnStart is a functional parameter for a HTTPCaller which specifies a callback that will be
|
||||
// called when connection establishment started. You can read more explanation about this parameter in HTTPCaller
|
||||
// annotation.
|
||||
func WithHTTPCallerOnConnStart(onConnStart func(suite *TraceSuite, network, addr string)) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.onConnStart = onConnStart
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerOnConnDone is a functional parameter for a HTTPCaller which specifies a callback that will be
|
||||
// called when connection establishment finished. You can read more explanation about this parameter in HTTPCaller
|
||||
// annotation.
|
||||
func WithHTTPCallerOnConnDone(conConnDone func(suite *TraceSuite, network, addr string, err error)) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.onConnDone = conConnDone
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerOnTLSStart is a functional parameter for a HTTPCaller which specifies a callback that will be
|
||||
// called when tls handshake started. You can read more explanation about this parameter in HTTPCaller annotation.
|
||||
func WithHTTPCallerOnTLSStart(onTLSStart func(suite *TraceSuite)) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.onTLSStart = onTLSStart
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerOnTLSDone is a functional parameter for a HTTPCaller which specifies a callback that will be
|
||||
// called when tls handshake ended. You can read more explanation about this parameter in HTTPCaller annotation.
|
||||
func WithHTTPCallerOnTLSDone(onTLSDone func(suite *TraceSuite, state tls.ConnectionState, err error)) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.onTLSDone = onTLSDone
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerOnWroteRequest is a functional parameter for a HTTPCaller which specifies a callback that will be
|
||||
// called when request has been written. You can read more explanation about this parameter in HTTPCaller annotation.
|
||||
func WithHTTPCallerOnWroteRequest(onWroteRequest func(suite *TraceSuite)) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.onWroteHeaders = onWroteRequest
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerOnFirstByteReceived is a functional parameter for a HTTPCaller which specifies a callback that will be
|
||||
// called when first response byte has been received. You can read more explanation about this parameter in HTTPCaller
|
||||
// annotation.
|
||||
func WithHTTPCallerOnFirstByteReceived(onGotFirstByte func(suite *TraceSuite)) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.onFirstByteReceived = onGotFirstByte
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerOnReq is a functional parameter for a HTTPCaller which specifies a callback that will be
|
||||
// called before the start of the http call execution. You can read more explanation about this parameter in HTTPCaller
|
||||
// annotation.
|
||||
func WithHTTPCallerOnReq(onReq func(suite *TraceSuite)) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.onReq = onReq
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerOnResp is a functional parameter for a HTTPCaller which specifies a callback that will be
|
||||
// called when response is received. You can read more explanation about this parameter in HTTPCaller annotation.
|
||||
func WithHTTPCallerOnResp(onResp func(suite *TraceSuite, info *HTTPCallInfo)) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.onResp = onResp
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPCallerLogger is a functional parameter for a HTTPCaller which specifies a logger.
|
||||
// If not specified, logs will be omitted.
|
||||
func WithHTTPCallerLogger(logger Logger) HTTPCallerOption {
|
||||
return func(options *httpCallerOptions) {
|
||||
options.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
// NewHttpCaller returns a new HTTPCaller. URL parameter is the only required one, other options might be specified via
|
||||
// functional parameters, otherwise default values will be used where applicable.
|
||||
func NewHttpCaller(url string, options ...HTTPCallerOption) *HTTPCaller {
|
||||
opts := httpCallerOptions{
|
||||
callFrequency: defaultHTTPCallFrequency,
|
||||
maxConcurrentCalls: defaultHTTPMaxConcurrentCalls,
|
||||
method: defaultHTTPMethod,
|
||||
timeout: defaultTimeout,
|
||||
client: &http.Client{},
|
||||
}
|
||||
for _, opt := range options {
|
||||
opt(&opts)
|
||||
}
|
||||
|
||||
return &HTTPCaller{
|
||||
client: opts.client,
|
||||
|
||||
callFrequency: opts.callFrequency,
|
||||
maxConcurrentCalls: opts.maxConcurrentCalls,
|
||||
|
||||
url: url,
|
||||
host: opts.host,
|
||||
headers: opts.headers,
|
||||
method: opts.method,
|
||||
body: opts.body,
|
||||
timeout: opts.timeout,
|
||||
|
||||
isValidResponse: opts.isValidResponse,
|
||||
|
||||
workChan: make(chan struct{}, opts.maxConcurrentCalls),
|
||||
doneChan: make(chan struct{}),
|
||||
|
||||
onDNSStart: opts.onDNSStart,
|
||||
onDNSDone: opts.onDNSDone,
|
||||
onConnStart: opts.onConnStart,
|
||||
onConnDone: opts.onConnDone,
|
||||
onTLSStart: opts.onTLSStart,
|
||||
onTLSDone: opts.onTLSDone,
|
||||
onWroteHeaders: opts.onWroteHeaders,
|
||||
onFirstByteReceived: opts.onFirstByteReceived,
|
||||
onReq: opts.onReq,
|
||||
onResp: opts.onResp,
|
||||
|
||||
logger: opts.logger,
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPCaller represents a prober performing http calls and collecting relevant statistics.
|
||||
type HTTPCaller struct {
|
||||
client *http.Client
|
||||
|
||||
// callFrequency is a parameter which specifies how often to send a new request. You might need to increase
|
||||
// maxConcurrentCalls value to achieve required value.
|
||||
callFrequency time.Duration
|
||||
|
||||
// maxConcurrentCalls is a maximum number of calls that might be performed concurrently. In other words,
|
||||
// a number of "workers" that will try to perform probing concurrently.
|
||||
// Default number is specified in defaultHTTPMaxConcurrentCalls
|
||||
maxConcurrentCalls int
|
||||
|
||||
// url is an url which will be used in all probe requests, mandatory in constructor.
|
||||
url string
|
||||
|
||||
// host allows to override a Host header
|
||||
host string
|
||||
|
||||
// headers are headers that which will be used in all probe requests, default are none.
|
||||
headers http.Header
|
||||
|
||||
// method is a http request method which will be used in all probe requests,
|
||||
// default is specified in defaultHTTPMethod
|
||||
method string
|
||||
|
||||
// body is a http request body which will be used in all probe requests, default is none.
|
||||
body []byte
|
||||
|
||||
// timeout is a http call timeout, default is specified in defaultTimeout.
|
||||
timeout time.Duration
|
||||
|
||||
// isValidResponse is a function that will be used to validate whether a response is valid up to clients choice.
|
||||
// You can think of it as a verification that response contains data that you expected. This information will be
|
||||
// passed back in HTTPCallInfo during an onResp callback and HTTPStatistics during an onFinish callback
|
||||
// or a Statistics call.
|
||||
isValidResponse func(response *http.Response, body []byte) bool
|
||||
|
||||
workChan chan struct{}
|
||||
doneChan chan struct{}
|
||||
doneWg sync.WaitGroup
|
||||
|
||||
// All callbacks except onReq and onResp are based on a httptrace callbacks, meaning they are called at the time
|
||||
// and contain signature same as you would expect in httptrace library. In addition to that each callback has a
|
||||
// TraceSuite as a first argument, which will help you to propagate data between these callbacks. You can read more
|
||||
// about it in TraceSuite annotation.
|
||||
|
||||
// onDNSStart is a callback which is called when a dns lookup starts. It's based on a httptrace.DNSStart callback.
|
||||
onDNSStart func(suite *TraceSuite, info httptrace.DNSStartInfo)
|
||||
// onDNSDone is a callback which is called when a dns lookup ends. It's based on a httptrace.DNSDone callback.
|
||||
onDNSDone func(suite *TraceSuite, info httptrace.DNSDoneInfo)
|
||||
// onConnStart is a callback which is called when a connection dial starts. It's based on a httptrace.ConnectStart
|
||||
// callback.
|
||||
onConnStart func(suite *TraceSuite, network, addr string)
|
||||
// onConnDone is a callback which is called when a connection dial ends. It's based on a httptrace.ConnectDone
|
||||
// callback.
|
||||
onConnDone func(suite *TraceSuite, network, addr string, err error)
|
||||
// onTLSStart is a callback which is called when a tls handshake starts. It's based on a httptrace.TLSHandshakeStart
|
||||
// callback.
|
||||
onTLSStart func(suite *TraceSuite)
|
||||
// onTLSDone is a callback which is called when a tls handshake ends. It's based on a httptrace.TLSHandshakeDone
|
||||
// callback.
|
||||
onTLSDone func(suite *TraceSuite, state tls.ConnectionState, err error)
|
||||
// onWroteHeaders is a callback which is called when request headers where written. It's based on a
|
||||
// httptrace.WroteHeaders callback.
|
||||
onWroteHeaders func(suite *TraceSuite)
|
||||
// onFirstByteReceived is a callback which is called when first response bytes were received. It's based on a
|
||||
// httptrace.GotFirstResponseByte callback.
|
||||
onFirstByteReceived func(suite *TraceSuite)
|
||||
|
||||
// onReq is a custom callback which is called before http client starts request execution.
|
||||
onReq func(suite *TraceSuite)
|
||||
// onResp is a custom callback which is called when a response is received.
|
||||
onResp func(suite *TraceSuite, info *HTTPCallInfo)
|
||||
|
||||
// logger is a logger implementation, default is none.
|
||||
logger Logger
|
||||
}
|
||||
|
||||
// Stop gracefully stops the execution of a HTTPCaller.
|
||||
func (c *HTTPCaller) Stop() {
|
||||
close(c.doneChan)
|
||||
c.doneWg.Wait()
|
||||
}
|
||||
|
||||
// Run starts execution of a probing.
|
||||
func (c *HTTPCaller) Run() {
|
||||
c.run(context.Background())
|
||||
}
|
||||
|
||||
// RunWithContext starts execution of a probing and allows providing a context.
|
||||
func (c *HTTPCaller) RunWithContext(ctx context.Context) {
|
||||
c.run(ctx)
|
||||
}
|
||||
|
||||
func (c *HTTPCaller) run(ctx context.Context) {
|
||||
c.runWorkScheduler(ctx)
|
||||
c.runCallers(ctx)
|
||||
c.doneWg.Wait()
|
||||
}
|
||||
|
||||
func (c *HTTPCaller) runWorkScheduler(ctx context.Context) {
|
||||
c.doneWg.Add(1)
|
||||
go func() {
|
||||
defer c.doneWg.Done()
|
||||
|
||||
ticker := time.NewTicker(c.callFrequency)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
c.workChan <- struct{}{}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-c.doneChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (c *HTTPCaller) runCallers(ctx context.Context) {
|
||||
for i := 0; i < c.maxConcurrentCalls; i++ {
|
||||
c.doneWg.Add(1)
|
||||
go func() {
|
||||
defer c.doneWg.Done()
|
||||
for {
|
||||
logger := c.logger
|
||||
if logger == nil {
|
||||
logger = NoopLogger{}
|
||||
}
|
||||
select {
|
||||
case <-c.workChan:
|
||||
if err := c.makeCall(ctx); err != nil {
|
||||
logger.Errorf("failed making a call: %v", err)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-c.doneChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// TraceSuite is a struct that is passed to each callback. It contains a bunch of time helpers, that you can use with
|
||||
// a corresponding getter. These timers are set before making a corresponding callback, meaning that when an onDNSStart
|
||||
// callback will be called - TraceSuite will already have filled dnsStart field. In addition to that, it contains
|
||||
// an Extra field of type any which you can use in any custom way you might need. Before each callback call, mutex
|
||||
// is used, meaning all operations inside your callback are concurrent-safe.
|
||||
// Keep in mind, that if your http client set up to follow redirects - timers will be overwritten.
|
||||
type TraceSuite struct {
|
||||
mu sync.Mutex
|
||||
|
||||
generalStart time.Time
|
||||
generalEnd time.Time
|
||||
dnsStart time.Time
|
||||
dnsEnd time.Time
|
||||
connStart time.Time
|
||||
connEnd time.Time
|
||||
tlsStart time.Time
|
||||
tlsEnd time.Time
|
||||
wroteHeaders time.Time
|
||||
firstByteReceived time.Time
|
||||
|
||||
Extra any
|
||||
}
|
||||
|
||||
// GetGeneralStart returns a general http request execution start time.
|
||||
func (s *TraceSuite) GetGeneralStart() time.Time {
|
||||
return s.generalStart
|
||||
}
|
||||
|
||||
// GetGeneralEnd returns a general http response time.
|
||||
func (s *TraceSuite) GetGeneralEnd() time.Time {
|
||||
return s.generalEnd
|
||||
}
|
||||
|
||||
// GetDNSStart returns a time of a dns lookup start.
|
||||
func (s *TraceSuite) GetDNSStart() time.Time {
|
||||
return s.dnsStart
|
||||
}
|
||||
|
||||
// GetDNSEnd returns a time of a dns lookup send.
|
||||
func (s *TraceSuite) GetDNSEnd() time.Time {
|
||||
return s.dnsEnd
|
||||
}
|
||||
|
||||
// GetConnStart returns a time of a connection dial start.
|
||||
func (s *TraceSuite) GetConnStart() time.Time {
|
||||
return s.connStart
|
||||
}
|
||||
|
||||
// GetConnEnd returns a time of a connection dial end.
|
||||
func (s *TraceSuite) GetConnEnd() time.Time {
|
||||
return s.connEnd
|
||||
}
|
||||
|
||||
// GetTLSStart returns a time of a tls handshake start.
|
||||
func (s *TraceSuite) GetTLSStart() time.Time {
|
||||
return s.tlsStart
|
||||
}
|
||||
|
||||
// GetTLSEnd returns a time of a tls handshake end.
|
||||
func (s *TraceSuite) GetTLSEnd() time.Time {
|
||||
return s.tlsEnd
|
||||
}
|
||||
|
||||
// GetWroteHeaders returns a time when request headers were written.
|
||||
func (s *TraceSuite) GetWroteHeaders() time.Time {
|
||||
return s.wroteHeaders
|
||||
}
|
||||
|
||||
// GetFirstByteReceived returns a time when first response bytes were received.
|
||||
func (s *TraceSuite) GetFirstByteReceived() time.Time {
|
||||
return s.firstByteReceived
|
||||
}
|
||||
|
||||
func (c *HTTPCaller) getClientTrace(suite *TraceSuite) *httptrace.ClientTrace {
|
||||
return &httptrace.ClientTrace{
|
||||
DNSStart: func(info httptrace.DNSStartInfo) {
|
||||
suite.mu.Lock()
|
||||
defer suite.mu.Unlock()
|
||||
|
||||
suite.dnsStart = time.Now()
|
||||
if c.onDNSStart != nil {
|
||||
c.onDNSStart(suite, info)
|
||||
}
|
||||
},
|
||||
DNSDone: func(info httptrace.DNSDoneInfo) {
|
||||
suite.mu.Lock()
|
||||
defer suite.mu.Unlock()
|
||||
|
||||
suite.dnsEnd = time.Now()
|
||||
if c.onDNSDone != nil {
|
||||
c.onDNSDone(suite, info)
|
||||
}
|
||||
},
|
||||
ConnectStart: func(network, addr string) {
|
||||
suite.mu.Lock()
|
||||
defer suite.mu.Unlock()
|
||||
|
||||
suite.connStart = time.Now()
|
||||
if c.onConnStart != nil {
|
||||
c.onConnStart(suite, network, addr)
|
||||
}
|
||||
},
|
||||
ConnectDone: func(network, addr string, err error) {
|
||||
suite.mu.Lock()
|
||||
defer suite.mu.Unlock()
|
||||
|
||||
suite.connEnd = time.Now()
|
||||
if c.onConnDone != nil {
|
||||
c.onConnDone(suite, network, addr, err)
|
||||
}
|
||||
},
|
||||
TLSHandshakeStart: func() {
|
||||
suite.mu.Lock()
|
||||
defer suite.mu.Unlock()
|
||||
|
||||
suite.tlsStart = time.Now()
|
||||
if c.onTLSStart != nil {
|
||||
c.onTLSStart(suite)
|
||||
}
|
||||
},
|
||||
TLSHandshakeDone: func(state tls.ConnectionState, err error) {
|
||||
suite.mu.Lock()
|
||||
defer suite.mu.Unlock()
|
||||
|
||||
suite.tlsEnd = time.Now()
|
||||
if c.onTLSDone != nil {
|
||||
c.onTLSDone(suite, state, err)
|
||||
}
|
||||
},
|
||||
WroteHeaders: func() {
|
||||
suite.mu.Lock()
|
||||
defer suite.mu.Unlock()
|
||||
|
||||
suite.wroteHeaders = time.Now()
|
||||
if c.onWroteHeaders != nil {
|
||||
c.onWroteHeaders(suite)
|
||||
}
|
||||
},
|
||||
GotFirstResponseByte: func() {
|
||||
suite.mu.Lock()
|
||||
defer suite.mu.Unlock()
|
||||
|
||||
suite.firstByteReceived = time.Now()
|
||||
if c.onFirstByteReceived != nil {
|
||||
c.onFirstByteReceived(suite)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *HTTPCaller) makeCall(ctx context.Context) error {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
||||
defer cancel()
|
||||
|
||||
suite := TraceSuite{
|
||||
generalStart: time.Now(),
|
||||
}
|
||||
traceCtx := httptrace.WithClientTrace(ctx, c.getClientTrace(&suite))
|
||||
req, err := http.NewRequestWithContext(traceCtx, c.method, c.url, bytes.NewReader(c.body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header = c.headers
|
||||
if c.host != "" {
|
||||
req.Host = c.host
|
||||
}
|
||||
|
||||
if c.onReq != nil {
|
||||
suite.mu.Lock()
|
||||
c.onReq(&suite)
|
||||
suite.mu.Unlock()
|
||||
}
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp.Body.Close()
|
||||
isValidResponse := true
|
||||
if c.isValidResponse != nil {
|
||||
isValidResponse = c.isValidResponse(resp, body)
|
||||
}
|
||||
if c.onResp != nil {
|
||||
suite.mu.Lock()
|
||||
defer suite.mu.Unlock()
|
||||
|
||||
suite.generalEnd = time.Now()
|
||||
c.onResp(&suite, &HTTPCallInfo{
|
||||
StatusCode: resp.StatusCode,
|
||||
IsValidResponse: isValidResponse,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HTTPCallInfo represents a data set which passed as a function argument to an onResp callback.
|
||||
type HTTPCallInfo struct {
|
||||
// StatusCode is a response status code
|
||||
StatusCode int
|
||||
|
||||
// IsValidResponse represents a fact of whether a response is treated as valid. You can read more about it in
|
||||
// HTTPCaller annotation.
|
||||
IsValidResponse bool
|
||||
}
|
||||
53
vendor/github.com/prometheus-community/pro-bing/logger.go
generated
vendored
Normal file
53
vendor/github.com/prometheus-community/pro-bing/logger.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
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{}) {
|
||||
}
|
||||
106
vendor/github.com/prometheus-community/pro-bing/packetconn.go
generated
vendored
Normal file
106
vendor/github.com/prometheus-community/pro-bing/packetconn.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
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
|
||||
SetBroadcastFlag() 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
|
||||
}
|
||||
980
vendor/github.com/prometheus-community/pro-bing/ping.go
generated
vendored
Normal file
980
vendor/github.com/prometheus-community/pro-bing/ping.go
generated
vendored
Normal file
@@ -0,0 +1,980 @@
|
||||
// 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
|
||||
|
||||
networkIP = "ip"
|
||||
networkIPv4 = "ip4"
|
||||
networkIPv6 = "ip6"
|
||||
)
|
||||
|
||||
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: networkIP,
|
||||
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
|
||||
|
||||
// ResolveTimeout specifies a timeout to resolve an IP address or domain name
|
||||
ResolveTimeout 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
|
||||
addr net.Addr
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
var (
|
||||
ipaddr *net.IPAddr
|
||||
err error
|
||||
)
|
||||
if p.ResolveTimeout > time.Duration(0) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
ips []net.IP
|
||||
)
|
||||
ctx, cancel := context.WithTimeout(ctx, p.ResolveTimeout)
|
||||
defer cancel()
|
||||
ips, err = net.DefaultResolver.LookupIP(ctx, p.network, p.addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(ips) == 0 {
|
||||
return fmt.Errorf("lookup %s failed: no addresses found", p.addr)
|
||||
}
|
||||
ipaddr = &net.IPAddr{IP: ips[0]}
|
||||
for _, ip := range ips {
|
||||
if p.network == networkIPv6 {
|
||||
if ip.To4() == nil && ip.To16() != nil {
|
||||
ipaddr = &net.IPAddr{IP: ip}
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
if ip.To4() != nil {
|
||||
ipaddr = &net.IPAddr{IP: ip}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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 networkIPv4:
|
||||
p.network = networkIPv4
|
||||
case networkIPv6:
|
||||
p.network = networkIPv6
|
||||
default:
|
||||
p.network = networkIP
|
||||
}
|
||||
}
|
||||
|
||||
// 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()
|
||||
return ctx.Err()
|
||||
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
|
||||
|
||||
var loss float64
|
||||
if sent > 0 {
|
||||
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<<b.c))
|
||||
}
|
||||
|
||||
func newExpBackoff(baseDelay time.Duration, maxExp int64) expBackoff {
|
||||
return expBackoff{baseDelay: baseDelay, maxExp: maxExp}
|
||||
}
|
||||
|
||||
func (p *Pinger) recvICMP(
|
||||
conn packetConn,
|
||||
recv chan<- *packet,
|
||||
) error {
|
||||
// Start by waiting for 50 µs and increase to a possible maximum of ~ 100 ms.
|
||||
expBackoff := newExpBackoff(50*time.Microsecond, 11)
|
||||
delay := expBackoff.Get()
|
||||
|
||||
// Workaround for https://github.com/golang/go/issues/47369
|
||||
offset := 0
|
||||
if p.ipv4 && !p.Privileged() && runtime.GOOS == "darwin" {
|
||||
offset = 20
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-p.done:
|
||||
return nil
|
||||
default:
|
||||
bytes := make([]byte, p.getMessageLength()+offset)
|
||||
if err := conn.SetReadDeadline(time.Now().Add(delay)); err != nil {
|
||||
return err
|
||||
}
|
||||
n, ttl, addr, err := conn.ReadFrom(bytes)
|
||||
if err != nil {
|
||||
if p.OnRecvError != nil {
|
||||
p.OnRecvError(err)
|
||||
}
|
||||
if neterr, ok := err.(*net.OpError); ok {
|
||||
if neterr.Timeout() {
|
||||
// Read timeout
|
||||
delay = expBackoff.Get()
|
||||
continue
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-p.done:
|
||||
return nil
|
||||
case recv <- &packet{bytes: bytes, nbytes: n, ttl: ttl, addr: addr}:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getPacketUUID scans the tracking slice for matches.
|
||||
func (p *Pinger) getPacketUUID(pkt []byte) (*uuid.UUID, error) {
|
||||
var packetUUID uuid.UUID
|
||||
err := packetUUID.UnmarshalBinary(pkt[timeSliceLength : timeSliceLength+trackerLength])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding tracking UUID: %w", err)
|
||||
}
|
||||
|
||||
for _, item := range p.trackerUUIDs {
|
||||
if item == packetUUID {
|
||||
return &packetUUID, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// getCurrentTrackerUUID grabs the latest tracker UUID.
|
||||
func (p *Pinger) getCurrentTrackerUUID() uuid.UUID {
|
||||
return p.trackerUUIDs[len(p.trackerUUIDs)-1]
|
||||
}
|
||||
|
||||
func (p *Pinger) processPacket(recv *packet) error {
|
||||
receivedAt := time.Now()
|
||||
var proto int
|
||||
if p.ipv4 {
|
||||
proto = protocolICMP
|
||||
// Workaround for https://github.com/golang/go/issues/47369
|
||||
recv.nbytes = stripIPv4Header(recv.nbytes, recv.bytes)
|
||||
} else {
|
||||
proto = protocolIPv6ICMP
|
||||
}
|
||||
|
||||
var m *icmp.Message
|
||||
var err error
|
||||
if m, err = icmp.ParseMessage(proto, recv.bytes); err != nil {
|
||||
return fmt.Errorf("error parsing icmp message: %w", err)
|
||||
}
|
||||
|
||||
if m.Type != ipv4.ICMPTypeEchoReply && m.Type != ipv6.ICMPTypeEchoReply {
|
||||
// Not an echo reply, ignore it
|
||||
return nil
|
||||
}
|
||||
|
||||
// If initial ip is a broadcast ip, ping responses will come from machines' in the
|
||||
// subnet, thus ip will differ. Below gets real ip from received package.
|
||||
var realIP *net.IPAddr
|
||||
|
||||
switch v := recv.addr.(type) {
|
||||
case *net.IPAddr: // For ICMP
|
||||
realIP = v
|
||||
case *net.UDPAddr:
|
||||
realIP = &net.IPAddr{IP: v.IP}
|
||||
default:
|
||||
p.logger.Infof("received address: %s it neither an Ip address (ICMP) nor UDP address, shouldn't happen. using initial address", recv.addr)
|
||||
realIP = p.ipaddr
|
||||
}
|
||||
|
||||
inPkt := &Packet{
|
||||
Nbytes: recv.nbytes,
|
||||
IPAddr: realIP,
|
||||
Addr: realIP.String(),
|
||||
TTL: recv.ttl,
|
||||
ID: p.id,
|
||||
}
|
||||
|
||||
switch pkt := m.Body.(type) {
|
||||
case *icmp.Echo:
|
||||
if !p.matchID(pkt.ID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(pkt.Data) < timeSliceLength+trackerLength {
|
||||
return fmt.Errorf("insufficient data received; got: %d %v",
|
||||
len(pkt.Data), pkt.Data)
|
||||
}
|
||||
|
||||
pktUUID, err := p.getPacketUUID(pkt.Data)
|
||||
if err != nil || pktUUID == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
timestamp := bytesToTime(pkt.Data[:timeSliceLength])
|
||||
inPkt.Rtt = receivedAt.Sub(timestamp)
|
||||
inPkt.Seq = pkt.Seq
|
||||
// If we've already received this sequence, ignore it.
|
||||
if _, inflight := p.awaitingSequences[*pktUUID][pkt.Seq]; !inflight {
|
||||
p.PacketsRecvDuplicates++
|
||||
if p.OnDuplicateRecv != nil {
|
||||
p.OnDuplicateRecv(inPkt)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// remove it from the list of sequences we're waiting for so we don't get duplicates.
|
||||
delete(p.awaitingSequences[*pktUUID], pkt.Seq)
|
||||
p.updateStatistics(inPkt)
|
||||
default:
|
||||
// Very bad, not sure how this can happen
|
||||
return fmt.Errorf("invalid ICMP echo reply; type: '%T', '%v'", pkt, pkt)
|
||||
}
|
||||
|
||||
if p.OnRecv != nil {
|
||||
p.OnRecv(inPkt)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Pinger) sendICMP(conn packetConn) error {
|
||||
var dst net.Addr = p.ipaddr
|
||||
if p.protocol == "udp" {
|
||||
dst = &net.UDPAddr{IP: p.ipaddr.IP, Zone: p.ipaddr.Zone}
|
||||
}
|
||||
|
||||
currentUUID := p.getCurrentTrackerUUID()
|
||||
uuidEncoded, err := currentUUID.MarshalBinary()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to marshal UUID binary: %w", err)
|
||||
}
|
||||
t := append(timeToBytes(time.Now()), uuidEncoded...)
|
||||
if remainSize := p.Size - timeSliceLength - trackerLength; remainSize > 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 {
|
||||
// Try to set broadcast flag
|
||||
if errors.Is(err, syscall.EACCES) && runtime.GOOS == "linux" {
|
||||
if e := conn.SetBroadcastFlag(); e != nil {
|
||||
p.logger.Warnf("had EACCES syscall error, check your local firewall")
|
||||
}
|
||||
p.logger.Infof("Pinging a broadcast address")
|
||||
continue
|
||||
}
|
||||
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
|
||||
}
|
||||
158
vendor/github.com/prometheus-community/pro-bing/utils_linux.go
generated
vendored
Normal file
158
vendor/github.com/prometheus-community/pro-bing/utils_linux.go
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
//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),
|
||||
)
|
||||
}
|
||||
|
||||
func (c *icmpConn) SetBroadcastFlag() error {
|
||||
fd, err := getFD(c.c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.NewSyscallError(
|
||||
"setsockopt",
|
||||
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1),
|
||||
)
|
||||
}
|
||||
|
||||
func (c *icmpv4Conn) SetBroadcastFlag() 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_BROADCAST, 1),
|
||||
)
|
||||
}
|
||||
|
||||
func (c *icmpV6Conn) SetBroadcastFlag() 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_BROADCAST, 1),
|
||||
)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
60
vendor/github.com/prometheus-community/pro-bing/utils_other.go
generated
vendored
Normal file
60
vendor/github.com/prometheus-community/pro-bing/utils_other.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
//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
|
||||
}
|
||||
|
||||
// No need for SetBroadcastFlag in non-linux OSes
|
||||
func (c *icmpConn) SetBroadcastFlag() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *icmpv4Conn) SetBroadcastFlag() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *icmpV6Conn) SetBroadcastFlag() error {
|
||||
return nil
|
||||
}
|
||||
71
vendor/github.com/prometheus-community/pro-bing/utils_windows.go
generated
vendored
Normal file
71
vendor/github.com/prometheus-community/pro-bing/utils_windows.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
//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
|
||||
}
|
||||
|
||||
// No need for SetBroadcastFlag in non-linux OSes
|
||||
func (c *icmpConn) SetBroadcastFlag() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *icmpv4Conn) SetBroadcastFlag() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *icmpV6Conn) SetBroadcastFlag() error {
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user