Via headers are how SIP responses know how to find their way back to the requester. Each proxy adds a Via on the way out and pops it on the way back. The chain also serves as the loop detection mechanism — if a proxy sees its own Via on an incoming request, the request has looped.
Each SIP request carries one or more Via headers. The Via header chain represents the path the request has traveled. The first Via is the most recent proxy (or the originating UA); the last Via is the originator.
When a proxy receives a request:
When a response arrives, the proxy:
The chain ensures responses follow the same path as the request, in reverse. This is independent of the Route/Record-Route mechanism, which is for in-dialog request routing.
The branch parameter on the Via header serves two purposes:
Each transaction has a unique branch. RFC 3261 specifies that branches must start with the magic cookie z9hG4bK followed by a unique value. This combination identifies the transaction across all hops — a proxy can match a response to its transaction by matching the branch.
When a proxy receives a request, it computes its own branch deterministically from the Request-URI, To, From, Call-ID, CSeq, and the topmost Via. If a proxy sees its own Via with a matching branch on an incoming request, the request has looped through the same point with the same parameters — a real loop, not just a request that happens to traverse the same proxy twice for legitimate reasons.
The deterministic branch calculation means a proxy can detect loops without keeping persistent state of every request it has seen.
Loops happen when SIP routing creates a cycle. Common causes:
Without loop detection, a looped request would be forwarded indefinitely, consuming proxy resources and never delivering. The Via chain provides immediate detection.
When a loop is detected, the proxy responds 482 Loop Detected. The originating UA receives this and stops trying.
Loop detection via Via inspection is reliable when proxies follow RFC behavior, but it can fail if proxies do not properly check Via or if the loop traverses different paths each time (rotating between equivalent proxies).
Max-Forwards is the backstop. Each request starts with Max-Forwards: 70 (the default). Each proxy decrements it by one. If Max-Forwards reaches zero, the proxy responds 483 Too Many Hops without forwarding.
Max-Forwards limits any single SIP path to 70 hops, which is far more than any reasonable network needs. A request that hits 0 has either looped through dozens of intermediaries or traversed an absurdly complex routing topology.
The two mechanisms are complementary: Via detects exact loops, Max-Forwards stops paths that are too long for any reason.
Real-world SIP runs through NAT, which complicates response routing. Two parameters help:
When a proxy receives a request from a source IP that does not match the Via address (because of NAT), it adds received=<actual.source.ip> to the Via. This tells subsequent hops where the request actually came from, regardless of what the originator put in Via.
The originator includes rport in its Via. The proxy fills in the actual source port observed when receiving the request. Combined with received, this provides full source IP and port for response routing.
Both parameters are essential for SIP through NAT. Without them, a phone behind NAT could send a request from internal address 192.168.1.50:5060, the request arrives at the proxy with that internal Via, and any response would be sent to 192.168.1.50 — an unroutable address. With received and rport, the proxy knows to send the response to the public IP/port the NAT actually used.
The Via header records the path a SIP request has traveled. Each proxy adds its own Via on the way out and uses the chain to route responses back to the requester. The branch parameter on Via uniquely identifies each transaction. Via also serves as the primary mechanism for loop detection — a proxy that sees its own Via on an incoming request knows the request has looped.
The branch parameter uniquely identifies a SIP transaction. RFC 3261 requires it to start with the magic cookie z9hG4bK followed by a unique value. The branch lets proxies match responses to their transactions and detect loops. A proxy receiving a request that contains its own Via with the same branch knows the request has looped through the same point with the same parameters.
Via routes responses back to the request originator and is used for transaction-level routing. Each proxy adds a Via on the way and pops it on the way back. Record-Route is for routing in-dialog requests like re-INVITE and BYE — it tells endpoints which proxies to traverse for subsequent messages in the dialog. Via handles request/response, Record-Route handles dialog continuation.
Paste your SIP trace into SIPSymposium. The analyzer parses Via chains, identifies loops, decodes received and rport parameters, and shows the actual path requests took.