This is a creation in
Article, where the information may have evolved or changed.
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// taken from http://golang.org/src/pkg/net/ipraw_test.go
package ping
import (
"bytes"
"errors"
"net"
"os"
"time"
)
const (
icmpv4EchoRequest = 8
icmpv4EchoReply = 0
icmpv6EchoRequest = 128
icmpv6EchoReply = 129
)
type icmpMessage struct {
Type int // type
Code int // code
Checksum int // checksum
Body icmpMessageBody // body
}
type icmpMessageBody interface {
Len() int
Marshal() ([]byte, error)
}
//Marshal returns the binary enconding of the ICMP echo request or
//reply message M.
func (M *ICMPMESSAG e) Marshal ([]byte, error) {
b: = []byte{byte (M.type), Byte (M.code), 0, 0}
If m.body! = Nil && M.body.le N ()! = 0 {
MB, err: = M.body.marshal ()
if err! = Nil {
return nil, err
}
B = Append (b, mb ...)
}
Switch M.type {
Case icmpv6echorequest, icmpv6echoreply:
return B, nil
}
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
//Place checksum back in header; using ^= avoids the
//assumption the checksum bytes is Z Ero.
B[2] ^= byte (^s & 0xFF)
B[3] ^= byte (^s >> 8)
return B, nil
}
// parseICMPMessage parses b as an ICMP message.
func parseICMPMessage(b []byte) (*icmpMessage, error) {
msglen := len(b)
if msglen < 4 {
return nil, errors.New("message too short")
}
m := &icmpMessage{Type: int(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
if msglen > 4 {
var err error
switch m.Type {
case icmpv4EchoRequest, icmpv4EchoReply, icmpv6EchoRequest, icmpv6EchoReply:
m.Body, err = parseICMPEcho(b[4:])
if err != nil {
return nil, err
}
}
}
return m, nil
}
// imcpEcho represenets an ICMP echo request or reply message body.
type icmpEcho struct {
ID int // identifier
Seq int // sequence number
Data []byte // data
}
func (p *icmpEcho) Len() int {
if p == nil {
return 0
}
return 4 + len(p.Data)
}
// Marshal returns the binary enconding of the ICMP echo request or
// reply message body p.
func (p *icmpEcho) Marshal() ([]byte, error) {
b := make([]byte, 4+len(p.Data))
b[0], b[1] = byte(p.ID>>8), byte(p.ID&0xff)
b[2], b[3] = byte(p.Seq>>8), byte(p.Seq&0xff)
copy(b[4:], p.Data)
return b, nil
}
// parseICMPEcho parses b as an ICMP echo request or reply message body.
func parseICMPEcho(b []byte) (*icmpEcho, error) {
bodylen := len(b)
p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
if bodylen > 4 {
p.Data = make([]byte, bodylen-4)
copy(p.Data, b[4:])
}
return p, nil
}
func Ping(address string, timeout int) (alive bool) {
err := Pinger(address, timeout)
alive = err == nil
return
}
func Pinger(address string, timeout int) (err error) {
c, err := net.Dial("ip4:icmp", address)
if err != nil {
return
}
c.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Second))
defer c.Close()
Typ: = Icmpv4echorequest
XID, xseq: = OS. Getpid () &0XFFFF, 1
WB, err: = (&icmpmessage{
Type:typ, code:0,
Body: &icmpecho{
Id:xid, Seq:xseq,
data:bytes. Repeat ([]byte ("Go Go Gadget Ping!!!"), 3),
},
}). Marshal ()
If err! = Nil {
return
}
If _, err = C.write (WB); Err! = nil {
return
}
var m *icmpmessage
RB: = Make ([]byte, 20+len (WB)]
for {
if _, err = C.read (RB); Err! = Nil {
&NBSP;&N Bsp Return
}
RB = Ipv4payload (RB)
if m, err = Parseicmpmessage (RB); Err! = Nil {
Return
}
switch m.type {
case icmpv4echorequest, Icmpv6echorequest:
Continue
}
Break
}
return
}
func ipv4payload (b []byte) []byte {
If Len (b) < {
return b
}
Hdrlen: = Int (b[0]&0 x0f) << 2
Return B[hdrlen:]
}