golang实现ping命令
//Copyright2009TheGoAuthors.Allrightsreserved.
//UseofthissourcecodeisgovernedbyaBSD-style
//licensethatcanbefoundintheLICENSEfile.
//takenfromhttp://golang.org/src/pkg/net/ipraw_test.go
packageping
import(
"bytes"
"errors"
"net"
"os"
"time"
)
const(
icmpv4EchoRequest=8
icmpv4EchoReply=0
icmpv6EchoRequest=128
icmpv6EchoReply=129
)
typeicmpMessagestruct{
Typeint//type
Codeint//code
Checksumint//checksum
BodyicmpMessageBody//body
}
typeicmpMessageBodyinterface{
Len()int
Marshal()([]byte,error)
}
//MarshalreturnsthebinaryencondingoftheICMPechorequestor
//replymessagem.
func(micmpMessage)Marshal()([]byte,error){
b:=[]byte{byte(m.Type),byte(m.Code),0,0}
ifm.Body!=nil&&m.Body.Len()!=0{
mb,err:=m.Body.Marshal()
iferr!=nil{
returnnil,err
}
b=append(b,mb...)
}
switchm.Type{
caseicmpv6EchoRequest,icmpv6EchoReply:
returnb,nil
}
csumcv:=len(b)-1//checksumcoverage
s:=uint32(0)
fori:=0;i s+=uint32(b[i+1])<<8|uint32(b[i])
}
ifcsumcv&1==0{
s+=uint32(b[csumcv])
}
s=s>>16+s&0xffff
s=s+s>>16
//Placechecksumbackinheader;using^=avoidsthe
//assumptionthechecksumbytesarezero.
b[2]^=byte(^s&0xff)
b[3]^=byte(^s>>8)
returnb,nil
}
//parseICMPMessageparsesbasanICMPmessage.
funcparseICMPMessage(b[]byte)(icmpMessage,error){
msglen:=len(b)
ifmsglen<4{
returnnil,errors.New("messagetooshort")
}
m:=&icmpMessage{Type:int(b[0]),Code:int(b[1]),Checksum:int(b[2])<<8|int(b[3])}
ifmsglen>4{
varerrerror
switchm.Type{
caseicmpv4EchoRequest,icmpv4EchoReply,icmpv6EchoRequest,icmpv6EchoReply:
m.Body,err=parseICMPEcho(b[4:])
iferr!=nil{
returnnil,err
}
}
}
returnm,nil
}
//imcpEchorepresenetsanICMPechorequestorreplymessagebody.
typeicmpEchostruct{
IDint//identifier
Seqint//sequencenumber
Data[]byte//data
}
func(picmpEcho)Len()int{
ifp==nil{
return0
}
return4+len(p.Data)
}
//MarshalreturnsthebinaryencondingoftheICMPechorequestor
//replymessagebodyp.
func(picmpEcho)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)
returnb,nil
}
//parseICMPEchoparsesbasanICMPechorequestorreplymessagebody.
funcparseICMPEcho(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])}
ifbodwww.baiyuewang.netylen>4{
p.Data=make([]byte,bodylen-4)
copy(p.Data,b[4:])
}
returnp,nil
}
funcPing(addressstring,timeoutint)(alivebool){
err:=Pinger(address,timeout)
alive=err==nil
return
}
funcPinger(addressstring,timeoutint)(errerror){
c,err:=net.Dial("ip4:icmp",address)
iferr!=nil{
return
}
c.SetDeadline(time.Now().Add(time.Duration(timeout)time.Second))
deferc.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("GoGoGadgetPing!!!"),3),
},
}).Marshal()
iferr!=nil{
return
}
if_,err=c.Write(wb);err!=nil{
return
}
varmicmpMessage
rb:=make([]byte,20+len(wb))
for{
if_,err=c.Read(rb);err!=nil{
return
}
rb=ipv4Payload(rb)
ifm,err=parseICMPMessage(rb);err!=nil{
return
}
switchm.Type{
caseicmpv4EchoRequest,icmpv6EchoRequest:
continue
}
break
}
return
}
funcipv4Payload(b[]byte)[]byte{
iflen(b)<20{
returnb
}
hdrlen:=int(b[0]&0x0f)<<2
returnb[hdrlen:]
}
|
|