fix: Extract network metadata from tcpdump headers to populate SIP packet IPs

This commit is contained in:
Jose Luis Montañes Ojados
2026-01-19 15:40:11 +01:00
parent 2d99d8ddc4
commit f0911737f4
3 changed files with 104 additions and 10 deletions

Binary file not shown.

View File

@@ -6,6 +6,7 @@ import (
"io"
"strings"
"sync"
"time"
"telephony-inspector/internal/sip"
internalSSH "telephony-inspector/internal/ssh"
@@ -17,6 +18,7 @@ type Capturer struct {
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,10 +170,23 @@ func (c *Capturer) parseAndEmit(raw string) {
}
return
}
if packet != nil && c.OnPacket != nil {
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)
}
}
}
// findSIPStart returns the index of the start of a SIP message, or -1 if not found
func findSIPStart(line string) int {
@@ -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,
}
}

View File

@@ -19,6 +19,7 @@ type LocalCapturer struct {
cancel context.CancelFunc
running bool
mu sync.Mutex
currentNetInfo *NetInfo
// Callbacks
OnPacket func(*sip.Packet)
@@ -138,6 +139,13 @@ func (c *LocalCapturer) processStream(r io.Reader) {
line := scanner.Text()
// logger.Debug("Stdout: %s", line) // Commented out to reduce noise, enable if needed
// Check for tcpdump header
if netInfo := parseTcpdumpHeader(line); netInfo != nil {
c.currentNetInfo = netInfo
// Proceed to next line
continue
}
// Detect start of SIP message
if idx := findSIPStart(line); idx != -1 {
logger.Debug("SIP Start detected: %s", line)
@@ -190,6 +198,14 @@ func (c *LocalCapturer) parseAndEmit(raw string) {
return
}
if packet != nil {
// Attach network info if available
if c.currentNetInfo != nil {
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
}
logger.Debug("Packet parsed: %s %s -> %s", packet.Method, packet.SourceIP, packet.DestIP)
if c.OnPacket != nil {
c.OnPacket(packet)