Skip to content

STUN support

Scott Godin edited this page Apr 18, 2021 · 1 revision

Resiprocate implements STUN client and server support.

Table of Contents

Introduction

STUN - Simple Traversal of User Datagram Protocol (UDP) Through Network Address Translators (NATs)

Defined by: RFC 3489

STUN Server

reSIProcate is able to act as an STUN server on each configured UDP transport. This means that reSIProcate will accept and respond to STUN requests from external clients. Usually STUN is done through a separate STUN server which operates on a different port (or even a different machine). The advantage of using STUN through the SIP port is that this may help traversing even symmetric NATs. Though, this method is not very popular currently and it doesn't really help if RTP streams are involved.

To activate STUN server support you must simply pass the "StunEnabled" value with the "AddTransport" method.

Note: The DialogUsageManager::AddTransport method simply maps through to the SipStack::AddTransport but with fewer parameters. Therefore probably it's best to use the method on the SipStack directly.

STUN Client

The UdpTransport class includes support for sending STUN requests to a STUN server. To use this feature you need to store a pointer to UdpTransport when adding the transport:

 m_pUdpTransport = (resip::UdpTransport*)mStack->addTransport(UDP, UDPPort, V4, StunEnabled, IPAddress));

UdpTransport includes two methods for STUN client support:

 bool stunSendTest(const Tuple& dest);
 bool stunResult(Tuple& mappedAddress); 

The first one sends a STUN request to dest, the second one retrieves the result (if any).

Obviously this implementation is asynchronous. If you need to determine the mapped STUN address in a synchronous way (e.g. in order to make a call) you could use something similar to this:

      hostent* h = gethostbyname(STUNServer);
      in_addr sin_addr = *(struct in_addr*)h->h_addr;
      resip::Tuple tStunDest(sin_addr, STUNPort, UDP, Data::Empty);
 
      m_pUdpTransport->stunSendTest(tStunDest);
 
      mLastStunTestTime = GetTickCount();
 }

..for sending the STUN request and the following to retrieve a result synchronously:

     mMappedAddress.setPort(0);
 
     if (!m_pUdpTransport) return mMappedAddress;
 
     if (!m_pUdpTransport->stunResult(mMappedAddress))
     {
          // no valid result available, send another request
          SendStunTest();
     }
 
     else if ((GetTickCount() - mLastStunTestTime) > 1000 * 60 * 3) 
     {
          // don't use a STUN response that is older than 3 minutes
          SendStunTest();
     }
 
     DWORD dwTmpLastStunTestTime = mLastStunTestTime;
 
     while ((GetTickCount() - dwTmpLastStunTestTime) < 5 * 1000) // wait 5s for result
     {
          if (m_pUdpTransport->stunResult(mMappedAddress))
               break;
          Sleep(200);
     }
 
     return mMappedAddress;
 }

Modifying messages for STUN

To change the contact's host and port you need to use

setOverrideHostAndPort

Modifying the via header is unfortunately a bit more difficult because the stack relies on the via header for transport selection. Therefore the via needs to be changed after transport selection.

To do this you must derive a class from MessageDecorator and implement the code to modify the message in this class.

Adding this MessageDecorator to the message itself doesn't help much because it wouldn't be used for messages that are generated by dum internally. Therefore we now have a new setOutboundDecorator member in the profile. Add your custom messagedecorator to the profile and it will automatically be added to each messsage that is sent out in the context of this profile.

Clone this wiki locally