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); } } }