diff --git a/pkg/hop/hop.go b/pkg/hop/hop.go index bffae85..d8d60ee 100644 --- a/pkg/hop/hop.go +++ b/pkg/hop/hop.go @@ -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, @@ -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)), diff --git a/pkg/icmp/icmp.go b/pkg/icmp/icmp.go index 1a0de16..3e61b76 100644 --- a/pkg/icmp/icmp.go +++ b/pkg/icmp/icmp.go @@ -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) @@ -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'), }, } @@ -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 } @@ -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) @@ -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'), }, } @@ -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 } @@ -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) @@ -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 } @@ -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) @@ -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 } @@ -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 } } } diff --git a/pkg/mtr/mtr.go b/pkg/mtr/mtr.go index 71942dc..b675cef 100644 --- a/pkg/mtr/mtr.go +++ b/pkg/mtr/mtr.go @@ -6,7 +6,6 @@ import ( "math" "math/rand" "net" - "os" "sync" "time" @@ -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() @@ -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) @@ -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 {