[sr-dev] Log from outbound chat today

Olle E. Johansson oej at edvina.net
Wed Aug 8 14:31:38 CEST 2012


Friends,
I just wanted to mail out the chat log from todays chat about SIP Outbound in Kamailio. We discussed how outbound affects Kamailio today and how it may work in various modes:
- Kamailio as an edge proxy
- Kamailio as a registrar/location server behind edge proxys
- Kamailio as a standalone proxy/registrar 

We discussed both cases where client does support outbound and where the client does not support it and found that implementing SIP outbound can help both use cases.

This is for documentation, copied from my chat client as raw text. A bit messy, but it's all there.

/O


[1:33pm]oej:
My presentation is http://www.slideshare.net/oej/sip2012-outbound
[1:33pm]ibc:
(phone)
[1:33pm]oej:
Ok ibc
[1:33pm]pdunkley:
Thanks oej
[1:34pm]oej:
Was about to publish it soon anyway as part of SIP2012
[1:34pm]oej:
You just put some extra pressure on me to go ahead
[1:35pm]shaheryarkh:
nice presentation
[1:35pm]oej:
At this point I'm not aware of any SIP clients that support Outbound
[1:35pm]oej:
thanks
[1:36pm]oej:
libre has partial support, haven't checked with Alfred if he completed it
[1:37pm]oej:
I am pretty sure that ibc has something somewhere since he developed support for it in OverSIp.
[1:37pm]oej:
To do this in Asterisk, I would have to start with UUID creation
[1:37pm]ibc:
I'm back
[1:38pm]oej:
so ibc, do you know any clients with Outbound support - ws or no ws?
[1:39pm]ibc:
about clients supporting Outbound: by my experience we DONT need clients supporting Outbound in order to make it to work. All the SIP TCP clients "assume" that they will receive incoming request throght the connection of the registration, even if that is anti-RFC 3261, so it's just like adding a function force_outbound() in kamailio
[1:39pm]oej:
Right. So implementing outbound will make life easier for TCP clients behind NAt, regardless
[1:39pm]oej:
But for "true" outbound with the failover, we need two registrations to separate servers
[1:40pm]ibc:
well, JsSIP does support outbound, but supporting Outbound (in a client) is just about advertising it in the Supported header and being able to receive request throught and outbound connection (registration)
[1:40pm]oej:
And registering at least two times
[1:40pm]oej:
That's a requirement in the RFC
[1:40pm]ibc:
yes, for the +sip.instance and reg-id stuff, we do need Outbound  aware clients
[1:41pm]oej:
So I guess we need to create a client or several. I'll check with Alfred.
[1:41pm]ibc:
I would like to divide Outbound stuff in two parts:
[1:42pm]ibc:
1) the stuf made by the proxy (or EDGE proxy) by adding a Outbound flow token in RR or Path
[1:42pm]ibc:
2) the sip.instance and reg-id stuf for clean re-registration, proper device's binding update and Outbound failover
[1:43pm]oej:
So edgeproxy processing (flow token and path) and registrar/location server handling (contact storage, destination set, forking)
[1:43pm]oej:
Ok. So let's start with edgeproxy stuff
[1:43pm]oej:
That should be quite simple.
[1:43pm]ibc:
ok
[1:43pm]ibc:
that's not so simple :)
[1:43pm]oej:
Explain then :-)
[1:44pm]ibc:
lot of complexity in how to add and inspect the flow token in the RR / Route header
[1:44pm]ibc:
ok, please check this:
[1:44pm]ibc:
https://github.com/versatica/OverSIP/blob/master/lib/oversip/sip/modules/core.rb#L36
[1:44pm]ibc:
it's a bit documented
[1:44pm]ibc:
line 57:
[1:45pm]ibc:
# Outgoing initial request asking for Outbound. Just valid when:
[1:45pm]ibc:
        # - It's an initial request.
[1:45pm]ibc:
        # - Single Via (so there is no a proxy in front of us).
[1:45pm]ibc:
        # - It's an INVITE, REGISTER, SUBSCRIBE or REFER request.
[1:45pm]ibc:
        # - Has a preloaded top Route with ;ob param pointing to us, or has Contact with ;ob, or
[1:45pm]ibc:
        #  it's a REGISTER with ;+sip.instance.
[1:45pm]oej:
Is "Outgoing" from the core to the device in this case?
[1:46pm]ibc:
no, it means a request received by the proxy
[1:46pm]oej:
To start from the beginning
[1:46pm]oej:
1) Client opens connection (for connection oriented transports)
[1:46pm]ibc:
if those requirements are not satisfied, then outbound should not be applied because we could break things
[1:46pm]ibc:
ok
[1:46pm]oej:
2) Client sends REGISTER
[1:46pm]oej:
3) Edge proxy creates flow token
[1:47pm]oej:
Then?
[1:47pm]ibc:
yes but:
[1:47pm]ibc:
in step 3) the proxy MUST decide whether to create a token or not
[1:47pm]ibc:
so apply outbound or not (based on requirements above)
[1:47pm]oej:
Yep. The client indicates support for outbound
[1:47pm]ibc:
or force_outbound() is called
[1:48pm]oej:
4) Edge proxy adds Record-route and Path headers with flow token (?)
[1:48pm]ibc:
then the proxy creates a flow token and adds (in my case) two RR or Path, and adds the flow token as the RURI username of the top RR/Path
[1:48pm]ibc:
and *also* adds ;ob param to the top RR/Path
[1:49pm]oej:
For REGISTER, there's no RR? So PATH
[1:49pm]ibc:
yes, but exactly SAME value
[1:49pm]ibc:
or values
[1:49pm]oej:
agree
[1:49pm]oej:
then forward to location server
[1:49pm]ibc:
please let me re-check in which RR/path (top or second) must the token and ;ob be added
[1:49pm]oej:
Which will receive at least two register requests with different flow tokens
[1:49pm]oej:
and different paths
[1:50pm]oej:
So in Kamailio this will affect RR and Path modules so far.
[1:50pm]oej:
Anything else?
[1:50pm]ibc:
yes, the token and ;ob must be added in the top RR/Path as said above
[1:50pm]oej:
(we're not at the location server yet, forget that part)
[1:51pm]ibc:
yes, this is just about the EDGE proxy which is GRUU or +sip.instance/reg-id unaware
[1:51pm]ibc:
the REGISTER is routed to the registrar
[1:51pm]oej:
This is just for the incoming FIRST request after connection setup
[1:51pm]ibc:
the registar stores the Path headers
[1:51pm]oej:
In order for us to support the handling of that request, so far I see changes to RR and path modules - anyone else have other thoughts?
[1:51pm]oej:
pdunkley?
[1:51pm]ibc:
I see no other way
[1:52pm]oej:
miconda?
[1:52pm]ibc:
by the way, adding the flow token *always* should not break nothing
[1:52pm]pdunkley:
Sorry, I am doing three different things at once here.  I will need to re-read this later and catch up.
[1:52pm]oej:
;-)
[1:53pm]oej:
We're at the edge proxy, trying to sort things out.
[1:53pm]oej:
Ok, moving on to the registrar
[1:53pm]oej:
We save the contact, the path header as always
[1:53pm]ibc:
Outbound (in the EDGE proxy) is just about ading stuf to RR/Path, and the UAS is mandated to mirror those values as per RFC 3261, so we break nothing by always adding that stuf
[1:53pm]oej:
I think the usrloc module now save the instance id
[1:54pm]ibc:
and the Path URI's
[1:54pm]oej:
we already do path URI's
[1:54pm]ibc:
so a request arrives to the registrar for that AOR
[1:54pm]oej:
Do we need to respond differently to a register?
[1:54pm]ibc:
no (unless GRUU is required/supported)
[1:54pm]oej:
Or is it just a normal register, binding a contact with some properties to an AOR
[1:55pm]ibc:
normal, but if the registrar supports Outbound and the REGISTER asks for Outbound, then the registrar must store the sip.instance and reg-id
[1:55pm]ibc:
and "forget" the CSeq and Call-ID of the REGISTER
[1:55pm]ibc:
so a request arrives to the registrar for that AOR, then:
[1:56pm]ibc:
the registrar does lookup()
[1:56pm]ibc:
and for each binding with *same* sip.instance retrieves just *one*
[1:56pm]ibc:
(the one with best reg-id I hope)
[1:56pm]ibc:
also retrieves the Path URI's and adds them as Route headers
[1:57pm]ibc:
the top Route points to the EDGE proxy so routes the request to it
[1:57pm]oej:
But here's where we need to discuss the destination set in kamailio.
[1:57pm]oej:
If you suggest that the lookup function should only return ONE contact for one instance-id (one device) then how do we handle failover?
[1:57pm]ibc:
it should be the top Route (unless we manually modify it)
[1:57pm]ibc:
ok, let me explain:
[1:58pm]oej:
We branch with t_relay and the message fails in the edge proxy? Will the edge proxy return a specific code? How do we find the next contact?
[1:58pm]ibc:
yes, let me ;)
[1:58pm]ibc:
the registrar gets the binding with reg-id=1. The top Route points to the EDGE proxy so routes the request to it
[1:59pm]ibc:
the EDGE proxy receives the request and inspects the Routes
[1:59pm]ibc:
the top Route points to the EDGE proxy so it's removed
[1:59pm]ibc:
the second Route also points to it but it ALSO contains a ;ob param
[1:59pm]ibc:
so the Route is removed and the Route RURI username retrieved (which is the flow token)
[2:00pm]ibc:
the EDGE proxy gets the connection associated to that flow token and routes the request over it (by also adding RR and so on, of course)
[2:00pm]ibc:
now let's imagine that the connection is closed (reg-id=1)
[2:00pm]ibc:
the EGDE proxy knows that so replies 430 Flow Token
[2:01pm]ibc:
the registrar reveices the 430, deletes the selected binding for this transactions and gets the next one (reg-id=2) and tries again
[2:01pm]ibc:
the second binding (reg-id=2) could have been arrived to the registrar from a different EDGE proxy
[2:02pm]ibc:
(that's the philosofy of Outbound failover in fact)
[2:02pm]oej:
exactly
[2:03pm]oej:
In Kamailio, this stuff is handled in the routing script
[2:03pm]ibc:
there is more stuff when the EDGE proxy adds RR header(s) for a dialog in which Outbound was used, but it's not so hard
[2:03pm]oej:
So we need a funciton that we can call if we get 430 to check if there's an alternate path to the same instance id
[2:03pm]ibc:
I mean: for an in-dialog request
[2:03pm]ibc:
right
[2:03pm]oej:
lookup_outbound
[2:03pm]ibc:
or also if we get 408/503 from the EDGE proxy (down)
[2:04pm]pdunkley:
Is another function required, or can the existing lookup be used?
[2:04pm]oej:
We only use lookup once normally
[2:04pm]pdunkley:
Perhaps lookup() should return the best reg_id available, and then have another function to remove a binding.
[2:04pm]oej:
this needs to re-lookup and reset the r-uri
[2:04pm]ibc:
I think it should be intregatted within lookup() since in the first attemp the registrar has no way to know which one to use
[2:04pm]ibc:
and also the Route headers
[2:04pm]pdunkley:
Then calling lookup again (from the failure_route[] that handles the 430) should do the right thing?
[2:05pm]ibc:
(mirrored from the received Path headers but in reverse order)
[2:05pm]oej:
So we have  a request route, use t_relay and end up in branch route and maybe in response route and failure route
[2:05pm]oej:
Using Lookup again would break the syntax, I think that's bad
[2:05pm]ibc:
yes, but we also need that, upon a 430, kamailio *removes* the failing binding
[2:05pm]oej:
This is like dispatcher failover.
[2:05pm]oej:
Dispatcher adds all possible targets in an avp and sends to the first one
[2:06pm]oej:
Then in failure route I can select next and resend
[2:06pm]oej:
I tihnk we should have something similar
[2:06pm]ibc:
ok, makes sense. Perhaps we need a transaction flag that is activated when it belongs to an Outbound registration
[2:06pm]oej:
branch flag too
[2:06pm]oej:
to mark this branch as one that has possible candidates for failover
[2:07pm]oej:
So a new function should
[2:07pm]oej:
1) Remove binding to failed flow
[2:07pm]ibc:
so:  if reply==430 && isbflagset(OUTBOUND_BINDING) then:  outbound_next_lookup()
[2:07pm]pdunkley:
So have lookup functions that populate/use AVPs stored in the transaction, plus another function to remove a binding from the location table?
[2:07pm]oej:
2) Reset branch route and r-uri
[2:07pm]ibc:
not in the transaction but in the branch
[2:08pm]oej:
One transaction could be targeted to two AORs with two devices each, ending up in many branches with different instance IDs
[2:08pm]oej:
But each branch is only targeted towards one instance
[2:08pm]oej:
with multiple reg-ids - which each have a contact, path set (including flow token)
[2:08pm]ibc:
right
[2:09pm]ibc:
and remember that Contact URI is useless when using Outbound
[2:09pm]oej:
Absolutely. It's the flow token that relates to a UDP or TCP/TLS flow
[2:09pm]oej:
or ws STCP
[2:10pm]ibc:
the EDGE proxy does NOT route an initial or in-dialog request based on the RURI if it indicates Outbound request in the Route or Contact header
[2:10pm]ibc:
that's also true: Outbound is ALSO valid for UDP, but in that case the flow token must be decoded to the IP:port
[2:10pm]oej:
If the indicated flow-token does not relate to an active flow, it should fail directly without even trying
[2:11pm]ibc:
430
[2:11pm]oej:
So right, don't parse the r-uri and try to reach the client unless the client has an active flow towards you.
[2:11pm]ibc:
yes
[2:11pm]oej:
This will affect forwarding - stateful and stateless - in the edge proxy
[2:12pm]ibc:
and: if the EDGE proxy can detect that the flow token has not been generated by it, then it can reply 403 Forbidden
[2:12pm]ibc:
  Next, whether the Route header field contained an "ob" URI parameter
[2:12pm]ibc:
  or not, the proxy removes the Route header field value and forwards
[2:12pm]ibc:
  the request over the 'logical flow' identified by the flow token,
[2:12pm]ibc:
  that is known to deliver data to the specific target UA instance.  If
[2:12pm]ibc:
  the flow token has been tampered with, the proxy SHOULD send a 403
[2:12pm]ibc:
  (Forbidden) response.  If the flow no longer exists, the proxy SHOULD
[2:12pm]ibc:
  send a 430 (Flow Failed) response to the request.
[2:12pm]ibc:
in http://tools.ietf.org/html/rfc5626#section-5.3.1
[2:12pm]pdunkley:
I think this means that a outbound_route() function that is a bit like the loose_route() function (in terms of setting $du) is required.
[2:12pm]bulkorok left the chat room. (Quit: gone with the wind...)
[2:13pm]pdunkley:
If outbound_route() returns -1 then a 430 can be generated from Kamailio configuration?
[2:13pm]ibc:
yes
[2:14pm]ibc:
but, before calling to outbound_route() we need to check that we should do outbound
[2:14pm]ibc:
so:  is_outbound_requested()
[2:14pm]pdunkley:
Then say, if it returns 1 then it means either outbound is not being used (and Kamailio core/loose_route() can work out $du), and if it returns 2 then it means outbound is used and $du is set.  A bit like the multiple returns from loose_route().
[2:14pm]oej:
Or just a pseudovariable with a name that no one remembers? ;-)
[2:14pm]ibc:
and that should do soemthing like: https://github.com/versatica/OverSIP/blob/master/lib/oversip/sip/modules/core.rb#L57
[2:15pm]ibc:
$or = outbound_requested XD
[2:15pm]oej:
Sounds like a plan
[2:15pm]ibc:
we should also consider the case in which there is no EDGE proxy but just a single proxy/registrar
[2:16pm]oej:
How does outbound apply then?
[2:16pm]ibc:
it should also add outbound stuff and so, but here is no Path in the register so "something" (the flow token?) should also be stored in the location table
[2:16pm]ibc:
let's paint the use case:
[2:16pm]ibc:
REGISTER from the client to the single Kamailio
[2:17pm]oej:
You mean being able to re-use the connection anyway?
[2:17pm]oej:
Makes sense
[2:17pm]ibc:
Kamailio assigns a flow token for the connection and stores it within the binding
[2:17pm]ibc:
the client sends an INVITE
[2:17pm]oej:
I don't know how kamailio handles TCP connections today really
[2:17pm]oej:
Do we reuse them at all?
[2:17pm]pdunkley:
Only if you use the aliasing stuff :-)
[2:17pm]ibc:
kamailio adds two RR: the first one with the connection flow token, the top one without it, and routes the request
[2:18pm]oej:
I know we can keep them open, but I can't check if there's a connexction open to client y
[2:18pm]ibc:
aliasing stuf is a pain
[2:18pm]pdunkley:
If you call handle_ruri_alias() it sets $du to the address and port of the other end of the connection.  If $du exactly matches a connection it is reused.
[2:18pm]ibc:
and a risk. There could be 100 UAs registering the same 1.1.1.1 private address in the Contact
[2:19pm]pdunkley:
Yes, but that is what Kamailio currently does for TCP and TLS reuse - just answering oej's question.
[2:19pm]ibc:
sure
[2:19pm]ibc:
anyhow I would like to clarify that:
[2:19pm]oej:
At some point we need better connection management, also for TLS
[2:19pm]ibc:
current aliasing stuf is anti RFC 3261 (but it works)
[2:19pm]oej:
;-)
[2:19pm]pdunkley:
As long as - by using flow tokens etc - we can get the far end address and port into $du the connection will be reused.
[2:20pm]ibc:
if we replace aliasing with outbound, we are better
[2:20pm]ibc:
and if we force Outbound when the client does not request it (old devices) we are not worse than applying aliasing
[2:20pm]pdunkley:
In fact, the WS implementation is dependent on the fact that with the right stuff in $du connections are reused.
[2:20pm]oej:
Hmm. That alias handling may totally break TLS security unless there's a cert check involved
[2:21pm]ibc:
sure
[2:21pm]pdunkley:
Once Outbound is forced it'll be better - but at the moment it is what we have :-(
[2:21pm]oej:
That's life, as long as we agree on the current state and move forward ;-)
[2:21pm]ibc:
yes, but what I mean is that aliasing could be fully replaced by outbound and it would break nothing
[2:21pm]pdunkley:
That would be good.
[2:21pm]ibc:
(sorry, I must go or a while)
[2:22pm]oej:
I have a meeting coming up as well. Good chat. Peter - do you have enough input for a first stab at outbound?
[2:22pm]ibc:
I'll be latter (at ~15:30)
[2:22pm]ibc:
is this chat available in some web?
[2:22pm]ibc:
I want to twit it XD
[2:23pm]oej:
Have no idea if it's logged anywhere.
[2:23pm]pdunkley:
I need to re-read all of this, and the specification, and your presentation...  Then I'll have a think about it and post something to sr-dev.
[2:23pm]pdunkley:
It would be good if this was logged
[2:23pm]oej:
Let's continue on sr-dev :-)
[2:23pm]shaheryarkh:
good stuff
[2:23pm]shaheryarkh:
really informative
[2:23pm]shaheryarkh:
thanks everyone
[2:23pm]oej:
I agree to taking a copy and mailing out so it ends up in the mailing list
[2:23pm]oej:
archives
[2:24pm]oej:
Do you guys agree?
[2:24pm]pdunkley:
Yup
[2:24pm]oej:
ibc asked for it, so I take it he agrees to.
[2:24pm]ibc:
sure ;)
[2:24pm]shaheryarkh:
yes
[2:24pm]ibc:
bye!


More information about the sr-dev mailing list