16. Proxy Behavior
16 Proxy Behavior
16.1 Overview
SIP proxies are elements that route SIP requests to user agent servers and SIP responses to user agent clients. A request may traverse several proxies on its way to a UAS. Each will make routing decisions, modifying the request before forwarding it to the next element. Responses will route through the same set of proxies traversed by the request in the reverse order.
Being a proxy is a logical role for a SIP element. When a request arrives, an element that can play the role of a proxy first decides if it needs to respond to the request on its own. For instance, the request may be malformed or the element may need credentials from the client before acting as a proxy. The element MAY respond with any appropriate error code. When responding directly to a request, the element is playing the role of a UAS and MUST behave as described in Section 8.2.
A proxy can operate in either a stateful or stateless mode for each new request. When stateless, a proxy acts as a simple forwarding element. It forwards each request downstream to a single element determined by making a targeting and routing decision based on the request. It simply forwards every response it receives upstream. A stateless proxy discards information about a message once the message has been forwarded. A stateful proxy remembers information (specifically, transaction state) about each incoming request and any requests it sends as a result of processing the incoming request. It uses this information to affect the processing of future messages associated with that request. A stateful proxy MAY choose to "fork" a request, routing it to multiple destinations. Any request that is forwarded to more than one location MUST be handled statefully.
In some circumstances, a proxy MAY forward requests using stateful transports (such as TCP) without being transaction-stateful. For instance, a proxy MAY forward a request from one TCP connection to another transaction statelessly as long as it places enough information in the message to be able to forward the response down the same connection the request arrived on. Requests forwarded between different types of transports where the proxy's TU must take an active role in ensuring reliable delivery on one of the transports MUST be forwarded transaction statefully.
A stateful proxy MAY transition to stateless operation at any time during the processing of a request, so long as it did not do anything that would otherwise prevent it from being stateless initially (forking, for example, or generation of a 100 response). When performing such a transition, all state is simply discarded. The proxy SHOULD NOT initiate a CANCEL request.
Much of the processing involved when acting statelessly or statefully for a request is identical. The next several subsections are written from the point of view of a stateful proxy. The last section calls out those places where a stateless proxy behaves differently.
16.2 Stateful Proxy
When stateful, a proxy is purely a SIP transaction processing engine. Its behavior is modeled here in terms of the server and client transactions defined in Section 17. A stateful proxy has a server transaction associated with one or more client transactions by a higher layer proxy processing component (see figure 3), known as a proxy core. An incoming request is processed by a server transaction. Requests from the server transaction are passed to a proxy core. The proxy core determines where to route the request, choosing one or more next-hop locations. An outgoing request for each next-hop location is processed by its own associated client transaction. The proxy core collects the responses from the client transactions and uses them to send responses to the server transaction.
A stateful proxy creates a new server transaction for each new request received. Any retransmissions of the request will then be handled by that server transaction per Section 17. The proxy core MUST behave as a UAS with respect to sending an immediate provisional on that server transaction (such as 100 Trying) as described in Section 8.2.6. Thus, a stateful proxy SHOULD NOT generate 100 (Trying) responses to non-INVITE requests.
This is a model of proxy behavior, not of software. An implementation is free to take any approach that replicates the external behavior this model defines.
For all new requests, including any with unknown methods, an element intending to proxy the request MUST:
1. Validate the request (Section 16.3)
2. Preprocess routing information (Section 16.4)
3. Determine target(s) for the request (Section 16.5)
+--------------------+
| | +---+
| | | C |
| | | T |
| | +---+
+---+ | Proxy | +---+ CT = Client Transaction
| S | | "Higher" Layer | | C |
| T | | | | T | ST = Server Transaction
+---+ | | +---+
| | +---+
| | | C |
| | | T |
| | +---+
+--------------------+
Figure 3: Stateful Proxy Model
4. Forward the request to each target (Section 16.6)
5. Process all responses (Section 16.7)
16.3 Request Validation
Before an element can proxy a request, it MUST verify the message's validity. A valid message must pass the following checks:
1. Reasonable Syntax
2. URI scheme
3. Max-Forwards
4. (Optional) Loop Detection
5. Proxy-Require
6. Proxy-Authorization
If any of these checks fail, the element MUST behave as a user agent server (see Section 8.2) and respond with an error code.
Notice that a proxy is not required to detect merged requests and MUST NOT treat merged requests as an error condition. The endpoints receiving the requests will resolve the merge as described in Section 8.2.2.2.
-
Reasonable syntax check
The request MUST be well-formed enough to be handled with a server transaction. Any components involved in the remainder of these Request Validation steps or the Request Forwarding section MUST be well-formed. Any other components, well-formed or not, SHOULD be ignored and remain unchanged when the message is forwarded. For instance, an element would not reject a request because of a malformed Date header field. Likewise, a proxy would not remove a malformed Date header field before forwarding a request.
This protocol is designed to be extended. Future extensions may define new methods and header fields at any time. An element MUST NOT refuse to proxy a request because it contains a method or header field it does not know about.
-
URI scheme check
If the Request-URI has a URI whose scheme is not understood by the proxy, the proxy SHOULD reject the request with a 416 (Unsupported URI Scheme) response.
-
Max-Forwards check
The Max-Forwards header field (Section 20.22) is used to limit the number of elements a SIP request can traverse.
If the request does not contain a Max-Forwards header field, this check is passed.
If the request contains a Max-Forwards header field with a field value greater than zero, the check is passed.
If the request contains a Max-Forwards header field with a field value of zero (0), the element MUST NOT forward the request. If the request was for OPTIONS, the element MAY act as the final recipient and respond per Section 11. Otherwise, the element MUST return a 483 (Too many hops) response.
-
Optional Loop Detection check
An element MAY check for forwarding loops before forwarding a request. If the request contains a Via header field with a sent- by value that equals a value placed into previous requests by the proxy, the request has been forwarded by this element before. The request has either looped or is legitimately spiraling through the element. To determine if the request has looped, the element MAY perform the branch parameter calculation described in Step 8 of Section 16.6 on this message and compare it to the parameter received in that Via header field. If the parameters match, the request has looped. If they differ, the request is spiraling, and processing continues. If a loop is detected, the element MAY return a 482 (Loop Detected) response.
-
Proxy-Require check
Future extensions to this protocol may introduce features that require special handling by proxies. Endpoints will include a Proxy-Require header field in requests that use these features, telling the proxy not to process the request unless the feature is understood. If the request contains a Proxy-Require header field (Section 20.29) with one or more option-tags this element does not understand, the element MUST return a 420 (Bad Extension) response. The response MUST include an Unsupported (Section 20.40) header field listing those option-tags the element did not understand.
-
Proxy-Authorization check
If an element requires credentials before forwarding a request, the request MUST be inspected as described in Section 22.3. That section also defines what the element must do if the inspection fails.
16.4 Route Information Preprocessing
The proxy MUST inspect the Request-URI of the request. If the Request-URI of the request contains a value this proxy previously placed into a Record-Route header field (see Section 16.6 item 4), the proxy MUST replace the Request-URI in the request with the last value from the Route header field, and remove that value from the Route header field. The proxy MUST then proceed as if it received this modified request.
This will only happen when the element sending the request to the
proxy (which may have been an endpoint) is a strict router. This
rewrite on receive is necessary to enable backwards compatibility
with those elements. It also allows elements following this
specification to preserve the Request-URI through strict-routing
proxies (see Section 12.2.1.1).
This requirement does not obligate a proxy to keep state in order
to detect URIs it previously placed in Record-Route header fields.
Instead, a proxy need only place enough information in those URIs
to recognize them as values it provided when they later appear.
If the Request-URI contains a maddr parameter, the proxy MUST check to see if its value is in the set of addresses or domains the proxy is configured to be responsible for. If the Request-URI has a maddr parameter with a value the proxy is responsible for, and the request was received using the port and transport indicated (explicitly or by default) in the Request-URI, the proxy MUST strip the maddr and any non-default port or transport parameter and continue processing as if those values had not been present in the request. A request may arrive with a maddr matching the proxy, but on a port or transport different from that indicated in the URI. Such a request needs to be forwarded to the proxy using the indicated port and transport.
If the first value in the Route header field indicates this proxy, the proxy MUST remove that value from the request.
16.5 Determining Request Targets
Next, the proxy calculates the target(s) of the request. The set of targets will either be predetermined by the contents of the request or will be obtained from an abstract location service. Each target in the set is represented as a URI.
If the Request-URI of the request contains an maddr parameter, the Request-URI MUST be placed into the target set as the only target URI, and the proxy MUST proceed to Section 16.6.
If the domain of the Request-URI indicates a domain this element is not responsible for, the Request-URI MUST be placed into the target set as the only target, and the element MUST proceed to the task of Request Forwarding (Section 16.6).
There are many circumstances in which a proxy might receive a
request for a domain it is not responsible for. A firewall proxy
handling outgoing calls (the way HTTP proxies handle outgoing
requests) is an example of where this is likely to occur.
If the target set for the request has not been predetermined as described above, this implies that the element is responsible for the domain in the Request-URI, and the element MAY use whatever mechanism it desires to determine where to send the request. Any of these mechanisms can be modeled as accessing an abstract Location Service. This may consist of obtaining information from a location service created by a SIP Registrar, reading a database, consulting a presence server, utilizing other protocols, or simply performing an algorithmic substitution on the Request-URI. When accessing the location service constructed by a registrar, the Request-URI MUST first be canonicalized as described in Section 10.3 before being used as an index. The output of these mechanisms is used to construct the target set.
If the Request-URI does not provide sufficient information for the proxy to determine the target set, it SHOULD return a 485 (Ambiguous) response. This response SHOULD contain a Contact header field containing URIs of new addresses to be tried. For example, an INVITE to sip:John[email protected] may be ambiguous at a proxy whose location service has multiple John Smiths listed. See Section 21.4.23 for details.
Any information in or about the request or the current environment of the element MAY be used in the construction of the target set. For instance, different sets may be constructed depending on contents or the presence of header fields and bodies, the time of day of the request's arrival, the interface on which the request arrived, failure of previous requests, or even the element's current level of utilization.
As potential targets are located through these services, their URIs are added to the target set. Targets can only be placed in the target set once. If a target URI is already present in the set (based on the definition of equality for the URI type), it MUST NOT be added again.
A proxy MUST NOT add additional targets to the target set if the Request-URI of the original request does not indicate a resource this proxy is responsible for.
A proxy can only change the Request-URI of a request during
forwarding if it is responsible for that URI. If the proxy is not
responsible for that URI, it will not recurse on 3xx or 416
responses as described below.
If the Request-URI of the original request indicates a resource this proxy is responsible for, the proxy MAY continue to add targets to the set after beginning Request Forwarding. It MAY use any information obtained during that processing to determine new targets. For instance, a proxy may choose to incorporate contacts obtained in a redirect response (3xx) into the target set. If a proxy uses a dynamic source of information while building the target set (for instance, if it consults a SIP Registrar), it SHOULD monitor that source for the duration of processing the request. New locations SHOULD be added to the target set as they become available. As above, any given URI MUST NOT be added to the set more than once.
Allowing a URI to be added to the set only once reduces
unnecessary network traffic, and in the case of incorporating
contacts from redirect requests prevents infinite recursion.
For example, a trivial location service is a "no-op", where the target URI is equal to the incoming request URI. The request is sent to a specific next hop proxy for further processing. During request forwarding of Section 16.6, Item 6, the identity of that next hop, expressed as a SIP or SIPS URI, is inserted as the top-most Route header field value into the request.
If the Request-URI indicates a resource at this proxy that does not exist, the proxy MUST return a 404 (Not Found) response.
If the target set remains empty after applying all of the above, the proxy MUST return an error response, which SHOULD be the 480 (Temporarily Unavailable) response.
16.6 Request Forwarding
As soon as the target set is non-empty, a proxy MAY begin forwarding the request. A stateful proxy MAY process the set in any order. It MAY process multiple targets serially, allowing each client transaction to complete before starting the next. It MAY start client transactions with every target in parallel. It also MAY arbitrarily divide the set into groups, processing the groups serially and processing the targets in each group in parallel.
A common ordering mechanism is to use the qvalue parameter of targets obtained from Contact header fields (see Section 20.10). Targets are processed from highest qvalue to lowest. Targets with equal qvalues may be processed in parallel.
A stateful proxy must have a mechanism to maintain the target set as responses are received and associate the responses to each forwarded request with the original request. For the purposes of this model, this mechanism is a "response context" created by the proxy layer before forwarding the first request.
For each target, the proxy forwards the request following these steps:
1. Make a copy of the received request
2. Update the Request-URI
3. Update the Max-Forwards header field
4. Optionally add a Record-route header field value
5. Optionally add additional header fields
6. Postprocess routing information
7. Determine the next-hop address, port, and transport
8. Add a Via header field value
9. Add a Content-Length header field if necessary
10. Forward the new request
11. Set timer C
Each of these steps is detailed below:
1. Copy request
The proxy starts with a copy of the received request. The copy
MUST initially contain all of the header fields from the
received request. Fields not detailed in the processing
described below MUST NOT be removed. The copy SHOULD maintain
the ordering of the header fields as in the received request.
The proxy MUST NOT reorder field values with a common field
name (See Section 7.3.1). The proxy MUST NOT add to, modify,
or remove the message body.
An actual implementation need not perform a copy; the primary
requirement is that the processing for each next hop begin with
the same request.
2. Request-URI
The Request-URI in the copy's start line MUST be replaced with
the URI for this target. If the URI contains any parameters
not allowed in a Request-URI, they MUST be removed.
This is the essence of a proxy's role. This is the mechanism
through which a proxy routes a request toward its destination.
In some circumstances, the received Request-URI is placed into
the target set without being modified. For that target, the
replacement above is effectively a no-op.
3. Max-Forwards
If the copy contains a Max-Forwards header field, the proxy
MUST decrement its value by one (1).
If the copy does not contain a Max-Forwards header field, the
proxy MUST add one with a field value, which SHOULD be 70.
Some existing UAs will not provide a Max-Forwards header field
in a request.
4. Record-Route
If this proxy wishes to remain on the path of future requests
in a dialog created by this request (assuming the request
creates a dialog), it MUST insert a Record-Route header field
value into the copy before any existing Record-Route header
field values, even if a Route header field is already present.
Requests establishing a dialog may contain a preloaded Route
header field.
If this request is already part of a dialog, the proxy SHOULD
insert a Record-Route header field value if it wishes to remain
on the path of future requests in the dialog. In normal
endpoint operation as described in Section 12, these Record-
Route header field values will not have any effect on the route
sets used by the endpoints.
The proxy will remain on the path if it chooses to not insert a
Record-Route header field value into requests that are already
part of a dialog. However, it would be removed from the path
when an endpoint that has failed reconstitutes the dialog.
A proxy MAY insert a Record-Route header field value into any
request. If the request does not initiate a dialog, the
endpoints will ignore the value. See Section 12 for details on
how endpoints use the Record-Route header field values to
construct Route header fields.
Each proxy in the path of a request chooses whether to add a
Record-Route header field value independently - the presence of
a Record-Route header field in a request does not obligate this
proxy to add a value.
The URI placed in the Record-Route header field value MUST be a
SIP or SIPS URI. This URI MUST contain an lr parameter (see
Section 19.1.1). This URI MAY be different for each
destination the request is forwarded to. The URI SHOULD NOT
contain the transport parameter unless the proxy has knowledge
(such as in a private network) that the next downstream element
that will be in the path of subsequent requests supports that
transport.
The URI this proxy provides will be used by some other element
to make a routing decision. This proxy, in general, has no way
of knowing the capabilities of that element, so it must
restrict itself to the mandatory elements of a SIP
implementation: SIP URIs and either the TCP or UDP transports.
The URI placed in the Record-Route header field MUST resolve to the element inserting it (or a suitable stand-in) when the server location procedures of [4] are applied to it, so that subsequent requests reach the same SIP element. If the Request-URI contains a SIPS URI, or the topmost Route header field value (after the post processing of bullet 6) contains a SIPS URI, the URI placed into the Record-Route header field MUST be a SIPS URI. Furthermore, if the request was not received over TLS, the proxy MUST insert a Record-Route header field. In a similar fashion, a proxy that receives a request over TLS, but generates a request without a SIPS URI in the Request-URI or topmost Route header field value (after the post processing of bullet 6), MUST insert a Record-Route header field that is not a SIPS URI.
A proxy at a security perimeter must remain on the perimeter
throughout the dialog.
If the URI placed in the Record-Route header field needs to be
rewritten when it passes back through in a response, the URI
MUST be distinct enough to locate at that time. (The request
may spiral through this proxy, resulting in more than one
Record-Route header field value being added). Item 8 of
Section 16.7 recommends a mechanism to make the URI
sufficiently distinct.
The proxy MAY include parameters in the Record-Route header
field value. These will be echoed in some responses to the
request such as the 200 (OK) responses to INVITE. Such
parameters may be useful for keeping state in the message
rather than the proxy.
If a proxy needs to be in the path of any type of dialog (such
as one straddling a firewall), it SHOULD add a Record-Route
header field value to every request with a method it does not
understand since that method may have dialog semantics.
The URI a proxy places into a Record-Route header field is only
valid for the lifetime of any dialog created by the transaction
in which it occurs. A dialog-stateful proxy, for example, MAY
refuse to accept future requests with that value in the
Request-URI after the dialog has terminated. Non-dialog-
stateful proxies, of course, have no concept of when the dialog
has terminated, but they MAY encode enough information in the
value to compare it against the dialog identifier of future
requests and MAY reject requests not matching that information.
Endpoints MUST NOT use a URI obtained from a Record-Route
header field outside the dialog in which it was provided. See
Section 12 for more information on an endpoint's use of Record-Route header fields.
Record-routing may be required by certain services where the
proxy needs to observe all messages in a dialog. However, it
slows down processing and impairs scalability and thus proxies
should only record-route if required for a particular service.
The Record-Route process is designed to work for any SIP
request that initiates a dialog. INVITE is the only such
request in this specification, but extensions to the protocol
MAY define others.
5. Add Additional Header Fields
The proxy MAY add any other appropriate header fields to the
copy at this point.
6. Postprocess routing information
A proxy MAY have a local policy that mandates that a request
visit a specific set of proxies before being delivered to the
destination. A proxy MUST ensure that all such proxies are
loose routers. Generally, this can only be known with
certainty if the proxies are within the same administrative
domain. This set of proxies is represented by a set of URIs
(each of which contains the lr parameter). This set MUST be
pushed into the Route header field of the copy ahead of any
existing values, if present. If the Route header field is
absent, it MUST be added, containing that list of URIs.
If the proxy has a local policy that mandates that the request
visit one specific proxy, an alternative to pushing a Route
value into the Route header field is to bypass the forwarding
logic of item 10 below, and instead just send the request to
the address, port, and transport for that specific proxy. If
the request has a Route header field, this alternative MUST NOT
be used unless it is known that next hop proxy is a loose
router. Otherwise, this approach MAY be used, but the Route
insertion mechanism above is preferred for its robustness,
flexibility, generality and consistency of operation.
Furthermore, if the Request-URI contains a SIPS URI, TLS MUST
be used to communicate with that proxy.
If the copy contains a Route header field, the proxy MUST
inspect the URI in its first value. If that URI does not
contain an lr parameter, the proxy MUST modify the copy as
follows:
- The proxy MUST place the Request-URI into the Route header field as the last value.
- The proxy MUST then place the first Route header field value
into the Request-URI and remove that value from the Route
header field.
Appending the Request-URI to the Route header field is part of
a mechanism used to pass the information in that Request-URI
through strict-routing elements. "Popping" the first Route
header field value into the Request-URI formats the message the
way a strict-routing element expects to receive it (with its
own URI in the Request-URI and the next location to visit in
the first Route header field value).
7. Determine Next-Hop Address, Port, and Transport
The proxy MAY have a local policy to send the request to a
specific IP address, port, and transport, independent of the
values of the Route and Request-URI. Such a policy MUST NOT be
used if the proxy is not certain that the IP address, port, and
transport correspond to a server that is a loose router.
However, this mechanism for sending the request through a
specific next hop is NOT RECOMMENDED; instead a Route header
field should be used for that purpose as described above.
In the absence of such an overriding mechanism, the proxy
applies the procedures listed in [4] as follows to determine
where to send the request. If the proxy has reformatted the
request to send to a strict-routing element as described in
step 6 above, the proxy MUST apply those procedures to the
Request-URI of the request. Otherwise, the proxy MUST apply
the procedures to the first value in the Route header field, if
present, else the Request-URI. The procedures will produce an
ordered set of (address, port, transport) tuples.
Independently of which URI is being used as input to the
procedures of [4], if the Request-URI specifies a SIPS
resource, the proxy MUST follow the procedures of [4] as if the
input URI were a SIPS URI.
As described in [4], the proxy MUST attempt to deliver the
message to the first tuple in that set, and proceed through the
set in order until the delivery attempt succeeds.
For each tuple attempted, the proxy MUST format the message as
appropriate for the tuple and send the request using a new
client transaction as detailed in steps 8 through 10.
Since each attempt uses a new client transaction, it represents a new branch. Thus, the branch parameter provided with the Via header field inserted in step 8 MUST be different for each attempt.
If the client transaction reports failure to send the request
or a timeout from its state machine, the proxy continues to the
next address in that ordered set. If the ordered set is
exhausted, the request cannot be forwarded to this element in
the target set. The proxy does not need to place anything in
the response context, but otherwise acts as if this element of
the target set returned a 408 (Request Timeout) final response.
8. Add a Via header field value
The proxy MUST insert a Via header field value into the copy
before the existing Via header field values. The construction
of this value follows the same guidelines of Section 8.1.1.7.
This implies that the proxy will compute its own branch
parameter, which will be globally unique for that branch, and
contain the requisite magic cookie. Note that this implies that
the branch parameter will be different for different instances
of a spiraled or looped request through a proxy.
Proxies choosing to detect loops have an additional constraint
in the value they use for construction of the branch parameter.
A proxy choosing to detect loops SHOULD create a branch
parameter separable into two parts by the implementation. The
first part MUST satisfy the constraints of Section 8.1.1.7 as
described above. The second is used to perform loop detection
and distinguish loops from spirals.
Loop detection is performed by verifying that, when a request
returns to a proxy, those fields having an impact on the
processing of the request have not changed. The value placed
in this part of the branch parameter SHOULD reflect all of
those fields (including any Route, Proxy-Require and Proxy-
Authorization header fields). This is to ensure that if the
request is routed back to the proxy and one of those fields
changes, it is treated as a spiral and not a loop (see Section
16.3). A common way to create this value is to compute a
cryptographic hash of the To tag, From tag, Call-ID header
field, the Request-URI of the request received (before
translation), the topmost Via header, and the sequence number
from the CSeq header field, in addition to any Proxy-Require
and Proxy-Authorization header fields that may be present. The
algorithm used to compute the hash is implementation-dependent, but MD5 (RFC 1321 [35]), expressed in hexadecimal, is a reasonable choice. (Base64 is not permissible for a token.)
If a proxy wishes to detect loops, the "branch" parameter it
supplies MUST depend on all information affecting processing of
a request, including the incoming Request-URI and any header
fields affecting the request's admission or routing. This is
necessary to distinguish looped requests from requests whose
routing parameters have changed before returning to this
server.
The request method MUST NOT be included in the calculation of
the branch parameter. In particular, CANCEL and ACK requests
(for non-2xx responses) MUST have the same branch value as the
corresponding request they cancel or acknowledge. The branch
parameter is used in correlating those requests at the server
handling them (see Sections 17.2.3 and 9.2).
9. Add a Content-Length header field if necessary
If the request will be sent to the next hop using a stream-
based transport and the copy contains no Content-Length header
field, the proxy MUST insert one with the correct value for the
body of the request (see Section 20.14).
10. Forward Request
A stateful proxy MUST create a new client transaction for this
request as described in Section 17.1 and instructs the
transaction to send the request using the address, port and
transport determined in step 7.
11. Set timer C
In order to handle the case where an INVITE request never
generates a final response, the TU uses a timer which is called
timer C. Timer C MUST be set for each client transaction when
an INVITE request is proxied. The timer MUST be larger than 3
minutes. Section 16.7 bullet 2 discusses how this timer is
updated with provisional responses, and Section 16.8 discusses
processing when it fires.
16.7 Response Processing
When a response is received by an element, it first tries to locate a client transaction (Section 17.1.3) matching the response. If none is found, the element MUST process the response (even if it is an informational response) as a stateless proxy (described below). If a match is found, the response is handed to the client transaction.
Forwarding responses for which a client transaction (or more
generally any knowledge of having sent an associated request) is
not found improves robustness. In particular, it ensures that
"late" 2xx responses to INVITE requests are forwarded properly.
As client transactions pass responses to the proxy layer, the following processing MUST take place:
1. Find the appropriate response context
2. Update timer C for provisional responses
3. Remove the topmost Via
4. Add the response to the response context
5. Check to see if this response should be forwarded immediately
6. When necessary, choose the best final response from the
response context
If no final response has been forwarded after every client transaction associated with the response context has been terminated, the proxy must choose and forward the "best" response from those it has seen so far.
The following processing MUST be performed on each response that is forwarded. It is likely that more than one response to each request will be forwarded: at least each provisional and one final response.
7. Aggregate authorization header field values if necessary
8. Optionally rewrite Record-Route header field values
9. Forward the response
10. Generate any necessary CANCEL requests
Each of the above steps are detailed below:
1. Find Context
The proxy locates the "response context" it created before
forwarding the original request using the key described in
Section 16.6. The remaining processing steps take place in
this context.
2. Update timer C for provisional responses
For an INVITE transaction, if the response is a provisional
response with status codes 101 to 199 inclusive (i.e., anything
but 100), the proxy MUST reset timer C for that client
transaction. The timer MAY be reset to a different value, but
this value MUST be greater than 3 minutes.
3. Via
The proxy removes the topmost Via header field value from the
response.
If no Via header field values remain in the response, the
response was meant for this element and MUST NOT be forwarded.
The remainder of the processing described in this section is
not performed on this message, the UAC processing rules
described in Section 8.1.3 are followed instead (transport
layer processing has already occurred).
This will happen, for instance, when the element generates
CANCEL requests as described in Section 10.
4. Add response to context
Final responses received are stored in the response context
until a final response is generated on the server transaction
associated with this context. The response may be a candidate
for the best final response to be returned on that server
transaction. Information from this response may be needed in
forming the best response, even if this response is not chosen.
If the proxy chooses to recurse on any contacts in a 3xx
response by adding them to the target set, it MUST remove them
from the response before adding the response to the response
context. However, a proxy SHOULD NOT recurse to a non-SIPS URI
if the Request-URI of the original request was a SIPS URI. If
the proxy recurses on all of the contacts in a 3xx response, the proxy SHOULD NOT add the resulting contactless response to the response context.
Removing the contact before adding the response to the response
context prevents the next element upstream from retrying a
location this proxy has already attempted.
3xx responses may contain a mixture of SIP, SIPS, and non-SIP
URIs. A proxy may choose to recurse on the SIP and SIPS URIs
and place the remainder into the response context to be
returned, potentially in the final response.
If a proxy receives a 416 (Unsupported URI Scheme) response to
a request whose Request-URI scheme was not SIP, but the scheme
in the original received request was SIP or SIPS (that is, the
proxy changed the scheme from SIP or SIPS to something else
when it proxied a request), the proxy SHOULD add a new URI to
the target set. This URI SHOULD be a SIP URI version of the
non-SIP URI that was just tried. In the case of the tel URL,
this is accomplished by placing the telephone-subscriber part
of the tel URL into the user part of the SIP URI, and setting
the hostpart to the domain where the prior request was sent.
See Section 19.1.6 for more detail on forming SIP URIs from tel
URLs.
As with a 3xx response, if a proxy "recurses" on the 416 by
trying a SIP or SIPS URI instead, the 416 response SHOULD NOT
be added to the response context.
5. Check response for forwarding
Until a final response has been sent on the server transaction,
the following responses MUST be forwarded immediately:
- Any provisional response other than 100 (Trying)
- Any 2xx response
If a 6xx response is received, it is not immediately forwarded,
but the stateful proxy SHOULD cancel all client pending
transactions as described in Section 10, and it MUST NOT create
any new branches in this context.
This is a change from RFC 2543, which mandated that the proxy
was to forward the 6xx response immediately. For an INVITE
transaction, this approach had the problem that a 2xx response
could arrive on another branch, in which case the proxy would
have to forward the 2xx. The result was that the UAC could receive a 6xx response followed by a 2xx response, which should never be allowed to happen. Under the new rules, upon receiving a 6xx, a proxy will issue a CANCEL request, which will generally result in 487 responses from all outstanding client transactions, and then at that point the 6xx is forwarded upstream.
After a final response has been sent on the server transaction,
the following responses MUST be forwarded immediately:
- Any 2xx response to an INVITE request
A stateful proxy MUST NOT immediately forward any other
responses. In particular, a stateful proxy MUST NOT forward
any 100 (Trying) response. Those responses that are candidates
for forwarding later as the "best" response have been gathered
as described in step "Add Response to Context".
Any response chosen for immediate forwarding MUST be processed
as described in steps "Aggregate Authorization Header Field
Values" through "Record-Route".
This step, combined with the next, ensures that a stateful
proxy will forward exactly one final response to a non-INVITE
request, and either exactly one non-2xx response or one or more
2xx responses to an INVITE request.
6. Choosing the best response
A stateful proxy MUST send a final response to a response
context's server transaction if no final responses have been
immediately forwarded by the above rules and all client
transactions in this response context have been terminated.
The stateful proxy MUST choose the "best" final response among
those received and stored in the response context.
If there are no final responses in the context, the proxy MUST
send a 408 (Request Timeout) response to the server
transaction.
Otherwise, the proxy MUST forward a response from the responses
stored in the response context. It MUST choose from the 6xx
class responses if any exist in the context. If no 6xx class
responses are present, the proxy SHOULD choose from the lowest
response class stored in the response context. The proxy MAY
select any response within that chosen class. The proxy SHOULD
give preference to responses that provide information affecting resubmission of this request, such as 401, 407, 415, 420, and 484 if the 4xx class is chosen.
A proxy which receives a 503 (Service Unavailable) response
SHOULD NOT forward it upstream unless it can determine that any
subsequent requests it might proxy will also generate a 503.
In other words, forwarding a 503 means that the proxy knows it
cannot service any requests, not just the one for the Request-
URI in the request which generated the 503. If the only
response that was received is a 503, the proxy SHOULD generate
a 500 response and forward that upstream.
The forwarded response MUST be processed as described in steps
"Aggregate Authorization Header Field Values" through "Record-
Route".
For example, if a proxy forwarded a request to 4 locations, and
received 503, 407, 501, and 404 responses, it may choose to
forward the 407 (Proxy Authentication Required) response.
1xx and 2xx responses may be involved in the establishment of
dialogs. When a request does not contain a To tag, the To tag
in the response is used by the UAC to distinguish multiple
responses to a dialog creating request. A proxy MUST NOT
insert a tag into the To header field of a 1xx or 2xx response
if the request did not contain one. A proxy MUST NOT modify
the tag in the To header field of a 1xx or 2xx response.
Since a proxy may not insert a tag into the To header field of
a 1xx response to a request that did not contain one, it cannot
issue non-100 provisional responses on its own. However, it
can branch the request to a UAS sharing the same element as the
proxy. This UAS can return its own provisional responses,
entering into an early dialog with the initiator of the
request. The UAS does not have to be a discreet process from
the proxy. It could be a virtual UAS implemented in the same
code space as the proxy.
3-6xx responses are delivered hop-by-hop. When issuing a 3-6xx
response, the element is effectively acting as a UAS, issuing
its own response, usually based on the responses received from
downstream elements. An element SHOULD preserve the To tag
when simply forwarding a 3-6xx response to a request that did
not contain a To tag.
A proxy MUST NOT modify the To tag in any forwarded response to
a request that contains a To tag.
While it makes no difference to the upstream elements if the proxy replaced the To tag in a forwarded 3-6xx response, preserving the original tag may assist with debugging.
When the proxy is aggregating information from several
responses, choosing a To tag from among them is arbitrary, and
generating a new To tag may make debugging easier. This
happens, for instance, when combining 401 (Unauthorized) and
407 (Proxy Authentication Required) challenges, or combining
Contact values from unencrypted and unauthenticated 3xx
responses.
7. Aggregate Authorization Header Field Values
If the selected response is a 401 (Unauthorized) or 407 (Proxy
Authentication Required), the proxy MUST collect any WWW-
Authenticate and Proxy-Authenticate header field values from
all other 401 (Unauthorized) and 407 (Proxy Authentication
Required) responses received so far in this response context
and add them to this response without modification before
forwarding. The resulting 401 (Unauthorized) or 407 (Proxy
Authentication Required) response could have several WWW-
Authenticate AND Proxy-Authenticate header field values.
This is necessary because any or all of the destinations the
request was forwarded to may have requested credentials. The
client needs to receive all of those challenges and supply
credentials for each of them when it retries the request.
Motivation for this behavior is provided in Section 26.
8. Record-Route
If the selected response contains a Record-Route header field
value originally provided by this proxy, the proxy MAY choose
to rewrite the value before forwarding the response. This
allows the proxy to provide different URIs for itself to the
next upstream and downstream elements. A proxy may choose to
use this mechanism for any reason. For instance, it is useful
for multi-homed hosts.
If the proxy received the request over TLS, and sent it out
over a non-TLS connection, the proxy MUST rewrite the URI in
the Record-Route header field to be a SIPS URI. If the proxy
received the request over a non-TLS connection, and sent it out
over TLS, the proxy MUST rewrite the URI in the Record-Route
header field to be a SIP URI.
The new URI provided by the proxy MUST satisfy the same constraints on URIs placed in Record-Route header fields in requests (see Step 4 of Section 16.6) with the following modifications:
The URI SHOULD NOT contain the transport parameter unless the
proxy has knowledge that the next upstream (as opposed to
downstream) element that will be in the path of subsequent
requests supports that transport.
When a proxy does decide to modify the Record-Route header
field in the response, one of the operations it performs is
locating the Record-Route value that it had inserted. If the
request spiraled, and the proxy inserted a Record-Route value
in each iteration of the spiral, locating the correct value in
the response (which must be the proper iteration in the reverse
direction) is tricky. The rules above recommend that a proxy
wishing to rewrite Record-Route header field values insert
sufficiently distinct URIs into the Record-Route header field
so that the right one may be selected for rewriting. A
RECOMMENDED mechanism to achieve this is for the proxy to
append a unique identifier for the proxy instance to the user
portion of the URI.
When the response arrives, the proxy modifies the first
Record-Route whose identifier matches the proxy instance. The
modification results in a URI without this piece of data
appended to the user portion of the URI. Upon the next
iteration, the same algorithm (find the topmost Record-Route
header field value with the parameter) will correctly extract
the next Record-Route header field value inserted by that
proxy.
Not every response to a request to which a proxy adds a
Record-Route header field value will contain a Record-Route
header field. If the response does contain a Record-Route
header field, it will contain the value the proxy added.
9. Forward response
After performing the processing described in steps "Aggregate
Authorization Header Field Values" through "Record-Route", the
proxy MAY perform any feature specific manipulations on the
selected response. The proxy MUST NOT add to, modify, or
remove the message body. Unless otherwise specified, the proxy
MUST NOT remove any header field values other than the Via
header field value discussed in Section 16.7 Item 3. In
particular, the proxy MUST NOT remove any "received" parameter
it may have added to the next Via header field value while processing the request associated with this response. The proxy MUST pass the response to the server transaction associated with the response context. This will result in the response being sent to the location now indicated in the topmost Via header field value. If the server transaction is no longer available to handle the transmission, the element MUST forward the response statelessly by sending it to the server transport. The server transaction might indicate failure to send the response or signal a timeout in its state machine. These errors would be logged for diagnostic purposes as appropriate, but the protocol requires no remedial action from the proxy.
The proxy MUST maintain the response context until all of its
associated transactions have been terminated, even after
forwarding a final response.
10. Generate CANCELs
If the forwarded response was a final response, the proxy MUST
generate a CANCEL request for all pending client transactions
associated with this response context. A proxy SHOULD also
generate a CANCEL request for all pending client transactions
associated with this response context when it receives a 6xx
response. A pending client transaction is one that has
received a provisional response, but no final response (it is
in the proceeding state) and has not had an associated CANCEL
generated for it. Generating CANCEL requests is described in
Section 9.1.
The requirement to CANCEL pending client transactions upon
forwarding a final response does not guarantee that an endpoint
will not receive multiple 200 (OK) responses to an INVITE. 200
(OK) responses on more than one branch may be generated before
the CANCEL requests can be sent and processed. Further, it is
reasonable to expect that a future extension may override this
requirement to issue CANCEL requests.
16.8 Processing Timer C
If timer C should fire, the proxy MUST either reset the timer with any value it chooses, or terminate the client transaction. If the client transaction has received a provisional response, the proxy MUST generate a CANCEL request matching that transaction. If the client transaction has not received a provisional response, the proxy MUST behave as if the transaction received a 408 (Request Timeout) response. Allowing the proxy to reset the timer allows the proxy to dynamically extend the transaction's lifetime based on current conditions (such as utilization) when the timer fires.
16.9 Handling Transport Errors
If the transport layer notifies a proxy of an error when it tries to forward a request (see Section 18.4), the proxy MUST behave as if the forwarded request received a 503 (Service Unavailable) response.
If the proxy is notified of an error when forwarding a response, it drops the response. The proxy SHOULD NOT cancel any outstanding client transactions associated with this response context due to this notification.
If a proxy cancels its outstanding client transactions, a single
malicious or misbehaving client can cause all transactions to fail
through its Via header field.
16.10 CANCEL Processing
A stateful proxy MAY generate a CANCEL to any other request it has generated at any time (subject to receiving a provisional response to that request as described in section 9.1). A proxy MUST cancel any pending client transactions associated with a response context when it receives a matching CANCEL request.
A stateful proxy MAY generate CANCEL requests for pending INVITE client transactions based on the period specified in the INVITE's Expires header field elapsing. However, this is generally unnecessary since the endpoints involved will take care of signaling the end of the transaction.
While a CANCEL request is handled in a stateful proxy by its own server transaction, a new response context is not created for it. Instead, the proxy layer searches its existing response contexts for the server transaction handling the request associated with this CANCEL. If a matching response context is found, the element MUST immediately return a 200 (OK) response to the CANCEL request. In this case, the element is acting as a user agent server as defined in Section 8.2. Furthermore, the element MUST generate CANCEL requests for all pending client transactions in the context as described in Section 16.7 step 10.
If a response context is not found, the element does not have any knowledge of the request to apply the CANCEL to. It MUST statelessly forward the CANCEL request (it may have statelessly forwarded the associated request previously). 16.11 Stateless Proxy
When acting statelessly, a proxy is a simple message forwarder. Much of the processing performed when acting statelessly is the same as when behaving statefully. The differences are detailed here.
A stateless proxy does not have any notion of a transaction, or of the response context used to describe stateful proxy behavior. Instead, the stateless proxy takes messages, both requests and responses, directly from the transport layer (See section 18). As a result, stateless proxies do not retransmit messages on their own. They do, however, forward all retransmissions they receive (they do not have the ability to distinguish a retransmission from the original message). Furthermore, when handling a request statelessly, an element MUST NOT generate its own 100 (Trying) or any other provisional response.
A stateless proxy MUST validate a request as described in Section 16.3
A stateless proxy MUST follow the request processing steps described in Sections 16.4 through 16.5 with the following exception:
o A stateless proxy MUST choose one and only one target from the
target set. This choice MUST only rely on fields in the
message and time-invariant properties of the server. In
particular, a retransmitted request MUST be forwarded to the
same destination each time it is processed. Furthermore,
CANCEL and non-Routed ACK requests MUST generate the same
choice as their associated INVITE.
A stateless proxy MUST follow the request processing steps described in Section 16.6 with the following exceptions:
o The requirement for unique branch IDs across space and time
applies to stateless proxies as well. However, a stateless
proxy cannot simply use a random number generator to compute
the first component of the branch ID, as described in Section
16.6 bullet 8. This is because retransmissions of a request
need to have the same value, and a stateless proxy cannot tell
a retransmission from the original request. Therefore, the
component of the branch parameter that makes it unique MUST be
the same each time a retransmitted request is forwarded. Thus
for a stateless proxy, the branch parameter MUST be computed as
a combinatoric function of message parameters which are
invariant on retransmission.
The stateless proxy MAY use any technique it likes to guarantee uniqueness of its branch IDs across transactions. However, the following procedure is RECOMMENDED. The proxy examines the branch ID in the topmost Via header field of the received request. If it begins with the magic cookie, the first component of the branch ID of the outgoing request is computed as a hash of the received branch ID. Otherwise, the first component of the branch ID is computed as a hash of the topmost Via, the tag in the To header field, the tag in the From header field, the Call-ID header field, the CSeq number (but not method), and the Request-URI from the received request. One of these fields will always vary across two different transactions.
o All other message transformations specified in Section 16.6
MUST result in the same transformation of a retransmitted
request. In particular, if the proxy inserts a Record-Route
value or pushes URIs into the Route header field, it MUST place
the same values in retransmissions of the request. As for the
Via branch parameter, this implies that the transformations
MUST be based on time-invariant configuration or
retransmission-invariant properties of the request.
o A stateless proxy determines where to forward the request as
described for stateful proxies in Section 16.6 Item 10. The
request is sent directly to the transport layer instead of
through a client transaction.
Since a stateless proxy must forward retransmitted requests to
the same destination and add identical branch parameters to
each of them, it can only use information from the message
itself and time-invariant configuration data for those
calculations. If the configuration state is not time-invariant
(for example, if a routing table is updated) any requests that
could be affected by the change may not be forwarded
statelessly during an interval equal to the transaction timeout
window before or after the change. The method of processing
the affected requests in that interval is an implementation
decision. A common solution is to forward them transaction
statefully.
Stateless proxies MUST NOT perform special processing for CANCEL requests. They are processed by the above rules as any other requests. In particular, a stateless proxy applies the same Route header field processing to CANCEL requests that it applies to any other request. Response processing as described in Section 16.7 does not apply to a proxy behaving statelessly. When a response arrives at a stateless proxy, the proxy MUST inspect the sent-by value in the first (topmost) Via header field value. If that address matches the proxy, (it equals a value this proxy has inserted into previous requests) the proxy MUST remove that header field value from the response and forward the result to the location indicated in the next Via header field value. The proxy MUST NOT add to, modify, or remove the message body. Unless specified otherwise, the proxy MUST NOT remove any other header field values. If the address does not match the proxy, the message MUST be silently discarded.
16.12 Summary of Proxy Route Processing
In the absence of local policy to the contrary, the processing a proxy performs on a request containing a Route header field can be summarized in the following steps.
1. The proxy will inspect the Request-URI. If it indicates a
resource owned by this proxy, the proxy will replace it with
the results of running a location service. Otherwise, the
proxy will not change the Request-URI.
2. The proxy will inspect the URI in the topmost Route header
field value. If it indicates this proxy, the proxy removes it
from the Route header field (this route node has been
reached).
3. The proxy will forward the request to the resource indicated
by the URI in the topmost Route header field value or in the
Request-URI if no Route header field is present. The proxy
determines the address, port and transport to use when
forwarding the request by applying the procedures in [4] to
that URI.
If no strict-routing elements are encountered on the path of the request, the Request-URI will always indicate the target of the request.
16.12.1 Examples
16.12.1.1 Basic SIP Trapezoid
This scenario is the basic SIP trapezoid, U1 -> P1 -> P2 -> U2, with both proxies record-routing. Here is the flow. U1 sends:
INVITE sip:[email protected] SIP/2.0
Contact: sip:[email protected]
to P1. P1 is an outbound proxy. P1 is not responsible for domain.com, so it looks it up in DNS and sends it there. It also adds a Record-Route header field value:
INVITE sip:[email protected] SIP/2.0
Contact: sip:[email protected]
Record-Route: `<sip:p1.example.com;lr>`
P2 gets this. It is responsible for domain.com so it runs a location service and rewrites the Request-URI. It also adds a Record-Route header field value. There is no Route header field, so it resolves the new Request-URI to determine where to send the request:
INVITE sip:[email protected] SIP/2.0
Contact: sip:[email protected]
Record-Route: `<sip:p2.domain.com;lr>`
Record-Route: `<sip:p1.example.com;lr>`
The callee at u2.domain.com gets this and responds with a 200 OK:
SIP/2.0 200 OK
Contact: sip:[email protected]
Record-Route: `<sip:p2.domain.com;lr>`
Record-Route: `<sip:p1.example.com;lr>`
The callee at u2 also sets its dialog state's remote target URI to sip:[email protected] and its route set to:
(`<sip:p2.domain.com;lr>`,`<sip:p1.example.com;lr>`)
This is forwarded by P2 to P1 to U1 as normal. Now, U1 sets its dialog state's remote target URI to sip:[email protected] and its route set to:
(`<sip:p1.example.com;lr>`,`<sip:p2.domain.com;lr>`)
Since all the route set elements contain the lr parameter, U1 constructs the following BYE request:
BYE sip:[email protected] SIP/2.0
Route: `<sip:p1.example.com;lr>`,`<sip:p2.domain.com;lr>`
As any other element (including proxies) would do, it resolves the URI in the topmost Route header field value using DNS to determine where to send the request. This goes to P1. P1 notices that it is not responsible for the resource indicated in the Request-URI so it doesn't change it. It does see that it is the first value in the Route header field, so it removes that value, and forwards the request to P2:
BYE sip:[email protected] SIP/2.0
Route: `<sip:p2.domain.com;lr>`
P2 also notices it is not responsible for the resource indicated by the Request-URI (it is responsible for domain.com, not u2.domain.com), so it doesn't change it. It does see itself in the first Route header field value, so it removes it and forwards the following to u2.domain.com based on a DNS lookup against the Request-URI:
BYE sip:[email protected] SIP/2.0
16.12.1.2 Traversing a Strict-Routing Proxy
In this scenario, a dialog is established across four proxies, each of which adds Record-Route header field values. The third proxy implements the strict-routing procedures specified in RFC 2543 and many works in progress.
U1->P1->P2->P3->P4->U2
The INVITE arriving at U2 contains:
INVITE sip:[email protected] SIP/2.0
Contact: sip:[email protected]
Record-Route: `<sip:p4.domain.com;lr>`
Record-Route: `<sip:p3.middle.com>`
Record-Route: `<sip:p2.example.com;lr>`
Record-Route: `<sip:p1.example.com;lr>`
Which U2 responds to with a 200 OK. Later, U2 sends the following BYE request to P4 based on the first Route header field value.
BYE sip:[email protected] SIP/2.0
Route: `<sip:p4.domain.com;lr>`
Route: `<sip:p3.middle.com>`
Route: `<sip:p2.example.com;lr>`
Route: `<sip:p1.example.com;lr>`
P4 is not responsible for the resource indicated in the Request-URI so it will leave it alone. It notices that it is the element in the first Route header field value so it removes it. It then prepares to send the request based on the now first Route header field value of sip:p3.middle.com, but it notices that this URI does not contain the lr parameter, so before sending, it reformats the request to be:
BYE sip:p3.middle.com SIP/2.0
Route: `<sip:p2.example.com;lr>`
Route: `<sip:p1.example.com;lr>`
Route: `<sip:[email protected]>`
P3 is a strict router, so it forwards the following to P2:
BYE sip:p2.example.com;lr SIP/2.0
Route: `<sip:p1.example.com;lr>`
Route: `<sip:[email protected]>`
P2 sees the request-URI is a value it placed into a Record-Route header field, so before further processing, it rewrites the request to be:
BYE sip:[email protected] SIP/2.0
Route: `<sip:p1.example.com;lr>`
P2 is not responsible for u1.example.com, so it sends the request to P1 based on the resolution of the Route header field value.
P1 notices itself in the topmost Route header field value, so it removes it, resulting in:
BYE sip:[email protected] SIP/2.0
Since P1 is not responsible for u1.example.com and there is no Route header field, P1 will forward the request to u1.example.com based on the Request-URI.
16.12.1.3 Rewriting Record-Route Header Field Values
In this scenario, U1 and U2 are in different private namespaces and they enter a dialog through a proxy P1, which acts as a gateway between the namespaces.
U1->P1->U2
U1 sends:
INVITE sip:[email protected] SIP/2.0
Contact: `<sip:[email protected]>`
P1 uses its location service and sends the following to U2:
INVITE sip:[email protected] SIP/2.0
Contact: `<sip:[email protected]>`
Record-Route: `<sip:gateway.rightprivatespace.com;lr>`
U2 sends this 200 (OK) back to P1:
SIP/2.0 200 OK
Contact: `<sip:[email protected]>`
Record-Route: `<sip:gateway.rightprivatespace.com;lr>`
P1 rewrites its Record-Route header parameter to provide a value that U1 will find useful, and sends the following to U1:
SIP/2.0 200 OK
Contact: `<sip:[email protected]>`
Record-Route: `<sip:gateway.leftprivatespace.com;lr>`
Later, U1 sends the following BYE request to P1:
BYE sip:[email protected] SIP/2.0
Route: `<sip:gateway.leftprivatespace.com;lr>`
which P1 forwards to U2 as:
BYE sip:[email protected] SIP/2.0