Skip to content

Instantly share code, notes, and snippets.

@artyom
Last active November 9, 2016 07:32
Show Gist options
  • Save artyom/eb6da83b46e10a4ac02f4146f44afd12 to your computer and use it in GitHub Desktop.
Save artyom/eb6da83b46e10a4ac02f4146f44afd12 to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"net"
"os"
"time"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
)
func main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, "usage: %v ip address\n", os.Args[0])
os.Exit(1)
}
addr := os.Args[1]
rtt, err := ping(addr)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Println(addr, rtt)
}
func ping(addr string) (time.Duration, error) {
dst := net.ParseIP(addr)
if dst == nil {
return 0, fmt.Errorf("%q is not a valid ip address", addr)
}
c, err := icmp.ListenPacket("udp4", "0.0.0.0")
if err != nil {
return 0, err
}
c.SetDeadline(time.Now().Add(3 * time.Second))
defer c.Close()
msg := icmp.Message{
Type: ipv4.ICMPTypeEcho,
Body: &icmp.Echo{
ID: os.Getpid() & 0xffff, Seq: 1,
Data: []byte("ping"),
},
}
b, err := msg.Marshal(nil)
if err != nil {
return 0, err
}
buf := make([]byte, 1500)
start := time.Now()
if _, err := c.WriteTo(b, &net.UDPAddr{IP: dst}); err != nil {
return 0, err
}
n, _, err := c.ReadFrom(buf)
if err != nil {
return 0, err
}
rtt := time.Since(start)
rm, err := icmp.ParseMessage(1, buf[:n])
if err != nil {
return 0, err
}
if rm.Type != ipv4.ICMPTypeEchoReply {
return 0, fmt.Errorf("got %+v; want echo reply\n", rm)
}
return rtt, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment