I can't quite agree that you need two servers for the job and this is proven to be true by my test setup. Following is how it works:
1. Network setup is as follows:
private public UA1 NAT SER UA2 [ ]---------{ }--------< >---[ ]
2. SER configured as follows:
route { if (search("User-Agent: Cisco ATA.*")) { add_rport(); fix_nated_contact(); }; rewriteFromRoute();
[REGISTRATION STUFF STRIPPED]
if (method=="INVITE") { addRecordRoute(); };
t_on_positive("1") # forward to current uri now if (!t_relay()) { sl_reply_error(); }; }
reply_route[1] { if (search("Server: Cisco ATA.*") { fix_nated_contact(); } }
3. Registration
When registration request from UA1 arrives, we add received and rport into the first Via field, which allows us to properly route reply later on and also we rewrite Contact field with real IP:PORT, therefore registration information is correct and we can contact UA1 if necessary. By selecting a small registration expiration interval on UA1 it is possible to keep the nat binding alive.
4. Call from UA1 to UA2
- UA1 send INVITE request to SER. This request is passed through add_rport() and fix_nated_contact() - SER replies with 100 Trying to UA1 to the correct address/port due to received/rport added on the previous step - SER forwards INVITE request to UA1 with RecordRoute and rport/received added and Contact fixed - UA2 replies with 100 Trying. The response contains the second Via field with correct received/rport, but it doesn't matter since reply ignored anyway - UA2 replies with 180 Ringing. The response contains the second Via field with correct received/rport allowing to forward it properly - SER forwards 180 Ringing to UA1 - When the user picks up the phone, UA2 replies with 200 OK, again it contains proper received/rport in the second Via field - SER forwards 200 OK to UA1 - UA1 replies to SER with ACK, upon receiving it SER inserts received/rport into the first Via field - SER forwards ACK to UA2 [call in progress] - When the user at UA2 hangs us, UA2 seds a BYE to SER with Route filled with real IP:PORT of the UA1 from the Contact field it received in the original INVITE - SER forwards BYE to UA1 using IP:PORT from Route field - UA1 replies with 200 OK to SER - SER forwards 200 OK reply to UA2
5. Call from UA2 to UA1
- UA2 send INVITE request to SER - SER replies with 100 Trying to UA2 - SER looks up into registration database and forwards INVITE to UA1 with RecordRoute added - UA1 replies with 100 Trying. Received/rport added into the first Via field, but it doesn't matter since reply ignored anyway - UA1 replies with 180 Ringing. Received/rport added into the first Via field, but it doesn't really matter - SER forwards 180 Ringing to UA1 - When the user picks up the phone, UA1 replies with 200 OK. Contact field is fixed in reply_route[1] - SER forwards 200 OK to UA2 - UA2 replies to SER with ACK, Route field is is filled with IP:PORT from the Contact field in 200 OK - SER forwards ACK to UA1 using IP:PORT from Route field [call in progress] - When the user at UA2 hangs us, UA2 sends a BYE to SER with Route filled with real IP:PORT of the UA1 from the Contact field it received in the original 200 OK - SER forwards BYE to UA1 using IP:PORT from Route field - UA1 replies with 200 OK to SER - SER forwards 200 OK reply to UA2
As you can see, as long as signalling concerned, it is possible to reliably traverse NAT without any additional servers. Of course this requires a reliable way to determine that a client supports symmetric signalling. In our particular case, it is done by searching for "Server: Cisco ATA.*" or "User-Agent: Cisco ATA.*"
-Maxim
Jiri Kuthan wrote:
Few more notes on this construct:
a it takes two servers in series; the first one in chain makes the NAT fixing job, the other one acts as proxy/registrar; the reason is the NAT changes to a request are only used to generate outoging request and do not affect registrar; thus, you first need to send the updated request out; one could still have only one server running (be it easier or not) with a routing policy, which makes the request pass the same server in two rounds -- first one de-natifying, the second real one
b it takes generating symmetric replies and accepting rport in relayed replies -- I think that is a reasonable thing to add to ser core
c the routing policy needs to be set up in such a way, the de-natifying instance of SER is always in the path -- otherwise subsequent inbound requests would be routed based-on Contact directly to NAT, would not use symmetric path opened by initial REGISTERs and fail; the denatifier thus needs to use record-routing
d for the same reason, all initial inbound requests to natted users proxied by the main server need to be statically routed to the de-natifier
-Jiri
the examples bellow demonstrate in ascii charts some more details; A:B is address:port of natted phone, X:Y the natted A:B, C:D that of denatifier
network setting:
fone F: A:B NAT N: X:Y proxy D proxy P ~ /------\ ~ /-------------\ /--------------\ |phone | -------->~----------->|denattifying |--------------->|registrar/ | ------/ ~ |ser/outbound | |inbound proxy | ~ |proxy | --------------/ -------------/\ ^ \ / ----> outbound / domains
- registers go from F, are rewritten by D and processed at P
- INVITEs from F visit D, Contact is rewritten, rport is introduced, request is record-routed, so that other party's request visit D too;
- INVITEs from outside visit first P, contacts rewritten previously by D are put in r-uri, requests are forwarded statically to D, and D forwardes by uri to the fone F
At 06:27 PM 1/10/2003, Maxim Sobolev wrote:
On Fri, Jan 10, 2003 at 03:37:46PM +0200, Maxim Sobolev wrote:
Sounds reasonably - I'll do it that way.
I am planning add a new nathelper module, which will export the following functions:
add_rport() - insert a rport= parameter into the first Via field fix_nated_contact() - replaces host:port in Contact field with host:port we received this message from add_direction_passive() - adds direction=passive option to the SDP
Then it would be possible to do the following at the very top of config before any other REGISTER/INVITE processing:
if (method == "INVITE" || method == "REGISTER") { if (search("User-Agent: Cisco ATA.*") { add_rport(); if (method == "INVITE") { add_direction_passive(); }; if (method == "REGISTER") { fix_nated_contact(); }; }; };
Does it sound reasonably for you?
-Maxim
Thanks!
-Maxim
On Fri, Jan 10, 2003 at 02:15:11PM +0100, Jan Janak wrote:
On 10-01 14:32, Maxim Sobolev wrote:
Folks,
I need an advise on how to better implement one feature, which isn't currently present in SER. We need to allow UAs behind NAT properly register with the registrar - by "properly" I mean that host:port portion of URI in Contact field should not be used, but host:port the request came from should be used instead. By definition we know that those UAs will support symmetric SIP signalling, so that this scheme will work just fine.
In my opinion there are two ways to do it: either add new rewritecontact* family of functions similar to rewritehost ones. or add a new flag for the save() function. This is where I need your help - which implementation looks better for you (or maybe you have even some better idea), since we are really interested in inclusion of our changes into the mainline to reduce our local hacks.
This should be implemented as a standalone module for ser. I want to keep registrar clean, it should not be aware of NATs. So, create a new module for ser that will contain all the NAT traversal helper functions, the functions will be then called from the config script.
That includes modifications of contact, adding rport to Via and so on.
regards, Jan.
Serusers mailing list serusers@lists.iptel.org http://lists.iptel.org/mailman/listinfo/serusers
Serusers mailing list serusers@lists.iptel.org http://lists.iptel.org/mailman/listinfo/serusers
-- Jiri Kuthan http://iptel.org/~jiri/