bcap/bcap.go
2026-02-04 13:33:54 +08:00

1360 lines
48 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package bcap
import (
"fmt"
"net"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/gopacket/gopacket"
"github.com/gopacket/gopacket/layers"
)
// ════════════════════════════════════════════════
// 错误类型定义 / Error Type Definitions
// ════════════════════════════════════════════════
// ParseErrorType 解析错误类型 / Parse error type
type ParseErrorType int
const (
ErrTypeNone ParseErrorType = iota // 无错误 / No error
ErrTypeLinkLayer // 链路层错误 / Link layer error
ErrTypeNetwork // 网络层错误 / Network layer error
ErrTypeTransport // 传输层错误 / Transport layer error
ErrTypeUnsupported // 不支持的协议 / Unsupported protocol
)
// ParseError 解析错误结构体,包含详细的错误信息
// ParseError structure containing detailed error information
type ParseError struct {
Type ParseErrorType // 错误类型 / Error type
Layer string // 出错的层 / Layer where error occurred
Message string // 错误信息 / Error message
Err error // 原始错误 / Original error
}
func (e *ParseError) Error() string {
if e.Err != nil {
return fmt.Sprintf("[%s] %s: %v", e.Layer, e.Message, e.Err)
}
return fmt.Sprintf("[%s] %s", e.Layer, e.Message)
}
// NewParseError 创建新的解析错误 / Create new parse error
func NewParseError(errType ParseErrorType, layer, message string, err error) *ParseError {
return &ParseError{
Type: errType,
Layer: layer,
Message: message,
Err: err,
}
}
// ════════════════════════════════════════════════
// 状态常量定义 / State Constants
// ════════════════════════════════════════════════════════════════════════════════
// TCP 状态描述符定义 / TCP state descriptor definitions
const (
StateUnknown uint8 = 0 // 未知状态 / Unknown state
StateTcpConnect1 uint8 = 1 // 三次握手第一步 (SYN) / Three-way handshake step 1 (SYN)
StateTcpConnect2 uint8 = 2 // 三次握手第二步 (SYN-ACK) / Three-way handshake step 2 (SYN-ACK)
StateTcpConnect3 uint8 = 3 // 三次握手第三步 (ACK) / Three-way handshake step 3 (ACK)
StateTcpDisconnect1 uint8 = 4 // 四次挥手第一步 (FIN) / Four-way handshake step 1 (FIN)
StateTcpDisconnect2 uint8 = 5 // 四次挥手第二步 (ACK) / Four-way handshake step 2 (ACK)
StateTcpDisconnect23 uint8 = 6 // 四次挥手第二三步合并 (FIN-ACK) / Four-way handshake step 2+3 combined
StateTcpDisconnect3 uint8 = 7 // 四次挥手第三步 (FIN) / Four-way handshake step 3 (FIN)
StateTcpDisconnect4 uint8 = 8 // 四次挥手第四步 (ACK) / Four-way handshake step 4 (ACK)
StateTcpAckOk uint8 = 9 // 正常 ACK / Normal ACK
StateTcpRetransmit uint8 = 10 // TCP 重传 / TCP retransmission
StateTcpEce uint8 = 11 // TCP ECE 标志 / TCP ECE flag
StateTcpCwr uint8 = 12 // TCP CWR 标志 / TCP CWR flag
StateTcpRst uint8 = 13 // TCP RST 标志 / TCP RST flag
StateTcpKeepalive uint8 = 14 // TCP 保活 / TCP keepalive
StateUdp uint8 = 20 // UDP 数据包 / UDP packet
StateIcmp uint8 = 30 // ICMP 数据包 / ICMP packet
StateIcmpv6 uint8 = 31 // ICMPv6 数据包 / ICMPv6 packet
)
// 默认配置常量 / Default configuration constants
const (
DefaultConnectionTimeout = 5 * time.Minute // 默认连接超时时间 / Default connection timeout
DefaultCleanupInterval = 1 * time.Minute // 默认清理间隔 / Default cleanup interval
DefaultShardCount = 32 // 默认分片数量 / Default shard count
)
// ════════════════════════════════════════════════
// 回调函数类型定义 / Callback Function Types
// ════════════════════════════════════════════════
// ConnectionCallback 连接事件回调函数类型
// ConnectionCallback connection event callback function type
type ConnectionCallback func(info PacketInfo)
// ErrorCallback 错误事件回调函数类型
// ErrorCallback error event callback function type
type ErrorCallback func(err *ParseError, packet gopacket.Packet)
// ════════════════════════════════════════════════════════════════════════════════
// 配置结构体 / Configuration Structures
// ════════════════════════════════════════════════════════════════════════════════
// PacketsConfig 数据包管理器配置
// PacketsConfig configuration for packets manager
type PacketsConfig struct {
// 连接超时时间,超过此时间未活动的连接将被清理
// Connection timeout, connections inactive beyond this time will be cleaned up
ConnectionTimeout time.Duration
// 自动清理间隔,设置为 0 则禁用自动清理
// Auto cleanup interval, set to 0 to disable auto cleanup
CleanupInterval time.Duration
// 是否启用懒加载模式(按需解析详细信息)
// Whether to enable lazy parsing mode (parse details on demand)
LazyParsing bool
// 是否启用调试日志
// Whether to enable debug logging
EnableDebugLog bool
// 分片数量(用于减少锁竞争)
// Shard count (for reducing lock contention)
ShardCount int
// 新连接回调 / New connection callback
OnNewConnection ConnectionCallback
// 连接关闭回调 / Connection closed callback
OnConnectionClosed ConnectionCallback
// 错误回调 / Error callback
OnError ErrorCallback
}
// DefaultConfig 返回默认配置
// DefaultConfig returns default configuration
func DefaultConfig() *PacketsConfig {
return &PacketsConfig{
ConnectionTimeout: DefaultConnectionTimeout,
CleanupInterval: DefaultCleanupInterval,
LazyParsing: false,
EnableDebugLog: false,
ShardCount: DefaultShardCount,
}
}
// ════════════════════════════════════════════════
// 统计信息结构体 / Statistics Structures
// ════════════════════════════════════════════════
// ErrorStats 错误统计信息
// ErrorStats error statistics
type ErrorStats struct {
LinkLayerErrors uint64 // 链路层错误数 / Link layer error count
NetworkErrors uint64 // 网络层错误数 / Network layer error count
TransportErrors uint64 // 传输层错误数 / Transport layer error count
UnsupportedErrors uint64 // 不支持协议错误数 / Unsupported protocol error count
TotalErrors uint64 // 总错误数 / Total error count
}
// ConnectionStats 连接统计信息
// ConnectionStats connection statistics
type ConnectionStats struct {
ActiveConnections int64 // 当前活跃连接数 / Current active connections
TotalConnections uint64 // 历史总连接数 / Total historical connections
ClosedConnections uint64 // 已关闭连接数 / Closed connections
TimeoutConnections uint64 // 超时清理的连接数 / Timeout cleaned connections
TcpConnections int64 // TCP 连接数 / TCP connection count
UdpConnections int64 // UDP 连接数 / UDP connection count
IcmpConnections int64 // ICMP 连接数 / ICMP connection count
}
// Stats 综合统计信息
// Stats comprehensive statistics
type Stats struct {
Errors ErrorStats // 错误统计 / Error statistics
Connections ConnectionStats // 连接统计 / Connection statistics
StartTime time.Time // 启动时间 / Start time
LastCleanup time.Time // 上次清理时间 / Last cleanup time
}
// ════════════════════════════════════════════════
// 数据包信息结构体 / Packet Info Structure
// ════════════════════════════════════════════════════════════════════════════════
// PacketInfo 数据包信息结构体,包含完整的网络层和传输层信息
// PacketInfo structure containing complete network and transport layer information
type PacketInfo struct {
Key string // 连接唯一标识 / Unique connection identifier
ReverseKey string // 反向连接标识 / Reverse connection identifier
Type string // 协议类型: tcp/udp/icmp/icmpv6 / Protocol type
SrcMac net.HardwareAddr // 源 MAC 地址 / Source MAC address
DstMac net.HardwareAddr // 目标 MAC 地址 / Destination MAC address
SrcIP string // 源 IP 地址 / Source IP address
SrcPort string // 源端口 (TCP/UDP) / Source port
DstIP string // 目标 IP 地址 / Destination IP address
DstPort string // 目标端口 (TCP/UDP) / Destination port
// 时间戳相关字段 / Timestamp related fields
Timestamp time.Time // 数据包时间戳 / Packet timestamp
TimestampMicros int64 // 微秒级时间戳 / Microsecond timestamp
RelativeTime time.Duration // 相对于首包的时间偏移 / Time offset relative to first packet
// ICMP 相关字段 / ICMP related fields
IcmpType uint8 // ICMP 类型 / ICMP type
IcmpCode uint8 // ICMP 代码 / ICMP code
IcmpChecksum uint16 // ICMP 校验和 / ICMP checksum
IcmpId uint16 // ICMP 标识符 / ICMP identifier
IcmpSeq uint16 // ICMP 序列号 / ICMP sequence number
// 连接统计字段 / Connection statistics fields
PacketCount uint64 // 该连接的数据包计数 / Packet count for this connection
ByteCount uint64 // 该连接的字节计数 / Byte count for this connection
FirstSeen time.Time // 首次出现时间 / First seen time
LastSeen time.Time // 最后出现时间 / Last seen time
// 内部状态字段 / Internal state fields
comment string // 用户自定义注释 / User-defined comment
packet gopacket.Packet // 原始数据包 / Raw packet
tcpSeq uint32 // TCP 序列号 / TCP sequence number
tcpAck uint32 // TCP 确认号 / TCP acknowledgment number
tcpWindow uint16 // TCP 窗口大小 / TCP window size
tcpPayloads int // 载荷长度 / Payload length
finState bool // TCP FIN 标志 / TCP FIN flag
synState bool // TCP SYN 标志 / TCP SYN flag
isFirst bool // 是否为首次出现 / Whether first occurrence
stateDescript uint8 // 状态描述符 / State descriptor
}
// PacketInfo 的 Getter 方法 / PacketInfo getter methods
func (p PacketInfo) StateDescript() uint8 { return p.stateDescript }
func (p PacketInfo) TcpPayloads() int { return p.tcpPayloads }
func (p PacketInfo) FinState() bool { return p.finState }
func (p PacketInfo) SynState() bool { return p.synState }
func (p PacketInfo) TcpWindow() uint16 { return p.tcpWindow }
func (p PacketInfo) TcpAck() uint32 { return p.tcpAck }
func (p PacketInfo) TcpSeq() uint32 { return p.tcpSeq }
func (p PacketInfo) Packet() gopacket.Packet { return p.packet }
func (p PacketInfo) Comment() string { return p.comment }
func (p *PacketInfo) SetComment(comment string) { p.comment = comment }
// ════════════════════════════════════════════════
// 分片 Map 实现(减少锁竞争)/ Sharded Map Implementation (reduce lock contention)
// ════════════════════════════════════════════════
// shard 单个分片
// shard single shard
type shard struct {
sync.RWMutex
items map[string]PacketInfo
}
// shardedMap 分片 Map通过将数据分散到多个分片来减少锁竞争
// shardedMap sharded map, reduces lock contention by distributing data across multiple shards
type shardedMap struct {
shards []*shard
shardCount int
}
// newShardedMap 创建新的分片 Map
// newShardedMap creates a new sharded map
func newShardedMap(shardCount int) *shardedMap {
if shardCount <= 0 {
shardCount = DefaultShardCount
}
sm := &shardedMap{
shards: make([]*shard, shardCount),
shardCount: shardCount,
}
for i := 0; i < shardCount; i++ {
sm.shards[i] = &shard{
items: make(map[string]PacketInfo),
}
}
return sm
}
// getShard 根据 key 获取对应的分片
// getShard gets the shard for a given key
func (sm *shardedMap) getShard(key string) *shard {
hash := fnvHash(key)
return sm.shards[hash%uint32(sm.shardCount)]
}
// fnvHash FNV-1a 哈希函数,用于快速计算字符串哈希
// fnvHash FNV-1a hash function for fast string hashing
func fnvHash(key string) uint32 {
hash := uint32(2166136261)
for i := 0; i < len(key); i++ {
hash ^= uint32(key[i])
hash *= 16777619
}
return hash
}
// Get 获取值 / Get value
func (sm *shardedMap) Get(key string) (PacketInfo, bool) {
shard := sm.getShard(key)
shard.RLock()
val, ok := shard.items[key]
shard.RUnlock()
return val, ok
}
// Set 设置值 / Set value
func (sm *shardedMap) Set(key string, value PacketInfo) {
shard := sm.getShard(key)
shard.Lock()
shard.items[key] = value
shard.Unlock()
}
// Delete 删除值 / Delete value
func (sm *shardedMap) Delete(key string) {
shard := sm.getShard(key)
shard.Lock()
delete(shard.items, key)
shard.Unlock()
}
// DeleteBatch 批量删除 / Batch delete
func (sm *shardedMap) DeleteBatch(keys []string) {
// 按分片分组 keys / Group keys by shard
shardKeys := make(map[int][]string)
for _, key := range keys {
hash := fnvHash(key)
shardIdx := int(hash % uint32(sm.shardCount))
shardKeys[shardIdx] = append(shardKeys[shardIdx], key)
}
// 对每个分片批量删除 / Batch delete for each shard
for shardIdx, keys := range shardKeys {
shard := sm.shards[shardIdx]
shard.Lock()
for _, key := range keys {
delete(shard.items, key)
}
shard.Unlock()
}
}
// Len 获取总长度 / Get total length
func (sm *shardedMap) Len() int {
total := 0
for _, shard := range sm.shards {
shard.RLock()
total += len(shard.items)
shard.RUnlock()
}
return total
}
// GetAll 获取所有项 / Get all items
func (sm *shardedMap) GetAll() []PacketInfo {
var result []PacketInfo
for _, shard := range sm.shards {
shard.RLock()
for _, v := range shard.items {
result = append(result, v)
}
shard.RUnlock()
}
return result
}
// Range 遍历所有项 / Range over all items
func (sm *shardedMap) Range(f func(key string, value PacketInfo) bool) {
for _, shard := range sm.shards {
shard.RLock()
for k, v := range shard.items {
if !f(k, v) {
shard.RUnlock()
return
}
}
shard.RUnlock()
}
}
// Clear 清空所有项 / Clear all items
func (sm *shardedMap) Clear() {
for _, shard := range sm.shards {
shard.Lock()
shard.items = make(map[string]PacketInfo)
shard.Unlock()
}
}
// ════════════════════════════════════════════════
// 对象池(减少内存分配)/ Object Pool (reduce memory allocation)
// ════════════════════════════════════════════════
// stringBuilderPool strings.Builder 对象池
var stringBuilderPool = sync.Pool{
New: func() interface{} {
return &strings.Builder{}
},
}
// getStringBuilder 从对象池获取 strings.Builder
// getStringBuilder gets strings.Builder from pool
func getStringBuilder() *strings.Builder {
return stringBuilderPool.Get().(*strings.Builder)
}
// putStringBuilder 将 strings.Builder 放回对象池
// putStringBuilder puts strings.Builder back to pool
func putStringBuilder(sb *strings.Builder) {
sb.Reset()
stringBuilderPool.Put(sb)
}
// buildKey 使用对象池优化的 key 构建函数
// buildKey optimized key building function using object pool
func buildKey(protocol, srcIP, srcPort, dstIP, dstPort string) string {
sb := getStringBuilder()
defer putStringBuilder(sb)
sb.WriteString(protocol)
sb.WriteString("://")
sb.WriteString(srcIP)
if srcPort != "" {
sb.WriteString(":")
sb.WriteString(srcPort)
}
sb.WriteString("=")
sb.WriteString(dstIP)
if dstPort != "" {
sb.WriteString(":")
sb.WriteString(dstPort)
}
return sb.String()
}
// ════════════════════════════════════════════════
// Packets 主结构体 / Packets Main Structure
// ════════════════════════════════════════════════
// Packets 数据包管理器,用于跟踪和解析网络数据包
// Packets manager for tracking and parsing network packets
type Packets struct {
config *PacketsConfig // 配置 / Configuration
connections *shardedMap // 连接映射表 / Connection map
stats Stats // 统计信息 / Statistics
statsLock sync.RWMutex // 统计信息锁 / Statistics lock
startTime time.Time // 启动时间 / Start time
firstPacketTime time.Time // 首个数据包时间 / First packet time
cleanupTicker *time.Ticker // 清理定时器 / Cleanup ticker
stopCleanup chan struct{} // 停止清理信号 / Stop cleanup signal
cleanupOnce sync.Once // 确保只启动一次清理 / Ensure cleanup starts only once
}
// NewPackets 创建新的数据包管理器实例(使用默认配置)
// NewPackets creates a new Packets manager instance (with default config)
func NewPackets() *Packets {
return NewPacketsWithConfig(DefaultConfig())
}
// NewPacketsWithConfig 使用自定义配置创建数据包管理器
// NewPacketsWithConfig creates Packets manager with custom config
func NewPacketsWithConfig(config *PacketsConfig) *Packets {
if config == nil {
config = DefaultConfig()
}
p := &Packets{
config: config,
connections: newShardedMap(config.ShardCount),
startTime: time.Now(),
stopCleanup: make(chan struct{}),
}
p.stats.StartTime = p.startTime
// 启动自动清理 goroutine / Start auto cleanup goroutine
if config.CleanupInterval > 0 {
p.startAutoCleanup()
}
return p
}
// startAutoCleanup 启动自动清理 goroutine
// startAutoCleanup starts auto cleanup goroutine
func (p *Packets) startAutoCleanup() {
p.cleanupOnce.Do(func() {
p.cleanupTicker = time.NewTicker(p.config.CleanupInterval)
go func() {
for {
select {
case <-p.cleanupTicker.C:
p.CleanupExpiredConnections()
case <-p.stopCleanup:
p.cleanupTicker.Stop()
return
}
}
}()
})
}
// Stop 停止数据包管理器(停止自动清理)
// Stop stops the packets manager (stops auto cleanup)
func (p *Packets) Stop() {
close(p.stopCleanup)
}
// ════════════════════════════════════════════════
// 统计和查询方法 / Statistics and Query Methods
// ════════════════════════════════════════════════
// GetStats 获取统计信息
// GetStats gets statistics
func (p *Packets) GetStats() Stats {
p.statsLock.RLock()
defer p.statsLock.RUnlock()
stats := p.stats
stats.Connections.ActiveConnections = int64(p.connections.Len())
return stats
}
// GetConnectionCount 获取当前活跃连接数
// GetConnectionCount gets current active connection count
func (p *Packets) GetConnectionCount() int {
return p.connections.Len()
}
// GetAllConnections 获取所有活跃连接
// GetAllConnections gets all active connections
func (p *Packets) GetAllConnections() []PacketInfo {
return p.connections.GetAll()
}
// GetConnectionsByIP 根据 IP 地址查询连接
// GetConnectionsByIP queries connections by IP address
func (p *Packets) GetConnectionsByIP(ip string) []PacketInfo {
var result []PacketInfo
p.connections.Range(func(key string, value PacketInfo) bool {
if value.SrcIP == ip || value.DstIP == ip {
result = append(result, value)
}
return true
})
return result
}
// GetConnectionsByPort 根据端口查询连接
// GetConnectionsByPort queries connections by port
func (p *Packets) GetConnectionsByPort(port string) []PacketInfo {
var result []PacketInfo
p.connections.Range(func(key string, value PacketInfo) bool {
if value.SrcPort == port || value.DstPort == port {
result = append(result, value)
}
return true
})
return result
}
// GetConnectionsByType 根据协议类型查询连接
// GetConnectionsByType queries connections by protocol type
func (p *Packets) GetConnectionsByType(protocolType string) []PacketInfo {
var result []PacketInfo
p.connections.Range(func(key string, value PacketInfo) bool {
if value.Type == protocolType {
result = append(result, value)
}
return true
})
return result
}
// Key 根据 key 获取连接信息
// Key gets connection info by key
func (p *Packets) Key(key string) (PacketInfo, bool) {
return p.connections.Get(key)
}
// SetComment 设置连接注释
// SetComment sets connection comment
func (p *Packets) SetComment(key, comment string) {
if info, ok := p.connections.Get(key); ok {
info.comment = comment
p.connections.Set(key, info)
}
}
// ════════════════════════════════════════════════
// 连接清理方法 / Connection Cleanup Methods
// ════════════════════════════════════════════════
// CleanupExpiredConnections 清理过期连接
// CleanupExpiredConnections cleans up expired connections
func (p *Packets) CleanupExpiredConnections() int {
now := time.Now()
timeout := p.config.ConnectionTimeout
var expiredKeys []string
// 收集过期的 keys / Collect expired keys
p.connections.Range(func(key string, value PacketInfo) bool {
if now.Sub(value.LastSeen) > timeout {
expiredKeys = append(expiredKeys, key)
}
return true
})
// 批量删除 / Batch delete
if len(expiredKeys) > 0 {
p.connections.DeleteBatch(expiredKeys)
// 更新统计 / Update statistics
p.statsLock.Lock()
p.stats.Connections.TimeoutConnections += uint64(len(expiredKeys))
p.stats.LastCleanup = now
p.statsLock.Unlock()
}
return len(expiredKeys)
}
// ClearAllConnections 清空所有连接
// ClearAllConnections clears all connections
func (p *Packets) ClearAllConnections() {
p.connections.Clear()
p.statsLock.Lock()
p.stats.Connections.ActiveConnections = 0
p.statsLock.Unlock()
}
// ════════════════════════════════════════════════
// 错误处理方法 / Error Handling Methods
// ════════════════════════════════════════════════
// recordError 记录错误统计
// recordError records error statistics
func (p *Packets) recordError(errType ParseErrorType) {
p.statsLock.Lock()
defer p.statsLock.Unlock()
p.stats.Errors.TotalErrors++
switch errType {
case ErrTypeLinkLayer:
p.stats.Errors.LinkLayerErrors++
case ErrTypeNetwork:
p.stats.Errors.NetworkErrors++
case ErrTypeTransport:
p.stats.Errors.TransportErrors++
case ErrTypeUnsupported:
p.stats.Errors.UnsupportedErrors++
}
}
// handleError 处理错误(记录统计并调用回调)
// handleError handles error (records statistics and calls callback)
func (p *Packets) handleError(parseErr *ParseError, packet gopacket.Packet) {
p.recordError(parseErr.Type)
if p.config.EnableDebugLog {
fmt.Printf("[ERROR] %s\n", parseErr.Error())
}
if p.config.OnError != nil {
p.config.OnError(parseErr, packet)
}
}
// ════════════════════════════════════════════════
// 数据包解析方法 / Packet Parsing Methods
// ════════════════════════════════════════════════
// ParsePacket 解析数据包,支持 Ethernet、Linux SLL、Linux SLL2 等链路层格式
// ParsePacket parses packets, supporting Ethernet, Linux SLL, Linux SLL2 and other link layer formats
//
// 参数 / Parameters:
// - packet: gopacket 数据包对象 / gopacket packet object
// - opts: 可选参数opts[0] 可以是 *[]byte 类型的 MAC 地址(用于 nfqueue 等场景)
// / Optional parameters, opts[0] can be *[]byte type MAC address (for nfqueue scenarios)
//
// 返回 / Returns:
// - PacketInfo: 解析后的数据包信息 / Parsed packet information
// - error: 解析错误 / Parse error
func (p *Packets) ParsePacket(packet gopacket.Packet, opts ...interface{}) (PacketInfo, error) {
var info PacketInfo
// 提取时间戳 / Extract timestamp
metadata := packet.Metadata()
if metadata != nil {
info.Timestamp = metadata.Timestamp
info.TimestampMicros = metadata.Timestamp.UnixMicro()
// 记录首个数据包时间 / Record first packet time
if p.firstPacketTime.IsZero() {
p.firstPacketTime = metadata.Timestamp
}
// 计算相对时间 / Calculate relative time
info.RelativeTime = metadata.Timestamp.Sub(p.firstPacketTime)
} else {
info.Timestamp = time.Now()
info.TimestampMicros = info.Timestamp.UnixMicro()
}
// ────────────────────────────────────────────────
// 链路层:提取 MAC 地址 / Link Layer: Extract MAC addresses
// 支持 Ethernet、Linux SLL、Linux SLL2 / Support Ethernet, Linux SLL, Linux SLL2
// ────────────────────────────────────────────────
var srcMac, dstMac net.HardwareAddr
// 情况 1: 标准以太网层 / Case 1: Standard Ethernet layer
if ethLayer := packet.Layer(layers.LayerTypeEthernet); ethLayer != nil {
eth := ethLayer.(*layers.Ethernet)
srcMac = eth.SrcMAC
dstMac = eth.DstMAC
} else if sllLayer := packet.Layer(layers.LayerTypeLinuxSLL); sllLayer != nil {
// 情况 2: Linux SLL (cooked capture v1) / Case 2: Linux SLL (cooked capture v1)
sll := sllLayer.(*layers.LinuxSLL)
if sll.AddrType == 1 && sll.AddrLen == 6 { // 1 = ARPHRD_ETHER
srcMac = sll.Addr
}
} else if sll2Layer := packet.Layer(layers.LayerTypeLinuxSLL2); sll2Layer != nil {
// 情况 3: Linux SLL2 (cooked capture v2) / Case 3: Linux SLL2 (cooked capture v2)
sll2 := sll2Layer.(*layers.LinuxSLL2)
if sll2.ARPHardwareType == 1 && sll2.AddrLength == 6 { // 1 = ARPHRD_ETHER
srcMac = sll2.Addr
}
}
// 可选:使用外部提供的 MAC 地址覆盖 / Optional: Override with externally provided MAC
for k, v := range opts {
if k == 0 {
if b, ok := v.(*[]byte); ok && b != nil && len(*b) == 6 {
srcMac = net.HardwareAddr(*b)
}
}
}
info.SrcMac = srcMac
info.DstMac = dstMac
// ────────────────────────────────────────────────
// 网络层:提取 IP 地址 / Network Layer: Extract IP addresses
// ────────────────────────────────────────────────
if nw := packet.NetworkLayer(); nw != nil {
srcp, dstp := nw.NetworkFlow().Endpoints()
info.SrcIP = srcp.String()
info.DstIP = dstp.String()
} else {
parseErr := NewParseError(ErrTypeNetwork, "Network", "no valid network layer found", nil)
p.handleError(parseErr, packet)
return info, parseErr
}
// ────────────────────────────────────────────────
// 传输层:解析 TCP/UDP/ICMP / Transport Layer: Parse TCP/UDP/ICMP
// ────────────────────────────────────────────────
// TCP 协议 / TCP protocol
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
if tcp, ok := tcpLayer.(*layers.TCP); ok {
return p.parseTcp(info, packet, tcpLayer, tcp)
}
}
// UDP 协议 / UDP protocol
if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil {
if udp, ok := udpLayer.(*layers.UDP); ok {
return p.parseUdp(info, packet, udpLayer, udp)
}
}
// ICMPv4 协议 / ICMPv4 protocol
if icmpLayer := packet.Layer(layers.LayerTypeICMPv4); icmpLayer != nil {
if icmp, ok := icmpLayer.(*layers.ICMPv4); ok {
return p.parseIcmp(info, packet, icmpLayer, icmp)
}
}
// ICMPv6 协议 / ICMPv6 protocol
if icmpv6Layer := packet.Layer(layers.LayerTypeICMPv6); icmpv6Layer != nil {
if icmpv6, ok := icmpv6Layer.(*layers.ICMPv6); ok {
return p.parseIcmpv6(info, packet, icmpv6Layer, icmpv6)
}
}
// 不支持的协议类型 / Unsupported protocol type
parseErr := NewParseError(ErrTypeUnsupported, "Transport",
"unsupported packet type (not TCP/UDP/ICMP/ICMPv6)", nil)
p.handleError(parseErr, packet)
return info, parseErr
}
// parseTcp 解析 TCP 数据包并进行状态跟踪
// parseTcp parses TCP packets and performs state tracking
func (p *Packets) parseTcp(info PacketInfo, packet gopacket.Packet, layer gopacket.Layer, tcp *layers.TCP) (PacketInfo, error) {
// 使用优化的 key 构建 / Use optimized key building
info.Key = buildKey("tcp", info.SrcIP, fmt.Sprintf("%d", tcp.SrcPort), info.DstIP, fmt.Sprintf("%d", tcp.DstPort))
info.ReverseKey = buildKey("tcp", info.DstIP, fmt.Sprintf("%d", tcp.DstPort), info.SrcIP, fmt.Sprintf("%d", tcp.SrcPort))
info.Type = "tcp"
info.SrcPort = fmt.Sprintf("%d", tcp.SrcPort)
info.DstPort = fmt.Sprintf("%d", tcp.DstPort)
info.packet = packet
info.tcpSeq = tcp.Seq
info.tcpAck = tcp.Ack
info.tcpPayloads = len(layer.LayerPayload())
info.finState = tcp.FIN
info.synState = tcp.SYN
info.tcpWindow = tcp.Window
// 获取上一个同方向的数据包 / Get the last packet in the same direction
lastPacket, exists := p.connections.Get(info.Key)
// 如果是新连接,初始化状态 / If it's a new connection, initialize state
if !exists {
lastPacket = PacketInfo{
Key: info.Key,
ReverseKey: info.ReverseKey,
Type: "tcp",
SrcIP: info.SrcIP,
SrcPort: info.SrcPort,
DstIP: info.DstIP,
DstPort: info.DstPort,
FirstSeen: info.Timestamp,
LastSeen: info.Timestamp,
PacketCount: 0,
ByteCount: 0,
tcpSeq: tcp.Seq,
tcpAck: tcp.Ack,
tcpWindow: tcp.Window,
tcpPayloads: len(layer.LayerPayload()),
finState: tcp.FIN,
synState: tcp.SYN,
isFirst: true,
stateDescript: StateUnknown,
}
// 更新统计 / Update statistics
p.statsLock.Lock()
p.stats.Connections.TotalConnections++
atomic.AddInt64(&p.stats.Connections.TcpConnections, 1)
p.statsLock.Unlock()
// 触发新连接回调 / Trigger new connection callback
if p.config.OnNewConnection != nil {
p.config.OnNewConnection(lastPacket)
}
}
// 更新连接统计 / Update connection statistics
info.FirstSeen = lastPacket.FirstSeen
info.LastSeen = info.Timestamp
info.PacketCount = lastPacket.PacketCount + 1
info.ByteCount = lastPacket.ByteCount + uint64(len(packet.Data()))
// 获取反向连接的数据包 / Get the reverse direction packet
lastReverse, _ := p.connections.Get(info.ReverseKey)
// 继承上一个数据包的注释和 MAC 地址 / Inherit comment and MAC addresses from last packet
if !lastPacket.isFirst {
info.comment = lastPacket.comment
if lastPacket.SrcMac != nil && len(info.SrcMac) == 0 {
info.SrcMac = lastPacket.SrcMac
}
if lastPacket.DstMac != nil && len(info.DstMac) == 0 {
info.DstMac = lastPacket.DstMac
}
}
if lastReverse.SrcMac != nil && len(info.DstMac) == 0 {
info.DstMac = lastReverse.SrcMac
}
// ────────────────────────────────────────────────
// TCP 状态机判断 / TCP state machine
// ────────────────────────────────────────────────
connectionClosed := false
// RST 标志:连接重置 / RST flag: connection reset
if tcp.RST {
info.stateDescript = StateTcpRst
p.connections.Delete(info.Key)
p.connections.Delete(info.ReverseKey)
connectionClosed = true
// 更新统计 / Update statistics
p.statsLock.Lock()
p.stats.Connections.ClosedConnections++
atomic.AddInt64(&p.stats.Connections.TcpConnections, -1)
p.statsLock.Unlock()
// 触发连接关闭回调 / Trigger connection closed callback
if p.config.OnConnectionClosed != nil {
p.config.OnConnectionClosed(info)
}
return info, nil
}
// 三次握手 / Three-way handshake
if tcp.SYN && !tcp.ACK {
info.stateDescript = StateTcpConnect1 // SYN
} else if tcp.SYN && tcp.ACK {
info.stateDescript = StateTcpConnect2 // SYN-ACK
} else if tcp.ACK {
if !tcp.FIN {
// 三次握手第三步 / Three-way handshake step 3
if lastReverse.tcpSeq+1 == tcp.Ack && lastReverse.stateDescript == StateTcpConnect2 {
info.stateDescript = StateTcpConnect3
} else if tcp.CWR {
info.stateDescript = StateTcpCwr
} else if tcp.ECE {
info.stateDescript = StateTcpEce
}
if info.stateDescript != StateUnknown {
goto savereturn
}
// TCP 保活检测 / TCP keepalive detection
if info.tcpSeq == lastReverse.tcpAck-1 && info.tcpSeq == lastPacket.tcpSeq+uint32(lastPacket.tcpPayloads)-1 {
info.stateDescript = StateTcpKeepalive
goto savereturn
}
// TCP 重传检测 / TCP retransmission detection
if !lastPacket.isFirst {
if info.tcpSeq < lastPacket.tcpSeq+uint32(lastPacket.tcpPayloads) {
info.stateDescript = StateTcpRetransmit
goto savereturn
}
}
// 四次挥手完成 / Four-way handshake completed
if lastReverse.finState && lastPacket.finState {
info.stateDescript = StateTcpDisconnect4
p.connections.Delete(info.Key)
p.connections.Delete(info.ReverseKey)
connectionClosed = true
// 更新统计 / Update statistics
p.statsLock.Lock()
p.stats.Connections.ClosedConnections++
atomic.AddInt64(&p.stats.Connections.TcpConnections, -1)
p.statsLock.Unlock()
// 触发连接关闭回调 / Trigger connection closed callback
if p.config.OnConnectionClosed != nil {
p.config.OnConnectionClosed(info)
}
return info, nil
}
// 四次挥手第二步 / Four-way handshake step 2
if lastReverse.finState && lastReverse.tcpSeq+1 == info.tcpAck {
info.stateDescript = StateTcpDisconnect2
goto savereturn
}
// 正常 ACK / Normal ACK
info.stateDescript = StateTcpAckOk
} else {
// 四次挥手 / Four-way handshake
if !lastReverse.finState {
info.stateDescript = StateTcpDisconnect1 // FIN
} else {
if lastReverse.finState && lastReverse.tcpSeq+1 == info.tcpAck &&
lastPacket.tcpAck == info.tcpAck && lastPacket.tcpSeq == info.tcpSeq {
info.stateDescript = StateTcpDisconnect3 // FIN (step 3)
} else {
info.stateDescript = StateTcpDisconnect23 // FIN-ACK (step 2+3 combined)
}
}
}
}
savereturn:
// 只有在连接未关闭时才保存 / Only save if connection is not closed
if !connectionClosed {
p.connections.Set(info.Key, info)
}
return info, nil
}
// parseUdp 解析 UDP 数据包
// parseUdp parses UDP packets
func (p *Packets) parseUdp(info PacketInfo, packet gopacket.Packet, layer gopacket.Layer, udp *layers.UDP) (PacketInfo, error) {
// 使用优化的 key 构建 / Use optimized key building
info.Key = buildKey("udp", info.SrcIP, fmt.Sprintf("%d", udp.SrcPort), info.DstIP, fmt.Sprintf("%d", udp.DstPort))
info.ReverseKey = buildKey("udp", info.DstIP, fmt.Sprintf("%d", udp.DstPort), info.SrcIP, fmt.Sprintf("%d", udp.SrcPort))
info.Type = "udp"
info.SrcPort = fmt.Sprintf("%d", udp.SrcPort)
info.DstPort = fmt.Sprintf("%d", udp.DstPort)
info.packet = packet
info.tcpPayloads = len(layer.LayerPayload())
info.stateDescript = StateUdp
// 获取已存在的连接信息 / Get existing connection info
lastPacket, exists := p.connections.Get(info.Key)
if !exists {
// 新 UDP 连接 / New UDP connection
info.FirstSeen = info.Timestamp
info.LastSeen = info.Timestamp
info.PacketCount = 1
info.ByteCount = uint64(len(packet.Data()))
// 更新统计 / Update statistics
p.statsLock.Lock()
p.stats.Connections.TotalConnections++
atomic.AddInt64(&p.stats.Connections.UdpConnections, 1)
p.statsLock.Unlock()
// 触发新连接回调 / Trigger new connection callback
if p.config.OnNewConnection != nil {
p.config.OnNewConnection(info)
}
} else {
// 更新已存在的连接 / Update existing connection
info.FirstSeen = lastPacket.FirstSeen
info.LastSeen = info.Timestamp
info.PacketCount = lastPacket.PacketCount + 1
info.ByteCount = lastPacket.ByteCount + uint64(len(packet.Data()))
info.comment = lastPacket.comment
// 继承 MAC 地址 / Inherit MAC addresses
if lastPacket.SrcMac != nil && len(info.SrcMac) == 0 {
info.SrcMac = lastPacket.SrcMac
}
if lastPacket.DstMac != nil && len(info.DstMac) == 0 {
info.DstMac = lastPacket.DstMac
}
}
p.connections.Set(info.Key, info)
return info, nil
}
// parseIcmp 解析 ICMPv4 数据包
// parseIcmp parses ICMPv4 packets
func (p *Packets) parseIcmp(info PacketInfo, packet gopacket.Packet, layer gopacket.Layer, icmp *layers.ICMPv4) (PacketInfo, error) {
info.Type = "icmp"
info.IcmpType = uint8(icmp.TypeCode.Type())
info.IcmpCode = uint8(icmp.TypeCode.Code())
info.IcmpChecksum = icmp.Checksum
info.IcmpId = icmp.Id
info.IcmpSeq = icmp.Seq
info.tcpPayloads = len(layer.LayerPayload())
info.stateDescript = StateIcmp
// ICMP 的 Key 格式icmp://srcIP=dstIP:type:code:id:seq
// ICMP Key format: icmp://srcIP=dstIP:type:code:id:seq
sb := getStringBuilder()
defer putStringBuilder(sb)
sb.WriteString("icmp://")
sb.WriteString(info.SrcIP)
sb.WriteString("=")
sb.WriteString(info.DstIP)
sb.WriteString(":")
sb.WriteString(fmt.Sprintf("%d:%d:%d:%d", info.IcmpType, info.IcmpCode, info.IcmpId, info.IcmpSeq))
info.Key = sb.String()
sb.Reset()
sb.WriteString("icmp://")
sb.WriteString(info.DstIP)
sb.WriteString("=")
sb.WriteString(info.SrcIP)
sb.WriteString(":")
sb.WriteString(fmt.Sprintf("%d:%d:%d:%d", info.IcmpType, info.IcmpCode, info.IcmpId, info.IcmpSeq))
info.ReverseKey = sb.String()
info.packet = packet
// 获取已存在的连接信息 / Get existing connection info
lastPacket, exists := p.connections.Get(info.Key)
if !exists {
// 新 ICMP 连接 / New ICMP connection
info.FirstSeen = info.Timestamp
info.LastSeen = info.Timestamp
info.PacketCount = 1
info.ByteCount = uint64(len(packet.Data()))
// 更新统计 / Update statistics
p.statsLock.Lock()
p.stats.Connections.TotalConnections++
atomic.AddInt64(&p.stats.Connections.IcmpConnections, 1)
p.statsLock.Unlock()
// 触发新连接回调 / Trigger new connection callback
if p.config.OnNewConnection != nil {
p.config.OnNewConnection(info)
}
} else {
// 更新已存在的连接 / Update existing connection
info.FirstSeen = lastPacket.FirstSeen
info.LastSeen = info.Timestamp
info.PacketCount = lastPacket.PacketCount + 1
info.ByteCount = lastPacket.ByteCount + uint64(len(packet.Data()))
info.comment = lastPacket.comment
// 继承 MAC 地址 / Inherit MAC addresses
if lastPacket.SrcMac != nil && len(info.SrcMac) == 0 {
info.SrcMac = lastPacket.SrcMac
}
if lastPacket.DstMac != nil && len(info.DstMac) == 0 {
info.DstMac = lastPacket.DstMac
}
}
p.connections.Set(info.Key, info)
return info, nil
}
// parseIcmpv6 解析 ICMPv6 数据包
// parseIcmpv6 parses ICMPv6 packets
func (p *Packets) parseIcmpv6(info PacketInfo, packet gopacket.Packet, layer gopacket.Layer, icmpv6 *layers.ICMPv6) (PacketInfo, error) {
info.Type = "icmpv6"
info.IcmpType = uint8(icmpv6.TypeCode.Type())
info.IcmpCode = uint8(icmpv6.TypeCode.Code())
info.IcmpChecksum = icmpv6.Checksum
info.tcpPayloads = len(layer.LayerPayload())
info.stateDescript = StateIcmpv6
// ICMPv6 的 Key 格式icmpv6://srcIP=dstIP:type:code
// ICMPv6 Key format: icmpv6://srcIP=dstIP:type:code
sb := getStringBuilder()
defer putStringBuilder(sb)
sb.WriteString("icmpv6://")
sb.WriteString(info.SrcIP)
sb.WriteString("=")
sb.WriteString(info.DstIP)
sb.WriteString(":")
sb.WriteString(fmt.Sprintf("%d:%d", info.IcmpType, info.IcmpCode))
info.Key = sb.String()
sb.Reset()
sb.WriteString("icmpv6://")
sb.WriteString(info.DstIP)
sb.WriteString("=")
sb.WriteString(info.SrcIP)
sb.WriteString(":")
sb.WriteString(fmt.Sprintf("%d:%d", info.IcmpType, info.IcmpCode))
info.ReverseKey = sb.String()
info.packet = packet
// 获取已存在的连接信息 / Get existing connection info
lastPacket, exists := p.connections.Get(info.Key)
if !exists {
// 新 ICMPv6 连接 / New ICMPv6 connection
info.FirstSeen = info.Timestamp
info.LastSeen = info.Timestamp
info.PacketCount = 1
info.ByteCount = uint64(len(packet.Data()))
// 更新统计 / Update statistics
p.statsLock.Lock()
p.stats.Connections.TotalConnections++
atomic.AddInt64(&p.stats.Connections.IcmpConnections, 1)
p.statsLock.Unlock()
// 触发新连接回调 / Trigger new connection callback
if p.config.OnNewConnection != nil {
p.config.OnNewConnection(info)
}
} else {
// 更新已存在的连接 / Update existing connection
info.FirstSeen = lastPacket.FirstSeen
info.LastSeen = info.Timestamp
info.PacketCount = lastPacket.PacketCount + 1
info.ByteCount = lastPacket.ByteCount + uint64(len(packet.Data()))
info.comment = lastPacket.comment
// 继承 MAC 地址 / Inherit MAC addresses
if lastPacket.SrcMac != nil && len(info.SrcMac) == 0 {
info.SrcMac = lastPacket.SrcMac
}
if lastPacket.DstMac != nil && len(info.DstMac) == 0 {
info.DstMac = lastPacket.DstMac
}
}
p.connections.Set(info.Key, info)
return info, nil
}
// ════════════════════════════════════════════════
// 辅助方法和工具函数 / Helper Methods and Utility Functions
// ════════════════════════════════════════════════
// GetStateDescription 获取状态描述符的文本描述
// GetStateDescription gets text description of state descriptor
func GetStateDescription(state uint8) string {
switch state {
case StateUnknown:
return "Unknown"
case StateTcpConnect1:
return "TCP SYN"
case StateTcpConnect2:
return "TCP SYN-ACK"
case StateTcpConnect3:
return "TCP ACK (Connected)"
case StateTcpDisconnect1:
return "TCP FIN (Step 1)"
case StateTcpDisconnect2:
return "TCP ACK (Step 2)"
case StateTcpDisconnect23:
return "TCP FIN-ACK (Step 2+3)"
case StateTcpDisconnect3:
return "TCP FIN (Step 3)"
case StateTcpDisconnect4:
return "TCP ACK (Closed)"
case StateTcpAckOk:
return "TCP ACK"
case StateTcpRetransmit:
return "TCP Retransmission"
case StateTcpEce:
return "TCP ECE"
case StateTcpCwr:
return "TCP CWR"
case StateTcpRst:
return "TCP RST"
case StateTcpKeepalive:
return "TCP Keepalive"
case StateUdp:
return "UDP"
case StateIcmp:
return "ICMP"
case StateIcmpv6:
return "ICMPv6"
default:
return fmt.Sprintf("Unknown(%d)", state)
}
}
// FormatDuration 格式化时间间隔为人类可读格式
// FormatDuration formats duration to human readable format
func FormatDuration(d time.Duration) string {
if d < time.Microsecond {
return fmt.Sprintf("%dns", d.Nanoseconds())
} else if d < time.Millisecond {
return fmt.Sprintf("%.2fµs", float64(d.Nanoseconds())/1000.0)
} else if d < time.Second {
return fmt.Sprintf("%.2fms", float64(d.Microseconds())/1000.0)
} else if d < time.Minute {
return fmt.Sprintf("%.2fs", d.Seconds())
} else if d < time.Hour {
return fmt.Sprintf("%.2fm", d.Minutes())
}
return fmt.Sprintf("%.2fh", d.Hours())
}
// FormatBytes 格式化字节数为人类可读格式
// FormatBytes formats bytes to human readable format
func FormatBytes(bytes uint64) string {
const unit = 1024
if bytes < unit {
return fmt.Sprintf("%d B", bytes)
}
div, exp := uint64(unit), 0
for n := bytes / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.2f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
}
// PrintStats 打印统计信息(用于调试)
// PrintStats prints statistics (for debugging)
func (p *Packets) PrintStats() {
stats := p.GetStats()
fmt.Println("════════════════════════════════════════")
fmt.Println("Packet Statistics / 数据包统计")
fmt.Println("════════════════════════════════════════")
fmt.Printf("Start Time / 启动时间: %s\n", stats.StartTime.Format("2006-01-02 15:04:05"))
fmt.Printf("Uptime / 运行时间: %s\n", FormatDuration(time.Since(stats.StartTime)))
fmt.Println()
fmt.Println("Connection Statistics / 连接统计:")
fmt.Printf(" Active / 活跃: %d\n", stats.Connections.ActiveConnections)
fmt.Printf(" Total / 总计: %d\n", stats.Connections.TotalConnections)
fmt.Printf(" Closed / 已关闭: %d\n", stats.Connections.ClosedConnections)
fmt.Printf(" Timeout / 超时: %d\n", stats.Connections.TimeoutConnections)
fmt.Printf(" TCP: %d\n", stats.Connections.TcpConnections)
fmt.Printf(" UDP: %d\n", stats.Connections.UdpConnections)
fmt.Printf(" ICMP: %d\n", stats.Connections.IcmpConnections)
fmt.Println()
fmt.Println("Error Statistics / 错误统计:")
fmt.Printf(" Total / 总计: %d\n", stats.Errors.TotalErrors)
fmt.Printf(" Link Layer / 链路层: %d\n", stats.Errors.LinkLayerErrors)
fmt.Printf(" Network / 网络层: %d\n", stats.Errors.NetworkErrors)
fmt.Printf(" Transport / 传输层: %d\n", stats.Errors.TransportErrors)
fmt.Printf(" Unsupported / 不支持: %d\n", stats.Errors.UnsupportedErrors)
if !stats.LastCleanup.IsZero() {
fmt.Println()
fmt.Printf("Last Cleanup / 上次清理: %s\n", stats.LastCleanup.Format("2006-01-02 15:04:05"))
}
fmt.Println("════════════════════════════════════════")
}
// ExportConnectionsToJSON 导出连接信息为 JSON 格式(示例)
// ExportConnectionsToJSON exports connections to JSON format (example)
func (p *Packets) ExportConnectionsToJSON() string {
connections := p.GetAllConnections()
sb := getStringBuilder()
defer putStringBuilder(sb)
sb.WriteString("[\n")
for i, conn := range connections {
if i > 0 {
sb.WriteString(",\n")
}
sb.WriteString(fmt.Sprintf(` {
"key": "%s",
"type": "%s",
"src_ip": "%s",
"src_port": "%s",
"dst_ip": "%s",
"dst_port": "%s",
"packet_count": %d,
"byte_count": %d,
"state": "%s",
"first_seen": "%s",
"last_seen": "%s",
"duration": "%s"
}`,
conn.Key,
conn.Type,
conn.SrcIP,
conn.SrcPort,
conn.DstIP,
conn.DstPort,
conn.PacketCount,
conn.ByteCount,
GetStateDescription(conn.stateDescript),
conn.FirstSeen.Format(time.RFC3339),
conn.LastSeen.Format(time.RFC3339),
FormatDuration(conn.LastSeen.Sub(conn.FirstSeen)),
))
}
sb.WriteString("\n]")
return sb.String()
}