i00 NAT Forwarder
Automatic port forwarding for your UPnP enabled router.
Introduction
I wrote this application as I thought there were several things lacking with router port forwards, such as the ability to map port forwards to computer names rather than IP addresses, thus limiting the computer to have a static IP. There are also other advantages such as portability, ease of use etc.
A summary of advantages are listed below:
- Allows mapping to computer names as well as IP addresses.
- Allows computers to have dynamic IP addresses and still have port forwarding (thus allowing easy connectivity to multiple "other" networks without having to change your IP or set it in your router).
- Circumvents Netgear's restriction on not allowing port redirecting - Netgear routers do not allow you to forward a port on a different external port to the port that it is being hosted on through their interface.
- Portability - Allows you to take your computer from one network to another, and cupled with a dyndns client have everything "just work" on your new network, imagine being able to move your web server from one network to another without having to change anything!
The only requirement for this app is a UPnP enabled router.
I have tested this on Server 2012, but it should work on anything Vista + ... and may work on previous OS' as well.
I have tested the software on the following brands of router: Netgear, Billion.
Screenshots

Method
The UPnP access is done with the NATUPNPLib.dll that comes with Windows, this requires the SSDP Discovery Service to be enabled (NAT Forwarder will ask you to start it if it is not running when it starts).NAT Forwarder can be installed as a service through the interface and automatically checks that ports are open at the interval specified in the settings page.
The main function of the project is, of course, to automate port forwards through UPnP routers. To do this "NATUPnP 1.0 Type Library" was used.
To implement UPnP; first make sure that the "SSDP Discovery Service" is running, to do this click Start then Run, type services.msc and click OK.
Find the "SSDP Discovery Service" in the list and make sure its status is running, if it is stoped right click on it and select start; if it is disabled, right click on it, select properties set the startup type to automatic, click OK, then right click on the service and click start.
In your project add a reference to the COM library: "NATUPnP 1.0 Type Library"
You should now have the ability to manage port forwards from your project.
To make things easier the below class can be used to manage port forwards:
'i00 .Net NAT Forwarder
'©i00 Productions All rights reserved
'Created by Kris Bennett
'----------------------------------------------------------------------------------------------------
'All property in this file is and remains the property of i00 Productions, regardless of its usage,
'unless stated otherwise in writing from i00 Productions.
'
'i00 is not and shall not be held accountable for any damages directly or indirectly caused by the
'use or miss-use of this product.
Public Class UPnP
Implements IDisposable
'Variables for the COM objects we are going to use
Private UPnPNAT As NATUPNPLib.UPnPNAT
Public Mappings As NATUPNPLib.IStaticPortMappingCollection
'Returns true if UPnP is enabled
Dim mc_Enabled As Boolean
Public ReadOnly Property UPnPEnabled() As Boolean
Get
Return mc_Enabled
End Get
End Property
'List of protocols that we can port forward to (used in functions)
Public Enum Protocol
TCP
UDP
End Enum
#Region "Constructors / Destructors"
Public Sub New()
'create our COM object to manage port forwards
UPnPNAT = New NATUPNPLib.UPnPNAT
'check that mappings can be obtained from the router and load the mapping COM object to our Mappings variable
Me.GetMappings()
End Sub
'check that mappings can be obtained from the router and load the mapping COM object to our Mappings variable
Private Sub GetMappings()
Try
'try to get the static port mappings from the router... using the NATUPNPLib.UPnPNAT COM library...
Mappings = UPnPNAT.StaticPortMappingCollection()
If Mappings Is Nothing Then
'no static mapping object returned - UPnP is not enabled
mc_Enabled = False
Else
'UPnP is enabled and working
mc_Enabled = True
End If
Catch ex As NotImplementedException
mc_Enabled = False
End Try
End Sub
Private disposedValue As Boolean = False 'To detect redundant calls
'Remove the com objects from memory...
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If Mappings IsNot Nothing Then System.Runtime.InteropServices.Marshal.ReleaseComObject(Mappings)
If UPnPNAT IsNot Nothing Then System.Runtime.InteropServices.Marshal.ReleaseComObject(UPnPNAT)
End If
Me.disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
#Region "Router functions"
'Adds a port forwarding rule to the router...
Public Sub Add(ByVal InternalIP As String, ByVal InternalPort As Integer, ByVal ExternalPort As Integer, ByVal Protocol As Protocol, ByVal Description As String)
'check that UPnP is enabled
If Not UPnPEnabled Then Throw New Exception("Could not find a UPnP enabled router")
'check that the port isnot already mapped
If Exists(ExternalPort, Protocol) Then Throw New Exception("Mapping already exists")
'add the port mapping
Mappings.Add(ExternalPort, Protocol.ToString(), InternalPort, InternalIP, True, Description)
End Sub
'Removes a port mapping rule from the router...
Public Sub Remove(ByVal ExternalPort As Integer, ByVal Protocol As Protocol)
'check that UPnP is enabled
If Not UPnPEnabled Then Throw New Exception("Could not find a UPnP enabled router")
'check that the port isnot already mapped
If Not Exists(ExternalPort, Protocol) Then Throw New ArgumentException("Mapping does not exist")
'remove the port mapping
Mappings.Remove(ExternalPort, Protocol.ToString)
End Sub
'See if the
Public Function Exists(ByVal ExternalPort As Integer, ByVal Protocol As Protocol) As Boolean
'check that UPnP is enabled
If Not UPnPEnabled Then Throw New Exception("Could not find a UPnP enabled router")
'go through each port that is mapped in our UPnP enabled router to see if the port has been mapped...
For Each mapping In Mappings.OfType(Of NATUPNPLib.IStaticPortMapping)()
'if the external port and protocol are what we are looking for then we are mapped...
If mapping.ExternalPort.Equals(ExternalPort) AndAlso mapping.Protocol.ToString.Equals(Protocol.ToString) Then Return True
Next
'we do not have this mapping rule if we got this far
Return False
End Function
Public Function Exists(ByVal ExternalPort As Integer, ByVal Protocol As Protocol, ByVal InternalIP As String, ByVal InternalPort As Integer, ByVal Description As String) As Boolean
'check that UPnP is enabled
If Not UPnPEnabled Then Throw New Exception("Could not find a UPnP enabled router")
' Begin checking
For Each mapping In Mappings.OfType(Of NATUPNPLib.IStaticPortMapping)()
'if the external port, protocol, IP, internal port, and description are what we are looking for then we are mapped...
If mapping.ExternalPort.Equals(ExternalPort) AndAlso mapping.Protocol.ToString.Equals(Protocol.ToString) AndAlso mapping.InternalClient.Equals(InternalIP) AndAlso mapping.InternalPort.Equals(InternalPort) AndAlso mapping.Description.Equals(Description) Then Return True
Next
'we do not have this mapping rule if we got this far
Return False
End Function
#End Region
End Class
We now have an easy to use wrapper for easy port forwards, some examples of how to use this wrapper are listed below:To check UPnP is enabled:
Using UPnP As New UPnP
Return UPnP.UPnPEnabled
End Using
To add a port map:
Using UPnP As New UPnP
UPnP.Add(localIP As String, Port As Integer, ExternalPort As Integer, prot As Protocol, desc As String)
End Using
To remove a port map:
Using UPnP As New UPnP
UPnP.Remove(Port As Integer, Prot As Protocol)
End Using
To check if a port is mapped:
Using UPnP As New UPnP
Return UPnP.Exists(Port As Integer, Prot As Protocol)
End Using
To load a list of port mappings from the router:
Using UPnP As New UPnP
For Each mapping As NATUPNPLib.IStaticPortMapping In UPnP.staticMapping
Debug.Print "Local IP: " & mapping.InternalClient & vbcrlf & _
"Local Port: " & mapping.InternalPort & vbcrlf & _
"External Port: " & mapping.ExternalPort & vbcrlf & _
"Description: " & mapping.Description & vbcrlf & _
"Portocol: " & mapping.prot.ToString() & vbcrlf & _
"----------"
Next
End Using
Change Log
20130302
Initial Release