in client.go [881:956]
func icmpRecvMsg(c net.PacketConn, proto EthrProtocol, timeout time.Duration, neededPeer string, neededSig []byte, neededIcmpBody []byte, neededIcmpSeq int) (string, bool, error) {
peerAddr := ""
isLast := false
err := c.SetDeadline(time.Now().Add(timeout))
if err != nil {
ui.printErr("Failed to set Deadline. Error: %v", err)
return peerAddr, isLast, err
}
for {
peerAddr = ""
b := make([]byte, 1500)
n, peer, err := c.ReadFrom(b)
if err != nil {
if proto == ICMP {
// In case of non-ICMP TraceRoute, it is expected that no packet is received
// in some case, e.g. when packet reach final hop and TCP connection establishes.
ui.printDbg("Failed to receive ICMP packet. Error: %v", err)
}
return peerAddr, isLast, err
}
if n == 0 {
continue
}
ui.printDbg("Packet:\n%s", hex.Dump(b[:n]))
ui.printDbg("Finding Pattern\n%v", hex.Dump(neededSig[:4]))
peerAddr = peer.String()
if neededPeer != "" && peerAddr != neededPeer {
ui.printDbg("Matching peer is not found.")
continue
}
icmpMsg, err := icmp.ParseMessage(IcmpProto(), b[:n])
if err != nil {
ui.printDbg("Failed to parse ICMP message: %v", err)
continue
}
if icmpMsg.Type == ipv4.ICMPTypeTimeExceeded || icmpMsg.Type == ipv6.ICMPTypeTimeExceeded {
body := icmpMsg.Body.(*icmp.TimeExceeded).Data
index := bytes.Index(body, neededSig[:4])
if index > 0 {
if proto == TCP {
ui.printDbg("Found correct ICMP error message. PeerAddr: %v", peerAddr)
return peerAddr, isLast, nil
} else if proto == ICMP {
if index < 4 {
ui.printDbg("Incorrect length of ICMP message.")
continue
}
innerIcmpMsg, _ := icmp.ParseMessage(IcmpProto(), body[index-4:])
switch innerIcmpMsg.Body.(type) {
case *icmp.Echo:
seq := innerIcmpMsg.Body.(*icmp.Echo).Seq
if seq == neededIcmpSeq {
return peerAddr, isLast, nil
}
default:
// Ignore as this is not the right ICMP packet.
ui.printDbg("Unable to recognize packet.")
}
}
} else {
ui.printDbg("Pattern %v not found.", hex.Dump(neededSig[:4]))
}
}
if proto == ICMP && (icmpMsg.Type == ipv4.ICMPTypeEchoReply || icmpMsg.Type == ipv6.ICMPTypeEchoReply) {
echo := icmpMsg.Body.(*icmp.Echo)
ethrUnused(echo)
b, _ := icmpMsg.Body.Marshal(1)
if string(b[4:]) != string(neededIcmpBody) {
continue
}
isLast = true
return peerAddr, isLast, nil
}
}
}