mirror of
https://github.com/snltty/linker.git
synced 2025-10-07 01:52:51 +08:00
139 lines
4.7 KiB
C#
139 lines
4.7 KiB
C#
using linker.libs;
|
|
using linker.tunnel.transport;
|
|
using Mono.Nat;
|
|
using System.Collections.Concurrent;
|
|
|
|
namespace linker.tunnel
|
|
{
|
|
/// <summary>
|
|
/// 给网关添加端口映射
|
|
/// </summary>
|
|
public sealed class TunnelUpnpTransfer
|
|
{
|
|
|
|
private readonly SemaphoreSlim locker = new SemaphoreSlim(1, 1);
|
|
private readonly ConcurrentDictionary<NatProtocol, INatDevice> natDevices = new ConcurrentDictionary<NatProtocol, INatDevice>();
|
|
|
|
public MapInfo MapInfo { get; private set; }
|
|
public MapInfo MapInfo1 { get; private set; }
|
|
|
|
public MapInfo PortMap => MapInfo1 ?? MapInfo;
|
|
|
|
private readonly TransportUdpPortMap transportUdpPortMap;
|
|
private readonly TransportTcpPortMap transportTcpPortMap;
|
|
public TunnelUpnpTransfer(TransportUdpPortMap transportUdpPortMap,TransportTcpPortMap transportTcpPortMap)
|
|
{
|
|
this.transportUdpPortMap = transportUdpPortMap;
|
|
this.transportTcpPortMap = transportTcpPortMap;
|
|
|
|
NatUtility.DeviceFound += DeviceFound;
|
|
NatUtility.StartDiscovery();
|
|
LoopDiscovery();
|
|
|
|
}
|
|
|
|
private void LoopDiscovery()
|
|
{
|
|
TimerHelper.SetInterval(() =>
|
|
{
|
|
NatUtility.StopDiscovery();
|
|
NatUtility.StartDiscovery();
|
|
|
|
return true;
|
|
}, 60 * 1000);
|
|
}
|
|
private void DeviceFound(object sender, DeviceEventArgs args)
|
|
{
|
|
INatDevice device = args.Device;
|
|
|
|
if (natDevices.Count == 0 || natDevices.TryGetValue(device.NatProtocol, out INatDevice _device))
|
|
{
|
|
natDevices.AddOrUpdate(device.NatProtocol, device, (a, b) => device);
|
|
}
|
|
AddMap();
|
|
}
|
|
private void AddMap()
|
|
{
|
|
if (natDevices.Count == 0 || MapInfo == null) return;
|
|
|
|
TimerHelper.Async(async () =>
|
|
{
|
|
await locker.WaitAsync();
|
|
|
|
INatDevice device = natDevices.FirstOrDefault().Value;
|
|
|
|
try
|
|
{
|
|
if (await HasMap(device, Protocol.Tcp, MapInfo.PublicPort) == false)
|
|
{
|
|
Mapping mapping = new Mapping(Protocol.Tcp, MapInfo.PrivatePort, MapInfo.PublicPort, 720, $"linker-tcp-{MapInfo.PublicPort}-{MapInfo.PrivatePort}");
|
|
await device.CreatePortMapAsync(mapping);
|
|
Mapping m = await device.GetSpecificMappingAsync(Protocol.Tcp, mapping.PublicPort);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
try
|
|
{
|
|
if (await HasMap(device, Protocol.Udp, MapInfo.PublicPort) == false)
|
|
{
|
|
Mapping mapping = new Mapping(Protocol.Udp, MapInfo.PrivatePort, MapInfo.PublicPort, 720, $"linker-udp-{MapInfo.PublicPort}-{MapInfo.PrivatePort}");
|
|
await device.CreatePortMapAsync(mapping);
|
|
Mapping m = await device.GetSpecificMappingAsync(Protocol.Udp, mapping.PublicPort);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
locker.Release();
|
|
});
|
|
}
|
|
private async Task<bool> HasMap(INatDevice device, Protocol protocol, int publicPort)
|
|
{
|
|
try
|
|
{
|
|
Mapping m = await device.GetSpecificMappingAsync(protocol, publicPort);
|
|
return true;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置端口映射,内网端口和外网端口一样
|
|
/// </summary>
|
|
/// <param name="privatePort"></param>
|
|
public void SetMap(int privatePort)
|
|
{
|
|
MapInfo = new MapInfo { PrivatePort = privatePort, PublicPort = privatePort };
|
|
AddMap();
|
|
|
|
_ = transportTcpPortMap.Listen(privatePort);
|
|
_ = transportUdpPortMap.Listen(privatePort);
|
|
}
|
|
/// <summary>
|
|
/// 设置端口映射,内网端口和外网端口不一样
|
|
/// </summary>
|
|
/// <param name="privatePort"></param>
|
|
/// <param name="publicPort"></param>
|
|
public void SetMap(int privatePort, int publicPort)
|
|
{
|
|
MapInfo1 = new MapInfo { PrivatePort = privatePort, PublicPort = publicPort };
|
|
|
|
_ = transportTcpPortMap.Listen(privatePort);
|
|
_ = transportUdpPortMap.Listen(privatePort);
|
|
}
|
|
}
|
|
|
|
public sealed class MapInfo
|
|
{
|
|
public int PrivatePort { get; set; }
|
|
public int PublicPort { get; set; }
|
|
}
|
|
}
|