afring

package
v1.0.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 8, 2024 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package afring implements a capture.Source and a capture.SourceZeroCopy that allows reading network packets from Linux network interfaces via the AF_PACKET / TPacket ring buffer mechanism. This implementation relies on performing optimized `PPOLL()` syscalls to the MMAP'ed socket to fetch blocks of packets. The ring buffer is configurable (depending on the expected throughput). This capture method is optimally suited for production-level packet capture since it achieves blazing-fast capture rates (in particular in zero-copy mode).

Index

Constants

View Source
const (
	DefaultSnapLen = (1 << 16) // DefaultSnapLen : 64 kiB
)

Variables

View Source
var (

	// ErrMockBufferNotPopulated signifies that the mock ring buffer is being run in no drain
	// mode although not being fully populated (which will most likely lead to issues when
	// consuming from it)
	ErrMockBufferNotPopulated = errors.New("mock ring buffer not fully populated, cannot run in no drain mode")
)

Functions

This section is empty.

Types

type MockSource

type MockSource struct {
	*Source

	MockFd *socket.MockFileDescriptor
	// contains filtered or unexported fields
}

MockSource denotes a fully mocked ring buffer source, behaving just like one Since it wraps a regular Source, it can be used as a stand-in replacement without any further code modifications:

src, err := afring.NewSource("eth0", <options>...) ==> src, err := afring.NewMockSource("eth0", <options>...)

func NewMockSource

func NewMockSource(_ string, options ...Option) (*MockSource, error)

NewMockSource instantiates a new mock ring buffer source, wrapping a regular Source

func (*MockSource) AddPacket

func (m *MockSource) AddPacket(pkt capture.Packet) error

AddPacket adds a new mock packet to the source This can happen prior to calling run or continuously while consuming data, mimicking the function of an actual ring buffer. Consequently, if the ring buffer is full and elements not yet consumed this function may block

func (*MockSource) AddPacketFromSource

func (m *MockSource) AddPacketFromSource(src capture.Source) error

AddPacketFromSource consumes a single packet from the provided source and adds it to the source This can happen prior to calling run or continuously while consuming data, mimicking the function of an actual ring buffer. Consequently, if the ring buffer is full and elements not yet consumed this function may block

func (*MockSource) CanAddPackets

func (m *MockSource) CanAddPackets() bool

CanAddPackets returns if any more packets can be added to the mock source (allowing to non-blockingly assert if the buffer / channel is full or will be on the next operation)

func (*MockSource) Close

func (m *MockSource) Close() error

Close stops / closes the capture source

func (*MockSource) Done

func (m *MockSource) Done()

Done notifies the mock source that no more mock packets will be added, causing the ring buffer filling routine / channel to terminate once all packets have been written to the ring buffer

func (*MockSource) FinalizeBlock

func (m *MockSource) FinalizeBlock(force bool)

FinalizeBlock flushes the current block buffer and puts it onto the channel for consumption

func (*MockSource) ForceBlockRelease

func (m *MockSource) ForceBlockRelease()

ForceBlockRelease releases all blocks to the kernel (in order to "unblock" any potential mock capture from the consuming routine without having to attempt a failed packet consumption)

func (*MockSource) ForceBlockskUnavailable

func (m *MockSource) ForceBlockskUnavailable()

ForceBlockskUnavailable marks all blocks to be unavailable (in order to prevent any access to blocks potentially unconsumed at / after a point in time where this method is called)

func (*MockSource) PacketAddCallbackFn

func (m *MockSource) PacketAddCallbackFn(fn func(payload []byte, totalLen uint32, pktType, ipLayerOffset byte)) *MockSource

PacketAddCallbackFn provides an optional callback function that is called when a packet is added to the mock source (e.g. to build a reference for comparison)

func (*MockSource) Pipe

func (m *MockSource) Pipe(src capture.Source, doneReadingChan chan struct{}) (errChan chan error)

Pipe continuously pipes packets from the provided source through this one, mimicking the ring buffer / TPacketHeader block retirement setting for population of the ring buffer

func (*MockSource) Run

func (m *MockSource) Run() <-chan error

Run executes processing of packets in the background, mimicking the function of an actual kernel packet ring buffer

type MockSourceNoDrain

type MockSourceNoDrain struct {
	*MockSource
	// contains filtered or unexported fields
}

MockSourceNoDrain denotes a fully mocked, high-throughput ring buffer source, behaving just like one with the notable exception that blocks / packets are not drained but reused instead. Since it wraps a regular Source, it can be used as a stand-in replacement without any further code modifications:

src, err := afring.NewSource("eth0", <options>...) ==> src, err := afring.NewMockSourceNoDrain("eth0", <options>...)

func NewMockSourceNoDrain

func NewMockSourceNoDrain(iface string, options ...Option) (*MockSourceNoDrain, error)

NewMockSourceNoDrain instantiates a new high-throughput mock ring buffer source, wrapping a regular Source

func (*MockSourceNoDrain) Close

func (m *MockSourceNoDrain) Close() error

Close stops / closes the capture source

func (*MockSourceNoDrain) Done

func (m *MockSourceNoDrain) Done()

Done notifies the mock source that no more mock packets will be added, causing the ring buffer filling routine to terminate

func (*MockSourceNoDrain) Run

func (m *MockSourceNoDrain) Run(releaseInterval time.Duration) (<-chan error, error)

Run acts as a high-throughput mode to allow continuous reading the same data currently in the mock buffer without consuming it and with minimal overhead from handling the mock socket / semaphore It is intended to be used in benchmarks using the mock source to minimize measurement noise from the mock implementation itself

type Option

type Option func(*Source)

Option denotes a functional option for the Source

func BufferSize

func BufferSize(blockSize, nBlocks int) Option

BufferSize sets the block size / number of blocks for the ring buffer

func CaptureLength

func CaptureLength(strategy link.CaptureLengthStrategy) Option

CaptureLength sets a snapLen / capture length (max. number of bytes captured per packet)

func Promiscuous

func Promiscuous(enable bool) Option

Promiscuous enables / disables promiscuous capture mode

type Source

type Source struct {
	sync.Mutex
	// contains filtered or unexported fields
}

Source denotes an AF_PACKET capture source making use of a ring buffer

func NewSource

func NewSource(iface string, options ...Option) (*Source, error)

NewSource instantiates a new AF_PACKET capture source making use of a ring buffer

func NewSourceFromLink(link *link.Link, options ...Option) (*Source, error)

NewSourceFromLink instantiates a new AF_PACKET capture source making use of a ring buffer taking an existing link instance

func (*Source) Close

func (s *Source) Close() error

Close stops / closes the capture source

func (s *Source) Link() *link.Link

Link returns the underlying link

func (*Source) NewPacket

func (s *Source) NewPacket() capture.Packet

NewPacket creates an empty "buffer" packet to be used as destination for the NextPacket() / NextPayload() / NextIPPacket() methods (the latter two by calling .Payload() / .IPLayer() on the created buffer). It ensures that a valid packet of appropriate structure / length is created

func (*Source) NextIPPacket

func (s *Source) NextIPPacket(pBuf capture.IPLayer) (ipLayer capture.IPLayer, pktType capture.PacketType, pktLen uint32, err error)

NextIPPacket receives the IP layer of the next packet from the source and returns it. The operation is blocking. In case a non-nil "buffer" IPLayer is provided it will be populated with the data (and returned). The buffer can be reused. Otherwise a new IPLayer is allocated.

func (*Source) NextIPPacketZeroCopy

func (s *Source) NextIPPacketZeroCopy() (ipLayer capture.IPLayer, pktType capture.PacketType, pktLen uint32, err error)

NextIPPacketZeroCopy receives the IP layer of the next packet from the source and returns it. The operation is blocking. The returned IPLayer provides direct zero-copy access to the underlying data source (e.g. a ring buffer). Procedurally, the method extracts the next packet from either the current block or advances to the next one (fetching / returning its first packet IP layer).

func (*Source) NextPacket

func (s *Source) NextPacket(pBuf capture.Packet) (pkt capture.Packet, err error)

NextPacket receives the next packet from the source and returns it. The operation is blocking. In case a non-nil "buffer" Packet is provided it will be populated with the data (and returned). The buffer packet can be reused. Otherwise a new Packet is allocated.

func (*Source) NextPacketFn

func (s *Source) NextPacketFn(fn func(payload []byte, totalLen uint32, pktType capture.PacketType, ipLayerOffset byte) error) error

NextPacketFn executes the provided function on the next packet received on the source. If possible, the operation should provide a zero-copy way of interaction with the payload / metadata. All operations on the data must be completed prior to any subsequent call to any Next*() method.

func (*Source) NextPayload

func (s *Source) NextPayload(pBuf []byte) (payload []byte, pktType capture.PacketType, pktLen uint32, err error)

NextPayload receives the raw payload of the next packet from the source and returns it. The operation is blocking. In case a non-nil "buffer" byte slice / payload is provided it will be populated with the data (and returned). The buffer can be reused. Otherwise a new byte slice / payload is allocated.

func (*Source) NextPayloadZeroCopy

func (s *Source) NextPayloadZeroCopy() (payload []byte, pktType capture.PacketType, pktLen uint32, err error)

NextPayloadZeroCopy receives the raw payload of the next packet from the source and returns it. The operation is blocking. The returned payload provides direct zero-copy access to the underlying data source (e.g. a ring buffer). Procedurally, the method extracts the next packet from either the current block or advances to the next one (fetching / returning its first packet).

func (*Source) Stats

func (s *Source) Stats() (capture.Stats, error)

Stats returns (and clears) the packet counters of the underlying source

func (*Source) Unblock

func (s *Source) Unblock() error

Unblock ensures that a potentially ongoing blocking poll operation is released (returning an ErrCaptureUnblock from any potentially ongoing call to Next*() that might currently be blocked)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL