Extending functionality of SIPc with STUN/TURN/ICE
Wookyun Kho
Columbia Univercity
New York, NY 10026
wk2153@columbia.edu
Contents
¡¤ Abstract
¡¤ Overview
¡¤ Related
work
¡¤ Background
¡¤ Implementation details
¡¤ Tests
¡¤ References
¡¤ SIPc's bug list
¡¤ Future
work
¡¤ Miscellaneous
Abstract
The current version of SIPc cannot traverse a NAT whose mapping is address and port-dependent (symmetric). To make SIPc work with address and port-dependent NAT, it needs to use a relay server. My work was to implement a STUN/TURN/ICE based on the recent IETF BEHAVE working group's drafts [2, 3, 4] and integrating it with SIPc. With STUN/TURN/ICE, SIPc can use a relay server (TURN server) to relay media stream to communicate with other clients. So, now SIPc can potentially traverse any kind of NAT.
Overview
My project was to implement STUN/TURN/ICE and integrating it with SIPc. STUN is used for obtaining external IP address. ICE uses STUN and TURN to find an appropriate external IP address for media data transmission.
As Figure 1 shows, when both clients are behind address and port-dependent NAT, media goes through a relay server(TURN server). If there is no STUN/TURN/ICE, media packets will be dropped by the NAT.
Related Work
- IETF
BEHAVE working group's STUN/TURN/ICE
- STUN/TURN/ICE implemented voip telephony
program: xten (http:://www.xten.com)
- Original STUN module of SIPc was built by Kundan. In the recent STUN related drafts, the
terminologies for NAT mapping have been changed and more functionality has been
added. Therefore, I updated the original STUN module and added TURN
functionalities. Also, I made ICE module in SIPc, and
implemented STUN/TURN server.
(STUN server is originally embedded in a STUN module, but I split stun
server from SIPc.)
¡¤ NAT mapping
1.
Endpoint-Independent Mapping:
The NAT reuses the port mapping for subsequent packets sent from the same internal IP address and port (X:x) to any external IP address and port. Specifically, X1':x1' equals X2':x2' for all values of Y2:y2.
2. Address-Dependent Mapping:
The NAT reuses the port mapping for subsequent packets sent from the same internal IP address and port (X:x) to the same external IP address, regardless of the external port. Specifically, X1':x1' equals X2':x2' if and only if, Y2 equals Y1.
3. Address and Port-Dependent Mapping:
The NAT reuses the port mapping for subsequent packets sent from the same internal IP address and port (X:x) to the same external IP address and port while the mapping is still active. Specifically, X1':x1' equals X2':x2' if and only if, Y2:y2 equals Y1:y1.
4. Simple Traversal Underneath Network Address Translators (STUN)
STUN is a lightweight protocol that serves as a tool for application protocols in dealing with NAT traversal. It allows a client to determine the IP address and port allocated to them by a NAT and to keep NAT bindings open.
¡¤ Traversal Using Relay NAT (TURN)
TURN is a usage of the Simple Traversal of UDP Underneath NAT (STUN) Protocol for asking the STUN server to relay packets towards a client. This is useful for clients behind NATs whose mapping behavior is address and port dependent.
¡¤ Interactive Connectivity Establishment (ICE)
ICE is a protocol for Network Address Translator (NAT) traversal for multimedia session signaling protocols based on the offer/answer model, such as the Session Initiation Protocol (SIP). ICE makes use of the Simple Traversal of UDP Underneath NAT (STUN) protocol, applying its binding discovery and relay usages, in addition to define a new usage for checking connectivity between peers.
Implementation Details
- I
implemented the functional portions on STUN/TURN/ICE drafts as much as I could.
Following features were not implemented. : 1) Security 2) Server Resource
Related Attributes
- A list of attributes implemented and left is given in here. A detailed description of them is given in STUN[2]/TURN[3]/ICE[4]
drafts.
¡¤ Integration with SIPc
Modified
Files
1. sipc/controller.tcl
2. sipc/controller_invite.tcl
3. sipc/sdp.tcl
4. sipc/sipstack/stun.tcl
5. addressbook_callarrive.tcl : main is modified
6. sipc/stun/stun.tcl
Added
Files
1. sipc/stun/ice.tcl
2. stun_server.tcl
Update
Details
1. sipc/controller.tcl
- In Controller::call,
in case of the first call, SIPc needs to put ¡°candidates¡± information into INVITE message.
To do that, I added code to get address candidates information by calling a
function in ice.tcl.
- In Controller::call,
right before SIPc sends INVITE message to proxy
server, I appended ¡°a¡±
attributes which have ¡°candidates¡± information to the end of SDP message.
2. sipc/controller_invite.tcl
- In Controller::inviteAccept,
append ¡°candidates¡± information
to 200 OK message. Since SIPc doesn¡¯t support 183 message (in ICE tutorial, Rosenberg recommended to use
183 message to send ¡°candidates¡± information, but SIPc doesn¡¯t support 183 message, so I just appended it to 200 OK message)
- In Controller::inviteAccept,
right after SIPc sends 200 OK message, both end
clients start connectivity check. At this point, callee
is waiting for a STUN ¡°Binding Request¡± message. This is handled by calling ICE::listen.
- In Controller::inviteResponseHandle,
as soon as a caller receives 200 OK message from a callee,
the caller parses the SDP, gets ¡°candidates¡± information of the callee, and starts
connectivity check process. This is handled by calling ICE::chkConns.
- In Controller::startMedia, if
connectivity check succeeds, in ICE::chkConns, array ICE::selIP and ICE::selPort will
be set like ICE::selIP(<media type name>). Thus, in startMedia,
if these are set correctly, rhost and rport will be set by ICE::selIP
and ICE::selPort.
- During the project, I used sip.antisip.com sip proxy
server. However, this proxy server was not a usual sip proxy server. It changes
a part of the SIP message such as contact header and (m) attributes, so it
tried to act like a relay server. Because of that, right before sipc starts ratmedia, I forced sipc to use default voice media port. If we can find or
implement sip proxy server which implements rport
option correctly, we don't have to force SIPc to use
the default voice media port number. (The code for forcing SIPc
to use the default port number is "set lport $Media::a_mediainit($type,port)" in Controller::startMedia.
You can remove this line after you find a correctly working server.)
3. sipc/sdp.tcl
- In SP::parse, I added some codes
to parse ¡°candidate¡±
attributes. This candidate information will be stored in ICE::peerlist.
- I made another function named SDP::encodeICECANDS
to encode candidates information.
4. sipc/sipstack/stun.tcl
- According to new characteristics of stun, most of codes are
little bit changed. (e.g. there is no more NAT mapping
type checking)
5. addressbook_callarrive.tcl
- Since the original SDP message didn't have (a) attributes
for candidates information, these (a) attributes cause some problem in this
process. So, I added some codes to remove these (a) attribues
from sdp message.
- Since sipc already parsed candidates information from sdp
message, it's fine to remove them.
6. sipc/stun/stun.tcl (TURN
implementation)
- Following things are added based on the latest STUN/TURN
drafts.
- New Messaqe Handle
1) Allocate Request (Section 9.1 [3])
2) Set Active Destination (Section 9.2 [3])
3) Send Indication (Section 9.5 [3])
4) Data Indication (Section 9.6 [3])
7. sipc/stun/ice.tcl
- All ICE functionalities are implemented in this file.
1) getCandidates
Return candidates list and save this information in ICE::mylist.
2) chkConns
This module is for connectivity check and is used by
Caller(or active client). After sipc receives a 200
OK message, it starts ICE::chkConns module to do
connectivity check. This module makes connectivity check list with candidate
list of the node and other call peer and sends a Binding Request message to the
address specified in the check list. If there is a Binding Response, it stops
and starts media.
3) listen
This module is also for connectivity check and is used by Callee(or passive client). After sipc
receives ACK message, it starts listen module until it receives Binding Request
message from caller(or active client). If sipc receives Binding Request message, it sends back
Binding Response message, and starts to run media.
8. STUN and TURN server
- This is served as STUN/TURN server.
- When both clients are behind address and port dependent
NAT, this server will be served as relay server.
- Because ratmedia is using random
port number for sending media, STUN server is temporarily set as checking
incoming messages only by ip address.
- If ratmedia works correctly, it
should check with both IP address and Port number since it would be possible
there are more than 1 clients behind a NAT. (usually
more than 1)
¡¤ List of Fully/Partially Implemented Requests and Attributes of STUN/TURN/ICE
1) STUN - Binding Request, MAPPED-ADDRESS, XOR-MAPPED-ADDRESS, ERROR-CODE
2) TURN - LIFETIME, REMOTE-ADDRESS, DATA, RELAY-ADDRESS
3) ICE - Gathering Candidates, Prioritization, Encoding in SDP, Connectivity Check
¡¤ List of Unimplemented Requestes
and Attributes of STUN/TURN/ICE
1) STUN - USERNAME,
PASSWORD, MESSAGE-INTEGRITY, FINGERPRINT, REALM, NONCE, SERVER,
ALTERNATE-SERVER, REFRESH-INTERVAL
2) TURN - Connect
Request, BANDWIDTH, REQUESTED-PORT-PROPS, REQUESTED-TRANSPORT, REQUESTED-IP,
TIMER-VAL
3) ICE - Frozen
Algorithm
Tests
¡¤ Test Case
1. Both clients
are behind Port dependent NAT
2. Both Clients
are behind End point independent NAT
3. One client is
behind Port dependent NAT, and another one is on public side
- For each of them, test call establishment
References
[1] Network
Address Translation (NAT) Behavioral Requirements for Unicast UDP (RFC 4787)
[2] Simple Traversal Underneath Network Address Translators
(NAT) (STUN)
[3] Obtaining Relay Addresses from Simple Traversal Underneath
NAT (STUN)
[4] Interactive Connectivity Establishment (ICE): A Methodology
for Network Address Translator (NAT) Traversal for Offer/Answer Protocols
- Debug ratmedia, then we can use my stun server with
more than 1 clients behind a same NAT at the same
time. Since the current version of ratmedia is using
random port number for sending media stream, it's not possible for STUN/TURN
server to know from where the incoming media comes. After debugging ratmedia, remove line 382 (set index [lsearch
$STUN::conns UDP:$mappedip*]) and uncomment line 385 in stun_server.tcl.
- Implement rport option of conductor sip proxy
server, then we can get rid of the code that I put in Controller::invite
to force SIPc to use a default media port.
SIPc's Bug List
- Sip proxy server, conductor.cs.columbia.edu, doesn't implement rport option. : I thought that conductor should implement rport option. Because of that, it took quite much time
figure out what the problem is. After I figured out what the problem was, I
reported this to Jongyul, and tried to find another
sip proxy server which implements rport option. I've
tried several proxy servers, but most of them didn't implement rport option. Finally, I found sip.antisip.com, and it
implements rport option correctly.
- When both clients are behind Address and Port dependent NAT, SIPc needs relay server to transmit media data each other.
For that, before SIPc starts to send media packets
through relay server, SIPc's external ip and port number for media should be registered in relay
server. However, ratmedia, SIPc's
media application, is using random port for sending data. Because of that,
relay server couldn't recognize incoming message from SIPc
as a data to be relayed, so I temporarily set stun server to use only ip address to recognize incoming message. I reported this
problem to Xiaotao, and Salman.
- The sip proxy server(sip.antisip.com) is not an usual
sip proxy server. Usually, sip proxy server must not change contact header or
(m) attributes of sdp message, but sip.antisip.com
proxy server does. Actually, sip.antisip.com is trying to act like relay
server, so it allocates port number to client, and it puts its ip address and this allocated port number in sdp. Because of that, I added a line in Controller::invite
to force SIPc use its default media port instead of
the port which is specified in INVITE message. If we fix sipd
to support rport option, we can remove this line.
- When SIPc tried to send INVITE message through
sip.antisip.com, sip.antisip.com sent back 401 error message, but SIPc didn't have 401 handling process. So, I reported this
to Xiatao Wu, the main author of SIPc,
and he fixed that problem.
- When p2p-sipc is behind any NAT, it cannot register itself in open DHT. : My
module cannot work with p2p-sipc. I reported this to Kundan.
Miscellaneous
¡¤ How to Configure NAT?
- You can configure some kinds of NAT by using iptables,
but it's not enough for address and port dependent NAT. To configure address
and port dependent NAT, you might need to make a small program.
1. Port dependent NAT
- iptables -t nat -A
POSTROUTING -p udp -j SNAT -s <localip>
--to <NAT box IP>
(ex) iptables -t nat -A
POSTROUTING -p udp -j SNAT -s 10.0.1.0/24 --to
128.59.23.62
2. End point independent NAT
- Add one more command to port dependent NAT
- iptables -t nat -A
PREROUTING -p udp -j DNAT -s <NAT bod IP> --to <localip>
(ex) iptables -t nat -A
PREROUTING -p udp -j DNAT -s 128.59.23.62 --to
10.0.1.10
¡¤ Installing STUN/TURN server
- Install Tcl and Tcl udp extension.
=> Get Tcl installation file :
http://www.activestate.com/Products/ActiveTcl/
=> Get Tcl udp extention installation file : http://tcludp.sourceforge.net/
- With "show" command, you can see current connection list. (2 line
information per every connection)
<internal tuple> <external tuple>
<allocated ip-addr> <allocated
port> <socket> <remaining life time - msec>
- Internal/External tuple is like below:
<protocol>:<ipaddr1>:<port1>:<ipaddr2>:<port2>
Ex) UDP:128.59.23.59:5060:128.59.19.182:3478
UDP:128.59.19.182:43286:128.59.23.62:5060
128.59.19.182 43286 sock1245 10840