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:
Public Class UPnP
Implements IDisposable
Private UPnPNAT As NATUPNPLib.UPnPNAT
Public Mappings As NATUPNPLib.IStaticPortMappingCollection
Dim mc_Enabled As Boolean
Public ReadOnly Property UPnPEnabled() As Boolean
Get
Return mc_Enabled
End Get
End Property
Public Enum Protocol
TCP
UDP
End Enum
#Region "Constructors / Destructors"
Public Sub New()
UPnPNAT = New NATUPNPLib.UPnPNAT
Me.GetMappings()
End Sub
Private Sub GetMappings()
Try
Mappings = UPnPNAT.StaticPortMappingCollection()
If Mappings Is Nothing Then
mc_Enabled = False
Else
mc_Enabled = True
End If
Catch ex As NotImplementedException
mc_Enabled = False
End Try
End Sub
Private disposedValue As Boolean = False
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"
Public Sub Add(ByVal InternalIP As String, ByVal InternalPort As Integer, ByVal ExternalPort As Integer, ByVal Protocol As Protocol, ByVal Description As String)
If Not UPnPEnabled Then Throw New Exception("Could not find a UPnP enabled router")
If Exists(ExternalPort, Protocol) Then Throw New Exception("Mapping already exists")
Mappings.Add(ExternalPort, Protocol.ToString(), InternalPort, InternalIP, True, Description)
End Sub
Public Sub Remove(ByVal ExternalPort As Integer, ByVal Protocol As Protocol)
If Not UPnPEnabled Then Throw New Exception("Could not find a UPnP enabled router")
If Not Exists(ExternalPort, Protocol) Then Throw New ArgumentException("Mapping does not exist")
Mappings.Remove(ExternalPort, Protocol.ToString)
End Sub
Public Function Exists(ByVal ExternalPort As Integer, ByVal Protocol As Protocol) As Boolean
If Not UPnPEnabled Then Throw New Exception("Could not find a UPnP enabled router")
For Each mapping In Mappings.OfType(Of NATUPNPLib.IStaticPortMapping)()
If mapping.ExternalPort.Equals(ExternalPort) AndAlso mapping.Protocol.ToString.Equals(Protocol.ToString) Then Return True
Next
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
If Not UPnPEnabled Then Throw New Exception("Could not find a UPnP enabled router")
For Each mapping In Mappings.OfType(Of NATUPNPLib.IStaticPortMapping)()
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
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