Subject: Re: [BEHAVE] Duplicate request handling

From: Philip Matthews <[email-masked]>
Date: Wed, 25 Jun 2008 08:56:49 -0400

I would like to come to a resolution on this issue, at least in the  
case of a TURN Allocate request.

To recap: Over UDP, requests can be retransmitted if the client does  
not initially receive a response. To ensure that the client receives a  
consistent answer, STUN requires that the server always return the  
same success response. However, currently the STUN and TURN  
specification say nothing about replying with the same failure code.

Benny pointed out a case where replying with the same failure code  
would be helpful:
     For example,
     imagine when TURN server first returns failure response, then
     successful response on the second Allocate retransmission. Client  
most
     likely will ignore the second response retransmission, hence client
     thinks that the Allocate has failed while the server thinks it has
     been successful.

However, Remi commented:
     So what is the big deal? The server will just garbage collect the  
allocation
     eventually. This is perfectly normal operation. Clients can  
always "vanish"
     unexpectedly, such as if their network connection fails.
     It's totally fine if the server thinks a request has succeeded  
and the client
     thinks it's failed. Only the opposite would be an issue.

Regarding the case of a TURN Allocate request, the TURN-08 says that  
the server must generate the same reply if the response is a success  
response, but the spec is currently silent on what to do if the  
response is an error response. From section 6.2 Receiving an Allocate  
request:
    2.  The server checks if the 5-tuple is currently in use by an
        existing allocation, or was it in use by another allocation
        within the last 2 minutes.  If yes, then there are two sub- 
cases:

        *  If the transport protocol in the 5-tuple is UDP, and if the
           5-tuple is currently in use by an existing allocation, and if
           the transaction id of the request matches the transaction id
           stored with the allocation, then the request is a
           retransmission of the original request.  The server replies
           either with a stored copy of the original response, or with a
           response rebuilt from the stored state data.  If the server
           chooses to rebuild the response, then (a) it need not parse
           the request further, but can immediately start building a
           success response, (b) the value of the LIFETIME attribute can
           be set to the current value of the time-to-expire timer, and
           (c) the server may need to include an extra field in the
           allocation to store the token returned in a RESERVATION-TOKEN
           attribute.

        *  Otherwise, the server rejects the request with a 437
           (Allocation Mismatch) error.

Implementing the above text does not require a lot of extra work. The  
server already needs to keep the allocation data structure containing  
the Transaction ID, and the server already needs to check if the 5- 
tuple is in use by another allocation. All that is required is to  
check if the transaction id on the incoming request matches the one  
stored in the allocation. The response can then be easily rebuilt from  
the stored state data.

However, as I see it, replying with the same failure code requires a  
whole new data structure that remembers recently failed Allocate  
transactions. The code around this data structure has to handle  
attacks like sending lots of unsuccessful Allocation request, a  
problem that the success case does not have to worry about.  I am  
wondering if this is really worth it, given that existing TURN  
mechanisms will handle the uncommon case of an Allocate request that  
fails on the first transmission but succeeds on a retransmission (as  
Remi points out).

Right now, I am leaning towards adding text pointing out this issue  
and saying that an implementation MAY return the same failure code,  
without requiring this behavior.

Comments?

- Philip

_______________________________________________
Behave mailing list
[email-masked]
https://www.ietf.org/mailman/listinfo/behave

---

From: Rémi Denis-Courmont <[email-masked]>
Date: Wed, 25 Jun 2008 16:12:44 +0300

> fails on the first transmission but succeeds on a retransmission (as

Servers don't want to keep track of errors. They write it to the log and 
forget about it. If the server returns an error because it is out of 
resources, it definitely does not want to do any book keeping.

Anyway. As I said, the server needs to cope with vanishing clients. There are 
so many different ways the client could be unable to release an allocation 
explicitly. The network connection could die. The client node could crash. 
The client radio could go out of range. Or the network could be 
mis-configured so that request are received by the server, but responses 
never hit the client.

You will find this problem in _every_ request-response/error protocol. It's 
all the same if a client tries to connect to a server. An initial SYN packet 
could trigger a SYN/RST (TCP accept queue full, or service being restarted), 
while the retransmit could trigger a successful SYN/ACK.

-- 
Rémi Denis-Courmont

---

From: "Benny Prijono" <[email-masked]>
Date: Wed, 25 Jun 2008 16:17:54 +0200

On Wed, Jun 25, 2008 at 2:56 PM, Philip Matthews
<[email-masked]> wrote:
>
> However, as I see it, replying with the same failure code requires a whole
> new data structure that remembers recently failed Allocate transactions. The

I imagine most people build the TURN protocol on top of the more
generic STUN protocol library, and remembering the last response sent
is part of the STUN library rather than TURN specific feature. So this
should just be a matter of sending the response statefully rather than
statelessly, so it's not really inventing a whole new data structure.

> code around this data structure has to handle attacks like sending lots of
> unsuccessful Allocation request, a problem that the success case does not
> have to worry about.  I am wondering if this is really worth it, given that
> existing TURN mechanisms will handle the uncommon case of an Allocate
> request that fails on the first transmission but succeeds on a
> retransmission (as Remi points out).
>

Cleaning up of allocation in the server may not be an issue indeed,
but these may:
 - server returns 486 (Allocation Quota Reached) for subsequent
allocation retries from the client because it has allocation from the
client while the client is not aware of it.
 - incorrect charging (provider/server charges the user/client for an
allocation that the client thinks had failed)

IMO that doesn't look too good.

And regarding the DoS attack potential, IMO it's not as bad as it
looks. For the bulk of 400 class error codes, the server doesn't need
to remember the last response since request retransmissions most
likely will trigger the same error anyway. So we only need to worry
about the "idempotent" response codes, and these would be 486
(Allocation Quota Reached) and 500 class responses. And these error
responses are generated *after* the authentication phase, so the DoS
attack potential is not increased at all with the feature.

Cheers
 Benny