Understanding the SIP Via Header

Every once in a while I feel the need to get away from SIP the architecture and write about SIP the protocol (which is a little bit like the department of redundancy department – Session Initiation Protocol Protocol).   Yes, I adore all those servers and services, but it’s the bits and bytes that attracted me to SIP in the first place.

Waylon Jennings said it best in his song, “Luckenbach, Texas.”

Maybe it’s time we got back to the basics of love.

Today, I want to share the love and write about an extremely important, but sometimes misunderstood SIP header.

When a user agent client (UAC) creates a SIP request, it must insert a Via header into that request.  The Via header identifies the protocol name (SIP), protocol version (2.0), transport type (e.g. UDP or TCP), IP address of the UAC, and the protocol port (typically 5060) used for the request.  This information allows the recipient of the request (a user agent server) to return SIP responses to the correct device.  For example, if my SIP soft-phone were to send an INVITE request, it would contain a Via similar to the following.

Via: SIP/2.0/UDP

If I were operating in a point-to-point configuration, the soft-phone that received the INVITE would  inspect the Via header to determine the location of my PC.  It would then use that information to return a “100 Trying” response.  Of course, unless I am in a lab environment, I never use SIP in a point-to-point fashion.  Here at work, there are all sorts of SIP components between my soft-phone and the soft-phone I am calling.  There is a Session Manager, Communication Manager, and perhaps a Session Border Controller between us.  Thankfully, via headers are not reserved for endpoints.  Every SIP entity uses them.

The rules for processing Via headers are very simple.  Every UAC must add its own Via header before sending a SIP request.  If there is already a Via header in the message, the UAC adds the new one at the top of the list before sending it to the next hop.

Remember that INVITE I sent in my example?  When it ends up on the called party’s device, it might contain several Via headers.  When the called party is ready to send the “100 Trying,” it simply removes the top Via header and sends the response to the indicated party.  In my work configuration, that top Via would most likely identify a Session Manager.  However, if the soft client was a remote user, it would be my company’s SBC.  It doesn’t matter, though.  Whoever receives the response will remove the top Via header and send it to the next hop.  This keeps happening until the Trying message lands on my PC.

This Via stacking allows a SIP request to pass through any number of intermediaries and every recipient of that message will know exactly how to pass back any subsequent responses.

Ah, but there’s more

To keep things simple I failed to mention something important about Via headers.  Along with the protocol and IP information, every Via header contains a “branch” parameter.  Here is that Via again with a branch parameter I pulled from a Wireshark trace.

Via: SIP/2.0/UDP; branch=z9hG4bK10_16a83292baa1de54e0b7843_I

The branch parameter must be unique across space and time for all requests sent by a user agent.  The exceptions to this rule are CANCEL and ACK for non-2xx responses.  A CANCEL will have the same branch parameter as the request it cancels.  An ACK for a non-2xx response will have the same branch parameter as the INVITE whose response it acknowledges.

The uniqueness of the branch header is used to facilitate its use as a transaction ID.  A SIP transaction is a message exchange between two user agents that starts with a request and ends with a final response.  For a simple call, the INVITE through final response is one transaction, the ACK is another transaction, and the Bye through the 200 OK is yet another transaction.  All these transactions combine to make a single dialog.

If you crave more knowledge about SIP message uniqueness, please see my blog, Let’s Play (SIP) Tag.

The branch parameter always begins with the same string of seven characters — “z9hG4bK.”  This requirement was added to identify that the branch was created in accordance with RFC 3261 and not the older RFC 2543 which did not require global uniqueness.

Okay, that’s it.  I got my protocol fix for the day.  I hope you are as thrilled as I am.

Take me on out, Waylon…

So, Baby let’s sell your diamond ring

buy some boots and faded jeans

and go away


  1. I’m a Chinese, but I find it easier to read your articles than many Chinese blogs. Thanks!

  2. Thanks, for your blogs, its totally helpful. My Question is regarding branch.
    branch=z9hG4bK77ef4c2312983.1 , what does .1 represent here, Somewhere i found that i used for loop detection. But How? i didn’t understood. Can you please help.

  3. Matthew Kambic · · Reply

    Love these articles you do. It would be nice if you included a packet capture to look at so that we could see what this would look like.

    1. I have plenty of articles with SIP traces. I am sure you will find quite a few Via headers in them.

  4. how can i pass custom variable under fromHeader which can be captured at gateway

    1. SIP allows a UA to add custom headers. There is no guarantee that they will make it all the way through to destination (e.g. an SBC might strip out custom headers for security reasons), but SIP places no restrictions on adding them.

  5. Hi Andrew, I read somewhere that maximum 6 via headers are allowed in a sip message, Is there any logic behind that or it is just a standard.

    1. I know of no restriction to the number of via headers.

  6. Can you provide the list of Response codes that require ACK.

    1. Every final response (2xx – 6xx) requires an ACK.

  7. Do you know what does the function “strict branch” do?


  8. Question: my CANCEL message from the VOIP phone includes a different Call-ID header than the INVITE did and I see here you state: “A CANCEL will have the same branch parameter as the request it cancels.” What I’m experiencing is, my calls will not stop ringing on the other end despite canceling the call before caller answers. And this would explain why. Any insight as to why the branch parameters would be different.

    1. Sounds like something in the middle (an SBC perhaps) is messing with the messages.

  9. thanks, Ill try follow up then with the SIP server provider.

  10. I misinterpreted the Call-Id header, they are in fact the same between the INVITE and CANCEL. What Im not seeing is a 487 Request Terminated being received. Im unsure why this would be. The VoIP provider uses a 3rd party switch vendor, Im wondering if they are the culprit.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: