Skip to content

Commit

Permalink
Fix collecting wrong replys
Browse files Browse the repository at this point in the history
  • Loading branch information
sj14 authored and tonobo committed Apr 22, 2021
1 parent b494630 commit 1c17592
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 28 deletions.
3 changes: 1 addition & 2 deletions pkg/hop/hop.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (h *HopStatistic) MarshalJSON() ([]byte, error) {
Sent: h.Sent,
TTL: h.TTL,
Loss: h.Loss(),
Target: fmt.Sprintf("%v", h.Targets), // TODO:
Target: fmt.Sprintf("%v", h.Targets),
PacketBufferSize: h.RingBufferSize,
Last: h.Last.Elapsed.Seconds() * 1000,
Best: h.Best.Elapsed.Seconds() * 1000,
Expand Down Expand Up @@ -143,7 +143,6 @@ func (h *HopStatistic) Render(ptrLookup bool) {
i--
})
l := fmt.Sprintf("%d", h.RingBufferSize)

gm.Printf("%3d:|-- %-20s %5.1f%% %4d %6.1f %6.1f %6.1f %6.1f %"+l+"s\n",
h.TTL,
fmt.Sprintf("%.20s", h.lookupAddr(ptrLookup, 0)),
Expand Down
46 changes: 28 additions & 18 deletions pkg/icmp/icmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ type ICMPReturn struct {
}

// SendDiscoverICMP sends a ICMP to a given destination with a TTL to discover hops
func SendDiscoverICMP(localAddr string, dst net.Addr, ttl, pid int, timeout time.Duration, seq int) (hop ICMPReturn, err error) {
return SendICMP(localAddr, dst, "", ttl, pid, timeout, seq)
func SendDiscoverICMP(localAddr string, dst net.Addr, ttl, id int, timeout time.Duration, seq int) (hop ICMPReturn, err error) {
return SendICMP(localAddr, dst, "", ttl, id, timeout, seq)
}

// SendDiscoverICMPv6 sends a ICMP to a given destination with a TTL to discover hops
func SendDiscoverICMPv6(localAddr string, dst net.Addr, ttl, pid int, timeout time.Duration, seq int) (hop ICMPReturn, err error) {
return SendICMPv6(localAddr, dst, "", ttl, pid, timeout, seq)
func SendDiscoverICMPv6(localAddr string, dst net.Addr, ttl, id int, timeout time.Duration, seq int) (hop ICMPReturn, err error) {
return SendICMPv6(localAddr, dst, "", ttl, id, timeout, seq)
}

// SendICMP sends a ICMP to a given destination which requires a reply from that specific destination
func SendICMP(localAddr string, dst net.Addr, target string, ttl, pid int, timeout time.Duration, seq int) (hop ICMPReturn, err error) {
func SendICMP(localAddr string, dst net.Addr, target string, ttl, id int, timeout time.Duration, seq int) (hop ICMPReturn, err error) {
hop.Success = false
start := time.Now()
c, err := icmp.ListenPacket("ip4:icmp", localAddr)
Expand All @@ -58,7 +58,7 @@ func SendICMP(localAddr string, dst net.Addr, target string, ttl, pid int, timeo
wm := icmp.Message{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: pid, Seq: seq,
ID: id, Seq: seq,
Data: append(bs, 'x'),
},
}
Expand All @@ -71,7 +71,7 @@ func SendICMP(localAddr string, dst net.Addr, target string, ttl, pid int, timeo
return hop, err
}

peer, _, err := listenForSpecific4(c, time.Now().Add(timeout), target, append(bs, 'x'), seq, wb)
peer, _, err := listenForSpecific4(c, time.Now().Add(timeout), target, append(bs, 'x'), id, seq, wb)
if err != nil {
return hop, err
}
Expand All @@ -84,7 +84,7 @@ func SendICMP(localAddr string, dst net.Addr, target string, ttl, pid int, timeo
}

// SendICMPv6 sends a ICMP to a given destination which requires a reply from that specific destination
func SendICMPv6(localAddr string, dst net.Addr, target string, ttl, pid int, timeout time.Duration, seq int) (hop ICMPReturn, err error) {
func SendICMPv6(localAddr string, dst net.Addr, target string, ttl, id int, timeout time.Duration, seq int) (hop ICMPReturn, err error) {
hop.Success = false
start := time.Now()
c, err := icmp.ListenPacket("ip6:ipv6-icmp", localAddr)
Expand All @@ -107,7 +107,7 @@ func SendICMPv6(localAddr string, dst net.Addr, target string, ttl, pid int, tim
wm := icmp.Message{
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
Body: &icmp.Echo{
ID: pid, Seq: seq,
ID: id, Seq: seq,
Data: append(bs, 'x'),
},
}
Expand All @@ -120,7 +120,7 @@ func SendICMPv6(localAddr string, dst net.Addr, target string, ttl, pid int, tim
return hop, err
}

peer, _, err := listenForSpecific6(c, time.Now().Add(timeout), target, append(bs, 'x'), seq, wb)
peer, _, err := listenForSpecific6(c, time.Now().Add(timeout), target, append(bs, 'x'), id, seq, wb)
if err != nil {
return hop, err
}
Expand All @@ -132,7 +132,7 @@ func SendICMPv6(localAddr string, dst net.Addr, target string, ttl, pid int, tim
return hop, err
}

func listenForSpecific6(conn *icmp.PacketConn, deadline time.Time, neededPeer string, neededBody []byte, needSeq int, sent []byte) (string, []byte, error) {
func listenForSpecific6(conn *icmp.PacketConn, deadline time.Time, neededPeer string, neededBody []byte, id, needSeq int, sent []byte) (string, []byte, error) {
for {
b := make([]byte, 1500)
n, peer, err := conn.ReadFrom(b)
Expand All @@ -159,10 +159,11 @@ func listenForSpecific6(conn *icmp.PacketConn, deadline time.Time, neededPeer st
x, _ := icmp.ParseMessage(ProtocolIPv6ICMP, body[40:])
switch x.Body.(type) {
case *icmp.Echo:
seq := x.Body.(*icmp.Echo).Seq
if seq == needSeq {
echoBody := x.Body.(*icmp.Echo)
if echoBody.Seq == needSeq && echoBody.ID == id {
return peer.String(), []byte{}, nil
}
continue
default:
// ignore
}
Expand All @@ -173,13 +174,17 @@ func listenForSpecific6(conn *icmp.PacketConn, deadline time.Time, neededPeer st
if string(b[4:]) != string(neededBody) {
continue
}
return peer.String(), b[4:], nil
echoBody := x.Body.(*icmp.Echo)
if echoBody.Seq == needSeq && echoBody.ID == id {
return peer.String(), b[4:], nil
}
continue
}
}
}

// listenForSpecific4 listens for a reply from a specific destination with a specifi body and returns the body if returned
func listenForSpecific4(conn *icmp.PacketConn, deadline time.Time, neededPeer string, neededBody []byte, needSeq int, sent []byte) (string, []byte, error) {
func listenForSpecific4(conn *icmp.PacketConn, deadline time.Time, neededPeer string, neededBody []byte, pid, needSeq int, sent []byte) (string, []byte, error) {
for {
b := make([]byte, 1500)
n, peer, err := conn.ReadFrom(b)
Expand Down Expand Up @@ -209,10 +214,11 @@ func listenForSpecific4(conn *icmp.PacketConn, deadline time.Time, neededPeer st
x, _ := icmp.ParseMessage(ProtocolICMP, body[index:])
switch x.Body.(type) {
case *icmp.Echo:
seq := x.Body.(*icmp.Echo).Seq
if seq == needSeq {
echoBody := x.Body.(*icmp.Echo)
if echoBody.Seq == needSeq && echoBody.ID == pid {
return peer.String(), []byte{}, nil
}
continue
default:
// ignore
}
Expand All @@ -224,7 +230,11 @@ func listenForSpecific4(conn *icmp.PacketConn, deadline time.Time, neededPeer st
if string(b[4:]) != string(neededBody) {
continue
}
return peer.String(), b[4:], nil
echoBody := x.Body.(*icmp.Echo)
if echoBody.Seq == needSeq && echoBody.ID == pid {
return peer.String(), b[4:], nil
}
continue
}
}
}
17 changes: 9 additions & 8 deletions pkg/mtr/mtr.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"math"
"math/rand"
"net"
"os"
"sync"
"time"

Expand Down Expand Up @@ -135,7 +134,6 @@ func (m *MTR) Render(offset int) {
gm.MoveCursor(1, offset)
l := fmt.Sprintf("%d", m.ringBufferSize)
gm.Printf("HOP: %-20s %5s%% %4s %6s %6s %6s %6s %"+l+"s\n", "Address", "Loss", "Sent", "Last", "Avg", "Best", "Worst", "Packets")

for i := 1; i <= len(m.Statistic); i++ {
gm.MoveCursor(1, offset+i)
m.mutex.RLock()
Expand All @@ -150,10 +148,13 @@ func (m *MTR) Run(ch chan struct{}, count int) {

// discover discovers all hops on the route
func (m *MTR) discover(ch chan struct{}, count int) {
rand.Seed(time.Now().Unix())
seq := rand.Intn(math.MaxInt16)
// Sequences are incrementing as we don't won't to get old replys which might be from a previous run (where we timed out and continued).
// We can't use the process id as unique identifier as there might be multiple runs within a single binary, thus we use a fixed pseudo random number.
rand.Seed(time.Now().UnixNano())
seq := rand.Intn(math.MaxUint16)
id := rand.Intn(math.MaxUint16) & 0xffff

ipAddr := net.IPAddr{IP: net.ParseIP(m.Address)}
pid := os.Getpid() & 0xffff

for i := 1; i <= count; i++ {
time.Sleep(m.interval)
Expand All @@ -165,15 +166,15 @@ func (m *MTR) discover(ch chan struct{}, count int) {
var hopReturn icmp.ICMPReturn
var err error
if ipAddr.IP.To4() != nil {
hopReturn, err = icmp.SendDiscoverICMP(m.SrcAddress, &ipAddr, ttl, pid, m.timeout, seq)
hopReturn, err = icmp.SendDiscoverICMP(m.SrcAddress, &ipAddr, ttl, id, m.timeout, seq)
} else {
hopReturn, err = icmp.SendDiscoverICMPv6(m.SrcAddress, &ipAddr, ttl, pid, m.timeout, seq)
hopReturn, err = icmp.SendDiscoverICMPv6(m.SrcAddress, &ipAddr, ttl, id, m.timeout, seq)
}

m.mutex.Lock()
s := m.registerStatistic(ttl, hopReturn)
s.Dest = &ipAddr
s.PID = pid
s.PID = id
m.mutex.Unlock()
ch <- struct{}{}
if hopReturn.Addr == m.Address {
Expand Down

0 comments on commit 1c17592

Please sign in to comment.