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;
namespace linker.tun
@@ -118,18 +121,6 @@ namespace linker.tun
/// </summary>
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>
/// 带4字节头的包
/// </summary>
@@ -139,21 +130,72 @@ namespace linker.tun
/// </summary>
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)
{
Packet = buffer;
IPPacket = buffer.Slice(4);
Version = (byte)(IPPacket.Span[0] >> 4 & 0b1111);
if (Version == 4)
{
SourceIPAddress = IPPacket.Slice(12, 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)
{
SourceIPAddress = IPPacket.Slice(8, 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;
byte[] ipv6 = IPAddress.Parse("fe80::1818:1818:1818:1818").GetAddressBytes();
address.GetAddressBytes().CopyTo(ipv6, ipv6.Length - 4);
CommandHelper.Linux(string.Empty, new string[] {
$"ip tuntap add mode tun dev {Name}",
$"ip addr del {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"
});

View File

@@ -64,49 +64,60 @@ namespace linker.tun
{
try
{
WinTun.WintunGetAdapterLUID(adapter, out ulong luid);
{
WinTun.MIB_UNICASTIPADDRESS_ROW AddressRow = default;
WinTun.InitializeUnicastIpAddressEntry(ref AddressRow);
AddressRow.sin_family = 2;
AddressRow.sin_addr = BinaryPrimitives.ReadUInt32LittleEndian(address.GetAddressBytes());
AddressRow.OnLinkPrefixLength = prefixLength;
AddressRow.DadState = 4;
AddressRow.InterfaceLuid = luid;
uint LastError = WinTun.CreateUnicastIpAddressEntry(ref AddressRow);
if (LastError != 0) throw new InvalidOperationException();
}
AddIPV4();
AddIPV6();
break;
}
catch (Exception)
{
Thread.Sleep(1000);
}
if(i == 4)
if (i == 4)
{
error = ($"Failed to set adapter ip {Marshal.GetLastWin32Error():x2}");
Shutdown();
return false;
}
}
/*
{
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;
}
private void AddIPV4()
{
WinTun.WintunGetAdapterLUID(adapter, out ulong luid);
{
WinTun.MIB_UNICASTIPADDRESS_ROW AddressRow = default;
WinTun.InitializeUnicastIpAddressEntry(ref AddressRow);
AddressRow.sin_family = 2;
AddressRow.sin_addr = BinaryPrimitives.ReadUInt32LittleEndian(address.GetAddressBytes());
AddressRow.OnLinkPrefixLength = prefixLength;
AddressRow.DadState = 4;
AddressRow.InterfaceLuid = luid;
uint LastError = WinTun.CreateUnicastIpAddressEntry(ref AddressRow);
if (LastError != 0) throw new InvalidOperationException();
}
}
private void AddIPV6()
{
NetworkInterface networkInterface = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(c => c.Name == Name);
if (networkInterface != null)
{
var commands = networkInterface.GetIPProperties()
.UnicastAddresses
.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]);
}
}
public void Shutdown()
{
tokenSource?.Cancel();
@@ -341,3 +352,5 @@ namespace linker.tun
}
}
}

View File

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

View File

@@ -82,7 +82,7 @@ export default {
const tuntap = useTuntap();
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 fn = tuntap.running ? stopTuntap (tuntap.MachineId) : runTuntap(tuntap.MachineId);
tuntap.loading = true;

View File

@@ -78,41 +78,41 @@ namespace linker.plugins.tuntap.proxy
public async Task Callback(LinkerTunDevicPacket packet)
{
//IPV4
if (packet.Version == 4)
{
uint ip = BinaryPrimitives.ReadUInt32BigEndian(packet.DistIPAddress.Span);
// 广播组播
if (packet.DistIPAddress.GetIsBroadcastAddress())
{
if (connections.IsEmpty == false)
{
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);
if (connection != null)
{
ipConnections.AddOrUpdate(ip, connection, (a, b) => connection);
}
}
connection = await ConnectTunnel(ip);
if (connection != null)
{
await connection.SendAsync(packet.Packet);
}
else
{
ipConnections.AddOrUpdate(ip, connection, (a, b) => connection);
}
}
if (connection != null)
{
await connection.SendAsync(packet.Packet);
}
}
//IPV6 多播
else if (packet.Version == 6 && (packet.DistIPAddress.Span[0] & 0xFF) == 0xFF)
{
if (connections.IsEmpty == false)
{
await Task.WhenAll(connections.Values.Where(c => c != null && c.Connected).Select(c => c.SendAsync(packet.Packet)));
}
return;
}
}