|Guides

Reading a SIP Trace Without Losing Your Mind

SIP traces are text-based and readable, but finding the problem in hundreds of messages is overwhelming. A practical guide to cutting through the noise and getting to the answer fast.

You have a packet capture. Someone told you the answer is in there. You open it and there are 4,000 SIP messages, half of which are REGISTER keep-alives, and the other half are OPTIONS pings that have nothing to do with the problem. The call you care about is buried somewhere in the middle.

This is the part where most people give up and call the provider. But you do not have to read every message. You need a strategy for cutting through the noise and getting to the one that matters.

The problem with raw SIP traces

SIP is text-based, which is both its greatest strength and its most annoying property when troubleshooting. Every message is human-readable. That sounds great until you realize a single call generates 8-12 messages minimum (INVITE, 100, 180, 200, ACK, and eventually BYE, 200), and a busy system produces thousands of messages per hour. Most of them are routine and uninteresting.

The messages you care about are the ones where something went wrong. But they look exactly like the ones where everything went right, except for a different number on the first line.

Step 1: Kill the noise

Before you look at anything else, filter out the traffic that is definitely not your problem.

Remove REGISTERs. Unless you are specifically troubleshooting registration failures, REGISTER messages are just keep-alive noise. Every phone on the system sends them every few minutes. On a 50-phone system, that is hundreds of messages per hour that have nothing to do with call quality or call failures.

In Wireshark:

sip && !(sip.Method == REGISTER)

Remove OPTIONS. Many systems send OPTIONS messages as keep-alive pings between the PBX and the provider. They confirm the trunk is up. Unless the trunk itself is the problem, filter them out:

sip && !(sip.Method == REGISTER) && !(sip.Method == OPTIONS)

Remove SUBSCRIBE and NOTIFY. Presence and BLF (busy lamp field) traffic generates a constant stream of SUBSCRIBE/NOTIFY exchanges. On a system with BLF configured on every phone, this can be the majority of SIP traffic by volume:

sip && !(sip.Method == REGISTER) && !(sip.Method == OPTIONS) && !(sip.Method == SUBSCRIBE) && !(sip.Method == NOTIFY)

After these filters, you are left with actual call traffic: INVITEs, responses, and BYEs.

Step 2: Find the call

Now that the noise is gone, find the specific call you are looking for. You usually know at least one of these:

The phone number. Filter by the caller or callee:

sip.from.user == "2125551234" || sip.to.user == "2125551234"

The time. If you know approximately when the problem happened, scroll to that timestamp. Wireshark's time display (View > Time Display Format > Time of Day) makes this easier than reading Unix timestamps.

The error. If you know the call failed, find the failure:

sip.Status-Code >= 400

This shows every error response in the trace. From there, look at the To header to find the called number and the Call-ID to isolate the full dialog.

Step 3: Follow the Call-ID

Every message in a SIP call shares the same Call-ID header. Once you find any message from the call you care about, right-click on the Call-ID field and select "Apply as Filter > Selected." Now you see every message in that dialog, in order, with nothing else cluttering the view.

This is the single most useful trick for reading SIP traces. One filter and you go from thousands of messages to the 8-15 that tell the complete story of one call.

Step 4: Read the story

With the call isolated, read the messages in order. Every SIP call follows a predictable pattern, and deviations from that pattern are where the problems live.

Normal successful call:

  1. INVITE (caller to callee)
  2. 100 Trying (immediate acknowledgment)
  3. 180 Ringing (callee is ringing)
  4. 200 OK (callee answered)
  5. ACK (caller confirms)
  6. [media flows]
  7. BYE (one side hangs up)
  8. 200 OK (other side acknowledges)

What to look for:

No 100 Trying after the INVITE: The next hop never received the INVITE, or it crashed before it could respond. Network connectivity issue or the destination is down.

INVITE retransmissions: If you see the same INVITE sent multiple times (same Call-ID, same CSeq, same branch), the sender is not getting a response and is retrying per RFC 3261 timers. Something between the two sides is swallowing the packets.

180 Ringing but no 200 OK: The callee's phone rang but was never answered. If this is followed by a 480 (Temporarily Unavailable) or 487 (Request Terminated), that is normal. If it times out to a 408, the callee's phone might have crashed or lost connectivity while ringing.

200 OK with wrong SDP: If the call connects but audio does not work, look at the SDP body in the 200 OK. Check the c= line (connection address) and the m= line (media port). If the connection address is a private IP like 10.x.x.x or 192.168.x.x, that is your NAT problem. The remote side cannot send RTP to a private address.

BYE after exactly 30 seconds (or 15, or 60): A timer-based disconnect. This is almost always a session timer or a NAT pinhole timeout. If the BYE comes from the provider side, ask them about session timers. If the connection just drops without a BYE, your firewall's UDP timeout is probably too short.

Re-INVITE mid-call: A re-INVITE changes the media parameters of an existing call (hold, codec change, call transfer). If a re-INVITE fails, the call may drop or audio may stop. Check the response to the re-INVITE.

Step 5: Check the SDP

For audio quality issues, the signaling itself may look fine. The problem is in how the media session was negotiated. Look at the SDP bodies in the INVITE and the 200 OK:

v=0
o=- 12345 12345 IN IP4 10.0.0.50
c=IN IP4 10.0.0.50
m=audio 18000 RTP/AVP 0 8 101
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000

The critical fields:

  • c=IN IP4 10.0.0.50 -- where to send media. If this is a private IP, you have a NAT problem.
  • m=audio 18000 -- the RTP port. If this is 0, the stream has been rejected.
  • a=rtpmap lines -- the codecs. Both sides need to agree on at least one.

Compare the SDP in the INVITE with the SDP in the 200 OK. The 200 OK's SDP is the answer. If the caller offered G.711 and Opus but the answer only contains G.729, you know what codec is being used. If there is a codec mismatch or the answer contains no codecs the caller offered, the call will fail or have no audio.

When you would rather not do any of this

Everything described above works. It is also slow, manual, and requires you to hold the SIP state machine in your head while correlating messages across a potentially large capture.

If you have a pcap file and you want answers without doing the detective work yourself, SIP Call Stories reads the same capture file and produces a plain-English story for every call. It identifies the failures, explains what each response code means and what to check next, and flags problems like a registration that keeps failing or a codec negotiation that got rejected. You upload the file, pick a call from the list, and read what happened.

For the full technical breakdown including RTP stream analysis and per-call quality metrics, the PCAP Analyzer extracts every SIP dialog and RTP stream, maps them to each other, and calculates jitter, loss, and MOS scores per stream.

Both tools accept standard pcap and pcapng files, process them in memory, and never store your capture.

Frequently Asked Questions

How do I read a SIP trace?+

Start by finding the INVITE that started the call. Follow the Call-ID to see every message in that dialog. Read the responses in order: 100 Trying, 180 Ringing, 200 OK (success) or a 4xx/5xx error. If the call failed, the final response code tells you why -- use the SIP Response Code Lookup for quick reference. If the call connected but had audio issues, check the SDP bodies in the INVITE and 200 OK for the media addresses and codecs.

What is the fastest way to find a failed call in a SIP trace?+

Filter for error responses: status codes 400 and above. In Wireshark, use the display filter 'sip.Status-Code >= 400'. This immediately shows you every failed transaction without scrolling through hundreds of successful calls. Alternatively, upload the capture to the PCAP analyzer to have failures identified automatically.

Why does my SIP trace have so many REGISTER messages?+

Every phone re-registers periodically (usually every 60-300 seconds) to tell the registrar it is still online. On a system with 50 phones, that is hundreds of REGISTER/200 OK pairs per hour. Filter them out with 'sip && !(sip.Method == REGISTER)' to focus on actual call traffic.

siptroubleshootingpacket-capturevoippcap

Share

Opens your messaging app. We do not collect or store any phone numbers.
Opens your email client. We do not collect or store any email addresses through sharing.

Want to know when we publish new articles? Sign up for updates