Like street numbers for a house, the Internet was originally designed so that all network devices could be directly addressed. Every connected device was given at least one unique identifier, or IP address, which could be used to route network packets to and from the device. For a while this worked well and devices had end-to-end connectivity.

IPv4 addresses can be used to route to about 4 billion (232) devices, but the rapid growth of the Internet quickly exhausted that available real estate. In the late 1980’s, several methods were developed to conserve this rapidly dwindling address space. Network isolation became a key strategy in this effort, and it had a beneficial side-effect – increased security. If an attacker was unable to address a device to directly establish connectivity, then attacking it was more difficult.

Home Routers with NAT

A common means for achieving this network isolation in the home is through an IPv4 router which supports Network Address Translation (NAT). These devices do some useful things for you:

  1. They pick up a single, public IPv4 address from your Internet provider
  2. They hand out IPv4 addresses to devices on your local network, most often through DHCP, drawing from a pool of the IPv4 address space reserved for private networks
  3. They allow all of the devices on your network to share the single, public IPv4 address received from your Internet provider and handle the translation automatically from private to public address in conjunction with port information

The following diagram illustrates this kind of deployment for two private networks both connected to the Internet through a NAT.

image

With these features also come limitations. Note how both networks share the same private address space, both routers have the same 192.168.1.1 private IP address, and two different computers each have the same 192.168.1.20 private IP address. Devices on each private network can communicate within their own network, but how can they communicate with each other over the Internet?

Internet packets are routed using public addresses, and in the scenario above, each network only has one public IPv4 address. That means all packets go to the home router and it figures out whether to send them on to a device on the home network.

Here are 3 common strategies for achieving this routing between public and private networks:

  1. Automatic translation can occur when a home device makes an outgoing network connection. This allows the NAT to match the destination address and port to the originating local address and port, then translate between them as packets are sent and received.
  2. Manual configuration can be performed by an administrator where a given home router port can be redirected to a private device address and port. This allows communication from the public Internet to be directed to a private device by using the public IPv4 address of the home router in combination with an administrator defined port.
  3. Automatic configuration can be performed by devices or applications behind the home router using UPnP. This allows a device or application to map ports on the router automatically so an administrator doesn’t have to. Most home routers support UPnP today. An unfortunate problem with this approach is that UPnP requires a specific port to be chosen at the time of registration, and this can cause collisions if two callers attempt to register the same port. UPnPv2 and NAT-PMP address this shortcoming.

NAT Traversal & Security Considerations

The term NAT traversal refers to the ability for client devices to address and communicate with listening devices behind a NAT. This turns out to be an incredibly useful thing to do for games, peer-to-peer, and a variety of other applications.

Because of the security boundary offered by NAT configurations, a key tenant for any traversal technology is to continue to maintain that security boundary for existing applications and services. The technologies discussed in this article adhere to that tenant. For a detailed discussion of this topic, you may refer to this informational on Security Concerns With IP Tunneling.

Impact to Applications

Generally these strategies result in a decent connectivity story, though complicated, and this carries over into application development.

In NAT situations, devices don’t really have end-to-end addressability by default, and the port begins to play an overdeveloped role in routing to your home devices to compensate for private addresses not being publicly reachable.

If your application only makes outgoing connections, the NAT solution will generally handle this transparently for you. The complications occur in applications that not only make but also receive connections – again, very common with peer-to-peer networks and video games.

If your application listens on a particular port for incoming connections and relies strictly on IPv4, you might ordinarily need to resort to one of the following techniques:

  1. Add port mapping support to your application so it can automatically detect when it is behind a home router and configure the router to direct traffic to the application instance and port
  2. Instruct your users to do this manually (which requires far more networking knowledge than is desirable)

A key point and drawback to keep in mind is that there is a 1:1 mapping between the Internet facing port on the router and the private IP and port pair of your local device.

If you want to run a web server from behind your NAT, you might allocate port 80 on the NAT and have it direct traffic to port 80 on Computer 1. If you wanted Computer 2 on the same network to also host a website available on the Internet, a different port on the NAT would need to be allocated, such as port 81 since port 80 is already in use and mapped to Computer 1.

Visitors would then need to use the router’s public IP address combined with a distinct port to reach the appropriate web server. This is not ideal since web visitors may not be accustomed to having to specify a specific, non-default port.

Contention for well-known ports demonstrates just one of the problems that may be encountered when relying on port mapping instead of an IP address with enough specificity to more fully handle addressing.

With that in mind, we’ve made many of these complexities transparent for you in the .NET Framework 4.0.

If you’re using TcpListener or UdpClient, just pass into the constructor IPAddress.IPv6Any, then call AllowNatTraversal with a value of true.

var listener = new TcpListener(IPAddress.IPv6Any, 8000);
listener.AllowNatTraversal(true);
listener.Start();

You’ll notice we have been discussing IPv4, but the example above mentions IPv6. Have no fear, this will work over intermediate IPv4 networks, it just relies on the origin or destination endpoints supporting IPv6 and a couple key technologies which I’ll cover in more detail below. If your application must run on a PC which only has IPv4 installed, a condition that is becoming more rare, then unfortunately this new solution won’t help you right now.

Another point worth mentioning is that applications which wish to listen on all IP addresses today have to set up two listeners, one for IPv4 using IPAddress.Any and one using IPAddress.IPv6Any. We’re investigating ways to take advantage of “dual mode” sockets so you won’t need to worry about tying your application to a specific IP version in the future.

IPv6 Restores Addressability

What if all your network devices had a public IP address which could be used by other devices to directly communicate with them? This would eliminate the need to use NAT for addressing and once again achieve end-to-end connectivity. With IPv6, this is possible.

IPv6 has a significantly larger address space (2128 or about 3.4×1038), and with an address space this size, it is once again possible for every device connected to the Internet to be given a unique address.

But, there’s a problem. Much of the world is still using IPv4, so exactly how can your application take advantage of IPv6 addresses today?

Fortunately, a number of transparent solutions have been devised and implemented on platforms and devices so that your application doesn’t need to worry with the specifics so long as it listens on all available IP addresses.

6to4 Tunneling

Although applications generally don’t need to worry about the underlying mechanism used to allocate an IPv6 address, for context, one such solution is 6to4 tunneling.

This solution works great for devices that already have a public IPv4 address. A special range of IPv6 maps to the IPv4 address space, and so with a 6to4 tunnel gateway deployed at the edge, IPv6 connectivity can be automatically enabled.

Windows supports 6to4, so if your computer already has a public IPv4 address, or you take your laptop to a hotspot that assigns it one, it probably also has a public IPv6 address through the 6to4 pseudo adapter.

Of course, in the NAT scenario we’ve been discussing, only the home router has a public IPv4 address. So, to take advantage of 6to4, your router would need to be IPv6 compatible, it would need to be able to assign IPv6 addresses to the local network, and and it would need to have 6to4 tunneling built into it.

Presently, most home routers don’t support this, though it is something a Windows Server can be configured to do as can standard Windows versions supporting Internet Connection Sharing (ICS).

So if a home router holds the one and only public IPv4 address, and 6to4 isn’t an option, how can computers behind the NAT use IPv6?

Teredo Tunneling

Like 6to4, Teredo is another IPv6 transition technology which brings IPv6 connectivity to IPv4 networks. It is described by RFC 4380, is further extended by MS-TERE, and has even been implemented by the open source community as Miredo.

There are a number of technical articles on exactly how Teredo encapsulates IPv6 over IPv4/UDP, which most NATs can forward, so if you’re interested in those details you can find out more from the links at the end of the article.

What’s important to know here is that Windows OS versions starting with Windows XP SP2 and Windows Server 2003 provide a virtual Teredo adapter which can give you a public IPv6 address in the range 2001:0::/32. This address can be used to listen for incoming connections from the Internet and can be provided to IPv6 enabled clients that wish to connect to your listening service.

Teredo and related transition technologies free your application from worrying about how to address a computer behind a home router or NAT since typically all you need to do is connect to it using its IPv6 addresses.

New for .NET 4.0

We’re making some additions in the .NET Framework 4.0 starting with Beta 2 to make these great technologies easier for you to use. The .NET Framework client APIs already support address-based NAT traversal, so the main updates are for listeners.

Listeners

The TcpListener and UdpClient changes were previously mentioned. Use these new methods to toggle whether your application explicitly wants to allow or restrict NAT traversal support.

public class TcpListener

  public void AllowNatTraversal(bool);
}

public class UdpClient

  public void AllowNatTraversal(bool);
}

Sockets

If you’re using sockets directly, the interface is a little closer to what Winsock exposes via the IPV6_PROTECTION_LEVEL socket option. We have exposed this on the Socket class as a new method called SetIPProtectionLevel.

public class Socket
{
  public void SetIPProtectionLevel
    (IPProtectionLevel);
}

public enum IPProtectionLevel

    Unspecified = –1,    // platform default

    Unrestricted = 10,   // global with NAT traversal 
   
EdgeRestricted = 20, // global without NAT traversal
    Restricted = 30,     // site local
}

Set the IPProtectionLevel to Unrestricted prior to Bind to allow clients to connect to your listener deployed behind a NAT. This is what the System.Net listener implementations do when you invoke the previously mentioned AllowNatTraversal method.

EdgeRestricted allows clients to only connect to your listener on IP addresses that aren’t used for NAT traversal (like Teredo).

Restricted only allows intranet connectivity (site and local link).

The actual default setting is Unspecified and left to the underlying platform to determine.

Starting with Windows Vista, this is equivalent to Unrestricted when the Windows Firewall is enabled and an appropriate rule is configured per the instructions below and EdgeRestricted when it is disabled.

This honors that security point mentioned at the beginning of the article. Many IPv4 networks rely on NAT as a limited form of protection. The default setting protects applications from unintentionally exposing themselves to the Internet in NAT scenarios. Instead, applications must explicitly opt-in to NAT traversal using this socket option or by configuring a Windows Firewall rule.

Configuration

To enable you to easily turn these features on for your existing applications, you can also control this through app.config.

<system.net>
  <settings>
    <!-- default is platform defined (Unspecified) –>
    <socket ipProtectionLevel="Unrestricted | 
     
EdgeRestricted | Restricted | Unspecified"/>
  </settings>
</
system.net>

This setting will affect all listening sockets in an AppDomain.

Address Discovery

It’s not recommended to implement behavior that relies on direct knowledge of IP addresses since this would typically be handled through name resolution, but in some cases, like building peer to peer applications or your own discovery service, it can be useful.

To get the list of addresses on a host, you could do it the traditional way using System.Net.NetworkInformation to enumerate NetworkInterfaces and their addresses, but we’re adding some new methods which make this simpler and also “wake up” Teredo if it hasn’t been used recently.

public class IPGlobalProperties
{

  public UnicastIPAddressInformationCollection 
    GetUnicastAddresses();

  public IAsyncResult BeginGetUnicastAddresses
    (AsyncCallback, object);

  public UnicastIPAddressInformationCollection
    EndGetUnicastAddresses(IAsyncResult);
}

This allows you to enumerate addresses as follows.

var addressInfoCollection =
  IPGlobalProperties.GetIPGlobalProperties()
    .GetUnicastAddresses();

foreach(var addressInfo in addressInfoCollection)

   Console.WriteLine("Address: {0}",
        addressInfo.Address);
}

Once you have acquired this list of addresses, you can give the address list to your clients out of band and they can use Socket.Connect, TcpClient.Connect, or even WebRequest.Create to establish a connection to your service.

For a savvy way to publish your addresses so others can discover them, check out our Peer Name Resolution Protocol (PNRP). Another great discovery mechanism is the Collaboration API. The traditional mechanism is of course to use DNS and the System.Net APIs which accept a host name.

Finally, we’re also adding a convenient property to the IPAddress class so you can tell if an address you’re dealing with is an IPv6 Teredo address.

public class IPAddress

  public bool IsIPv6Teredo { get; }
}

This property is primarily intended to be used for debugging and test scenarios since you will typically want to listen on all available IP addresses so your application can automatically take advantage of new platform enhancements.

Right now, client support works transparently the whole way up the transport stack, and for listeners we support these new features with Sockets, TcpListener, and UdpClient. We hope to extend this to HttpListener in the future.

Windows Communication Foundation

WCF supports Teredo today for TCP channels when using the NetTcpSection.TeredoEnabled and TcpTransportElement.TeredoEnabled properties.

Firewall Considerations

By default, the Windows Firewall blocks incoming connections. For your listener to be accessible, you will want to create a firewall rule. This is true of any listening application, not just ones that wish to take advantage of NAT traversal. You can do this programmatically, and since adding firewall rules requires UAC elevation, application installation is the best time to do this. Even though the rule can be added at install time, it can be configured to activate only while the application is running.

The firewall can be controlled using COM interop. Add a project reference to FirewallApi.dll. You can then add a rule with the following code.

Guid netFwRuleUuid = new Guid("{2C5BC43E-3369-4C33-AB0C-BE9469677AF4}");
INetFwRule rule = (INetFwRule)Activator.CreateInstance(Type.GetTypeFromCLSID(netFwRuleUuid));

rule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW;
rule.ApplicationName = @"C:\Program Files\My Application\MyApplication.exe";
rule.Description = "My Rule Description";
rule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN;
rule.EdgeTraversal = true;
rule.Enabled = true;
rule.Grouping = "My Rule Group";
rule.Name = "My Rule Name";
rule.Protocol = (int)ProtocolType.Tcp;

Guid netFwPolicy2Uuid = new Guid("{E2B3C97F-6AE1-41AC-817A-F6F92166D7DD}");
INetFwPolicy2 policy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromCLSID(netFwPolicy2Uuid));
policy.Rules.Add(rule);

Note that to enable NAT traversal, the EdgeTraversal flag must be set to true since a firewall rule with a setting of false (the default) is used to prevent NAT traversal even when an application sets the IPProtectionLevel for its sockets to Unrestricted.

Starting with Windows 7, although you can still use the approach above, there is more control over the default NAT traversal behavior using the InetFwRule2 interface and NET_FW_EDGE_TRAVERSAL_TYPE.

Third party firewalls may require custom configuration or may prompt the user for permission on first application launch.

Parting Thoughts

With IPv6 and its related transition technologies becoming ubiquitous, now is a great time to take advantage of these capabilities in your applications, and the .NET Framework 4.0 makes it easy to get started.

Additional References

Microsoft IPv6 Website
IPv6 Transition Technologies
TechNet Teredo Overview
TechNet Using IPv6 and Teredo
MSDN Teredo Site
Firewall requirements for coexisting with Teredo
Security Concerns With IP Tunneling

Special thanks to Dave Thaler for his insights and expert feedback.

~ Aaron Oneal | NCL Program Manager