Documentation
¶
Overview ¶
Package capture turns bytes off the wire (or off disk) into decoded model.Packet values.
Everything here is pure Go. There is no libpcap/Npcap dependency and no cgo, which means `CGO_ENABLED=0 go build` produces a single static binary that runs in a scratch container and cross-compiles from any host. File replay works on every platform; live capture uses Linux AF_PACKET and is compiled out elsewhere.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrDone = errors.New("capture: source exhausted")
ErrDone is returned by Source.Next when the source is exhausted (end of a capture file, or a closed handle).
Functions ¶
This section is empty.
Types ¶
type FileSource ¶
type FileSource struct {
// contains filtered or unexported fields
}
FileSource replays a PCAP or PCAPNG file.
Replay is the backbone of the project's testing story: detections are deterministic functions of a capture file, so every detector has a regression test that is just "run this PCAP, expect these alerts". It is also what makes the demo runnable by someone with no network to sniff.
func OpenFile ¶
func OpenFile(path string) (*FileSource, error)
OpenFile opens a capture file, sniffing the container format from its magic bytes rather than trusting the extension.
type Interrupter ¶ added in v0.4.0
type Interrupter interface {
Interrupt() error
}
Interrupter is implemented by sources whose Next can block with no bound.
A file source always returns promptly, so it does not need this. A live interface does: AF_PACKET has no read deadline, and gopacket's EthernetHandle exposes no way to set one, so a read on a silent link waits for a packet that may never come. Cancelling the context cannot help on its own, because nothing is checked until the read returns.
Interrupt makes the pending read fail so the capture loop can finish. It must be safe to call from another goroutine, and safe to call more than once.
type LiveSource ¶
type LiveSource struct {
// contains filtered or unexported fields
}
LiveSource captures from a network interface using AF_PACKET.
This is gopacket's pure-Go capture path, not a libpcap binding, which is what lets the whole binary build with CGO_ENABLED=0 and ship in a scratch container. The tradeoff is that it is Linux-only — which is the right tradeoff for a sensor, since that is where sensors run.
Capturing requires CAP_NET_RAW. Grant it narrowly rather than running as root: setcap cap_net_raw,cap_net_admin=eip ./tracehound
func OpenLive ¶
func OpenLive(iface string, promiscuous bool) (*LiveSource, error)
OpenLive begins capturing on iface.
func (*LiveSource) Interrupt ¶ added in v0.4.0
func (s *LiveSource) Interrupt() error
Interrupt implements Interrupter.
AF_PACKET offers no read deadline and EthernetHandle exposes no way to set one, so closing the socket is the only thing that will wake a read that is waiting on a link with no traffic. The flag is set first: the reader has to see "we did this" before it sees the error the close produces, or a clean shutdown is reported as a capture failure.
Safe to call repeatedly, and safe to call alongside Close.
func (*LiveSource) Stats ¶
func (s *LiveSource) Stats() Stats
Stats implements Source, folding in the kernel's drop counter so that a sensor which cannot keep up says so rather than silently under-reporting.
AF_PACKET's TPACKET_GET_STATS is destructive: each call returns the counts *since the previous call* and resets them. Assigning the result would therefore report "0 dropped" on any call that happens to follow another closely, so the deltas are accumulated instead.
type Source ¶
type Source interface {
// Next returns the next decoded packet, or ErrDone when exhausted.
// Packets that cannot be decoded are skipped internally rather than
// surfaced as errors, so a single malformed frame never stops a capture.
Next() (model.Packet, error)
// LinkType describes the link layer of the source, for diagnostics.
LinkType() string
// Stats returns counters accumulated so far.
Stats() Stats
// Close releases the underlying handle.
Close() error
}
Source yields decoded packets.
Next returns packets by value, but Packet.Payload aliases an internal read buffer that is reused on the following call. Consumers that need the bytes after the next Next must copy them. This is the standard zero-copy contract for packet sources and is what keeps the hot path allocation-free.