vendor
This commit is contained in:
1
vendor/github.com/sparrc/go-ping/.gitignore
generated
vendored
Normal file
1
vendor/github.com/sparrc/go-ping/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
/ping
|
21
vendor/github.com/sparrc/go-ping/LICENSE
generated
vendored
Normal file
21
vendor/github.com/sparrc/go-ping/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Cameron Sparr
|
||||
|
||||
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.
|
82
vendor/github.com/sparrc/go-ping/README.md
generated
vendored
Normal file
82
vendor/github.com/sparrc/go-ping/README.md
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
# go-ping
|
||||
[](https://godoc.org/github.com/sparrc/go-ping)
|
||||
[](https://circleci.com/gh/sparrc/go-ping)
|
||||
|
||||
ICMP Ping library for Go, inspired by
|
||||
[go-fastping](https://github.com/tatsushid/go-fastping)
|
||||
|
||||
Here is a very simple example that sends & receives 3 packets:
|
||||
|
||||
```go
|
||||
pinger, err := ping.NewPinger("www.google.com")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pinger.Count = 3
|
||||
pinger.Run() // blocks until finished
|
||||
stats := pinger.Statistics() // get send/receive/rtt stats
|
||||
```
|
||||
|
||||
Here is an example that emulates the unix ping command:
|
||||
|
||||
```go
|
||||
pinger, err := ping.NewPinger("www.google.com")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pinger.OnRecv = func(pkt *ping.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 *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())
|
||||
pinger.Run()
|
||||
```
|
||||
|
||||
It sends ICMP packet(s) and waits for a response. If it receives a response,
|
||||
it calls the "receive" callback. When it's finished, it calls the "finish"
|
||||
callback.
|
||||
|
||||
For a full ping example, see
|
||||
[cmd/ping/ping.go](https://github.com/sparrc/go-ping/blob/master/cmd/ping/ping.go)
|
||||
|
||||
## Installation:
|
||||
|
||||
```
|
||||
go get github.com/sparrc/go-ping
|
||||
```
|
||||
|
||||
To install the native Go ping executable:
|
||||
|
||||
```bash
|
||||
go get github.com/sparrc/go-ping/...
|
||||
$GOPATH/bin/ping
|
||||
```
|
||||
|
||||
## Note on Linux Support:
|
||||
|
||||
This library attempts to send an
|
||||
"unprivileged" ping via UDP. On linux, this must be enabled by setting
|
||||
|
||||
```
|
||||
sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"
|
||||
```
|
||||
|
||||
If you do not wish to do this, you can set `pinger.SetPrivileged(true)` and
|
||||
use setcap to allow your binary using go-ping to bind to raw sockets
|
||||
(or just run as super-user):
|
||||
|
||||
```
|
||||
setcap cap_net_raw=+ep /bin/goping-binary
|
||||
```
|
||||
|
||||
See [this blog](https://sturmflut.github.io/linux/ubuntu/2015/01/17/unprivileged-icmp-sockets-on-linux/)
|
||||
and [the Go icmp library](https://godoc.org/golang.org/x/net/icmp) for more details.
|
9
vendor/github.com/sparrc/go-ping/circle.yml
generated
vendored
Normal file
9
vendor/github.com/sparrc/go-ping/circle.yml
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
test:
|
||||
post:
|
||||
- go build -race -o ping_linux ./cmd/ping/ping.go
|
||||
- sudo ./ping_linux --privileged -c 2 www.google.com
|
||||
- sudo ./ping_linux --privileged -c 3 -i 200ms www.google.com
|
||||
- sudo ./ping_linux --privileged -c 10 -i 100ms -t 1s www.google.com
|
||||
- GOOS=darwin go build -o ping_darwin ./cmd/ping/ping.go
|
||||
- mv ping_linux $CIRCLE_ARTIFACTS
|
||||
- mv ping_darwin $CIRCLE_ARTIFACTS
|
549
vendor/github.com/sparrc/go-ping/ping.go
generated
vendored
Normal file
549
vendor/github.com/sparrc/go-ping/ping.go
generated
vendored
Normal file
@ -0,0 +1,549 @@
|
||||
// Package ping is an ICMP ping library seeking to emulate the unix "ping"
|
||||
// command.
|
||||
//
|
||||
// Here is a very simple example that sends & receives 3 packets:
|
||||
//
|
||||
// pinger, err := ping.NewPinger("www.google.com")
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
//
|
||||
// pinger.Count = 3
|
||||
// pinger.Run() // blocks until finished
|
||||
// stats := pinger.Statistics() // get send/receive/rtt stats
|
||||
//
|
||||
// Here is an example that emulates the unix ping command:
|
||||
//
|
||||
// pinger, err := ping.NewPinger("www.google.com")
|
||||
// if err != nil {
|
||||
// fmt.Printf("ERROR: %s\n", err.Error())
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// pinger.OnRecv = func(pkt *ping.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 *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())
|
||||
// pinger.Run()
|
||||
//
|
||||
// It sends ICMP packet(s) and waits for a response. If it receives a response,
|
||||
// it calls the "receive" callback. When it's finished, it calls the "finish"
|
||||
// callback.
|
||||
//
|
||||
// For a full ping example, see "cmd/ping/ping.go".
|
||||
//
|
||||
package ping
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/icmp"
|
||||
"golang.org/x/net/ipv4"
|
||||
"golang.org/x/net/ipv6"
|
||||
)
|
||||
|
||||
const (
|
||||
timeSliceLength = 8
|
||||
protocolICMP = 1
|
||||
protocolIPv6ICMP = 58
|
||||
)
|
||||
|
||||
var (
|
||||
ipv4Proto = map[string]string{"ip": "ip4:icmp", "udp": "udp4"}
|
||||
ipv6Proto = map[string]string{"ip": "ip6:ipv6-icmp", "udp": "udp6"}
|
||||
)
|
||||
|
||||
// NewPinger returns a new Pinger struct pointer
|
||||
func NewPinger(addr string) (*Pinger, error) {
|
||||
ipaddr, err := net.ResolveIPAddr("ip", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ipv4 bool
|
||||
if isIPv4(ipaddr.IP) {
|
||||
ipv4 = true
|
||||
} else if isIPv6(ipaddr.IP) {
|
||||
ipv4 = false
|
||||
}
|
||||
|
||||
return &Pinger{
|
||||
ipaddr: ipaddr,
|
||||
addr: addr,
|
||||
Interval: time.Second,
|
||||
Timeout: time.Second * 100000,
|
||||
Count: -1,
|
||||
|
||||
network: "udp",
|
||||
ipv4: ipv4,
|
||||
size: timeSliceLength,
|
||||
|
||||
done: make(chan bool),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Pinger represents ICMP 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
|
||||
|
||||
// rtts is all of the Rtts
|
||||
rtts []time.Duration
|
||||
|
||||
// OnRecv is called when Pinger receives and processes a packet
|
||||
OnRecv func(*Packet)
|
||||
|
||||
// OnFinish is called when Pinger exits
|
||||
OnFinish func(*Statistics)
|
||||
|
||||
// stop chan bool
|
||||
done chan bool
|
||||
|
||||
ipaddr *net.IPAddr
|
||||
addr string
|
||||
|
||||
ipv4 bool
|
||||
source string
|
||||
size int
|
||||
sequence int
|
||||
network string
|
||||
}
|
||||
|
||||
type packet struct {
|
||||
bytes []byte
|
||||
nbytes 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
|
||||
|
||||
// NBytes is the number of bytes in the message.
|
||||
Nbytes int
|
||||
|
||||
// Seq is the ICMP sequence number.
|
||||
Seq 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
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// SetIPAddr sets the ip address of the target host.
|
||||
func (p *Pinger) SetIPAddr(ipaddr *net.IPAddr) {
|
||||
var ipv4 bool
|
||||
if isIPv4(ipaddr.IP) {
|
||||
ipv4 = true
|
||||
} else if isIPv6(ipaddr.IP) {
|
||||
ipv4 = false
|
||||
}
|
||||
|
||||
p.ipaddr = ipaddr
|
||||
p.addr = ipaddr.String()
|
||||
p.ipv4 = ipv4
|
||||
}
|
||||
|
||||
// IPAddr returns the ip address of the target host.
|
||||
func (p *Pinger) IPAddr() *net.IPAddr {
|
||||
return p.ipaddr
|
||||
}
|
||||
|
||||
// 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 {
|
||||
ipaddr, err := net.ResolveIPAddr("ip", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.SetIPAddr(ipaddr)
|
||||
p.addr = addr
|
||||
return nil
|
||||
}
|
||||
|
||||
// Addr returns the string ip address of the target host.
|
||||
func (p *Pinger) Addr() string {
|
||||
return p.addr
|
||||
}
|
||||
|
||||
// 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.network = "ip"
|
||||
} else {
|
||||
p.network = "udp"
|
||||
}
|
||||
}
|
||||
|
||||
// Privileged returns whether pinger is running in privileged mode.
|
||||
func (p *Pinger) Privileged() bool {
|
||||
return p.network == "ip"
|
||||
}
|
||||
|
||||
// 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() {
|
||||
p.run()
|
||||
}
|
||||
|
||||
func (p *Pinger) run() {
|
||||
var conn *icmp.PacketConn
|
||||
if p.ipv4 {
|
||||
if conn = p.listen(ipv4Proto[p.network], p.source); conn == nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if conn = p.listen(ipv6Proto[p.network], p.source); conn == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
defer conn.Close()
|
||||
defer p.finish()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
recv := make(chan *packet, 5)
|
||||
wg.Add(1)
|
||||
go p.recvICMP(conn, recv, &wg)
|
||||
|
||||
err := p.sendICMP(conn)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
timeout := time.NewTicker(p.Timeout)
|
||||
interval := time.NewTicker(p.Interval)
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
signal.Notify(c, syscall.SIGTERM)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-c:
|
||||
close(p.done)
|
||||
case <-p.done:
|
||||
wg.Wait()
|
||||
return
|
||||
case <-timeout.C:
|
||||
close(p.done)
|
||||
wg.Wait()
|
||||
return
|
||||
case <-interval.C:
|
||||
err = p.sendICMP(conn)
|
||||
if err != nil {
|
||||
fmt.Println("FATAL: ", err.Error())
|
||||
}
|
||||
case r := <-recv:
|
||||
err := p.processPacket(r)
|
||||
if err != nil {
|
||||
fmt.Println("FATAL: ", err.Error())
|
||||
}
|
||||
default:
|
||||
if p.Count > 0 && p.PacketsRecv >= p.Count {
|
||||
close(p.done)
|
||||
wg.Wait()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pinger) finish() {
|
||||
handler := p.OnFinish
|
||||
if handler != nil {
|
||||
s := p.Statistics()
|
||||
handler(s)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
loss := float64(p.PacketsSent-p.PacketsRecv) / float64(p.PacketsSent) * 100
|
||||
var min, max, total time.Duration
|
||||
if len(p.rtts) > 0 {
|
||||
min = p.rtts[0]
|
||||
max = p.rtts[0]
|
||||
}
|
||||
for _, rtt := range p.rtts {
|
||||
if rtt < min {
|
||||
min = rtt
|
||||
}
|
||||
if rtt > max {
|
||||
max = rtt
|
||||
}
|
||||
total += rtt
|
||||
}
|
||||
s := Statistics{
|
||||
PacketsSent: p.PacketsSent,
|
||||
PacketsRecv: p.PacketsRecv,
|
||||
PacketLoss: loss,
|
||||
Rtts: p.rtts,
|
||||
Addr: p.addr,
|
||||
IPAddr: p.ipaddr,
|
||||
MaxRtt: max,
|
||||
MinRtt: min,
|
||||
}
|
||||
if len(p.rtts) > 0 {
|
||||
s.AvgRtt = total / time.Duration(len(p.rtts))
|
||||
var sumsquares time.Duration
|
||||
for _, rtt := range p.rtts {
|
||||
sumsquares += (rtt - s.AvgRtt) * (rtt - s.AvgRtt)
|
||||
}
|
||||
s.StdDevRtt = time.Duration(math.Sqrt(
|
||||
float64(sumsquares / time.Duration(len(p.rtts)))))
|
||||
}
|
||||
return &s
|
||||
}
|
||||
|
||||
func (p *Pinger) recvICMP(
|
||||
conn *icmp.PacketConn,
|
||||
recv chan<- *packet,
|
||||
wg *sync.WaitGroup,
|
||||
) {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-p.done:
|
||||
return
|
||||
default:
|
||||
bytes := make([]byte, 512)
|
||||
conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
|
||||
n, _, err := conn.ReadFrom(bytes)
|
||||
if err != nil {
|
||||
if neterr, ok := err.(*net.OpError); ok {
|
||||
if neterr.Timeout() {
|
||||
// Read timeout
|
||||
continue
|
||||
} else {
|
||||
close(p.done)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recv <- &packet{bytes: bytes, nbytes: n}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pinger) processPacket(recv *packet) error {
|
||||
var bytes []byte
|
||||
var proto int
|
||||
if p.ipv4 {
|
||||
if p.network == "ip" {
|
||||
bytes = ipv4Payload(recv.bytes)
|
||||
} else {
|
||||
bytes = recv.bytes
|
||||
}
|
||||
proto = protocolICMP
|
||||
} else {
|
||||
bytes = recv.bytes
|
||||
proto = protocolIPv6ICMP
|
||||
}
|
||||
|
||||
var m *icmp.Message
|
||||
var err error
|
||||
if m, err = icmp.ParseMessage(proto, bytes[:recv.nbytes]); err != nil {
|
||||
return fmt.Errorf("Error parsing icmp message")
|
||||
}
|
||||
|
||||
if m.Type != ipv4.ICMPTypeEchoReply && m.Type != ipv6.ICMPTypeEchoReply {
|
||||
// Not an echo reply, ignore it
|
||||
return nil
|
||||
}
|
||||
|
||||
outPkt := &Packet{
|
||||
Nbytes: recv.nbytes,
|
||||
IPAddr: p.ipaddr,
|
||||
}
|
||||
|
||||
switch pkt := m.Body.(type) {
|
||||
case *icmp.Echo:
|
||||
outPkt.Rtt = time.Since(bytesToTime(pkt.Data[:timeSliceLength]))
|
||||
outPkt.Seq = pkt.Seq
|
||||
p.PacketsRecv += 1
|
||||
default:
|
||||
// Very bad, not sure how this can happen
|
||||
return fmt.Errorf("Error, invalid ICMP echo reply. Body type: %T, %s",
|
||||
pkt, pkt)
|
||||
}
|
||||
|
||||
p.rtts = append(p.rtts, outPkt.Rtt)
|
||||
handler := p.OnRecv
|
||||
if handler != nil {
|
||||
handler(outPkt)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Pinger) sendICMP(conn *icmp.PacketConn) error {
|
||||
var typ icmp.Type
|
||||
if p.ipv4 {
|
||||
typ = ipv4.ICMPTypeEcho
|
||||
} else {
|
||||
typ = ipv6.ICMPTypeEchoRequest
|
||||
}
|
||||
|
||||
var dst net.Addr = p.ipaddr
|
||||
if p.network == "udp" {
|
||||
dst = &net.UDPAddr{IP: p.ipaddr.IP, Zone: p.ipaddr.Zone}
|
||||
}
|
||||
|
||||
t := timeToBytes(time.Now())
|
||||
if p.size-timeSliceLength != 0 {
|
||||
t = append(t, byteSliceOfSize(p.size-timeSliceLength)...)
|
||||
}
|
||||
bytes, err := (&icmp.Message{
|
||||
Type: typ, Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: rand.Intn(65535),
|
||||
Seq: p.sequence,
|
||||
Data: t,
|
||||
},
|
||||
}).Marshal(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
if _, err := conn.WriteTo(bytes, dst); err != nil {
|
||||
if neterr, ok := err.(*net.OpError); ok {
|
||||
if neterr.Err == syscall.ENOBUFS {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
p.PacketsSent += 1
|
||||
p.sequence += 1
|
||||
break
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Pinger) listen(netProto string, source string) *icmp.PacketConn {
|
||||
conn, err := icmp.ListenPacket(netProto, source)
|
||||
if err != nil {
|
||||
fmt.Printf("Error listening for ICMP packets: %s\n", err.Error())
|
||||
close(p.done)
|
||||
return nil
|
||||
}
|
||||
return conn
|
||||
}
|
||||
|
||||
func byteSliceOfSize(n int) []byte {
|
||||
b := make([]byte, n)
|
||||
for i := 0; i < len(b); i++ {
|
||||
b[i] = 1
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func ipv4Payload(b []byte) []byte {
|
||||
if len(b) < ipv4.HeaderLen {
|
||||
return b
|
||||
}
|
||||
hdrlen := int(b[0]&0x0f) << 2
|
||||
return b[hdrlen:]
|
||||
}
|
||||
|
||||
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 isIPv6(ip net.IP) bool {
|
||||
return len(ip) == net.IPv6len
|
||||
}
|
||||
|
||||
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
|
||||
}
|
266
vendor/github.com/sparrc/go-ping/ping_test.go
generated
vendored
Normal file
266
vendor/github.com/sparrc/go-ping/ping_test.go
generated
vendored
Normal file
@ -0,0 +1,266 @@
|
||||
package ping
|
||||
|
||||
import (
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNewPingerValid(t *testing.T) {
|
||||
p, err := NewPinger("www.google.com")
|
||||
AssertNoError(t, err)
|
||||
AssertEqualStrings(t, "www.google.com", p.Addr())
|
||||
// DNS names should resolve into IP addresses
|
||||
AssertNotEqualStrings(t, "www.google.com", p.IPAddr().String())
|
||||
AssertTrue(t, isIPv4(p.IPAddr().IP))
|
||||
AssertFalse(t, p.Privileged())
|
||||
// Test that SetPrivileged works
|
||||
p.SetPrivileged(true)
|
||||
AssertTrue(t, p.Privileged())
|
||||
// Test setting to ipv4 address
|
||||
err = p.SetAddr("www.google.com")
|
||||
AssertNoError(t, err)
|
||||
AssertTrue(t, isIPv4(p.IPAddr().IP))
|
||||
// Test setting to ipv6 address
|
||||
err = p.SetAddr("ipv6.google.com")
|
||||
AssertNoError(t, err)
|
||||
AssertTrue(t, isIPv6(p.IPAddr().IP))
|
||||
|
||||
p, err = NewPinger("localhost")
|
||||
AssertNoError(t, err)
|
||||
AssertEqualStrings(t, "localhost", p.Addr())
|
||||
// DNS names should resolve into IP addresses
|
||||
AssertNotEqualStrings(t, "localhost", p.IPAddr().String())
|
||||
AssertTrue(t, isIPv4(p.IPAddr().IP))
|
||||
AssertFalse(t, p.Privileged())
|
||||
// Test that SetPrivileged works
|
||||
p.SetPrivileged(true)
|
||||
AssertTrue(t, p.Privileged())
|
||||
// Test setting to ipv4 address
|
||||
err = p.SetAddr("www.google.com")
|
||||
AssertNoError(t, err)
|
||||
AssertTrue(t, isIPv4(p.IPAddr().IP))
|
||||
// Test setting to ipv6 address
|
||||
err = p.SetAddr("ipv6.google.com")
|
||||
AssertNoError(t, err)
|
||||
AssertTrue(t, isIPv6(p.IPAddr().IP))
|
||||
|
||||
p, err = NewPinger("127.0.0.1")
|
||||
AssertNoError(t, err)
|
||||
AssertEqualStrings(t, "127.0.0.1", p.Addr())
|
||||
AssertTrue(t, isIPv4(p.IPAddr().IP))
|
||||
AssertFalse(t, p.Privileged())
|
||||
// Test that SetPrivileged works
|
||||
p.SetPrivileged(true)
|
||||
AssertTrue(t, p.Privileged())
|
||||
// Test setting to ipv4 address
|
||||
err = p.SetAddr("www.google.com")
|
||||
AssertNoError(t, err)
|
||||
AssertTrue(t, isIPv4(p.IPAddr().IP))
|
||||
// Test setting to ipv6 address
|
||||
err = p.SetAddr("ipv6.google.com")
|
||||
AssertNoError(t, err)
|
||||
AssertTrue(t, isIPv6(p.IPAddr().IP))
|
||||
|
||||
p, err = NewPinger("ipv6.google.com")
|
||||
AssertNoError(t, err)
|
||||
AssertEqualStrings(t, "ipv6.google.com", p.Addr())
|
||||
// DNS names should resolve into IP addresses
|
||||
AssertNotEqualStrings(t, "ipv6.google.com", p.IPAddr().String())
|
||||
AssertTrue(t, isIPv6(p.IPAddr().IP))
|
||||
AssertFalse(t, p.Privileged())
|
||||
// Test that SetPrivileged works
|
||||
p.SetPrivileged(true)
|
||||
AssertTrue(t, p.Privileged())
|
||||
// Test setting to ipv4 address
|
||||
err = p.SetAddr("www.google.com")
|
||||
AssertNoError(t, err)
|
||||
AssertTrue(t, isIPv4(p.IPAddr().IP))
|
||||
// Test setting to ipv6 address
|
||||
err = p.SetAddr("ipv6.google.com")
|
||||
AssertNoError(t, err)
|
||||
AssertTrue(t, isIPv6(p.IPAddr().IP))
|
||||
|
||||
// ipv6 localhost:
|
||||
p, err = NewPinger("::1")
|
||||
AssertNoError(t, err)
|
||||
AssertEqualStrings(t, "::1", p.Addr())
|
||||
AssertTrue(t, isIPv6(p.IPAddr().IP))
|
||||
AssertFalse(t, p.Privileged())
|
||||
// Test that SetPrivileged works
|
||||
p.SetPrivileged(true)
|
||||
AssertTrue(t, p.Privileged())
|
||||
// Test setting to ipv4 address
|
||||
err = p.SetAddr("www.google.com")
|
||||
AssertNoError(t, err)
|
||||
AssertTrue(t, isIPv4(p.IPAddr().IP))
|
||||
// Test setting to ipv6 address
|
||||
err = p.SetAddr("ipv6.google.com")
|
||||
AssertNoError(t, err)
|
||||
AssertTrue(t, isIPv6(p.IPAddr().IP))
|
||||
}
|
||||
|
||||
func TestNewPingerInvalid(t *testing.T) {
|
||||
_, err := NewPinger("127.0.0.0.1")
|
||||
AssertError(t, err, "127.0.0.0.1")
|
||||
|
||||
_, err = NewPinger("127..0.0.1")
|
||||
AssertError(t, err, "127..0.0.1")
|
||||
|
||||
_, err = NewPinger("wtf")
|
||||
AssertError(t, err, "wtf")
|
||||
|
||||
_, err = NewPinger(":::1")
|
||||
AssertError(t, err, ":::1")
|
||||
|
||||
_, err = NewPinger("ipv5.google.com")
|
||||
AssertError(t, err, "ipv5.google.com")
|
||||
}
|
||||
|
||||
func TestSetIPAddr(t *testing.T) {
|
||||
googleaddr, err := net.ResolveIPAddr("ip", "www.google.com")
|
||||
if err != nil {
|
||||
t.Fatal("Can't resolve www.google.com, can't run tests")
|
||||
}
|
||||
|
||||
// Create a localhost ipv4 pinger
|
||||
p, err := NewPinger("localhost")
|
||||
AssertNoError(t, err)
|
||||
AssertEqualStrings(t, "localhost", p.Addr())
|
||||
|
||||
// set IPAddr to google
|
||||
p.SetIPAddr(googleaddr)
|
||||
AssertEqualStrings(t, googleaddr.String(), p.Addr())
|
||||
}
|
||||
|
||||
func TestStatisticsSunny(t *testing.T) {
|
||||
// Create a localhost ipv4 pinger
|
||||
p, err := NewPinger("localhost")
|
||||
AssertNoError(t, err)
|
||||
AssertEqualStrings(t, "localhost", p.Addr())
|
||||
|
||||
p.PacketsSent = 10
|
||||
p.PacketsRecv = 10
|
||||
p.rtts = []time.Duration{
|
||||
time.Duration(1000),
|
||||
time.Duration(1000),
|
||||
time.Duration(1000),
|
||||
time.Duration(1000),
|
||||
time.Duration(1000),
|
||||
time.Duration(1000),
|
||||
time.Duration(1000),
|
||||
time.Duration(1000),
|
||||
time.Duration(1000),
|
||||
time.Duration(1000),
|
||||
}
|
||||
|
||||
stats := p.Statistics()
|
||||
if stats.PacketsRecv != 10 {
|
||||
t.Errorf("Expected %v, got %v", 10, stats.PacketsRecv)
|
||||
}
|
||||
if stats.PacketsSent != 10 {
|
||||
t.Errorf("Expected %v, got %v", 10, stats.PacketsSent)
|
||||
}
|
||||
if stats.PacketLoss != 0 {
|
||||
t.Errorf("Expected %v, got %v", 0, stats.PacketLoss)
|
||||
}
|
||||
if stats.MinRtt != time.Duration(1000) {
|
||||
t.Errorf("Expected %v, got %v", time.Duration(1000), stats.MinRtt)
|
||||
}
|
||||
if stats.MaxRtt != time.Duration(1000) {
|
||||
t.Errorf("Expected %v, got %v", time.Duration(1000), stats.MaxRtt)
|
||||
}
|
||||
if stats.AvgRtt != time.Duration(1000) {
|
||||
t.Errorf("Expected %v, got %v", time.Duration(1000), stats.AvgRtt)
|
||||
}
|
||||
if stats.StdDevRtt != time.Duration(0) {
|
||||
t.Errorf("Expected %v, got %v", time.Duration(0), stats.StdDevRtt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatisticsLossy(t *testing.T) {
|
||||
// Create a localhost ipv4 pinger
|
||||
p, err := NewPinger("localhost")
|
||||
AssertNoError(t, err)
|
||||
AssertEqualStrings(t, "localhost", p.Addr())
|
||||
|
||||
p.PacketsSent = 20
|
||||
p.PacketsRecv = 10
|
||||
p.rtts = []time.Duration{
|
||||
time.Duration(10),
|
||||
time.Duration(1000),
|
||||
time.Duration(1000),
|
||||
time.Duration(10000),
|
||||
time.Duration(1000),
|
||||
time.Duration(800),
|
||||
time.Duration(1000),
|
||||
time.Duration(40),
|
||||
time.Duration(100000),
|
||||
time.Duration(1000),
|
||||
}
|
||||
|
||||
stats := p.Statistics()
|
||||
if stats.PacketsRecv != 10 {
|
||||
t.Errorf("Expected %v, got %v", 10, stats.PacketsRecv)
|
||||
}
|
||||
if stats.PacketsSent != 20 {
|
||||
t.Errorf("Expected %v, got %v", 20, stats.PacketsSent)
|
||||
}
|
||||
if stats.PacketLoss != 50 {
|
||||
t.Errorf("Expected %v, got %v", 50, stats.PacketLoss)
|
||||
}
|
||||
if stats.MinRtt != time.Duration(10) {
|
||||
t.Errorf("Expected %v, got %v", time.Duration(10), stats.MinRtt)
|
||||
}
|
||||
if stats.MaxRtt != time.Duration(100000) {
|
||||
t.Errorf("Expected %v, got %v", time.Duration(100000), stats.MaxRtt)
|
||||
}
|
||||
if stats.AvgRtt != time.Duration(11585) {
|
||||
t.Errorf("Expected %v, got %v", time.Duration(11585), stats.AvgRtt)
|
||||
}
|
||||
if stats.StdDevRtt != time.Duration(29603) {
|
||||
t.Errorf("Expected %v, got %v", time.Duration(29603), stats.StdDevRtt)
|
||||
}
|
||||
}
|
||||
|
||||
// Test helpers
|
||||
func AssertNoError(t *testing.T, err error) {
|
||||
if err != nil {
|
||||
t.Errorf("Expected No Error but got %s, Stack:\n%s",
|
||||
err, string(debug.Stack()))
|
||||
}
|
||||
}
|
||||
|
||||
func AssertError(t *testing.T, err error, info string) {
|
||||
if err == nil {
|
||||
t.Errorf("Expected Error but got %s, %s, Stack:\n%s",
|
||||
err, info, string(debug.Stack()))
|
||||
}
|
||||
}
|
||||
|
||||
func AssertEqualStrings(t *testing.T, expected, actual string) {
|
||||
if expected != actual {
|
||||
t.Errorf("Expected %s, got %s, Stack:\n%s",
|
||||
expected, actual, string(debug.Stack()))
|
||||
}
|
||||
}
|
||||
|
||||
func AssertNotEqualStrings(t *testing.T, expected, actual string) {
|
||||
if expected == actual {
|
||||
t.Errorf("Expected %s, got %s, Stack:\n%s",
|
||||
expected, actual, string(debug.Stack()))
|
||||
}
|
||||
}
|
||||
|
||||
func AssertTrue(t *testing.T, b bool) {
|
||||
if !b {
|
||||
t.Errorf("Expected True, got False, Stack:\n%s", string(debug.Stack()))
|
||||
}
|
||||
}
|
||||
|
||||
func AssertFalse(t *testing.T, b bool) {
|
||||
if b {
|
||||
t.Errorf("Expected False, got True, Stack:\n%s", string(debug.Stack()))
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user