配色: 字号:
golang实现ping命令
2016-11-10 | 阅:  转:  |  分享 
  
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:]

}

献花(0)
+1
(本文系thedust79首藏)