capture

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package capture provides packet sources.

Everything downstream consumes the Source interface, so an offline pcap file, a live libpcap handle and a future eBPF or ETW backend are interchangeable. Offline reading is not only a test convenience: it is how the tool is used against captures taken elsewhere, and it is the reason the entire pipeline can be exercised in CI without privileges.

Index

Constants

This section is empty.

Variables

View Source
var ErrUnsupportedPlatform = errors.New("live capture is not supported on this platform")

ErrUnsupportedPlatform is returned by OpenLive where live capture is not implemented. Reading capture files still works everywhere.

Functions

func CaptureFilter

func CaptureFilter(lt layers.LinkType, snaplen int) ([]bpf.RawInstruction, error)

CaptureFilter returns a kernel BPF program that keeps the traffic a TLS inventory can learn from — TCP and UDP — and drops everything else.

UDP is here for QUIC. Restricting it to port 443 would be the same mistake as restricting TCP to 443, and the userspace check that follows is cheap: a QUIC Initial has the top two bits of its first byte set, so almost all other UDP traffic is rejected on one byte.

The filter runs in the kernel, so what it rejects costs nothing. What it accepts is deliberately wider than strictly necessary:

IPv6 is accepted wholesale rather than checked for next_header == TCP. A packet carrying a Hop-by-Hop or Routing extension header has a next_header that is not 6, and a filter that tested that byte would silently drop every such flow. Walking an extension header chain in BPF is possible and not worth it; gopacket decodes them correctly a few microseconds later. Undercounting is the failure mode this tool exists to avoid, and IPv6 is a minority of traffic on the hosts it will run on.

IPv4 fragments are also accepted: a non-first fragment carries protocol 6 with no TCP header, and is discarded harmlessly during decode.

An unsupported link type returns a nil program, meaning no kernel filter. That is correct but slower, never wrong.

func DefaultInterface

func DefaultInterface() (string, error)

DefaultInterface picks the interface to capture on when none was named: the first one that is up, is not loopback, and has a routable address.

func Done

func Done(err error) bool

Done reports whether err signals normal exhaustion rather than a fault.

func LiveSupported

func LiveSupported() bool

LiveSupported reports whether this build can capture live traffic.

Types

type InterfaceInfo

type InterfaceInfo struct {
	Name      string
	Up        bool
	Loopback  bool
	Addresses []string
}

InterfaceInfo describes a capturable network interface.

func Interfaces

func Interfaces() ([]InterfaceInfo, error)

Interfaces lists the network interfaces capture can be opened on.

The names it returns are the names `watch -i` accepts, which is why this is not simply net.Interfaces() everywhere: on Windows the capture device is an Npcap GUID path, and listing the friendly adapter names would print names that cannot be used.

type LiveOptions

type LiveOptions struct {
	// Snaplen is the maximum bytes captured per packet.
	Snaplen int

	// Promiscuous puts the interface into promiscuous mode.
	//
	// Off by default, deliberately. This is an endpoint inventory: the
	// question is what *this host* negotiates, and promiscuous mode answers
	// a different and much more invasive one — it captures the neighbours'
	// traffic too, on any network where that is still possible. Defaulting
	// to on would make a tool that reads hostnames quietly collect other
	// people's.
	Promiscuous bool

	// BufferBytes is the kernel capture buffer size. Larger buffers lose
	// fewer packets in bursts at the cost of latency.
	BufferBytes int

	// ReadTimeout bounds how long a read blocks before returning empty, so
	// that shutdown is responsive on a quiet interface.
	ReadTimeout time.Duration

	// NoFilter disables the kernel BPF filter and passes every packet to
	// userspace. Useful when a link type has no filter or when debugging a
	// suspected filter bug.
	NoFilter bool
}

LiveOptions configures a live capture. The zero value is usable.

type PermissionError

type PermissionError struct {
	Op   string
	Path string
	Err  error
	Hint string
}

PermissionError reports that capture was refused for lack of privilege, and carries the platform-specific way to fix it.

This is worth a dedicated type because "operation not permitted" is the single most common first experience of a packet capture tool, and a bare errno teaches the user nothing.

func (*PermissionError) Error

func (e *PermissionError) Error() string

func (*PermissionError) Unwrap

func (e *PermissionError) Unwrap() error

type SetupError

type SetupError struct {
	Op   string
	Err  error
	Hint string
}

SetupError reports that capture cannot start because a prerequisite is missing, as distinct from privilege being refused.

It exists so that the two are not conflated. PermissionError prints "permission denied" unconditionally, which is right for its case and actively misleading for this one: a Windows machine with no Npcap installed would otherwise be told it lacked administrator rights, and sent looking for an elevated prompt that cannot help.

func (*SetupError) Error

func (e *SetupError) Error() string

func (*SetupError) Unwrap

func (e *SetupError) Unwrap() error

type Source

type Source interface {
	// Next returns the next packet. It returns io.EOF when the source is
	// exhausted. Data is only valid until the following call.
	Next() (data []byte, ci gopacket.CaptureInfo, err error)
	// LinkType reports the link layer of the packets this source yields.
	LinkType() layers.LinkType
	// Name identifies the source in logs and reports.
	Name() string
	Close() error
}

Source yields packets until it is exhausted or closed.

func OpenFile

func OpenFile(path string) (Source, error)

OpenFile opens a capture file, detecting pcap or pcapng from its magic rather than from the filename, since both extensions are used for both formats in the wild.

This path uses pcapgo, which is pure Go. Reading a capture therefore needs neither cgo nor libpcap nor any privilege.

func OpenLive

func OpenLive(iface string, opts LiveOptions) (Source, error)

OpenLive begins capturing on iface. An empty iface selects the default.

Jump to

Keyboard shortcuts

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