NAT UPNP Traversal

Commonly used NAT device traversal solution includes: STUN, ICE, UPNP and so on. UPNP is probably the easiest way to traverse a personal router if it supports this feature. I will explain how to traverse a LinkSys WRT54G router using Java library SBBI. Following code shows how to forward port 8889 on router’s WAN interface to port 7101 of the testing computer. To compile following code, please go to sbbi.net to download the library.

Environment:
The LinkSys router has a WAN IP: 10.69.138.54  (because this router connects to another personal router)
The testing computer connects to the router, it has IP address: 192.168.1.100, default gateway is: 192.168.1.1

Code to auto forward port 8889 to 7101:

public static void main(String[] args) throws Exception {
  InternetGatewayDevice IGDs[] = InternetGatewayDevice.getDevices(5000);
  if(IGDs == null || IGDs.length==0){
    System.err.println("No IGD Found");
    System.exit(1);
  }
  InternetGatewayDevice dev = IGDs[0];
  System.out.println("Local IP addr:"+InetAddress.getLocalHost().getHostAddress());
  System.out.println("Router external IP addr:"+dev.getExternalIPAddress());
  System.out.println("Router current mappings table size: " + dev.getNatTableSize());
  if(dev.addPortMapping("MyMapping", null, 7101, 8889, InetAddress.getLocalHost().getHostAddress(), 0, "TCP")){
    //the api for deleting mapping is: dev.deletePortMapping(null, 8889, "TCP");
    System.out.println("After mapping, router current mappings table size: " + dev.getNatTableSize());
    if(dev.getSpecificPortMappingEntry(null, 8889, "TCP")!=null)
      System.out.println("Port 8889 mapping is confirmed.");
    else
      System.err.println("Port 8889 mapping is NOT confirmed.");
  }else
      System.err.println("Mapping failed");
}

The output of a successful running should be similar to following:

Local IP addr:192.168.1.100
Router external IP addr:10.69.138.54
Router current mappings table size: 29
After mapping, router current mappings table size: 30
Port 8889 mapping is confirmed.

Now, we could use following simple ADF page “helloworld.jsp” to verify by accessing the page via both local IP and router’s WAN IP respectively:

View page via local network interface
View page via local network interface

 

View page from router's WAN interface
View page via router's WAN interface

The code of above page is:

Hello there, you are from IP address:<af:outputText id="clientIP"
    value="#{facesContext.externalContext.request.remoteAddr}"/>

Next, I will test the UDP ports forwarding. Firstly, I map UDP port 4444 and 4445 on router’s WAN interface to testing computer’s local network interface port 4444 and 4445 respectively. You could do this by modifying above code. After that, open JMStudio and VLC player. In JMStudio, click File->Transmit and browse to a media file (eg. xxx.mpg) or use webcam to capture. Use following setting (router’s WAN IP) after click “next”:

JMStudio setting
JMStudio setting

In VLC, open following network stream:

VLC Setting
VLC Setting

Now start VLC and JMStudio, we could see following, please note that the image is not in sync because of the buffering I guess, but they are from same video:

JMStudio play mpg/webcam capture, VLC receive via RTP
JMStudio play mpg/webcam capture, VLC receive via RTP

The SBBI library has provided sufficient, at least to me, functions to work with router having UPNP feature. However, if you feel it’s not enough for you or you want to program for other type of UPNP devices, you could refer to upnp.org, where the detailed specification of discovering, controlling an UPNP device is defined. Before that, you could also go to here to check if what you want has already been provided.