for (;;) { unsignedchar data[2048]; int rc; structtimevaltimeout = {3, 0}; //wait max 3 seconds for a reply fd_set read_set; socklen_t slen; structicmphdrrcv_hdr;
funcchecksum(b []byte)uint16 { csumcv := len(b) - 1// checksum coverage s := uint32(0) for i := 0; i < csumcv; i += 2 { s += uint32(b[i+1])<<8 | uint32(b[i]) } if csumcv&1 == 0 { s += uint32(b[csumcv]) } s = s>>16 + s&0xffff s = s + s>>16 return ^uint16(s) }
ip := net.ParseIP(os.Args[1]) if !isIPv4(ip) && !isIPv6(ip) { addrs, err := net.LookupHost(os.Args[1]) if err != nil { fmt.Printf("name or service not known: %v\n", err) os.Exit(1) } ip = net.ParseIP(addrs[0]) }
var proto int var conn *icmp.PacketConn var err error switch { case isIPv4(ip): conn, err = icmp.ListenPacket("ip4:icmp", "0.0.0.0") proto = ProtocolICMP case isIPv6(ip): conn, err = icmp.ListenPacket("ip6:icmp", "0.0.0.0") proto = ProtocolIPv6ICMP default: log.Fatalln("unreachable") } if err != nil { fmt.Printf("failed to ListenPacket: %v\n", err) os.Exit(1) }
lastSeq := 0 for { lastID := rand.Intn(0xffff) lastSeq++ bytes_, err := (&icmp.Message{ Type: ipv4.ICMPTypeEcho, Code: 0, Body: &icmp.Echo{ ID: lastID, Seq: lastSeq, Data: timeToBytes(time.Now()), }, }).Marshal(nil) if err != nil { log.Fatalf("unexpected: %v\n", err) } retry: if _, err := conn.WriteTo(bytes_, &net.IPAddr{IP: ip}); err != nil { if neterr, ok := err.(*net.OpError); ok { if neterr.Err == syscall.ENOBUFS { goto retry } } log.Fatalf("unexpected: %v\n", err) }
// 收包 b := make([]byte, 2048) for { n, ra, err := conn.ReadFrom(b) if err != nil { log.Fatalf("unexpected: %v\n", err) }
raAddr := ra.(*net.IPAddr) var protoResp int if isIPv4(raAddr.IP) { protoResp = ProtocolICMP } else { protoResp = ProtocolIPv6ICMP }
// 不匹配的协议, 直接跳过 if proto != protoResp { continue }
// 解包错误, 视为丢包 m, err := icmp.ParseMessage(protoResp, b[:n]) if err != nil { fmt.Printf("packet loss\n") continue }
funcmain() { // Tracing an IP packet route to www.baidu.com.
const host = "baidu.com" ips, err := net.LookupIP(host) if err != nil { log.Fatal(err) } var dst net.IPAddr for _, ip := range ips { if ip.To4() != nil { dst.IP = ip fmt.Printf("using %v for tracing an IP packet route to %s\n", dst.IP, host) break } } if dst.IP == nil { log.Fatal("no A record found") }
c, err := net.ListenPacket("ip4:1", "0.0.0.0") // ICMP for IPv4 if err != nil { log.Fatal(err) } defer c.Close() p := ipv4.NewPacketConn(c)
rb := make([]byte, 1500) for i := 1; i <= 64; i++ { // up to 64 hops wm.Body.(*icmp.Echo).Seq = i wb, err := wm.Marshal(nil) if err != nil { log.Fatal(err) } if err := p.SetTTL(i); err != nil { log.Fatal(err) }
// In the real world usually there are several // multiple traffic-engineered paths for each hop. // You may need to probe a few times to each hop. begin := time.Now() if _, err := p.WriteTo(wb, nil, &dst); err != nil { log.Fatal(err) } if err := p.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil { log.Fatal(err) } n, cm, peer, err := p.ReadFrom(rb) if err != nil { if err, ok := err.(net.Error); ok && err.Timeout() { fmt.Printf("%v\t*\n", i) continue } log.Fatal(err) } rm, err := icmp.ParseMessage(1, rb[:n]) if err != nil { log.Fatal(err) } rtt := time.Since(begin)
// In the real world you need to determine whether the // received message is yours using ControlMessage.Src, // ControlMessage.Dst, icmp.Echo.ID and icmp.Echo.Seq. switch rm.Type { case ipv4.ICMPTypeTimeExceeded: names, _ := net.LookupAddr(peer.String()) fmt.Printf("%d\t%v %+v %v\n\t%+v\n", i, peer, names, rtt, cm) case ipv4.ICMPTypeEchoReply: names, _ := net.LookupAddr(peer.String()) fmt.Printf("%d\t%v %+v %v\n\t%+v\n", i, peer, names, rtt, cm) return default: log.Printf("unknown ICMP message: %+v\n", rm) } } }