package main import ( "bytes" "flag" "log" "net" "os" "time" ) var targetAddr = flag.String("tgt", "127.0.0.1", "target address") func main() { flag.Parse() id := os.Getpid() & 0xffff exchangeICMPEcho(*targetAddr, newICMPEchoRequest(id, 1, 128, []byte("Go Go Gadget Ping!!!"))) } func exchangeICMPEcho(target string, echo []byte) { c, err := net.ListenPacket("ip4:icmp", "") // talk with anybody who interest in specified protocol if err != nil { log.Fatal(err) } c.SetDeadline(time.Now().Add(300 * time.Millisecond)) defer c.Close() taddr, err := net.ResolveIPAddr("ip4", target) if err != nil { log.Fatal(err) } _, err = c.WriteTo(echo, taddr) if err != nil { log.Fatal(err) } reply := make([]byte, 128) for { _, raddr, err := c.ReadFrom(reply) if err != nil { log.Fatal(err) } if !raddr.(*net.IPAddr).IP.Equal(taddr.IP) { continue } if reply[0] != ICMP4_ECHO_REPLY { continue } xid, xseqnum := parseICMPEchoReply(echo) rid, rseqnum := parseICMPEchoReply(reply) if rid != xid || rseqnum != xseqnum { log.Fatalf("MISMATCH: id = %v, seqnum = %v; expected id = %v, seqnum = %v", rid, rseqnum, xid, xseqnum) } log.Println("done") break } } const ( ICMP4_ECHO_REQUEST = 8 ICMP4_ECHO_REPLY = 0 ) func newICMPEchoRequest(id, seqnum, msglen int, filler []byte) []byte { b := newICMPInfoMessage(id, seqnum, msglen, filler) b[0] = ICMP4_ECHO_REQUEST // calculate ICMP checksum cklen := len(b) s := uint32(0) for i := 0; i < cklen-1; i += 2 { s += uint32(b[i+1])<<8 | uint32(b[i]) } if cklen&1 == 1 { s += uint32(b[cklen-1]) } s = (s >> 16) + (s & 0xffff) s = s + (s >> 16) // place checksum back in header; using ^= avoids the // assumption the checksum bytes are zero b[2] ^= uint8(^s & 0xff) b[3] ^= uint8(^s >> 8) return b } func newICMPInfoMessage(id, seqnum, msglen int, filler []byte) []byte { b := make([]byte, msglen) copy(b[8:], bytes.Repeat(filler, (msglen-8)/len(filler)+1)) b[0] = 0 // type b[1] = 0 // code b[2] = 0 // checksum b[3] = 0 // checksum b[4] = uint8(id >> 8) // identifier b[5] = uint8(id & 0xff) // identifier b[6] = uint8(seqnum >> 8) // sequence number b[7] = uint8(seqnum & 0xff) // sequence number return b } func parseICMPEchoReply(b []byte) (id, seqnum int) { id = int(b[4])<<8 | int(b[5]) seqnum = int(b[6])<<8 | int(b[7]) return }