UPnP 路由器端口转发的便利性与实现

网络配置中,端口转发是一个常见的需求,它允许外部网络通过特定的端口访问内部网络中的服务。传统的端口转发通常需要将端口映射到静态IP地址上,这限制了计算机必须拥有一个固定的IP地址。而UPnP(通用即插即用)技术的出现,为端口转发带来了更多的灵活性和便利性。

UPnP技术的主要优势包括:

  • 能够将端口转发映射到计算机名称,而不仅仅是IP地址。
  • 允许计算机拥有动态IP地址,同时实现端口转发。
  • 绕过Netgear路由器不允许在同一外部端口上进行端口重定向的限制。
  • 便携性,允许将计算机从一个网络移动到另一个网络,并且配合动态域名系统(DDNS)客户端,实现“即插即用”。

要实现这些功能,路由器需要支持UPnP。

实现方法

实现UPnP端口转发的步骤如下:

  1. 确保“SSDP发现服务”正在运行。
  2. 在项目中添加对“NATUPnP 1.0 Type Library”的引用。
  3. 使用以下类来管理端口转发。

以下是一个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是否启用、添加端口映射、移除端口映射以及检查端口是否已映射。

使用示例

  • 检查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
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485