|
@@ -62,13 +62,10 @@ import (
|
|
"time"
|
|
"time"
|
|
"trial/ping/probing/icmp"
|
|
"trial/ping/probing/icmp"
|
|
|
|
|
|
- "git.wecise.com/wecise/common/logger"
|
|
|
|
- "git.wecise.com/wecise/common/matrix/cfg"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/google/uuid"
|
|
"golang.org/x/sync/errgroup"
|
|
"golang.org/x/sync/errgroup"
|
|
)
|
|
)
|
|
|
|
|
|
-var mcfg = cfg.MConfig()
|
|
|
|
var receive_buffer_count = mcfg.GetInt("ping.recv.buf.count", 10)
|
|
var receive_buffer_count = mcfg.GetInt("ping.recv.buf.count", 10)
|
|
var ping_ttl = mcfg.GetInt("ping.ttl", 64)
|
|
var ping_ttl = mcfg.GetInt("ping.ttl", 64)
|
|
var ping_interval = mcfg.GetDuration("ping.interval", 1000*time.Millisecond)
|
|
var ping_interval = mcfg.GetDuration("ping.interval", 1000*time.Millisecond)
|
|
@@ -87,9 +84,6 @@ const (
|
|
// New returns a new Pinger struct pointer.
|
|
// New returns a new Pinger struct pointer.
|
|
func New(addr string) *Pinger {
|
|
func New(addr string) *Pinger {
|
|
r := rand.New(rand.NewSource(getSeed()))
|
|
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{
|
|
return &Pinger{
|
|
Count: -1,
|
|
Count: -1,
|
|
Interval: time.Second,
|
|
Interval: time.Second,
|
|
@@ -97,15 +91,13 @@ func New(addr string) *Pinger {
|
|
Size: timeSliceLength + trackerLength,
|
|
Size: timeSliceLength + trackerLength,
|
|
Timeout: time.Duration(math.MaxInt64),
|
|
Timeout: time.Duration(math.MaxInt64),
|
|
|
|
|
|
- addr: addr,
|
|
|
|
- done: make(chan interface{}),
|
|
|
|
- id: r.Intn(math.MaxUint16),
|
|
|
|
- trackerUUIDs: []uuid.UUID{firstUUID},
|
|
|
|
- ipaddr: nil,
|
|
|
|
- ipv4: false,
|
|
|
|
- network: "ip",
|
|
|
|
- protocol: "udp",
|
|
|
|
- awaitingSequences: firstSequence,
|
|
|
|
|
|
+ addr: addr,
|
|
|
|
+ done: make(chan interface{}),
|
|
|
|
+ id: r.Intn(math.MaxUint16),
|
|
|
|
+ ipaddr: nil,
|
|
|
|
+ ipv4: false,
|
|
|
|
+ network: "ip",
|
|
|
|
+ protocol: "udp",
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -117,6 +109,9 @@ func NewPinger(addr string) (*Pinger, error) {
|
|
|
|
|
|
// Pinger represents a packet sender/receiver.
|
|
// Pinger represents a packet sender/receiver.
|
|
type Pinger struct {
|
|
type Pinger struct {
|
|
|
|
+ // Size of packet being sent
|
|
|
|
+ Size int
|
|
|
|
+
|
|
// Interval is the wait time between each packet send. Default is 1s.
|
|
// Interval is the wait time between each packet send. Default is 1s.
|
|
Interval time.Duration
|
|
Interval time.Duration
|
|
|
|
|
|
@@ -129,9 +124,6 @@ type Pinger struct {
|
|
// interrupted.
|
|
// interrupted.
|
|
Count int
|
|
Count int
|
|
|
|
|
|
- // Debug runs in debug mode
|
|
|
|
- Debug bool
|
|
|
|
-
|
|
|
|
// Number of packets sent
|
|
// Number of packets sent
|
|
PacketsSent int
|
|
PacketsSent int
|
|
|
|
|
|
@@ -174,12 +166,6 @@ type Pinger struct {
|
|
// OnDuplicateRecv is called when a packet is received that has already been received.
|
|
// OnDuplicateRecv is called when a packet is received that has already been received.
|
|
OnDuplicateRecv func(*Packet)
|
|
OnDuplicateRecv func(*Packet)
|
|
|
|
|
|
- // Size of packet being sent
|
|
|
|
- Size int
|
|
|
|
-
|
|
|
|
- // Tracker: Used to uniquely identify packets - Deprecated
|
|
|
|
- Tracker uint64
|
|
|
|
-
|
|
|
|
// Source is the source IP address
|
|
// Source is the source IP address
|
|
Source string
|
|
Source string
|
|
|
|
|
|
@@ -190,15 +176,9 @@ type Pinger struct {
|
|
ipaddr *net.IPAddr
|
|
ipaddr *net.IPAddr
|
|
addr string
|
|
addr string
|
|
|
|
|
|
- // trackerUUIDs is the list of UUIDs being used for sending packets.
|
|
|
|
- trackerUUIDs []uuid.UUID
|
|
|
|
-
|
|
|
|
ipv4 bool
|
|
ipv4 bool
|
|
id int
|
|
id int
|
|
sequence_base int
|
|
sequence_base 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 is one of "ip", "ip4", or "ip6".
|
|
network string
|
|
network string
|
|
// protocol is "icmp" or "udp".
|
|
// protocol is "icmp" or "udp".
|
|
@@ -207,26 +187,20 @@ type Pinger struct {
|
|
|
|
|
|
// Packet represents a received and processed ICMP echo packet.
|
|
// Packet represents a received and processed ICMP echo packet.
|
|
type Packet struct {
|
|
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
|
|
|
|
-
|
|
|
|
// Host is the string address of the host being pinged.
|
|
// Host is the string address of the host being pinged.
|
|
Host string
|
|
Host string
|
|
-
|
|
|
|
- // NBytes is the number of bytes in the message.
|
|
|
|
- Nbytes int
|
|
|
|
-
|
|
|
|
|
|
+ // IPAddr is the address of the host being pinged.
|
|
|
|
+ IPAddr *net.IPAddr
|
|
|
|
+ // ID is the ICMP identifier.
|
|
|
|
+ ID int
|
|
// Seq is the ICMP sequence number.
|
|
// Seq is the ICMP sequence number.
|
|
Seq int
|
|
Seq int
|
|
-
|
|
|
|
|
|
+ // NBytes is the number of bytes in the message.
|
|
|
|
+ Nbytes int
|
|
// TTL is the Time To Live on the packet.
|
|
// TTL is the Time To Live on the packet.
|
|
TTL int
|
|
TTL int
|
|
-
|
|
|
|
- // ID is the ICMP identifier.
|
|
|
|
- ID int
|
|
|
|
|
|
+ // Rtt is the round-trip time it took to ping.
|
|
|
|
+ Rtt time.Duration
|
|
}
|
|
}
|
|
|
|
|
|
// Statistics represent the stats of a currently running or finished
|
|
// Statistics represent the stats of a currently running or finished
|
|
@@ -358,6 +332,14 @@ func (p *Pinger) SetNetwork(n string) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ https://stackoverflow.com/questions/41423637/go-ping-library-for-unprivileged-icmp-ping-in-golang/41425527#41425527
|
|
|
|
+ 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
|
|
|
|
+ getcap /bin/goping-binary to validate
|
|
|
|
+*/
|
|
// SetPrivileged sets the type of ping pinger will send.
|
|
// SetPrivileged sets the type of ping pinger will send.
|
|
// false means pinger will send an "unprivileged" UDP ping.
|
|
// false means pinger will send an "unprivileged" UDP ping.
|
|
// true means pinger will send a "privileged" raw ICMP ping.
|
|
// true means pinger will send a "privileged" raw ICMP ping.
|
|
@@ -491,25 +473,25 @@ func (p *Pinger) runLoop() (time.Time, error) {
|
|
p.PacketsSent++
|
|
p.PacketsSent++
|
|
if p.OnSend != nil {
|
|
if p.OnSend != nil {
|
|
p.OnSend(&Packet{
|
|
p.OnSend(&Packet{
|
|
- Rtt: pkt.Rtt,
|
|
|
|
- IPAddr: pkt.IPAddr,
|
|
|
|
Host: p.addr,
|
|
Host: p.addr,
|
|
- Nbytes: pkt.Nbytes,
|
|
|
|
|
|
+ IPAddr: pkt.IPAddr,
|
|
|
|
+ ID: pkt.ID,
|
|
Seq: pkt.Seq - p.sequence_base,
|
|
Seq: pkt.Seq - p.sequence_base,
|
|
|
|
+ Nbytes: pkt.Nbytes,
|
|
TTL: pkt.TTL,
|
|
TTL: pkt.TTL,
|
|
- ID: pkt.ID,
|
|
|
|
|
|
+ Rtt: pkt.Rtt,
|
|
})
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pinfo.OnRecv = func(pkt *icmp.Packet) {
|
|
pinfo.OnRecv = func(pkt *icmp.Packet) {
|
|
inpkt := &Packet{
|
|
inpkt := &Packet{
|
|
- Rtt: pkt.Rtt,
|
|
|
|
- IPAddr: pkt.IPAddr,
|
|
|
|
Host: p.addr,
|
|
Host: p.addr,
|
|
- Nbytes: pkt.Nbytes,
|
|
|
|
|
|
+ IPAddr: pkt.IPAddr,
|
|
|
|
+ ID: pkt.ID,
|
|
Seq: pkt.Seq - p.sequence_base,
|
|
Seq: pkt.Seq - p.sequence_base,
|
|
|
|
+ Nbytes: pkt.Nbytes,
|
|
TTL: pkt.TTL,
|
|
TTL: pkt.TTL,
|
|
- ID: pkt.ID,
|
|
|
|
|
|
+ Rtt: pkt.Rtt,
|
|
}
|
|
}
|
|
if p.OnRecv != nil {
|
|
if p.OnRecv != nil {
|
|
p.OnRecv(inpkt)
|
|
p.OnRecv(inpkt)
|
|
@@ -519,13 +501,13 @@ func (p *Pinger) runLoop() (time.Time, error) {
|
|
}
|
|
}
|
|
pinfo.OnRecvDup = func(pkt *icmp.Packet) {
|
|
pinfo.OnRecvDup = func(pkt *icmp.Packet) {
|
|
inpkt := &Packet{
|
|
inpkt := &Packet{
|
|
- Rtt: pkt.Rtt,
|
|
|
|
- IPAddr: pkt.IPAddr,
|
|
|
|
Host: p.addr,
|
|
Host: p.addr,
|
|
- Nbytes: pkt.Nbytes,
|
|
|
|
|
|
+ IPAddr: pkt.IPAddr,
|
|
|
|
+ ID: pkt.ID,
|
|
Seq: pkt.Seq - p.sequence_base,
|
|
Seq: pkt.Seq - p.sequence_base,
|
|
|
|
+ Nbytes: pkt.Nbytes,
|
|
TTL: pkt.TTL,
|
|
TTL: pkt.TTL,
|
|
- ID: pkt.ID,
|
|
|
|
|
|
+ Rtt: pkt.Rtt,
|
|
}
|
|
}
|
|
if p.OnDuplicateRecv != nil {
|
|
if p.OnDuplicateRecv != nil {
|
|
p.OnDuplicateRecv(inpkt)
|
|
p.OnDuplicateRecv(inpkt)
|
|
@@ -628,27 +610,10 @@ func (p *Pinger) Statistics() *Statistics {
|
|
return &s
|
|
return &s
|
|
}
|
|
}
|
|
|
|
|
|
-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 {
|
|
func isIPv4(ip net.IP) bool {
|
|
return len(ip.To4()) == net.IPv4len
|
|
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()
|
|
var seed = time.Now().UnixNano()
|
|
|
|
|
|
// getSeed returns a goroutine-safe unique seed
|
|
// getSeed returns a goroutine-safe unique seed
|