Click here to Skip to main content
Click here to Skip to main content

STUN Client

By , 20 Apr 2007
 
Screenshot - stun.jpg

Introduction

STUN - Simple Traversal of User Datagram Protocol (UDP) through Network Address Translators (NATs). In few words, it just helps you to map your local computer IP:port to public IP:port.

STUN working idea is pretty simple. The client just sends a UDP packet out to the STUN server and the server answers back with IP:port you connected. STUN does three tests to detect the NAT type.

In test I, the client sends a STUN Binding Request to a server, 
without any flags set in the CHANGE-REQUEST attribute, 
and without the RESPONSE-ADDRESS attribute. This causes the server 
to send the response back to the address and port that the request came from.
           
In test II, the client sends a Binding Request with both the 
"change IP" and "change port" flags from the CHANGE-REQUEST attribute set.  
              
In test III, the client sends a Binding Request with only the "change port" flag set.
                          
                                    +--------+
                                    |  Test  |
                                    |   I    |
                                    +--------+
                                         |
                                         |
                                         V
                                        /\              /\
                                     N /  \ Y          /  \ Y             +--------+
                      UDP     <-------/Resp\--------->/ IP \------------->|  Test  |
                      Blocked         \ ?  /          \Same/              |   II   |
                                       \  /            \? /               +--------+
                                        \/              \/                    |
                                                         | N                  |
                                                         |                    V
                                                         V                    /\
                                                     +--------+  Sym.      N /  \
                                                     |  Test  |  UDP    <---/Resp\
                                                     |   II   |  Firewall   \ ?  /
                                                     +--------+              \  /
                                                         |                    \/
                                                         V                     |Y
                              /\                         /\                    |
               Symmetric  N  /  \       +--------+   N  /  \                   V
                  NAT  <--- / IP \<-----|  Test  |<--- /Resp\               Open
                            \Same/      |   I    |     \ ?  /               Internet
                             \? /       +--------+      \  /
                              \/                         \/
                              |                           |Y
                              |                           |
                              |                           V
                              |                           Full
                              |                           Cone
                              V              /\
                          +--------+        /  \ Y
                          |  Test  |------>/Resp\---->Restricted
                          |   III  |       \ ?  /
                          +--------+        \  /
                                             \/
                                              |N
                                              |       Port
                                              +------>Restricted

/// <summary>
/// UDP is always blocked.
/// </summary>
UdpBlocked,

/// <summary>
/// No NAT, public IP, no firewall.
/// </summary>
OpenInternet,

/// <summary>
/// No NAT, public IP, but symmetric UDP firewall.
/// </summary>
SymmetricUdpFirewall,

/// <summary>
/// A full cone NAT is one where all requests from the same internal 
/// IP address and port are mapped to the same external IP address and port.
/// Furthermore, any external host can send a packet to the internal host, 
/// by sending a packet to the mapped external address.
/// </summary>
FullCone,

/// <summary>
/// A restricted cone NAT is one where all requests from the same
/// internal IP address and port are mapped to the same external IP address and port.
///  Unlike a full cone NAT, an external host (with IP address X) 
/// can send a packet to the internal host only if the internal host 
/// had previously sent a packet to IP address X.
/// </summary>
RestrictedCone,

/// <summary>
/// A port restricted cone NAT is like a restricted cone NAT, but the restriction 
/// includes port numbers. Specifically, an external host can send a packet, 
/// with source IP address X and source port P, to the internal host only if 
/// the internal host had previously sent a packet to IP address X and port P.
/// </summary>
PortRestrictedCone,

/// <summary>
/// A symmetric NAT is one where all requests 
/// from the same internal IP address and port, 
/// to a specific destination IP address and port, are mapped to the same external 
/// IP address and port.  If the same host sends a packet with the same source address 
/// and port, but to a different destination, a different mapping is used. 
/// Furthermore, only the external host that
/// receives a packet can send a UDP packet back to the internal host.
/// </summary>
Symmetric

Using the Code

// Create new socket for STUN client.
Socket socket = new Socket
    (AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
socket.Bind(new IPEndPoint(IPAddress.Any,0));

// Query STUN server
STUN_Result result = STUN_Client.Query("stunserver.org",3478,socket);
if(result.NetType != STUN_NetType.UdpBlocked){
    // UDP blocked or !!!! bad STUN server
}
else{
    IPEndPoint publicEP = result.PublicEndPoint;
    // Do your stuff
}

History

  • 20.04.2007 - Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Ivar Lumi
Estonia Estonia
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralSTUN - Small typomemberMigounette23 May '08 - 23:26 
Section:
 
Nice work, but you made a little mistake regarding the retransmit time.
 
9.3 Formulating the Binding Request
 
Clients SHOULD
retransmit the request starting with an interval of 100ms, doubling
every retransmit until the interval reaches 1.6s. Retransmissions
continue with intervals of 1.6s until a response is received, or a
total of 9 requests have been sent. If no response is received by 1.6
seconds after the last request has been sent, the client SHOULD
consider the transaction to have failed. In other words, requests
would be sent at times 0ms, 100ms, 300ms, 700ms, 1500ms, 3100ms,
4700ms, 6300ms, and 7900ms. At 9500ms
 
Here is my proposal:
 
private static STUN_Message DoTransaction(STUN_Message request,Socket socket,IPEndPoint remoteEndPoint)
{
byte[] requestBytes = request.ToByteData();

// Retransmition table : 9500ms sound that the transaction has failed
int[] retransList = { 0, 100, 300, 700, 1500, 3100, 4700, 6300, 7900, 9500 };
int retransPos = 0;
 
DateTime startTime = DateTime.Now;
 
// We do it only 2 sec and retransmit with 100 ms.
while (retransPos < retransList.Length)
{
TimeSpan diffTime = DateTime.Now - startTime;
 
try
{
if (diffTime.TotalMilliseconds > retransList[retransPos])
{
// It's time for a retransmition
retransPos++;
socket.SendTo(requestBytes, remoteEndPoint);
}
 
// We got response.
if (socket.Poll(20, SelectMode.SelectRead))
{
byte[] receiveBuffer = new byte[512];
socket.Receive(receiveBuffer);
 
// Parse message
STUN_Message response = new STUN_Message();
response.Parse(receiveBuffer);
 
// Check that transaction ID matches or not response what we want.
if (request.TransactionID.Equals(response.TransactionID))
{
return response;
}
}
}
catch(Exception exception)
{
Console.WriteLine("Exception : " + exception.Message);
exception = null;
}
}
 
// Timeout detected or exception
return null;
}
GeneralRe: STUN - Small typomemberIvar Lumi26 May '08 - 2:17 
Hi,
 
Thats not typo, thats simplified solution.
Normally retransit wont happend in reallife, so if you retransmit 200mx,200ms , ... i dont see any problem about that.
But though it's not 100% RFC comilant ... .
 
Your approach is almost RFC comiplant, but if to splitting hair- -- except:
If no response is received by 1.6
seconds after the last request has been sent, the client SHOULD
consider the transaction to have failed.
QuestionHow to combine with RTC API [modified]memberjan de vries16 Feb '08 - 7:33 
Ivar, you're very good with all these protocols. Great code!
 
I would like to use your STUN Client in combination with the Microsoft RealTime Communications (RTC) API, because I'm working on a VoIP applicaton. This RTC API provides a number of hooks for plugging in some kind of portmapping functionality.
I found out that, with the help of your STUN Client class, I can create the required portmappings. But the RTC code doesn't seem to be able to use the mapped ports.
The reason could be that I create a socket, which I handover to your STUN Client to get the mapped address and port, but which I have to close before returning the control to the RTC code. Otherwise the RTC code generates an error (which I can understand, since it tries to open a socket on an address and port where another one is open already).
But could it be that the portmapping, created by your STUN Client, is removed from the NAT, the moment I close the socket that I used for creating the portmapping (by calling your STUN Client)?
 
modified on Sunday, February 17, 2008 2:09 AM

AnswerRe: How to combine with RTC APImemberIvar Lumi17 Feb '08 - 4:58 
Hi,
 
Bat keeps same port, if you close socket and re create it, as long as you use same IP endpoint for socket.
Generalcannot run net.slnmemberhafidz13 Feb '08 - 20:11 
i cannot run net.sln why?
i already install microsoft C# 2008 but still failed
please any advice
GeneralRe: cannot run net.slnmemberIvar Lumi13 Feb '08 - 20:22 
Hi,
 
This is standard soulution, so it must work nice with VS 2008 and 2005
GeneralRe: cannot open net.slnmemberhafidz13 Feb '08 - 20:29 
i'm sorry it's not cannot run actually cannot open it
why?Confused | :confused:
GeneralRe: cannot open net.slnmemberIvar Lumi13 Feb '08 - 21:00 
I don't know to suggest something. There must be something wrong with your VS installation.
Generaludp problem on WANmembermelfice8219 Nov '07 - 20:30 
hye...i have a problem..my UDP Server-Client only work on LAN environment but not on WAN..can i apply this STUN concept to solve my problem...coz on WAN the receiver cannot receive anything from the sender..please help me..i already run out of idea..tq
GeneralRe: udp problem on WANmemberIvar Lumi19 Nov '07 - 22:34 
Hi,
 
Yes you can use STUN to get public IP:port.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 20 Apr 2007
Article Copyright 2007 by Ivar Lumi
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid