How to use Golang to compose a raw TCP packet (using gopacket) and send it through a raw socket

I would like to create custome TCP packets using gopacket and then send them using raw sockets.

Here is a short and readable example program that demonstrates what I would like to do:

package main import ( "code.google.com/p/gopacket" "code.google.com/p/gopacket/examples/util" "code.google.com/p/gopacket/layers" "log" "net" ) func main() { defer util.Run()() // XXX create tcp/ip packet srcIP := net.ParseIP("127.0.0.1") dstIP := net.ParseIP("192.168.0.1") //srcIPaddr := net.IPAddr{ // IP: srcIP, //} dstIPaddr := net.IPAddr{ IP: dstIP, } ipLayer := layers.IPv4{ SrcIP: srcIP, DstIP: dstIP, Protocol: layers.IPProtocolTCP, } tcpLayer := layers.TCP{ SrcPort: layers.TCPPort(666), DstPort: layers.TCPPort(22), SYN: true, } tcpLayer.SetNetworkLayerForChecksum(&ipLayer) buf := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{ FixLengths: true, ComputeChecksums: true, } err := gopacket.SerializeLayers(buf, opts, &ipLayer, &tcpLayer) if err != nil { panic(err) } // XXX end of packet creation // XXX send packet ipConn, err := net.ListenPacket("ip4:tcp", "0.0.0.0") if err != nil { panic(err) } _, err = ipConn.WriteTo(buf.Bytes(), &dstIPaddr) if err != nil { panic(err) } log.Print("packet sent!\n") } 

However, the execution of this program does not work ... SerializeLayer failed. Here's the panic:

panic: invalid src IP 127.0.0.1

goroutine 16 [running]: runtime.panic (0x5bb020, 0xc2090723e0) / home / human / golang -empire / go / src / pkg / runtime / panic.c: 279 + 0xf5 main.main () / home / human / golang - empire / gopkg / src / github.com / david415 / HoneyBadger / packetSendTest.go: 41 + 0x464

goroutine 19 [finalizer wait]: runtime.park (0x413cc0, 0x7bc6c0, 0x7bb189) / home / holang -empire / go / src / pkg / runtime / proc.c: 1369 + 0x89 runtime.parkunlock (0x7bc6c0, 0x7b18 human / golang -empire / go / src / pkg / runtime / proc.c: 1385 + 0x3b runfinq () / home / holang -empire / go / src / pkg / runtime / mgc0.c: 2644 + 0xcf runtime.goexit ( ) / home / human / golang -empire / go / src / pkg / runtime / proc.c: 1445

+6
source share
1 answer

You ask the question: “craft custome [sic] TCP packets”, but your code makes it clear that you also want to create custom IP-layer 3 headers, and there is a difference between them. Also, you don't mention IPv4 and IPv6, but again, your code seems IPv4 specific.

Given your sample code, I assume that you want to set the full IPv4 header.

As with Go 1.3.3 and Go 1.4 will be released soon, you cannot do what you want using Core Go packages. To accomplish what you need, you need to do two things:

  • You need to create the source socket in Go. Contrary to other incorrect answers on this site, you can create a raw socket in Go using one of net.ListenPacket , net.DialIP or net.ListenIP .

For instance:

 conn, err := net.ListenIP("ip4:tcp", netaddr) if err != nil { log.Fatalf("ListenIP: %s\n", err) } 

creates a raw socket.

  1. If you want to set your own IPv4 Layer 3 header, you will need to set the socket option to enable features.

Your question does not indicate which OS and architecture you are using. On my Mac OS X laptop:

 % man ip . . . Outgoing packets automatically have an IP header prepended to them (based on the destination address and the protocol number the socket is created with), unless the IP_HDRINCL option has been set. 

IP_HDRINCL also available on Linux. Unfortunately, Core Go is not able to set the IP_HDRINCL socket IP_HDRINCL and has no way to set other IP socket parameters, such as IP_TTL . I have a set of private patches that allow you to use this functionality with Core Go, but that won't help you.

I believe that the next package has all the necessary ipv4 functions. Pay attention to the large package, and I did not use it myself. I did grep and it supports IP_HDRINCL on several platforms. You want to call NewRawConn to create a raw connection, and this function creates a raw socket and sets the socket parameter IP_HDRINCL .

See also here: raw-sockets-in-go and the code he wrote here latency to get a feel for a much simpler approach that can satisfy your needs if you just want to set TCP headers. However, note that this code does not allow you to set the IP addresses in the IPv4 IP header, which I suspect you want to do.

+8
source

Source: https://habr.com/ru/post/978907/


All Articles