Summary:ASTERISK-07157: [patch][post-1.4] IAX native bridge and NAT
Reporter:tjd (tjd)Labels:
Date Opened:2006-06-13 04:06:30Date Closed:2006-07-21 08:31:54
Versions:Frequency of
Environment:Attachments:( 0) transfer.diff
( 1) transfer2.diff
( 2) transfer3.diff
( 3) transfer4.diff
Description:For a call from client A to client B through server C, native bridging seems to (mostly) fail when A and/or B is behind NAT.  There are two cases I have identified (let's say A is the one with a NATed address):

1. C can see A's internal address, and passes this to B via the TXREQ packet.  Clearly B will not be able to successfully send a TXCNT packet to A.

2. C sees A's NATed address/port and correctly sends this to B in the TXREQ packet.  The TXCNT packet from B to A is then blocked by A's firewall/NAT.

C requires a TXREADY from both A and B to initiate the native bridge, which means A needs TXACC reply from B (from its TXCNT) *and* B needs a TXACC from A (from its TXCNT).  With NAT in the way this is unlikely to occur.

Also, to get a successful path between A and B doesn't require bi-directional paths originated from both ends.  You only need to originate from one end.



When a TXCNT is received (say, by B from A) and the source address of the packet differs to the transfer address given by the TXREQ (from C), then we change the transfer address to the packet's origin address.  The TXACC reply (back to A from B) should make it back though A's NAT.

Also, if B hasn't already received a TXACC from A, we then send another TXCNT to A (via the newly discovered address/port).  That way if the first TXCNT<->TXACC failed, this one should work.  The transfer state should take care of multiple TXCNT<->TXACCs, if they are successful.

That way both A and B will get bidirectional paths, so long as one can get a TXCNT to the other in the first instance.

I thought a man-in-the-middle attack may be a problem here, but I figure the A<->C and C<->B packets would need to be sniffed to get the information to do it.  So the end result is someone who was listening to the original call could potentially listen to it after a transfer?!?  Thoughts?

Note the attached patch is untested, and just for illustration.
Comments:By: tjd (tjd) 2006-06-13 05:26:38

Having thought about it a bit...

When a TXACC is received, you aren't going to know which TXCNT it is in reply to.  Unless:

a) You make an assumption that the address/port the TXACC comes from is the same you sent the TXCNT to.

b) You put some extra information into the TXCNT and TXACC.

By: Serge Vecher (serge-v) 2006-06-13 08:57:19

Please update to, there was a significant security issue resolved there. Also, update the patch. Thanks.

By: tjd (tjd) 2006-06-13 20:44:35

Okay, here's the patch against 1.2.9 (transfer2.diff).  I've also added the address check when the TXACC is received.

I am not sure if the retransmission of the TXCNT will cause a problem.  In fact, it may not be the way to implement this, but at least the idea is out there.

And I guess this change would also go into libiax too?

By: Serge Vecher (serge-v) 2006-06-14 08:30:52

Can also please fax a disclaimer to Digium and confirm when you do that. Thanks

By: tjd (tjd) 2006-06-15 03:25:11

Okay, the disclaimer is done.

Basically, I don't think my solution is very good.  Sending multiple TXCNTs is bad.  Also, modifying the "global" transfer address is not a good thing as it screws up retransmissions.  And getting multiple successful paths between A and B is also an issue.

Here is a third (somewhat lame) attempt at a solution (transfer3.diff).   It is essentially a 3 way handshake, except the last TXACC will break backwards compatibility :-(  And therefore, probably not worth posting.

I think the way to do it is this:

- Send the TXCNT to the address given in the TXREQ
- When a TXCNT is received, write the address/port it was received from into the TXACC reply.  Send the TXACC back to this address/port.
- When the TXACC is received, collect the address the other host received the TXCNT from, add the address the TXACC was received from, and send this in the TXREADY packet back to C.
- When a *single* TXREADY is received, the transfer can occur.  Collect the two addresses, and send them in the relevant TXREL packets.
- On receipt of the TXREL, use this address to transfer the call.  And cancel pending TXCNTs, so we don't get a TXREJ!

This will allow a transfer when only one host can initiate a connection to the other, it also will deal with multiple paths by picking one only, and will ensure A and B get the correct "synchronised" addresses.

It can also be made backwards compatible by examining the packet payload.  No payload - do it the old way.  At least I think so, anyway...

Worth pursuing?

By: Serge Vecher (serge-v) 2006-06-15 08:52:58

tjd: can you please join the #asterisk-dev channel on IRC or solicit feedback through asterisk-dev mailing list?

By: Serge Vecher (serge-v) 2006-06-16 11:55:29

marking this for consideration after 1.4-beta is forked from the trunk in upcoming weeks since this needs feedback from the development community.

tjd: please feel free to post updates here as you received the feedback from the list.

By: tjd (tjd) 2006-06-21 20:32:52

This is now effectively a one-line patch (transfer4.diff).  All I am doing is bringing the chan_iax2.c code in line with that in libiax2 by changing the transfer address on receipt of a TXCNT.  And I have fixed an erroneous comment.

I'm not sure of the timeline, but possibly this patch could make it into 1.4?  It is pretty simple.

Now that I have seen the code in libiax2, I understand why sometimes I could get a transfer working with NAT, and other times I couldn't.

By: Serge Vecher (serge-v) 2006-07-21 08:31:40

superceded by 7567. Closing ...