98.100、单独使用虚拟网卡
1、说明
说明
在你的.NET8.0+项目中,集成tun网卡,适用于windows
、linux
,源码在https://github.com/snltty/linker/tree/master/linker.tun
1、windows
- 下载wintun,选择适合你系统的
wintun.dll
放到项目根目录 - 在windows下,使用 wintun
WintunCreateAdapter
创建适配器,可以提供一个guid,如果不提供,将随机一个,这会导致注册表不断的产生新的记录 - 如果提供一个固定的guid,在程序的一次会话内可以重复删除和创建适配器,但是,如果你在多个会话内使用同一个guid,将会非常大概率创建适配器失败
- 所以
linker.tun
选择每次运行程序时生成guid,在本次会话内重复使用,且提供了LinkerTunDeviceAdapter.Clear()
让你选择在合适的适合清理注册表
2、linux
- 请确保你的系统拥有
tuntap
模块,ifconfig
、ip
、iptables
命令
2、编写一个简单的代码
说明
nuget 安装 linker.tun
,然后编写代码
internal class Program
{
public static LinkerTunDeviceAdapter linkerTunDeviceAdapter;
static void Main(string[] args)
{
linkerTunDeviceAdapter = new LinkerTunDeviceAdapter();
//初始化设备名,和读取数据回调
linkerTunDeviceAdapter.Initialize("linker111", new LinkerTunDeviceCallback());
//在初始化后,可以清理一些数据,在windows,将会清理适配器的注册表信息
//linkerTunDeviceAdapter.Clear();
//启动网卡,ip,掩码,mtu
linkerTunDeviceAdapter.Setup(IPAddress.Parse("192.168.55.2"), 24, 1416);
//设置NAT转发,这会将来到本网卡且目标IP不是本网卡IP的包转发到其它网卡
//linkerTunDeviceAdapter.SetNat();
//如果存在错误
if (string.IsNullOrWhiteSpace(linkerTunDeviceAdapter.Error))
{
Console.WriteLine(linkerTunDeviceAdapter.Error);
//关闭网卡
linkerTunDeviceAdapter.Shutdown();
}
Console.ReadLine();
}
}
public sealed class LinkerTunDeviceCallback : ILinkerTunDeviceCallback
{
//收到IP数据包
public async Task Callback(LinkerTunDevicPacket packet)
{
ICMPAnswer(packet);
await Task.CompletedTask;
}
private unsafe void ICMPAnswer(LinkerTunDevicPacket packet)
{
fixed (byte* ptr = packet.IPPacket.Span)
{
//ICMP包,且是 Request
if (ptr[9] == 1 && ptr[20] == 8)
{
Console.WriteLine($"ICMP to {new IPAddress(packet.IPPacket.Span.Slice(16, 4))}");
uint dist = BinaryPrimitives.ReadUInt32LittleEndian(packet.IPPacket.Span.Slice(16, 4));
//目的地址变源地址,
*(uint*)(ptr + 16) = *(uint*)(ptr + 12);
//假装是网关回复的
*(uint*)(ptr + 12) = dist;
//计算一次IP头校验和
*(ushort*)(ptr + 10) = 0;
*(ushort*)(ptr + 10) = Program.linkerTunDeviceAdapter.Checksum((ushort*)ptr, 20);
//改为ICMP Reply
*(ushort*)(ptr + 20) = 0;
//计算ICMP校验和
*(ushort*)(ptr + 22) = 0;
int length = packet.IPPacket.Span.Length - 20;
ushort sum = Program.linkerTunDeviceAdapter.Checksum((ushort*)(ptr + 20), length);
*(ushort*)(ptr + 22) = sum;
//写入网卡,回应这个ICMP请求
Program.linkerTunDeviceAdapter.Write(packet.IPPacket);
}
}
}
}