3 // Copyright 2009 The Go Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
7 // taken from http://golang.org/src/pkg/net/ipraw_test.go
17 func testPing(ip
string, config
*ScanConfig
, record
*ScanRecord
) bool {
19 if err
:= Pinger(ip
, config
.ScanMaxRTT
); err
!= nil {
22 if rtt
:= time
.Since(start
); rtt
> config
.ScanMinRTT
{
32 icmpv6EchoRequest
= 128
36 var ErrPingConnFailed
= errors
.New("ping: connect failed")
38 type icmpMessage
struct {
41 Checksum
int // checksum
42 Body icmpMessageBody
// body
45 type icmpMessageBody
interface {
47 Marshal() ([]byte, error
)
50 // Marshal returns the binary enconding of the ICMP echo request or
52 func (m
*icmpMessage
) Marshal() ([]byte, error
) {
53 b
:= []byte{byte(m
.Type
), byte(m
.Code
), 0, 0}
54 if m
.Body
!= nil && m
.Body
.Len() != 0 {
55 mb
, err
:= m
.Body
.Marshal()
62 case icmpv6EchoRequest
, icmpv6EchoReply
:
65 csumcv
:= len(b
) - 1 // checksum coverage
67 for i
:= 0; i
< csumcv
; i
+= 2 {
68 s
+= uint32(b
[i
+1])<<8 |
uint32(b
[i
])
71 s
+= uint32(b
[csumcv
])
75 // Place checksum back in header; using ^= avoids the
76 // assumption the checksum bytes are zero.
77 b
[2] ^= byte(^s
& 0xff)
82 // parseICMPMessage parses b as an ICMP message.
83 func parseICMPMessage(b
[]byte) (*icmpMessage
, error
) {
86 return nil, errors
.New("message too short")
88 m
:= &icmpMessage
{Type
: int(b
[0]), Code
: int(b
[1]), Checksum
: int(b
[2])<<8 |
int(b
[3])}
92 case icmpv4EchoRequest
, icmpv4EchoReply
, icmpv6EchoRequest
, icmpv6EchoReply
:
93 m
.Body
, err
= parseICMPEcho(b
[4:])
102 // imcpEcho represenets an ICMP echo request or reply message body.
103 type icmpEcho
struct {
105 Seq
int // sequence number
109 func (p
*icmpEcho
) Len() int {
113 return 4 + len(p
.Data
)
116 // Marshal returns the binary enconding of the ICMP echo request or
117 // reply message body p.
118 func (p
*icmpEcho
) Marshal() ([]byte, error
) {
119 b
:= make([]byte, 4+len(p
.Data
))
120 b
[0], b
[1] = byte(p
.ID
>>8), byte(p
.ID
&0xff)
121 b
[2], b
[3] = byte(p
.Seq
>>8), byte(p
.Seq
&0xff)
126 // parseICMPEcho parses b as an ICMP echo request or reply message body.
127 func parseICMPEcho(b
[]byte) (*icmpEcho
, error
) {
129 p
:= &icmpEcho
{ID
: int(b
[0])<<8 |
int(b
[1]), Seq
: int(b
[2])<<8 |
int(b
[3])}
131 p
.Data
= make([]byte, bodylen
-4)
137 func Ping(address
string, timeout time
.Duration
) error
{
138 return Pinger(address
, timeout
)
141 func Pinger(address
string, timeout time
.Duration
) error
{
142 typ
:= icmpv4EchoRequest
143 network
:= "ip4:icmp"
146 if ip
:= net
.ParseIP(address
); ip
!= nil && ip
.To4() == nil {
147 typ
= icmpv6EchoRequest
148 network
= "ip6:ipv6-icmp"
152 c
, err
:= net
.Dial(network
, address
)
154 return ErrPingConnFailed
157 deadline
:= time
.Now().Add(timeout
)
158 c
.SetReadDeadline(deadline
)
160 xid
, xseq
:= os
.Getpid()&0xffff, 1
161 wb
, err
:= (&icmpMessage
{
165 Data
: bytes
.Repeat([]byte("Go Go Gadget Ping!!!"), 3),
171 if _
, err
= c
.Write(wb
); err
!= nil {
175 rb
:= make([]byte, 20+len(wb
))
177 // read_timeout := deadline.Sub(time.Now())
178 // c.SetReadDeadline(time.Now().Add(read_timeout))
179 if _
, err
= c
.Read(rb
); err
!= nil {
185 if m
, err
= parseICMPMessage(rb
); err
!= nil {
189 case icmpv4EchoRequest
, icmpv6EchoRequest
:
197 func ipv4Payload(b
[]byte) []byte {
201 hdrlen
:= int(b
[0]&0x0f) << 2