Не удается добавить пользовательский слой в пакет из захвата

Я пытаюсь реализовать свой собственный уровень декодирования поверх TCP, пока он работает только тогда, когда я создаю пакет без какого-либо заголовка Eth/IP/TCP и вручную устанавливаю его уровень на свой пользовательский уровень. Данные пользовательского протокола находятся внутри обычной полезной нагрузки TCP.

Как мне декодировать только полезную нагрузку уровня TCP как другой уровень?

package main

import (
    "fmt"
    "github.com/google/gopacket"
    "github.com/google/gopacket/pcap"
)

var (
    pcapFile string = "capt.pcap"
    handle   *pcap.Handle
    err      error
)

type CustomLayer struct {
    SomeByte    byte
    AnotherByte byte
    restOfData  []byte
}

var CustomLayerType = gopacket.RegisterLayerType(
    2001,
    gopacket.LayerTypeMetadata{
        "CustomLayerType",
        gopacket.DecodeFunc(decodeCustomLayer),
    },
)

func (l CustomLayer) LayerType() gopacket.LayerType {
    return CustomLayerType
}

func (l CustomLayer) LayerContents() []byte {
    return []byte{l.SomeByte, l.AnotherByte}
}

func (l CustomLayer) LayerPayload() []byte {
    return l.restOfData
}

func decodeCustomLayer(data []byte, p gopacket.PacketBuilder) error {
    p.AddLayer(&CustomLayer{data[0], data[1], data[2:]})

    // nil means this is the last layer. No more decoding
    return nil
}

func main() {
    handle, err = pcap.OpenOffline(pcapFile)
    if err != nil {
        log.Fatal(err)
    }
    defer handle.Close()

    packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    for packet := range packetSource.Packets() {
        tcpLayer := packet.Layer(layers.LayerTypeTCP)
        if tcpLayer != nil {
            fmt.Println("TCP layer detected.")
            tcp, _ := tcpLayer.(*layers.TCP)
            fmt.Println("Sequence number: ", tcp.Seq)
            customLayer := packet.Layer(CustomLayerType)
            if customLayer != nil { // always nil
                customLayerContent, _ := customLayer.(*CustomLayer)
                // Now we can access the elements of the custom struct
                fmt.Println("Payload: ", customLayerContent.LayerPayload())
                fmt.Println("SomeByte element:", customLayerContent.SomeByte)
                fmt.Println("AnotherByte element:", customLayerContent.AnotherByte)
            }
        }
        fmt.Println()
    }
}

Большая часть кода взята из этого замечательного поста devdungeon.

1 ответ

Решение

Поскольку никто не ответил, я собираюсь ответить на него сам сейчас.

В основном у нас есть 3 варианта, чтобы справиться с этим:

  1. Создайте расширенный слой TCP, который обрабатывает наши дополнительные байты, и переопределите один по умолчанию, установив layers.LinkTypeMetadata[layers.LinkTypeTCP] к нашей расширенной версии. Посмотрите на этот пример.

  2. Создайте новый пакет из полезной нагрузки TCP, используя gopacket.NewPacket установка firstLayerDecoder в CustomLayerType и декодировать это нормально.

  3. Поскольку вам в основном не нужен фактический слой, а вместо этого заполненная структура CustomLayer просто напишите DecodeBytesToCustomStruct функция, где вы передаете полезную нагрузку TCP. Таким образом, мы можем даже вернуть несколько структур из одного пакета, что иначе было бы невозможно.

Опустить весь код CustomLayer сверху.

type CustomStruct struct {
    SomeByte    byte
    AnotherByte byte
    restOfData  []byte
}

func (customStruct *CustomStruct) DecodeStructFromBytes(data []byte) error { 
    customStruct.SomeByte = data[0]
    customStruct.AnotherByte = data[1]
    customStruct.restOfData = data[2:]
    return nil
}

В вашем main.go

for packet := range packetSource.Packets() {
    tcpLayer := packet.Layer(layers.LayerTypeTCP)
    if tcpLayer != nil {
        tcp, _ := tcpLayer.(*layers.TCP)
        if tcp.Payload != nil && len(tcpLayer.Payload) > 0 {
            customStruct := CustomStruct{}
            customStruct.DecodeStructFromBytes(tcp.Payload)
            fmt.Println("SomeByte element:", customStruct.SomeByte)
        }
    }
}

tcp.Payload такой же как packet.ApplicationLayer().Payload()

Другие вопросы по тегам