diff --git a/inspector.exe b/inspector.exe index 20988d3..2f5f5b6 100644 Binary files a/inspector.exe and b/inspector.exe differ diff --git a/internal/capture/capturer.go b/internal/capture/capturer.go index 573992b..0338dee 100644 --- a/internal/capture/capturer.go +++ b/internal/capture/capturer.go @@ -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, + } +} diff --git a/internal/capture/local.go b/internal/capture/local.go index fe7db49..eaaa2ef 100644 --- a/internal/capture/local.go +++ b/internal/capture/local.go @@ -15,10 +15,11 @@ import ( // LocalCapturer handles SIP packet capture locally via tcpdump type LocalCapturer struct { - cmd *exec.Cmd - cancel context.CancelFunc - running bool - mu sync.Mutex + cmd *exec.Cmd + 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)