This commit is contained in:
snltty
2024-08-18 17:38:01 +08:00
parent 4453aeea76
commit 26034bde71
6 changed files with 117 additions and 56 deletions

View File

@@ -1,4 +1,7 @@
using System.Net; using linker.libs.extends;
using System.Buffers.Binary;
using System.Net;
using System.Net.Sockets;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace linker.tun namespace linker.tun
@@ -118,18 +121,6 @@ namespace linker.tun
/// </summary> /// </summary>
public struct LinkerTunDevicPacket public struct LinkerTunDevicPacket
{ {
/// <summary>
/// 协议版本4或者6
/// </summary>
public byte Version;
/// <summary>
/// 源IP
/// </summary>
public ReadOnlyMemory<byte> SourceIPAddress;
/// <summary>
/// 目标IP
/// </summary>
public ReadOnlyMemory<byte> DistIPAddress;
/// <summary> /// <summary>
/// 带4字节头的包 /// 带4字节头的包
/// </summary> /// </summary>
@@ -139,21 +130,72 @@ namespace linker.tun
/// </summary> /// </summary>
public ReadOnlyMemory<byte> IPPacket; public ReadOnlyMemory<byte> IPPacket;
/// <summary>
/// 协议版本4或者6
/// </summary>
public byte Version;
/// <summary>
/// 协议
/// </summary>
public ProtocolType ProtocolType;
/// <summary>
/// 源IP
/// </summary>
public ReadOnlyMemory<byte> SourceIPAddress;
/// <summary>
/// 源端口
/// </summary>
public ushort SourcePort;
/// <summary>
/// 源
/// </summary>
public readonly IPEndPoint Source => new IPEndPoint(new IPAddress(SourceIPAddress.Span), SourcePort);
/// <summary>
/// 目标IP
/// </summary>
public ReadOnlyMemory<byte> DistIPAddress;
/// <summary>
/// 目标端口
/// </summary>
public ushort DistPort;
/// <summary>
/// 目标
/// </summary>
public readonly IPEndPoint Dist => new IPEndPoint(new IPAddress(DistIPAddress.Span), DistPort);
public void Unpacket(ReadOnlyMemory<byte> buffer) public void Unpacket(ReadOnlyMemory<byte> buffer)
{ {
Packet = buffer; Packet = buffer;
IPPacket = buffer.Slice(4); IPPacket = buffer.Slice(4);
Version = (byte)(IPPacket.Span[0] >> 4 & 0b1111); Version = (byte)(IPPacket.Span[0] >> 4 & 0b1111);
if (Version == 4) if (Version == 4)
{ {
SourceIPAddress = IPPacket.Slice(12, 4); SourceIPAddress = IPPacket.Slice(12, 4);
DistIPAddress = IPPacket.Slice(16, 4); DistIPAddress = IPPacket.Slice(16, 4);
ProtocolType = (ProtocolType)IPPacket.Span[9];
if (ProtocolType == ProtocolType.Tcp || ProtocolType == ProtocolType.Udp)
{
SourcePort = BinaryPrimitives.ReverseEndianness(IPPacket.Slice(20, 2).ToUInt16());
DistPort = BinaryPrimitives.ReverseEndianness(IPPacket.Slice(22, 2).ToUInt16());
}
} }
else if (Version == 6) else if (Version == 6)
{ {
SourceIPAddress = IPPacket.Slice(8, 16); SourceIPAddress = IPPacket.Slice(8, 16);
DistIPAddress = IPPacket.Slice(24, 16); DistIPAddress = IPPacket.Slice(24, 16);
ProtocolType = (ProtocolType)IPPacket.Span[6];
if (ProtocolType == ProtocolType.Tcp || ProtocolType == ProtocolType.Udp)
{
SourcePort = BinaryPrimitives.ReverseEndianness(IPPacket.Slice(42, 2).ToUInt16());
DistPort = BinaryPrimitives.ReverseEndianness(IPPacket.Slice(24, 2).ToUInt16());
}
} }
} }
} }

View File

@@ -53,10 +53,13 @@ namespace linker.tun
{ {
error = string.Empty; error = string.Empty;
byte[] ipv6 = IPAddress.Parse("fe80::1818:1818:1818:1818").GetAddressBytes();
address.GetAddressBytes().CopyTo(ipv6, ipv6.Length - 4);
CommandHelper.Linux(string.Empty, new string[] { CommandHelper.Linux(string.Empty, new string[] {
$"ip tuntap add mode tun dev {Name}", $"ip tuntap add mode tun dev {Name}",
$"ip addr del {address}/{prefixLength} dev {Name}",
$"ip addr add {address}/{prefixLength} dev {Name}", $"ip addr add {address}/{prefixLength} dev {Name}",
$"ip addr add {new IPAddress(ipv6)}/64 dev {Name}",
$"ip link set dev {Name} up" $"ip link set dev {Name} up"
}); });

View File

@@ -63,6 +63,28 @@ namespace linker.tun
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{ {
try try
{
AddIPV4();
AddIPV6();
break;
}
catch (Exception)
{
Thread.Sleep(1000);
}
if (i == 4)
{
error = ($"Failed to set adapter ip {Marshal.GetLastWin32Error():x2}");
Shutdown();
return false;
}
}
GetWindowsInterfaceNum();
tokenSource = new CancellationTokenSource();
return true;
}
private void AddIPV4()
{ {
WinTun.WintunGetAdapterLUID(adapter, out ulong luid); WinTun.WintunGetAdapterLUID(adapter, out ulong luid);
{ {
@@ -76,37 +98,26 @@ namespace linker.tun
uint LastError = WinTun.CreateUnicastIpAddressEntry(ref AddressRow); uint LastError = WinTun.CreateUnicastIpAddressEntry(ref AddressRow);
if (LastError != 0) throw new InvalidOperationException(); if (LastError != 0) throw new InvalidOperationException();
} }
break;
} }
catch (Exception) private void AddIPV6()
{ {
Thread.Sleep(1000); NetworkInterface networkInterface = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(c => c.Name == Name);
} if (networkInterface != null)
if(i == 4)
{ {
error = ($"Failed to set adapter ip {Marshal.GetLastWin32Error():x2}"); var commands = networkInterface.GetIPProperties()
Shutdown(); .UnicastAddresses
return false; .Where(c => c.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
.Select(c => new IPAddress(c.Address.GetAddressBytes(), 0))
.Select(c => $"netsh interface ipv6 delete address \"{Name}\" address=\"{c}\"").ToList();
byte[] ipv6 = IPAddress.Parse("fe80::1818:1818:1818:1818").GetAddressBytes();
address.GetAddressBytes().CopyTo(ipv6, ipv6.Length - 4);
commands.Add($"netsh interface ipv6 add address \"{Name}\" address=\"{new IPAddress(ipv6)}\"");
CommandHelper.Windows(string.Empty, [.. commands]);
} }
} }
/*
{
MIB_IPFORWARD_ROW2 row = default;
InitializeIpForwardEntry(ref row);
row.InterfaceLuid = luid;
row.PrefixLength = 0;
row.si_family = 2;
row.NextHop_si_family = 2;
row.sin_addr = 0;
row.NextHop_sin_addr = BinaryPrimitives.ReadUInt32LittleEndian(gateway.GetAddressBytes());
uint LastError = CreateIpForwardEntry2(ref row);
if (LastError != 0) throw new InvalidOperationException();
}
*/
GetWindowsInterfaceNum();
tokenSource = new CancellationTokenSource();
return true;
}
public void Shutdown() public void Shutdown()
{ {
tokenSource?.Cancel(); tokenSource?.Cancel();
@@ -341,3 +352,5 @@ namespace linker.tun
} }
} }
} }

View File

@@ -5,6 +5,7 @@ namespace linker.tun
internal static class WinTun internal static class WinTun
{ {
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 80)] [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 80)]
internal struct MIB_UNICASTIPADDRESS_ROW internal struct MIB_UNICASTIPADDRESS_ROW
{ {
@@ -20,6 +21,7 @@ namespace linker.tun
public int DadState; public int DadState;
} }
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 104)] [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 104)]
internal struct MIB_IPFORWARD_ROW2 internal struct MIB_IPFORWARD_ROW2
{ {
@@ -43,6 +45,7 @@ namespace linker.tun
[DllImport("iphlpapi.dll", SetLastError = true)] [DllImport("iphlpapi.dll", SetLastError = true)]
internal static extern uint CreateUnicastIpAddressEntry(ref MIB_UNICASTIPADDRESS_ROW Row); internal static extern uint CreateUnicastIpAddressEntry(ref MIB_UNICASTIPADDRESS_ROW Row);
[DllImport("iphlpapi.dll", SetLastError = true)] [DllImport("iphlpapi.dll", SetLastError = true)]
internal static extern void InitializeIpForwardEntry(ref MIB_IPFORWARD_ROW2 Row); internal static extern void InitializeIpForwardEntry(ref MIB_IPFORWARD_ROW2 Row);

View File

@@ -82,7 +82,7 @@ export default {
const tuntap = useTuntap(); const tuntap = useTuntap();
const globalData = injectGlobalData(); const globalData = injectGlobalData();
const showDelay = computed(()=>(globalData.value.config.Running.Tuntap.Switch & 2) == 2); const showDelay = computed(()=>((globalData.value.config.Running.Tuntap || {Switch:0}).Switch & 2) == 2);
const handleTuntap = (tuntap) => { const handleTuntap = (tuntap) => {
const fn = tuntap.running ? stopTuntap (tuntap.MachineId) : runTuntap(tuntap.MachineId); const fn = tuntap.running ? stopTuntap (tuntap.MachineId) : runTuntap(tuntap.MachineId);
tuntap.loading = true; tuntap.loading = true;

View File

@@ -78,18 +78,20 @@ namespace linker.plugins.tuntap.proxy
public async Task Callback(LinkerTunDevicPacket packet) public async Task Callback(LinkerTunDevicPacket packet)
{ {
//IPV4
if (packet.Version == 4) if (packet.Version == 4)
{ {
uint ip = BinaryPrimitives.ReadUInt32BigEndian(packet.DistIPAddress.Span); // 广播组播
if (packet.DistIPAddress.GetIsBroadcastAddress()) if (packet.DistIPAddress.GetIsBroadcastAddress())
{ {
if (connections.IsEmpty == false) if (connections.IsEmpty == false)
{ {
await Task.WhenAll(connections.Values.Where(c => c != null && c.Connected).Select(c => c.SendAsync(packet.Packet))); await Task.WhenAll(connections.Values.Where(c => c != null && c.Connected).Select(c => c.SendAsync(packet.Packet)));
} }
return;
} }
else
{ uint ip = BinaryPrimitives.ReadUInt32BigEndian(packet.DistIPAddress.Span);
if (ipConnections.TryGetValue(ip, out ITunnelConnection connection) == false || connection == null || connection.Connected == false) if (ipConnections.TryGetValue(ip, out ITunnelConnection connection) == false || connection == null || connection.Connected == false)
{ {
connection = await ConnectTunnel(ip); connection = await ConnectTunnel(ip);
@@ -102,17 +104,15 @@ namespace linker.plugins.tuntap.proxy
{ {
await connection.SendAsync(packet.Packet); await connection.SendAsync(packet.Packet);
} }
else
{
}
}
} }
//IPV6 多播
else if (packet.Version == 6 && (packet.DistIPAddress.Span[0] & 0xFF) == 0xFF) else if (packet.Version == 6 && (packet.DistIPAddress.Span[0] & 0xFF) == 0xFF)
{ {
if (connections.IsEmpty == false) if (connections.IsEmpty == false)
{ {
await Task.WhenAll(connections.Values.Where(c => c != null && c.Connected).Select(c => c.SendAsync(packet.Packet))); await Task.WhenAll(connections.Values.Where(c => c != null && c.Connected).Select(c => c.SendAsync(packet.Packet)));
} }
return;
} }
} }