using linker.libs;
using System.Net;
using System.Xml.Linq;
namespace linker.tun
{
public sealed class LinkerTunDeviceAdapter
{
private ILinkerTunDevice linkerTunDevice;
private ILinkerTunDeviceCallback linkerTunDeviceCallback;
private CancellationTokenSource cancellationTokenSource;
private string error = string.Empty;
public string Error => error;
private bool starting = false;
public LinkerTunDeviceStatus Status
{
get
{
if (linkerTunDevice == null) return LinkerTunDeviceStatus.Normal;
return linkerTunDevice.Running
? LinkerTunDeviceStatus.Running
: starting
? LinkerTunDeviceStatus.Starting
: LinkerTunDeviceStatus.Normal;
}
}
///
/// 构造
///
/// 数据包回调
public LinkerTunDeviceAdapter()
{
}
public void SetCallback(ILinkerTunDeviceCallback linkerTunDeviceCallback)
{
this.linkerTunDeviceCallback = linkerTunDeviceCallback;
}
///
/// 开启网卡
///
/// 网卡名,如果是osx,需要utunX的命名,X是一个数字
/// windows的时候,需要一个固定guid,不然网卡编号一直递增,注册表一直新增记录
/// 网卡IP
/// 掩码。一般24即可
public void SetUp(string name, Guid guid, IPAddress address, byte prefixLength)
{
if (starting) return;
Shutdown();
starting = true;
try
{
if (linkerTunDevice == null)
{
if (OperatingSystem.IsWindows())
{
linkerTunDevice = new LinkerWinTunDevice(name, guid);
}
else if (OperatingSystem.IsLinux())
{
linkerTunDevice = new LinkerLinuxTunDevice(name);
}
}
if (linkerTunDevice != null)
{
linkerTunDevice.Shutdown();
linkerTunDevice.SetUp(address, NetworkHelper.ToGatewayIP(address, prefixLength), prefixLength, out error);
if (string.IsNullOrWhiteSpace(error))
{
cancellationTokenSource = new CancellationTokenSource();
Task.Run(async () =>
{
while (cancellationTokenSource.IsCancellationRequested == false)
{
try
{
ReadOnlyMemory buffer = linkerTunDevice.Read();
if (buffer.Length == 0)
{
break;
}
LinkerTunDevicPacket packet = new LinkerTunDevicPacket();
packet.Packet = buffer;
ReadOnlyMemory ipPacket = buffer.Slice(4);
packet.Version = (byte)(ipPacket.Span[0] >> 4 & 0b1111);
if (packet.Version == 4)
{
packet.SourceIPAddress = ipPacket.Slice(12, 4);
packet.DistIPAddress = ipPacket.Slice(16, 4);
}
else if (packet.Version == 6)
{
packet.SourceIPAddress = ipPacket.Slice(8, 16);
packet.DistIPAddress = ipPacket.Slice(24, 16);
}
await linkerTunDeviceCallback.Callback(packet).ConfigureAwait(false);
}
catch (Exception)
{
break;
}
}
});
}
}
}
catch (Exception ex)
{
error = ex.Message;
}
finally
{
starting = false;
}
}
///
/// 关闭网卡
///
public void Shutdown()
{
cancellationTokenSource?.Cancel();
if (linkerTunDevice != null)
{
linkerTunDevice.Shutdown();
linkerTunDevice.RemoveNat();
}
error = string.Empty;
}
public void SetMtu(int value)
{
if (linkerTunDevice != null)
{
linkerTunDevice.SetMtu(value);
}
}
public void SetNat()
{
if (linkerTunDevice != null)
{
linkerTunDevice.SetNat();
}
}
public void RemoveNat()
{
if (linkerTunDevice != null)
{
linkerTunDevice.RemoveNat();
}
}
///
/// 添加路由
///
/// 路由记录,ip和掩码
/// 目标IP
public void AddRoute(LinkerTunDeviceRouteItem[] ips, IPAddress ip)
{
if (linkerTunDevice != null)
{
linkerTunDevice.AddRoute(ips, ip);
}
}
///
/// 删除路由
///
/// 路由记录,ip和掩码
public void DelRoute(LinkerTunDeviceRouteItem[] ips)
{
if (linkerTunDevice != null)
{
linkerTunDevice.DelRoute(ips);
}
}
///
/// 写入网卡
///
///
///
public bool Write(ReadOnlyMemory buffer)
{
if (linkerTunDevice != null)
{
return linkerTunDevice.Write(buffer);
}
return false;
}
///
/// 计算校验和
///
/// 包头开始位置
/// 包头长度
///
public unsafe ushort Checksum(ushort* addr, uint count)
{
ulong sum = 0;
while (count > 1)
{
sum += *addr++;
count -= 2;
}
if (count > 0)
{
sum += (ulong)((*addr) & ((((0xff00) & 0xff) << 8) | (((0xff00) & 0xff00) >> 8)));
}
while ((sum >> 16) != 0)
{
sum = (sum & 0xffff) + (sum >> 16);
}
sum = ~sum;
return ((ushort)sum);
}
}
}