Last active
April 18, 2024 11:45
-
-
Save lmas/c13d1c9de3b2224f9c26435eb56e6ef3 to your computer and use it in GitHub Desktop.
Simple utility package to send ICMP pings with Go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright © 2016 Alex | |
// | |
// This program is free software: you can redistribute it and/or modify it under | |
// the terms of the GNU Affero General Public License as published by the Free | |
// Software Foundation, either version 3 of the License, or (at your option) any | |
// later version. | |
// | |
// This program is distributed in the hope that it will be useful, but WITHOUT | |
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more | |
// details. | |
// | |
// You should have received a copy of the GNU Affero General Public License | |
// along with this program. If not, see <https://www.gnu.org/licenses/>. | |
package main | |
import ( | |
"fmt" | |
"log" | |
"net" | |
"os" | |
"time" | |
"golang.org/x/net/icmp" | |
"golang.org/x/net/ipv4" | |
) | |
func main() { | |
addr := "google.com" | |
dst, dur, err := Ping(addr) | |
if err != nil { | |
panic(err) | |
} | |
log.Printf("Ping %s (%s): %s\n", addr, dst, dur) | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
const ( | |
// Stolen from https://godoc.org/golang.org/x/net/internal/iana, | |
// can't import "internal" packages | |
ProtocolICMP = 1 | |
//ProtocolIPv6ICMP = 58 | |
) | |
// Default to listen on all IPv4 interfaces | |
var ListenAddr = "0.0.0.0" | |
// Mostly based on https://github.com/golang/net/blob/master/icmp/ping_test.go | |
// All ye beware, there be dragons below... | |
func Ping(addr string) (*net.IPAddr, time.Duration, error) { | |
// Start listening for icmp replies | |
c, err := icmp.ListenPacket("ip4:icmp", ListenAddr) | |
if err != nil { | |
return nil, 0, err | |
} | |
defer c.Close() | |
// Resolve any DNS (if used) and get the real IP of the target | |
dst, err := net.ResolveIPAddr("ip4", addr) | |
if err != nil { | |
panic(err) | |
return nil, 0, err | |
} | |
// Make a new ICMP message | |
m := icmp.Message{ | |
Type: ipv4.ICMPTypeEcho, Code: 0, | |
Body: &icmp.Echo{ | |
ID: os.Getpid() & 0xffff, Seq: 1, //<< uint(seq), // TODO | |
Data: []byte(""), | |
}, | |
} | |
b, err := m.Marshal(nil) | |
if err != nil { | |
return dst, 0, err | |
} | |
// Send it | |
start := time.Now() | |
n, err := c.WriteTo(b, dst) | |
if err != nil { | |
return dst, 0, err | |
} else if n != len(b) { | |
return dst, 0, fmt.Errorf("got %v; want %v", n, len(b)) | |
} | |
// Wait for a reply | |
reply := make([]byte, 1500) | |
err = c.SetReadDeadline(time.Now().Add(10 * time.Second)) | |
if err != nil { | |
return dst, 0, err | |
} | |
n, peer, err := c.ReadFrom(reply) | |
if err != nil { | |
return dst, 0, err | |
} | |
duration := time.Since(start) | |
// Pack it up boys, we're done here | |
rm, err := icmp.ParseMessage(ProtocolICMP, reply[:n]) | |
if err != nil { | |
return dst, 0, err | |
} | |
switch rm.Type { | |
case ipv4.ICMPTypeEchoReply: | |
return dst, duration, nil | |
default: | |
return dst, 0, fmt.Errorf("got %+v from %v; want echo reply", rm, peer) | |
} | |
} |
very helpful !!!
@tlhakhan sorry for such a late reply, probably missed a notification :(
This is old code by now, so of course any thoughts I had while writing it is now lost. Though I guess that check is for ICMP fragments, caused by poor connection or too large packet or yeah, some other fault on the host. A better way to handle it would be to retry sending it, instead of simply erroring out. But I think it was more for logging purposes.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Question:
On Line 59
Still learning deeper parts of golang, I'll give the icmp package a read.