Skip to content

Commit

Permalink
Make use of returned imcp header in time exeeded
Browse files Browse the repository at this point in the history
  • Loading branch information
Maartje Eyskens committed Aug 24, 2018
1 parent 21fddbc commit dd39cdc
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 25 deletions.
13 changes: 3 additions & 10 deletions hop/hop.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ type HopStatistic struct {
Sent int
TTL int
Target string
TargetIP *net.IPAddr
Last imcp.ICMPReturn
Best imcp.ICMPReturn
Worst imcp.ICMPReturn
Expand All @@ -38,26 +37,20 @@ func (s *HopStatistic) Next() {
if s.Target == "" {
return
}
if s.TargetIP == nil {
addr, err := net.ResolveIPAddr("ip4", s.Target)
if err != nil {
return
}
s.TargetIP = addr
}
s.pingSeq++
r, _ := imcp.SendIMCP("0.0.0.0", s.TargetIP, s.PID, s.Timeout, s.pingSeq)
r, _ := imcp.SendIMCP("0.0.0.0", s.Dest, s.Target, s.TTL, s.PID, s.Timeout, s.pingSeq)
s.Packets = s.Packets.Prev()
s.Packets.Value = r

s.Sent++

s.Last = r
if !r.Success {
s.Lost++
return // do not count failed into statistics
}

s.SumElapsed = r.Elapsed + s.SumElapsed
s.Last = r

if s.Best.Elapsed > r.Elapsed {
s.Best = r
Expand Down
38 changes: 23 additions & 15 deletions imcp/icmp.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package imcp

import (
"errors"
"bytes"
"fmt"
"net"
"time"
Expand Down Expand Up @@ -35,7 +35,7 @@ func SendDiscoverIMCP(localAddr string, dst net.Addr, ttl, pid int, timeout time
wm := icmp.Message{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: pid, Seq: 1,
ID: pid, Seq: seq,
Data: []byte(""),
},
}
Expand All @@ -61,14 +61,15 @@ func SendDiscoverIMCP(localAddr string, dst net.Addr, ttl, pid int, timeout time
}

// SendIMCP sends a IMCP to a given destination
func SendIMCP(localAddr string, dst net.Addr, pid int, timeout time.Duration, seq int) (hop ICMPReturn, err error) {
func SendIMCP(localAddr string, dst net.Addr, target string, ttl, pid int, timeout time.Duration, seq int) (hop ICMPReturn, err error) {
hop.Success = false
start := time.Now()
c, err := icmp.ListenPacket("ip4:icmp", localAddr)
if err != nil {
return hop, err
}
defer c.Close()
c.IPv4PacketConn().SetTTL(ttl)
err = c.SetDeadline(time.Now().Add(timeout))
if err != nil {
return hop, err
Expand All @@ -78,7 +79,7 @@ func SendIMCP(localAddr string, dst net.Addr, pid int, timeout time.Duration, se
wm := icmp.Message{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: pid, Seq: 0,
ID: pid, Seq: seq,
Data: []byte(body),
},
}
Expand All @@ -91,26 +92,26 @@ func SendIMCP(localAddr string, dst net.Addr, pid int, timeout time.Duration, se
return hop, err
}

_, err = listenForSpecific(c, time.Now().Add(timeout), dst.String(), body)
peer, _, err := listenForSpecific(c, time.Now().Add(timeout), target, body, seq, wb)
if err != nil {
return hop, err
}

elapsed := time.Since(start)
hop.Elapsed = elapsed
hop.Addr = dst.String()
hop.Addr = peer
hop.Success = true
return hop, err
}

// listenForSpecific listens for a reply from a specific destination with a specifi body and returns the body if returned
func listenForSpecific(conn *icmp.PacketConn, deadline time.Time, neededPeer, neededBody string) (string, error) {
func listenForSpecific(conn *icmp.PacketConn, deadline time.Time, neededPeer, neededBody string, needSeq int, sent []byte) (string, string, error) {
for {
bytes := make([]byte, 1500)
n, peer, err := conn.ReadFrom(bytes)
b := make([]byte, 1500)
n, peer, err := conn.ReadFrom(b)
if err != nil {
if neterr, ok := err.(*net.OpError); ok {
return "", neterr
return "", "", neterr
}
}
if n == 0 {
Expand All @@ -121,23 +122,30 @@ func listenForSpecific(conn *icmp.PacketConn, deadline time.Time, neededPeer, ne
continue
}

x, err := icmp.ParseMessage(1, bytes[:n])
x, err := icmp.ParseMessage(1, b[:n])
if err != nil {
continue
}

if x.Type.(ipv4.ICMPType).String() == "time exceeded" {
return "", errors.New("time exceeded")
body := x.Body.(*icmp.TimeExceeded).Data

index := bytes.Index(body, sent[:4])
if index > 0 {
x, _ := icmp.ParseMessage(1, body[index:])
seq := x.Body.(*icmp.Echo).Seq
if seq == needSeq {
return peer.String(), "", nil
}
}
}

if x.Type.(ipv4.ICMPType).String() == "echo reply" {
b, _ := x.Body.Marshal(1)
if string(b[4:]) != neededBody {
continue
}
return string(b[4:]), nil
return peer.String(), string(b[4:]), nil
}

panic(x.Type.(ipv4.ICMPType).String())
}
}

0 comments on commit dd39cdc

Please sign in to comment.