# 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)