using linker.libs; using System.Net; namespace linker.tun { /// /// linker tun网卡适配器,自动选择不同平台的实现 /// public sealed class LinkerTunDeviceAdapter { private ILinkerTunDevice linkerTunDevice; private ILinkerTunDeviceCallback linkerTunDeviceCallback; private CancellationTokenSource cancellationTokenSource; private string setupError = string.Empty; public string SetupError => setupError; private string natError = string.Empty; public string NatError => natError; private uint operating = 0; public LinkerTunDeviceStatus Status { get { if (linkerTunDevice == null) return LinkerTunDeviceStatus.Normal; return operating == 1 ? LinkerTunDeviceStatus.Operating : linkerTunDevice.Running ? LinkerTunDeviceStatus.Running : LinkerTunDeviceStatus.Normal; } } public LinkerTunDeviceAdapter() { } /// /// 初始化 /// /// 设备名 /// 读取数据回调 public void Initialize(string deviceName, ILinkerTunDeviceCallback linkerTunDeviceCallback) { this.linkerTunDeviceCallback = linkerTunDeviceCallback; if (linkerTunDevice == null) { if (OperatingSystem.IsWindows()) { linkerTunDevice = new LinkerWinTunDevice(deviceName, Guid.NewGuid()); } else if (OperatingSystem.IsLinux()) { linkerTunDevice = new LinkerLinuxTunDevice(deviceName); } /* else if (OperatingSystem.IsMacOS()) { linkerTunDevice = new LinkerOsxTunDevice("utun12138"); } */ } } /// /// 清理额外的数据,具体看不同平台的实现 /// public void Clear() { linkerTunDevice?.Clear(); } /// /// 开启网卡 /// /// 网卡IP /// 掩码。一般24即可 /// mtu public bool Setup(IPAddress address, byte prefixLength, int mtu) { if (Interlocked.CompareExchange(ref operating, 1, 0) == 1) { setupError = $"setup are operating"; return false; } try { if (linkerTunDevice == null) { setupError = $"{System.Runtime.InteropServices.RuntimeInformation.OSDescription} not support"; return false; } linkerTunDevice.Setup(address, NetworkHelper.ToGatewayIP(address, prefixLength), prefixLength, out setupError); if (string.IsNullOrWhiteSpace(setupError) == false) { return false; } linkerTunDevice.SetMtu(mtu); Read(); return true; } catch (Exception ex) { setupError = ex + ""; } finally { Interlocked.Exchange(ref operating, 0); } return false; } /// /// 关闭网卡 /// public bool Shutdown() { if (Interlocked.CompareExchange(ref operating, 1, 0) == 1) { setupError = $"shutdown are operating"; return false; } try { cancellationTokenSource?.Cancel(); linkerTunDevice?.Shutdown(); } catch (Exception) { } setupError = string.Empty; Interlocked.Exchange(ref operating, 0); return true; } /// /// 添加NAT转发,这会将来到本网卡且目标IP不是本网卡IP的包转发到其它网卡 /// public void SetNat() { linkerTunDevice?.RemoveNat(out string error); linkerTunDevice?.SetNat(out natError); } /// /// 移除NAT转发 /// public void RemoveNat() { linkerTunDevice?.RemoveNat(out string error); } /// /// 获取端口转发 /// /// public List GetForward() { return linkerTunDevice?.GetForward() ?? []; } /// /// 添加端口转发 /// /// public void AddForward(List forwards) { linkerTunDevice?.AddForward(forwards); } /// /// 移除端口转发 /// /// public void RemoveForward(List forwards) { linkerTunDevice?.RemoveForward(forwards); } /// /// 添加路由 /// /// /// public void AddRoute(LinkerTunDeviceRouteItem[] ips, IPAddress ip) { linkerTunDevice?.AddRoute(ips, ip); } /// /// 删除路由 /// /// public void DelRoute(LinkerTunDeviceRouteItem[] ips) { linkerTunDevice?.DelRoute(ips); } private void Read() { TimerHelper.Async(async () => { cancellationTokenSource = new CancellationTokenSource(); while (cancellationTokenSource.IsCancellationRequested == false) { try { ReadOnlyMemory buffer = linkerTunDevice.Read(); if (buffer.Length == 0) { Shutdown(); break; } LinkerTunDevicPacket packet = new LinkerTunDevicPacket(); packet.Unpacket(buffer); try { await linkerTunDeviceCallback.Callback(packet).ConfigureAwait(false); } catch (Exception ex) { setupError = ex.Message; } } catch (Exception ex) { setupError = ex.Message; Shutdown(); break; } } }); } /// /// 写入网卡 /// /// /// public bool Write(ReadOnlyMemory buffer) { if (linkerTunDevice != null) { return linkerTunDevice.Write(buffer); } return false; } /// /// 计算校验和 /// /// 包头开始位置 /// 长度,IP包仅包头,ICMP包则全部 /// 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); } } }