fix: Robust parsing of SIP messages from tcpdump output containing raw header artifacts

This commit is contained in:
Jose Luis Montañes Ojados
2026-01-19 15:35:13 +01:00
parent 4fa44fb9c7
commit 2d99d8ddc4
3 changed files with 36 additions and 14 deletions

Binary file not shown.

View File

@@ -115,7 +115,10 @@ func (c *Capturer) processStream(r io.Reader) {
line := scanner.Text() line := scanner.Text()
// Detect start of SIP message // Detect start of SIP message
if isSIPStart(line) { if idx := findSIPStart(line); idx != -1 {
// Clean the line (remove prefix garbage)
line = line[idx:]
// If we were building a message, parse it // If we were building a message, parse it
if buffer.Len() > 0 { if buffer.Len() > 0 {
c.parseAndEmit(buffer.String()) c.parseAndEmit(buffer.String())
@@ -161,21 +164,37 @@ func (c *Capturer) parseAndEmit(raw string) {
} }
} }
// isSIPStart checks if a line looks like the start of a SIP message // findSIPStart returns the index of the start of a SIP message, or -1 if not found
func isSIPStart(line string) bool { func findSIPStart(line string) int {
sipMethods := []string{"INVITE", "ACK", "BYE", "CANCEL", "REGISTER", "OPTIONS", "PRACK", "SUBSCRIBE", "NOTIFY", "PUBLISH", "INFO", "REFER", "MESSAGE", "UPDATE"} sipMethods := []string{"INVITE", "ACK", "BYE", "CANCEL", "REGISTER", "OPTIONS", "PRACK", "SUBSCRIBE", "NOTIFY", "PUBLISH", "INFO", "REFER", "MESSAGE", "UPDATE"}
// Response // Check for Response "SIP/2.0"
if strings.HasPrefix(line, "SIP/2.0") { if idx := strings.Index(line, "SIP/2.0 "); idx != -1 {
return true // Verify it's not part of a header like Via or Record-Route
} // We look at what comes before. If it's the start of the line or preceded by garbage (nulls etc), it's likely a start.
// If it is preceded by "Via: " or "Route: ", it is a header.
// Request prefix := strings.ToUpper(line[:idx])
for _, m := range sipMethods { if !strings.HasSuffix(prefix, "VIA: ") &&
if strings.HasPrefix(line, m+" ") { !strings.HasSuffix(prefix, "ROUTE: ") &&
return true !strings.HasSuffix(prefix, "VIA:") { // Handle varying spacing
return idx
} }
} }
return false // Check for Request "METHOD "
for _, m := range sipMethods {
target := m + " "
if idx := strings.Index(line, target); idx != -1 {
// Verify it's not CSeq, Allow, Rack, etc.
prefix := strings.ToUpper(line[:idx])
if !strings.HasSuffix(prefix, "CSEQ: ") &&
!strings.HasSuffix(prefix, "ALLOW: ") &&
!strings.HasSuffix(prefix, "RACK: ") &&
!strings.HasSuffix(prefix, "SUPPORTED: ") {
return idx
}
}
}
return -1
} }

View File

@@ -139,8 +139,11 @@ func (c *LocalCapturer) processStream(r io.Reader) {
// logger.Debug("Stdout: %s", line) // Commented out to reduce noise, enable if needed // logger.Debug("Stdout: %s", line) // Commented out to reduce noise, enable if needed
// Detect start of SIP message // Detect start of SIP message
if isSIPStart(line) { if idx := findSIPStart(line); idx != -1 {
logger.Debug("SIP Start detected: %s", line) logger.Debug("SIP Start detected: %s", line)
// Clean the line (remove prefix garbage)
line = line[idx:]
// If we were building a message, parse it // If we were building a message, parse it
if buffer.Len() > 0 { if buffer.Len() > 0 {
c.parseAndEmit(buffer.String()) c.parseAndEmit(buffer.String())