I'm trying to implement small traceroute utility as part of some crossplatform project. But I've found that under Windows, Go doesn't see any TTL exceed messages on raw icmp socket, despite the fact that I see those packets in wireshark.
Here is a full test that passes under *nix and fails under Windows:
package probes
import (
"fmt"
"net"
"testing"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"time"
)
func TestTtlExceed(t *testing.T) {
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil {
t.Fatalf("Cannot listen: %s", err.Error())
}
defer conn.Close()
go listen(conn, t)
msg := icmp.Message{
Code: 0,
Body: &icmp.Echo{
Seq: 1,
ID: 1,
Data: []byte{'t','e','s','t'},
},
Type:ipv4.ICMPTypeEcho,
}
wbuf, err := msg.Marshal(nil)
if err != nil {
t.Fatalf("Failed to marshal: %s", err.Error())
}
conn.IPv4PacketConn().SetTTL(1)
err = conn.SetWriteDeadline(time.Now().Add(time.Second))
if err != nil {
t.Fatalf("Failed to set dl: %s", err.Error())
}
_, err = conn.WriteTo(wbuf, &net.IPAddr{IP:net.ParseIP("8.8.8.8")})
if err != nil {
t.Fatalf("Failed to write: %s", err.Error())
}
time.Sleep(time.Second * 3)
}
func listen(conn *icmp.PacketConn, t *testing.T) {
got := false
conn.SetReadDeadline(time.Now().Add(time.Second * 2))
for {
buf := make([]byte, 256)
n, cm, peer, err := conn.IPv4PacketConn().ReadFrom(buf)
if err != nil {
// t.Fatalf("Error reading: %s", err.Error())
t.Logf("Error reading: %s", err.Error())
break
}
fmt.Printf("Got some: n: %v\tpeer:%s\tcm:%+#v
", n, peer.String(),cm)
got = true
/*buf := make([]byte, 256)
n, peer, err := conn.ReadFrom(buf)
if err != nil {
t.Fatalf("Listen failed: %s
", err.Error())
return
}
fmt.Printf("icmp: got
")
parsed, err := icmp.ParseMessage(1, buf[:n])
if err != nil {
t.Fatalf("Failed to parse icmp message: %s", err.Error())
return
}
fmt.Printf("Got message from %s: %+#v
", peer.String(), parsed)*/
}
if !got {
t.Fatalf("Got nothing from conn")
}
}
Any ideas about what's wrong with windows icmp raw socket?