在网络配置中,端口转发是一个常见的需求,它允许外部网络通过特定的端口访问内部网络中的服务。传统的端口转发通常需要将端口映射到静态IP地址上,这限制了计算机必须拥有一个固定的IP地址。而UPnP(通用即插即用)技术的出现,为端口转发带来了更多的灵活性和便利性。
UPnP技术的主要优势包括:
要实现这些功能,路由器需要支持UPnP。
实现UPnP端口转发的步骤如下:
以下是一个VB.NET的示例代码,用于管理端口转发:
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 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
' 释放资源
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If Mappings IsNot Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(Mappings)
End If
If UPnPNAT IsNot Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(UPnPNAT)
End If
Me.disposedValue = True
End If
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
' 端口转发功能
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")
End If
If Exists(ExternalPort, Protocol) Then
Throw New Exception("Mapping already exists")
End If
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")
End If
If Not Exists(ExternalPort, Protocol) Then
Throw New ArgumentException("Mapping does not exist")
End If
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")
End If
For Each mapping In Mappings.OfType(Of NATUPNPLib.IStaticPortMapping)()
If mapping.ExternalPort.Equals(ExternalPort) AndAlso mapping.Protocol.ToString.Equals(Protocol.ToString) Then
Return True
End If
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")
End If
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
End If
Next
Return False
End Function
End Class
通过上述代码,可以轻松地检查UPnP是否启用、添加端口映射、移除端口映射以及检查端口是否已映射。
UsingUPnPAs New UPnP Return UPnP.UPnPEnabled End Using
Using UPnP As New UPnP UPnP.Add(localIP As String, Port As Integer, ExternalPort As Integer, prot As Protocol, desc As String) End Using
Using UPnP As New UPnP UPnP.Remove(Port As Integer, Prot As Protocol) End Using
Using UPnP As New UPnP Return UPnP.Exists(Port As Integer, Prot As Protocol) End Using
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