Enze Chi
Enze Chi

Reputation: 1763

How to get header bytes/length with gopacket

Try to use gopacket to create an Ethernet packet (ARP, BGP, UDP, TCP) and get the header bytes and length of it.

Try to play with the example as below, try to list all layers and find the payload location then workout the total header length and bytes:

package main

import (
    "fmt"
    "net"

    "github.com/google/gopacket"
    "github.com/google/gopacket/layers"
)

func main() {
    var (
        buffer  gopacket.SerializeBuffer
        options gopacket.SerializeOptions
    )

    // Create the layers
    ethernetLayer := &layers.Ethernet{
        SrcMAC:       net.HardwareAddr{0xff, 0xaa, 0xfa, 0xaa, 0xff, 0xaa},
        DstMAC:       net.HardwareAddr{0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd},
        EthernetType: layers.EthernetTypeIPv4,
    }
    ipLayer := &layers.IPv4{
        SrcIP: net.IP{192, 168, 1, 3},
        DstIP: net.IP{8, 8, 8, 8},
        // Version: 4,
        // IHL:     5,
        Length: 24,
    }
    tcpLayer := &layers.TCP{
        SrcPort: layers.TCPPort(4321),
        DstPort: layers.TCPPort(80),
    }
    fmt.Println(tcpLayer)
    payload := []byte{10, 20, 30, 40, 50, 60}
    buffer = gopacket.NewSerializeBuffer()
    gopacket.SerializeLayers(buffer, options, ethernetLayer, ipLayer, tcpLayer, gopacket.Payload(payload))
    outgoingPacket := buffer.Bytes()

    packet := gopacket.NewPacket(outgoingPacket, layers.LayerTypeEthernet, gopacket.Default)

    for _, layer := range packet.Layers() {
        fmt.Println("Packet layer:", layer.LayerType())
    }
}

I got the error as below:

Packet layer: Ethernet
Packet layer: IPv4
Packet layer: DecodeFailure

Did I do anything wrong there?

Can anyone give me any idea how can I get the header bytes?

Upvotes: 3

Views: 2026

Answers (1)

nothingmuch
nothingmuch

Reputation: 1516

Firstly, as implied by your commented out IPv4 fields, layer.Error() contains more information:

if withErr, ok := layer.(interface{ Error() error }); ok {
    fmt.Pritnln(withError.Error())
}

In this case, when the IHL field is set to 5, which denotes the header length in 4 byte words. Since you specified a length of 24, there is a mismatch between the calculated length in IHL and the supplied length and gopacket crashes trying to parse that as an IPv6 packet. You can adjust the length to 20 and the header length to 5 in which case it parses without error, but that does not contain the tcp fields.

gopacket is not really intended for generation of packets, but for parsing captured ones.

If you really want to do that manually, I suggest you read the relevant RFCs and make sure you cover the various options, calculate checksums, set protocol (6 for tcp), correct length (tcp packets actually have a 32 byte header if I'm not mistaken), etc, which is quite involved.

Under normal circumstances this should all be taken care of by your operating system's sockets. Why are you attempting to generate this manually?

Upvotes: 0

Related Questions