Improve packet parsing

This commit is contained in:
Daniel 2021-03-29 13:39:36 +02:00
parent 3abaca1d90
commit 5d61b7b682
6 changed files with 62 additions and 21 deletions

View file

@ -179,11 +179,13 @@ func (q *Queue) packetHandler(ctx context.Context) func(nfqueue.Attribute) int {
verdictPending: abool.New(),
}
if attrs.Payload != nil {
pkt.Payload = *attrs.Payload
if attrs.Payload == nil {
// There is not payload.
log.Warningf("nfqueue: packet #%s has no payload", pkt.pktID)
return 0
}
if err := pmpacket.Parse(pkt.Payload, pkt.Info()); err != nil {
if err := pmpacket.Parse(*attrs.Payload, &pkt.Base); err != nil {
log.Warningf("nfqueue: failed to parse payload: %s", err)
_ = pkt.Drop()
return 0

View file

@ -65,6 +65,11 @@ func (pkt *packet) ID() string {
return fmt.Sprintf("pkt:%d qid:%d", pkt.pktID, pkt.queue.id)
}
// LoadPacketData does nothing on Linux, as data is always fully parsed.
func (pkt *packet) LoadPacketData() error {
return nil
}
// TODO(ppacher): revisit the following behavior:
// The legacy implementation of nfqueue (and the interception) module
// always accept a packet but may mark it so that a subsequent rule in

View file

@ -230,6 +230,7 @@ func GetPayload(packetID uint32, packetSize uint32) ([]byte, error) {
if packetSize < uint32(len(buf)) {
return buf[:packetSize], nil
}
return buf, nil
}

View file

@ -24,7 +24,7 @@ type Packet struct {
}
// GetPayload returns the full raw packet.
func (pkt *Packet) GetPayload() ([]byte, error) {
func (pkt *Packet) LoadPacketData() error {
pkt.lock.Lock()
defer pkt.lock.Unlock()
@ -33,17 +33,21 @@ func (pkt *Packet) GetPayload() ([]byte, error) {
payload, err := GetPayload(pkt.verdictRequest.id, pkt.verdictRequest.packetSize)
if err != nil {
log.Tracer(pkt.Ctx()).Warningf("windowskext: failed to load payload %s", err)
log.Errorf("windowskext: failed to load payload %s", err)
return nil, packet.ErrFailedToLoadPayload
log.Tracer(pkt.Ctx()).Warningf("windowskext: failed to load payload: %s", err)
return packet.ErrFailedToLoadPayload
}
err = packet.Parse(payload, &pkt.Base)
if err != nil {
log.Tracer(pkt.Ctx()).Warningf("windowskext: failed to parse payload: %s", err)
return packet.ErrFailedToLoadPayload
}
pkt.Payload = payload
}
if len(pkt.Payload) == 0 {
return nil, packet.ErrFailedToLoadPayload
if len(pkt.Raw()) == 0 {
return packet.ErrFailedToLoadPayload
}
return pkt.Payload, nil
return nil
}
// Accept accepts the packet.

View file

@ -4,14 +4,18 @@ import (
"context"
"fmt"
"net"
"github.com/google/gopacket"
)
// Base is a base structure for satisfying the Packet interface.
type Base struct {
ctx context.Context
info Info
connID string
Payload []byte
ctx context.Context
info Info
connID string
layers gopacket.Packet
layer3Data []byte
layer5Data []byte
}
// SetCtx sets the packet context.
@ -65,9 +69,24 @@ func (pkt *Base) HasPorts() bool {
return false
}
// GetPayload returns the packet payload. In some cases, this will fetch the payload from the os integration system.
func (pkt *Base) GetPayload() ([]byte, error) {
return pkt.Payload, ErrFailedToLoadPayload
// LoadPacketData loads packet data from the integration, if not yet done.
func (pkt *Base) LoadPacketData() error {
return ErrFailedToLoadPayload
}
// Layers returns the parsed layer data.
func (pkt *Base) Layers() gopacket.Packet {
return pkt.layers
}
// Raw returns the raw Layer 3 Network Data.
func (pkt *Base) Raw() []byte {
return pkt.layer3Data
}
// Payload returns the raw Layer 5 Network Data.
func (pkt *Base) Payload() []byte {
return pkt.layer5Data
}
// GetConnectionID returns the link ID for this packet.
@ -214,9 +233,14 @@ type Packet interface {
SetInbound()
SetOutbound()
HasPorts() bool
GetPayload() ([]byte, error)
GetConnectionID() string
// PAYLOAD
LoadPacketData() error
Layers() gopacket.Packet
Raw() []byte
Payload() []byte
// MATCHING
MatchesAddress(bool, IPProtocol, *net.IPNet, uint16) bool
MatchesIP(bool, *net.IPNet) bool

View file

@ -102,10 +102,11 @@ func checkError(packet gopacket.Packet, _ *Info) error {
}
// Parse parses an IP packet and saves the information in the given packet object.
func Parse(packetData []byte, pktInfo *Info) error {
func Parse(packetData []byte, pktBase *Base) (err error) {
if len(packetData) == 0 {
return errors.New("empty packet")
}
pktBase.layer3Data = packetData
ipVersion := packetData[0] >> 4
var networkLayerType gopacket.LayerType
@ -137,11 +138,15 @@ func Parse(packetData []byte, pktInfo *Info) error {
}
for _, dec := range availableDecoders {
if err := dec(packet, pktInfo); err != nil {
if err := dec(packet, pktBase.Info()); err != nil {
return err
}
}
pktBase.layers = packet
if packet.TransportLayer() != nil {
pktBase.layer5Data = packet.TransportLayer().LayerPayload()
}
return nil
}