Starting the TURN server

STUN and TURN are two protocols that were mentioned in the previous sections of the guide but were not covered in detail. In this section, you'll learn exactly what they are used for and you will also learn how to set up your own STUN/TURN server to allow your users to connect to each other as seamlessly as possible.

What is NAT?

NAT stands for Network Address Translation. NAT came about as a way to address the rapidly declining supply of IPv4 addresses. In a typical NAT configuration, routers will maintain one public IP address, while clients connected to the router will have their own IP address on a private subnet. When the router receives data, it will forward this data to the correct client based on the IP address of the sender and the port that the data was sent on.

The issue that arises in NAT configurations, is that clients that are connected to the router can find it difficult to communicate with clients outside of their private subnet. The clients in the subnet do not often know what the public IP address of their router is, and so cannot tell remote clients how to contact them reliably. This is the problem that STUN was meant to solve, and the solution is discussed in the next section.

Starting a STUN Server

STUN stands for Session Traversal Utilities for NAT. STUN is a protocol that allows clients behind a NAT to discover their public IP address. This allows clients that are behind a NAT to report this public IP address to remote clients. For more information on STUN, refer to RFC 5389.

The STUN server is a server-side component. As such, only C# and Java implementations are available. On your server, create an instance of FM.IceLink.StunServer. Invoke the Start method to start the server.

var stunServer = new FM.IceLink.StunServer();
stunServer.Start();
fm.icelink.StunServer stunServer = new fm.icelink.StunServer();
stunServer.start();

When your application shuts down, you can stop the server by invoking the Stop method.

stunServer.Stop();
stunServer.stop();

Next, you'll learn about TURN.

Starting a TURN Server

TURN stands for Traversal Using Relays around NAT. TURN is a protocol that allows clients behind restrictive firewalls to relay packets to other clients using a relay server. Unlike STUN, TURN is bandwidth-intensive, as all media data must flow through the relay server. As such, IceLink generally attempts to use TURN as a last resort if no other connection options are available. Another consequence of this is that TURN servers are generally secured - you must authenticate with the server in order to use it.

When you create a TURN server instance, you will have to specify an authentication callback. This callback will be called whenever a request is made to the TURN server. The result that you return from this callback will decide whether a user is allowed to use the server or not. There are two methods that you can use to return result, password-based and key-based.

In the first method, your auth callback must have some way to look up the password of a user and return it in plain text. This password is then compared on the server to the password that was specified in the TURN request. The code below demonstrates a simple example where each user/password combination is stored in a dictionary. Obviously, you should not do this in a production system. When you have the password of the user in question, you should invoke the FromPassword method of the TurnAuthResult class and return the result. If there is no user matching the specified username, you should return null, which will reject the TURN request.

var users = new Dictionary<string, string>
{
    {"anton.venema", "chocolate-donuts"}
};

var turnServer = new FM.IceLink.TurnServer((FM.IceLink.TurnAuthArgs args) =>
{
    if (users.Contains(args.Username))
    {
        return FM.IceLink.TurnAuthResult.FromPassword(users[args.Username]);
    }

    return null;
});

turnServer.Start();
Map<String, String> users = new HashMap<>();
users.put("anton.venema", "chocolate-donuts");

fm.icelink.TurnServer turnServer = new fm.icelink.TurnServer((fm.icelink.TurnAuthArgs args) -> {
    if (users.containsKey(args.getUsername())) {
        return fm.icelink.TurnAuthResult.fromPassword(users.get(args.getUsername());
    }

    return null;
});

turnServer.Start();

The other option you have is to use key-based authentication. Instead of FromPassword, you invoke the FromLongTermKeyBytes method of the TurnAuthResult class. The expected key is an MD5 hash of the following string "<username>:<realm>:<password>". As with passwords, these must be stored somewhere. The advantage to this method is that you are not storing passwords in plain-text. The following example demonstrates the use of this method.

Map<String, String> users = new HashMap<>();
users.put("anton.venema", "chocolate-donuts");

fm.icelink.TurnServer turnServer = new fm.icelink.TurnServer((fm.icelink.TurnAuthArgs args) -> {
    if (users.containsKey(args.getUsername())) {
        return fm.icelink.TurnAuthResult.fromPassword(users.get(args.getUsername());
    }

    return null;
});

turnServer.Start();
Map<String, byte[]> users = new HashMap<>();
users.put("anton.venema", ...);

fm.icelink.TurnServer turnServer = new fm.icelink.TurnServer((fm.icelink.TurnAuthArgs args) -> {
    if (users.containsKey(args.getUsername())) {
        return fm.icelink.TurnAuthResult.fromLongTermKeyBytes(users.get(args.getUsername());
    }

    return null;
});

turnServer.Start();

Your TURN server should now be operational. Note that if you run a TURN server, you do not need to run a separate STUN server. Your TURN server also supports the STUN protocol.

Configuring Your Firewall

The default configuration for many routers does not permit STUN and TURN traffic. Because of this, you will likely have to make a few modifications to your firewall or router configuration:

  • Open inbound UDP and/or TCP traffic in your OS firewall for the ports you are listening on (3478 and 443 by default).
  • Open inbound UDP and/or TCP traffic in your cloud firewall for the ports you are listening on (3478 and 443 by default).

You may also need to run your server-side component with administrator access.

Wrapping Up

You should now have a working STUN/TURN server. If you don't want to host your own server, we offer an API that wraps the excellent XirSys service. Refer to the advanced topic on Setting Up XirSys Integration for more information.