Files
2026-10-05 20:07:31 +02:00

82 lines
2.4 KiB
Go

// Package pcap writes classic libpcap capture files.
//
// Format reference: https://www.ietf.org/archive/id/draft-ietf-opsawg-pcap-04.html
package pcap
import (
"encoding/binary"
"fmt"
"io"
"time"
)
// DefaultSnapLen is the snapshot length written to the file header.
const DefaultSnapLen = 262144
const magicMicroseconds = 0xa1b2c3d4
// Common link-layer header types (LINKTYPE_* values from tcpdump.org).
const (
LinkTypeEthernet uint32 = 1
LinkTypeRaw uint32 = 101
LinkTypeIEEE80211 uint32 = 105
LinkTypeLinuxSLL uint32 = 113
LinkTypeLinuxSLL2 uint32 = 276
)
// LinkTypeName returns a human readable name for well known link types.
func LinkTypeName(lt uint32) string {
switch lt {
case LinkTypeEthernet:
return "Ethernet"
case LinkTypeRaw:
return "Raw IP"
case LinkTypeIEEE80211:
return "IEEE 802.11"
case LinkTypeLinuxSLL:
return "Linux cooked (SLL)"
case LinkTypeLinuxSLL2:
return "Linux cooked v2 (SLL2)"
}
return fmt.Sprintf("LINKTYPE %d", lt)
}
// Writer writes packets to a pcap file. The file header is written by NewWriter.
type Writer struct {
w io.Writer
snapLen uint32
}
// NewWriter writes a pcap file header (microsecond resolution, little endian)
// for the given link type and returns a Writer for appending packets.
func NewWriter(w io.Writer, linkType uint32) (*Writer, error) {
var hdr [24]byte
binary.LittleEndian.PutUint32(hdr[0:], magicMicroseconds)
binary.LittleEndian.PutUint16(hdr[4:], 2) // version major
binary.LittleEndian.PutUint16(hdr[6:], 4) // version minor
// hdr[8:16]: thiszone and sigfigs, always zero
binary.LittleEndian.PutUint32(hdr[16:], DefaultSnapLen)
binary.LittleEndian.PutUint32(hdr[20:], linkType)
if _, err := w.Write(hdr[:]); err != nil {
return nil, err
}
return &Writer{w: w, snapLen: DefaultSnapLen}, nil
}
// WritePacket appends one packet record with the given timestamp.
func (w *Writer) WritePacket(ts time.Time, data []byte) error {
if len(data) > int(w.snapLen) {
return fmt.Errorf("packet length %d exceeds snaplen %d", len(data), w.snapLen)
}
var hdr [16]byte
binary.LittleEndian.PutUint32(hdr[0:], uint32(ts.Unix()))
binary.LittleEndian.PutUint32(hdr[4:], uint32(ts.Nanosecond()/1000))
binary.LittleEndian.PutUint32(hdr[8:], uint32(len(data))) // captured length
binary.LittleEndian.PutUint32(hdr[12:], uint32(len(data))) // original length
if _, err := w.w.Write(hdr[:]); err != nil {
return err
}
_, err := w.w.Write(data)
return err
}