bcap/doc/api.md

727 lines
12 KiB
Markdown
Raw Normal View History

2026-03-24 23:39:55 +08:00
# bcap API 手册
开发者参考文档。快速接入说明见 [`../README.md`](../README.md)。
## 1. 主包职责
主包负责:
- 统一的报文事实层
- 统一的 flow 表达
- 统一的轻量 hint 层
- 以 TCP 为重点的轻状态跟踪
主包不负责:
- 报告生成
- 业务规则判断
- 用户侧展示文案
- 动作编排
- 深度流重组
- 应用层协议解析框架
核心对象:
- `Decoder`
- 单包事实解码
- `Tracker`
- flow 状态与轻量提示
- `Analyzer`
- `Decoder + Tracker` 组合入口
## 2. 公开入口
### 2.1 `Decoder`
构造:
```go
decoder := bcap.NewDecoder()
```
主要方法:
```go
Decode(packet gopacket.Packet) (Packet, error)
DecodeWithOptions(packet gopacket.Packet, opts DecodeOptions) (Packet, error)
```
使用时机:
- 只想获得单包事实
- 自己维护状态机
- 想把 `bcap` 当作标准化事实提取层
### 2.2 `Tracker`
构造:
```go
tracker := bcap.NewTracker()
tracker := bcap.NewTrackerWithConfig(cfg)
```
主要方法:
```go
Observe(packet Packet) (Observation, error)
CleanupExpiredFlows() int
ActiveFlowCount() int
Stop()
```
使用时机:
- 已经在别处完成解码
- 只想复用 `bcap` 的 flow / hint 跟踪能力
### 2.3 `Analyzer`
构造:
```go
analyzer := bcap.NewAnalyzer()
analyzer := bcap.NewAnalyzerWithConfig(cfg)
```
主要方法:
```go
ObservePacket(packet gopacket.Packet) (Observation, error)
ObservePacketWithOptions(packet gopacket.Packet, opts DecodeOptions) (Observation, error)
Decoder() *Decoder
Tracker() *Tracker
Stop()
```
使用时机:
- 在线抓包
- 离线遍历
- 绝大多数直接接入型工具
## 3. `DecodeOptions`
`DecodeOptions` 目前包含两个字段:
```go
type DecodeOptions struct {
BaseTime time.Time
SrcMACOverride net.HardwareAddr
}
```
字段:
- `BaseTime`
- 用于计算 `Packet.Meta.RelativeTime`
- `Analyzer.ObservePacket(...)` 未显式传入时,会自动以首包时间作为基准
- `SrcMACOverride`
- 用于覆盖源 MAC
## 4. 数据模型
### 4.1 `Packet`
`Packet` 表示单包事实。
```go
type Packet struct {
Meta Meta
Link LinkFacts
Network NetworkFacts
Transport TransportFacts
Raw RawFacts
}
```
不包含跨包推断结果。
### 4.2 `Meta`
```go
type Meta struct {
Timestamp time.Time
TimestampMicros int64
RelativeTime time.Duration
CaptureLength int
Length int
}
```
字段:
- `Timestamp` / `TimestampMicros`
- 捕获时间
- `RelativeTime`
- 相对 `BaseTime` 的时间差
- `CaptureLength`
- 实际捕获长度
- `Length`
- 原始报文长度
### 4.3 `LinkFacts`
```go
type LinkFacts struct {
Kind LinkKind
SrcMAC net.HardwareAddr
DstMAC net.HardwareAddr
}
```
当前支持的链路类型:
- `LinkKindEthernet`
- `LinkKindLinuxSLL`
- `LinkKindLinuxSLL2`
- `LinkKindUnknown`
### 4.4 `NetworkFacts`
```go
type NetworkFacts struct {
Family NetworkFamily
SrcIP string
DstIP string
TTL uint8
HopLimit uint8
ProtocolNumber uint16
ARP *ARPFacts
}
```
当前支持的网络族:
- `NetworkFamilyIPv4`
- `NetworkFamilyIPv6`
- `NetworkFamilyARP`
- `NetworkFamilyUnknown`
备注:
- IPv4 报文主要填 `TTL`
- IPv6 报文主要填 `HopLimit`
- ARP 报文会同时填充 `ARP`
### 4.5 `TransportFacts`
```go
type TransportFacts struct {
Kind ProtocolKind
Payload int
TCP *TCPFacts
UDP *UDPFacts
ICMP *ICMPFacts
Unknown *UnknownTransportFacts
}
```
当前支持协议:
- `ProtocolTCP`
- `ProtocolUDP`
- `ProtocolICMPv4`
- `ProtocolICMPv6`
- `ProtocolARP`
- `ProtocolUnknown`
### 4.6 协议事实结构
#### `TCPFacts`
```go
type TCPFacts struct {
SrcPort string
DstPort string
Seq uint32
Ack uint32
Window uint16
SYN bool
ACK bool
FIN bool
RST bool
ECE bool
CWR bool
PSH bool
Checksum uint16
Payload int
}
```
#### `UDPFacts`
```go
type UDPFacts struct {
SrcPort string
DstPort string
Length uint16
Payload int
}
```
#### `ICMPFacts`
```go
type ICMPFacts struct {
Version int
Type uint8
Code uint8
Checksum uint16
ID uint16
Seq uint16
Payload int
}
```
#### `ARPFacts`
```go
type ARPFacts struct {
Operation uint16
SenderMAC net.HardwareAddr
TargetMAC net.HardwareAddr
SenderIP string
TargetIP string
}
```
### 4.7 `FlowKey` / `FlowRef`
推荐使用结构化 flow不把字符串 key 当成唯一公共接口。
```go
type Endpoint struct {
IP string
Port string
}
type FlowKey struct {
Family NetworkFamily
Protocol ProtocolKind
Src Endpoint
Dst Endpoint
}
type FlowRef struct {
Forward FlowKey
Reverse FlowKey
Stable string
}
```
方法:
```go
func (f FlowKey) StableString() string
```
字段:
- `Forward`
- 当前方向
- `Reverse`
- 反向方向
- `Stable`
- 稳定字符串表达,可用于日志和 map key
### 4.8 `Observation`
```go
type Observation struct {
Packet Packet
Flow FlowRef
Hints HintSet
}
```
- `Packet`
- 报文事实
- `Flow`
- 流引用
- `Hints`
- 推断结果
## 5. Hint 模型
### 5.1 `HintSet`
```go
type HintSet struct {
Summary SummaryHint
Tags []Tag
TCP *TCPHint
UDP *UDPHint
ICMP *ICMPHint
ARP *ARPHint
}
```
- `Summary`
- 摘要代码
- `Tags`
- 标签集合
- 协议专属 hint
- 放在对应子结构中
### 5.2 TCP hints
```go
type TCPHint struct {
Phase TCPPhase
Event TCPEvent
LegacyState uint8
Seq uint32
Ack uint32
Window uint16
Payload int
Retransmission bool
Keepalive bool
KeepaliveResponse bool
RST bool
ECE bool
CWR bool
}
```
Phase
- `TCPPhaseHandshake`
- `TCPPhaseEstablished`
- `TCPPhaseTeardown`
- `TCPPhaseSpecial`
- `TCPPhaseUnknown`
Event
- `TCPEventSYN`
- `TCPEventSYNACK`
- `TCPEventHandshakeACK`
- `TCPEventACK`
- `TCPEventRetransmission`
- `TCPEventKeepalive`
- `TCPEventKeepaliveResp`
- `TCPEventFIN`
- `TCPEventFINACK`
- `TCPEventTeardownACK`
- `TCPEventRST`
- `TCPEventECE`
- `TCPEventCWR`
- `TCPEventUnknown`
常见 Tag
- `TagTCPHandshakeSYN`
- `TagTCPHandshakeSYNACK`
- `TagTCPHandshakeACK`
- `TagTCPTeardownFIN`
- `TagTCPTeardownFINACK`
- `TagTCPTeardownACK`
- `TagTCPPacket`
- `TagTCPRetransmit`
- `TagTCPKeepalive`
- `TagTCPKeepaliveResp`
- `TagTCPRst`
- `TagTCPEce`
- `TagTCPCwr`
### 5.3 UDP / ICMP / ARP hints
#### `UDPHint`
```go
type UDPHint struct {
Payload int
}
```
对应 Tag
- `TagUDPPacket`
#### `ICMPHint`
```go
type ICMPHint struct {
Version int
Type uint8
Code uint8
IsEcho bool
IsEchoReply bool
IsUnreachable bool
IsTimeExceeded bool
}
```
对应 Tag
- `TagICMPPacket`
- `TagICMPEchoRequest`
- `TagICMPEchoReply`
- `TagICMPUnreachable`
- `TagICMPTimeExceeded`
#### `ARPHint`
```go
type ARPHint struct {
Operation uint16
Request bool
Reply bool
}
```
对应 Tag
- `TagARPRequest`
- `TagARPReply`
## 6. TCP 跟踪边界
`Tracker` 对 TCP 只做轻量跟踪,不做完整 TCP 栈模拟。
当前覆盖:
- 握手识别
- 挥手识别
- 普通 ACK 识别
- 重传识别
- keepalive 识别
- keepalive response 识别
- RST / ECE / CWR 识别
实现说明:
- 基于 flow 跟踪
- 使用有限 segment 记忆辅助判断重传
- keepalive 使用启发式判断
- 支持超时清理
不覆盖:
- 严格 TCP 协议验证
- 深度重组
- 业务级根因结论
## 7. 配置
### 7.1 `PacketsConfig`
```go
type PacketsConfig struct {
ConnectionTimeout time.Duration
CleanupInterval time.Duration
}
```
字段:
- `ConnectionTimeout`
- flow 状态保留时长
- `CleanupInterval`
- 自动清理周期
默认值:
```go
const (
DefaultConnectionTimeout = 5 * time.Minute
DefaultCleanupInterval = 1 * time.Minute
)
```
默认配置:
```go
cfg := bcap.DefaultConfig()
```
### 7.2 生命周期方法
`Tracker`
- `CleanupExpiredFlows() int`
- `ActiveFlowCount() int`
- `Stop()`
`Analyzer`
- `Decoder() *Decoder`
- `Tracker() *Tracker`
- `Stop()`
备注:
- 长生命周期进程退出前调用 `Stop()`
- 如需自行控制清理节奏,可将 `CleanupInterval` 设为 `0`,再手动调用 `CleanupExpiredFlows()`
## 8. 错误模型
`bcap` 使用 `*ParseError` 表达解析问题:
```go
type ParseError struct {
Type ParseErrorType
Layer string
Message string
Err error
}
```
错误类型:
- `ErrTypeLinkLayer`
- `ErrTypeNetwork`
- `ErrTypeTransport`
- `ErrTypeUnsupported`
常见触发条件:
- 没有有效网络层
- 协议层对象类型不匹配
- 跟踪阶段缺少必须的协议事实
## 9. 子包
### 9.1 `libpcap`
`libpcap` 子包负责在线抓包输入。
入口:
- `FindAllDevs()`
- `NewCatch(host, filter)`
- `NewCatchEth(eth, filter)`
- `SetRecall(func(gopacket.Packet))`
- `Run()`
- `Stop()`
常见组合:
- 子包接收 `gopacket.Packet`
- 主包 `Analyzer` 做解析和提示
- 上层工具做展示和统计
### 9.2 `nfq`
`nfq` 子包负责 NFQUEUE 输入适配。
入口:
- `NewNfQueue(ctx, queid, maxqueue)`
- `SetRecall(func(id uint32, q *nfqueue.Nfqueue, p Packet))`
- `Run()`
- `Stop()`
备注:
- `nfq.Packet` 只是 NFQUEUE 输入包装
- 它不是主包的 `bcap.Packet`
- 一般仍然从其中取 `gopacket.Packet`,再交给 `Analyzer``Decoder`
## 10. 示例
### 10.1 直接用 `Analyzer`
```go
analyzer := bcap.NewAnalyzer()
defer analyzer.Stop()
obs, err := analyzer.ObservePacket(packet)
if err != nil {
return err
}
fmt.Println(obs.Flow.Stable)
fmt.Println(obs.Packet.Transport.Kind)
fmt.Println(obs.Hints.Summary.Code)
```
### 10.2 自己管理解码和跟踪
```go
decoder := bcap.NewDecoder()
tracker := bcap.NewTracker()
defer tracker.Stop()
decoded, err := decoder.DecodeWithOptions(packet, bcap.DecodeOptions{
BaseTime: firstPacketTS,
})
if err != nil {
return err
}
obs, err := tracker.Observe(decoded)
if err != nil {
return err
}
```
### 10.3 典型离线遍历
```go
f, err := os.Open("sample.pcap")
if err != nil {
return err
}
defer f.Close()
reader, err := pcapgo.NewReader(f)
if err != nil {
return err
}
source := gopacket.NewPacketSource(reader, reader.LinkType())
analyzer := bcap.NewAnalyzer()
defer analyzer.Stop()
for packet := range source.Packets() {
obs, err := analyzer.ObservePacket(packet)
if err != nil {
continue
}
fmt.Println(obs.Packet.Network.SrcIP, obs.Hints.Summary.Code)
}
```
## 11. 辅助函数
主包还提供两个轻量格式化函数:
- `FormatDuration(time.Duration) string`
- `FormatBytes(uint64) string`
用于轻量日志与终端展示。
## 12. 迁移说明
主包旧接口已经被清理,删除项包括:
- `Packets`
- `PacketInfo`
- `ParsePacket`
- `NewPackets`
- `NewPacketsWithConfig`
- `LegacyPacketInfoFromObservation`
- `GetStateDescription`
- `PrintStats`
- `ExportConnectionsToJSON`
迁移方向:
- 旧的单包解析入口迁到 `Decoder`
- 旧的“包 + 状态”混合对象迁到 `Observation`
- 旧的连接跟踪职责迁到 `Tracker`
- 大部分调用场景直接迁到 `Analyzer`
旧代码如果大量依赖字符串 key
- 新代码优先改为使用 `FlowRef.Forward` / `FlowRef.Reverse`
- 如果只是为了日志或 map key可以继续使用 `FlowRef.Stable`
## 13. 相关文档
- 快速入口见 [`../README.md`](../README.md)
- 设计备忘见 [`dev.md`](./dev.md)