[Home]

Summary:ASTERISK-10054: [patch] T.38 with devices behind NAT does not work in all circumstances
Reporter:Christoph Stadlmann (cstadlmann)Labels:
Date Opened:2007-08-09 09:42:14Date Closed:2010-03-23 12:25:13
Priority:MajorRegression?No
Status:Closed/CompleteComponents:Channels/NewFeature
Versions:Frequency of
Occurrence
Related
Issues:
Environment:Attachments:( 0) fulldebug.zip
( 1) sip.conf
( 2) sipshowpeer.txt
( 3) udptl-version3.patch
Description:There is a conceptual problem in chan_sip.c in 'process_sdp' when it processes UDPTL re-invites.

Let's look at the following scenario:

ATA1: IP 192.168.4.26, NAT IP 83.64.90.46
ATA2: IP 212.31.71.50

ATA1 send's a fax to ATA2, so ATA2 performs the reinvite within the RTP session. When ATA1 responds to the re-invite, it transmits it's IP address, which is of course not the NAT IP:

<--- SIP read from 83.64.90.46:10497 --->
SIP/2.0 200 OK
Via: SIP/2.0/UDP 85.193.128.15:5060;branch=z9hG4bK2b3e0f4c;rport=5060
From: <sip:073261066060@voip.mywave.at>;tag=as712ecf71
To: <sip:v205357an@voip.mywave.at>;tag=2135323211
Call-ID: 2073630983-10497-8@192.168.4.26
CSeq: 102 INVITE
Contact: <sip:v205357an@192.168.4.26:10497>
Supported: replaces, path
User-Agent: Grandstream HT-502 V0.2A 1.0.0.44
Allow: INVITE, ACK, OPTIONS, CANCEL, BYE, SUBSCRIBE, NOTIFY, INFO, REFER, UPDATE
Content-Type: application/sdp
Content-Length: 354

v=0
o=v205357an 8000 8001 IN IP4 192.168.4.26
s=SIP Call
c=IN IP4 192.168.4.26
t=0 0
m=image 54853 udptl t38
a=T38FaxVersion:0
a=T38MaxBitRate:9600
a=T38FaxFillBitRemoval:0
a=T38FaxTranscodingMMR:0
a=T38FaxTranscodingJBIG:0
a=T38FaxRateManagement:transferredTCF
a=T38FaxMaxBuffer:400
a=T38FaxMaxDatagram:400
a=T38FaxUdpEC:t38UDPRedundancy
<------------->

The function process_sdp now evaluates the line 'c=IN IP4 192.168.4.26' and sets sin.sin_addr accordingly. After 'ast_udptl_set_peer(p->udptl, &sin);' (Line 5041) all UDPTL packets are transmitted to the wrong IP address. Of course the NAT IP is stored when Asterisk receives the first packet, which is handled in udptl.c (Line 662). But if Asterisk never receives a packet, fax transmission fails because ATA1 never gets any packets. Especially Patton devices do not send packets at all until they receive ones.

To work around this issue, I implemented a very nasty patch to chan_sip.c:

Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c (revision 78416)
+++ channels/chan_sip.c (working copy)
@@ -5037,6 +5037,7 @@
/* Setup UDPTL port number */
if (p->udptl) {
if (udptlportno > 0) {
sin.sin_port = htons(udptlportno);
+ sin.sin_addr = p->recv.sin_addr;
ast_udptl_set_peer(p->udptl, &sin);
if (debug)
ast_log(LOG_DEBUG,"Peer T.38 UDPTL is at port %s:%d\n",ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));

With that patch, the packets are transmitted to the NAT IP of the device, and everything is fine. I know I should have implemented checks for NAT, but all our devices are behind NAT, so this is no problem.

Now comes the point where I need assistance from a chan_sip guru because that's not the only NAT issue. Although the packets are transmitted to the correct IP address now, any NAT router rejects the packets because the packtes come from a different port that the RTP packets were. So static port forwarding of the udptl ports is the only solution for now (Maybe Cisco routers with SIP fixup can handle it...), but only for ONE device. Multiple devices are not supported of course. Anyway, after the ATA or Patton received the packets from Asterisk, it starts transmitting packets and NAT is fine again.

So my idea is the following:
If Asterisk could transmit the first packets to a device behind NAT with ip:port from the RTP stream, the packets would arrive at the ATA without static port forwarding because of the established session. After the ATA transmits it's packets, we could use the port from the re-invite again.

So please guys think about that issue. Although it seems that I'm the only one in the world that plays around with T.38, a proper solution would be appreciated.
Comments:By: Joshua C. Colp (jcolp) 2007-08-10 08:53:53

What is your sip.conf like?

By: Christoph Stadlmann (cstadlmann) 2007-08-11 03:44:27

Because I use MySQL for all config files, sip.conf hat two parts:

'Static' part: sip.conf => mysql,asterisk,ast_config
'Dynamic' part: sippeers => mysql,asterisk,sip

I uploaded the static part as 'sip.conf' and one peer as 'sipshowpeer.txt'.

By: Christoph Stadlmann (cstadlmann) 2007-08-17 01:57:03

Any updates/ideas/thoughts here?

By: Christoph Stadlmann (cstadlmann) 2007-08-21 09:04:36

As of revision SVN-branch-1.4-r79998, here is my proposal for tweaking that NAT issue.

--- channels/chan_sip.c.orig 2007-08-20 11:07:46.695095949 +0200
+++ channels/chan_sip.c 2007-08-21 15:13:51.000000000 +0200
@@ -4872,6 +4872,7 @@
int vpeercapability = 0, vpeernoncodeccapability = 0;
struct sockaddr_in sin; /*!< media socket address */
struct sockaddr_in vsin; /*!< Video socket address */
+ struct sockaddr_in rsin; /*!< RTP socket address */

const char *codecs;
struct hostent *hp; /*!< RTP Audio host IP */
@@ -5032,7 +5033,9 @@
/* RTP addresses and ports for audio and video */
sin.sin_family = AF_INET;
vsin.sin_family = AF_INET;
+ rsin.sin_family = AF_INET;
memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+ memcpy(&rsin.sin_addr, hp->h_addr, sizeof(rsin.sin_addr));
if (vhp)
memcpy(&vsin.sin_addr, vhp->h_addr, sizeof(vsin.sin_addr));

@@ -5040,6 +5043,20 @@
if (p->udptl) {
if (udptlportno > 0) {
sin.sin_port = htons(udptlportno);
+
+ if ((ast_test_flag(&p->flags[0], SIP_NAT)) == SIP_NAT) {
+ ast_rtp_get_peer(p->rtp, &rsin);
+ if (strcasecmp(ast_inet_ntoa(rsin.sin_addr), "0.0.0.0") != 0) {
+ sin.sin_addr = rsin.sin_addr;
+ if (debug)
+ ast_log(LOG_DEBUG,"Peer T.38 UDPTL is behind NAT, using RTP port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+ } else {
+ sin.sin_addr = p->recv.sin_addr;
+ if (debug)
+ ast_log(LOG_DEBUG,"Peer T.38 UDPTL is behind NAT, using SIP port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+ }
+ }
+
ast_udptl_set_peer(p->udptl, &sin);
if (debug)
ast_log(LOG_DEBUG,"Peer T.38 UDPTL is at port %s:%d\n",ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));



So, what does my patch...
In most cases we have an existing RTP stream, so if NAT is detected, any proposal of the re-invite is updated with the ip address we know from the RTP stream.
If we don't have an existing RTP stream, we just use the ip address which we get from the SIP channel.

Of course this does not resolve all issues, but if you set up static port forwarding rules from Asterisk box to the device just for the UDPTL port range, everything works fine. Again, without port forwarding this patch does not work.

By: Christoph Stadlmann (cstadlmann) 2007-08-28 00:51:07

@file: Any comments to my patch proposal? You confirmed bug 10532 recently (and also bug 10274 which was also reported by me), so I guess we have to have a closer look at the the whole T.38 topic...

By: Christoph Stadlmann (cstadlmann) 2007-09-14 00:43:12

Any updates here, file? Is there any chance this patch will make it into branch? Maybe we could implement a parameter in sip.conf?

By: Joshua C. Colp (jcolp) 2008-05-27 08:27:50

Per a discussion on the dev list this is going to be made into an option.

By: Digium Subversion (svnbot) 2008-05-28 09:17:22

Repository: asterisk
Revision: 118646

U   branches/1.4/CHANGES
U   branches/1.4/channels/chan_sip.c
U   branches/1.4/configs/sip.conf.sample

------------------------------------------------------------------------
r118646 | file | 2008-05-28 09:17:18 -0500 (Wed, 28 May 2008) | 4 lines

Add an option to use the source IP address of RTP as the destination IP address of UDPTL when a specific option is enabled. If the remote side is properly configured (ports forwarded) then UDPTL will flow.
(closes issue ASTERISK-10054)
Reported by: cstadlmann

------------------------------------------------------------------------

http://svn.digium.com/view/asterisk?view=rev&revision=118646

By: Digium Subversion (svnbot) 2008-05-28 09:22:39

Repository: asterisk
Revision: 118647

_U  trunk/
U   trunk/CHANGES
U   trunk/channels/chan_sip.c
U   trunk/configs/sip.conf.sample

------------------------------------------------------------------------
r118647 | file | 2008-05-28 09:22:38 -0500 (Wed, 28 May 2008) | 12 lines

Merged revisions 118646 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
r118646 | file | 2008-05-28 11:23:34 -0300 (Wed, 28 May 2008) | 4 lines

Add an option to use the source IP address of RTP as the destination IP address of UDPTL when a specific option is enabled. If the remote side is properly configured (ports forwarded) then UDPTL will flow.
(closes issue ASTERISK-10054)
Reported by: cstadlmann

........

------------------------------------------------------------------------

http://svn.digium.com/view/asterisk?view=rev&revision=118647

By: Digium Subversion (svnbot) 2008-05-28 09:25:16

Repository: asterisk
Revision: 118648

_U  branches/1.6.0/
U   branches/1.6.0/CHANGES
U   branches/1.6.0/channels/chan_sip.c
U   branches/1.6.0/configs/sip.conf.sample

------------------------------------------------------------------------
r118648 | file | 2008-05-28 09:25:16 -0500 (Wed, 28 May 2008) | 20 lines

Merged revisions 118647 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk

................
r118647 | file | 2008-05-28 11:29:01 -0300 (Wed, 28 May 2008) | 12 lines

Merged revisions 118646 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
r118646 | file | 2008-05-28 11:23:34 -0300 (Wed, 28 May 2008) | 4 lines

Add an option to use the source IP address of RTP as the destination IP address of UDPTL when a specific option is enabled. If the remote side is properly configured (ports forwarded) then UDPTL will flow.
(closes issue ASTERISK-10054)
Reported by: cstadlmann

........

................

------------------------------------------------------------------------

http://svn.digium.com/view/asterisk?view=rev&revision=118648