fix: Extract network metadata from tcpdump headers to populate SIP packet IPs
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"telephony-inspector/internal/sip"
|
||||
internalSSH "telephony-inspector/internal/ssh"
|
||||
@@ -13,10 +14,11 @@ import (
|
||||
|
||||
// Capturer handles SIP packet capture via SSH
|
||||
type Capturer struct {
|
||||
sshClient *internalSSH.Client
|
||||
cleanup func() error
|
||||
running bool
|
||||
mu sync.Mutex
|
||||
sshClient *internalSSH.Client
|
||||
cleanup func() error
|
||||
running bool
|
||||
mu sync.Mutex
|
||||
currentNetInfo *NetInfo
|
||||
|
||||
// Callbacks
|
||||
OnPacket func(*sip.Packet)
|
||||
@@ -114,6 +116,15 @@ func (c *Capturer) processStream(r io.Reader) {
|
||||
|
||||
line := scanner.Text()
|
||||
|
||||
// Check for tcpdump header
|
||||
if netInfo := parseTcpdumpHeader(line); netInfo != nil {
|
||||
c.currentNetInfo = netInfo
|
||||
// If we were parsing a message, this header likely means the previous message ended (or it's just info)
|
||||
// But tcpdump prints header BEFORE payload.
|
||||
// Proceed to next line
|
||||
continue
|
||||
}
|
||||
|
||||
// Detect start of SIP message
|
||||
if idx := findSIPStart(line); idx != -1 {
|
||||
// Clean the line (remove prefix garbage)
|
||||
@@ -159,8 +170,21 @@ func (c *Capturer) parseAndEmit(raw string) {
|
||||
}
|
||||
return
|
||||
}
|
||||
if packet != nil && c.OnPacket != nil {
|
||||
c.OnPacket(packet)
|
||||
if packet != nil {
|
||||
// Attach network info if available
|
||||
if c.currentNetInfo != nil {
|
||||
// Use timestamp from packet header if possible, or keep what parser found?
|
||||
// Parser doesn't find time.
|
||||
packet.Timestamp = c.currentNetInfo.Timestamp
|
||||
packet.SourceIP = c.currentNetInfo.SourceIP
|
||||
packet.SourcePort = c.currentNetInfo.SourcePort
|
||||
packet.DestIP = c.currentNetInfo.DestIP
|
||||
packet.DestPort = c.currentNetInfo.DestPort
|
||||
}
|
||||
|
||||
if c.OnPacket != nil {
|
||||
c.OnPacket(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,3 +222,57 @@ func findSIPStart(line string) int {
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
// NetInfo stores network layer information from tcpdump headers
|
||||
type NetInfo struct {
|
||||
Timestamp time.Time
|
||||
SourceIP string
|
||||
SourcePort int
|
||||
DestIP string
|
||||
DestPort int
|
||||
}
|
||||
|
||||
func parseTcpdumpHeader(line string) *NetInfo {
|
||||
// Format: 15:35:10.430328 IP 192.168.0.164.51416 > 192.168.0.158.5060: ...
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 5 || parts[1] != "IP" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parse Timestamp
|
||||
// Using generic date + log time
|
||||
now := time.Now()
|
||||
t, err := time.Parse("15:04:05.000000", parts[0])
|
||||
if err == nil {
|
||||
t = time.Date(now.Year(), now.Month(), now.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), now.Location())
|
||||
} else {
|
||||
t = now
|
||||
}
|
||||
|
||||
// Helper to extract IP and Port
|
||||
parseIPPort := func(s string) (string, int) {
|
||||
lastDot := strings.LastIndex(s, ".")
|
||||
if lastDot == -1 {
|
||||
return s, 0
|
||||
}
|
||||
ip := s[:lastDot]
|
||||
portStr := s[lastDot+1:]
|
||||
// Remove trailing colon if present (dest)
|
||||
portStr = strings.TrimSuffix(portStr, ":")
|
||||
|
||||
var port int
|
||||
fmt.Sscanf(portStr, "%d", &port)
|
||||
return ip, port
|
||||
}
|
||||
|
||||
srcIP, srcPort := parseIPPort(parts[2])
|
||||
dstIP, dstPort := parseIPPort(parts[4])
|
||||
|
||||
return &NetInfo{
|
||||
Timestamp: t,
|
||||
SourceIP: srcIP,
|
||||
SourcePort: srcPort,
|
||||
DestIP: dstIP,
|
||||
DestPort: dstPort,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user