当前位置: 首页 > Linux

golang使用rawsockets构造UDP包

时间:2023-04-06 19:06:18 Linux

RAWSOCKET简介在TCP/IP协议中,最常见的有raw(SOCKET_RAW)、tcp(SOCKET_STREAM)、udp(SOCKET_DGRA)sockets。Rawsockets可以控制底层传输,允许数据包自组装,比如修改本地IP,发送Ping包,进行网络监控等。这里就不做详细介绍了,想了解的可以自行上网查看。要实现这个,首先看IP头结构:16位的总长度包括IP头的长度和数据的长度,8位协议填17,因为UDP协议类型是17.这里我想说明一下IP头中的headercheck。该值只检查IP头,不包含数据。这里给出校验算法,IP头和UDP头使用的校验算法是一样的。funccheckSum(msg[]byte)uint16{sum:=0forn:=1;n>16)+(sum&0xffff)sum+=(sum>>16)varans=uint16(^sum)returnans}下面开始填写IP头,这里用到了golang.org/x/net//destinationIP下的ipv4包dst:=net.IPv4(192,168,1,2)//源IPsrc:=net.IPv4(192,168,1,3)//填写ip头iph:=&ipv4.Header{Version:ipv4.Version,//IP头长度一般为20Len:ipv4.HeaderLen,TOS:0x00,//buff是数据TotalLen:ipv4.HeaderLen+len(buff),TTL:64,Flags:ipv4.DontFragment,FragOff:0,Protocol:17,Checksum:0,Src:src,Dst:dst,}h,err:=iph.Marshal()iferr!=nil{log.Fatalln(err)}//计算IP头的校验和值iph.Checksum=int(checkSum(h))接下来开始处理UDP头,先看UDP头的结构:UDP的结构header很简单,16-bitUDPchecksum涉及一个UDPpseudo-header。我们先来看一下UDP伪头的结构。程----------------------------------------|32bit源IP地址|--------------------------------------|32位目标IP地址|-------------------------------------------|0|8位原型|16bitheaderlength|----------------------------------------伪头包含源IP,目的IP,协议号,长度为16位。这个伪头只参与校验和的计算。下面开始填充UDP头://填充udp头//udp伪头udph:=make([]byte,20)//源ip地址udph[0],udph[1],udph[2],udph[3]=src[12],src[13],src[14],src[15]//目的ip地址udph[4],udph[5],udph[6],udph[7]=dst.IP[12],dst.IP[13],dst.IP[14],dst.IP[15]//协议类型udph[8],udph[9]=0x00,0x11//udp头长度udph[10],udph[11]=0x00,byte(len(buff)+8)//真正的udp头从下面开始//源端口号udph[12],udph[13]=0x27,0x10//目的端口号udph[14],udph[15]=0x17,0x70//udp头长度udph[16],udph[17]=0x00,byte(len(buff)+8)//校验和udph[18],udph[19]=0x00,0x00//计算校验值check:=checkSum(append(udph,buff...))udph[18],udph[19]=byte(check>>8&255),byte(check&255)below我们需要发送自己构造的UDP包,可以使用net下的ListenPacket。listener,err:=net.ListenPacket("ip4:udp","192.168.1.104")iferr!=nil{log.Fatal(err)}deferlistener.Close()//listener实现net.PacketConn接口r,err:=ipv4.NewRawConn(c)iferr!=nil{log.Fatal(err)}//发送自己构造的UDP包iferr=r.WriteTo(iph,append(udph[12:20],buff...),零);err!=nil{log.Fatal(err)}这个实现只在linux和mac上测试过。Windows需要依赖第三方,比如winpcap。结束语这里只给出了UDP的实现,TCP的实现比较复杂,以后会给出TCP实现的例子。