mirror of
https://github.com/snltty/linker.git
synced 2025-09-27 13:32:14 +08:00
183
This commit is contained in:
2
.github/workflows/dotnet.yml
vendored
2
.github/workflows/dotnet.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
|||||||
release_name: v1.8.3.${{ steps.date.outputs.today }}
|
release_name: v1.8.3.${{ steps.date.outputs.today }}
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
body: "1. 一些累计更新\r\n2. 修复socks5,解决CPU爆满问题,增加域名解析和HTTP代理\r\n3. 优化唤醒模块\r\n5. 管理端口改为1804,一个端口托管Web+Websocket"
|
body: "1. 一些累计更新\r\n2. 修复socks5,解决CPU爆满问题,增加本地域名解析,支持HTTP代理\r\n3. 优化唤醒模块\r\n4. 优化应用NAT,根据目标IP自动选择网卡\r\n5. 分离cdkey,使其可作用于任意模块"
|
||||||
- name: publish projects
|
- name: publish projects
|
||||||
run: ./publish.bat "C:\\Android\\android-sdk"
|
run: ./publish.bat "C:\\Android\\android-sdk"
|
||||||
- name: upload-win-x86-oss
|
- name: upload-win-x86-oss
|
||||||
|
1
src/linker.app/public/web/css/118.be8a94f0.css
Normal file
1
src/linker.app/public/web/css/118.be8a94f0.css
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.el-radio-group[data-v-3927a588]{margin-right:.6rem}.wrap[data-v-3927a588]{padding-bottom:1rem}.el-form-item[data-v-8eed28d4]{margin-bottom:1rem}.el-input-number--small[data-v-8eed28d4]{width:10rem!important}.el-form-item[data-v-3afdc5d4]{margin-bottom:1rem}.el-input-number--small[data-v-3afdc5d4]{width:10rem!important}.head .search>div[data-v-33dd67e0]{margin-right:1rem}.page[data-v-33dd67e0]{padding:2rem 0;display:inline-block}.el-form-item[data-v-33dd67e0]{margin-bottom:1rem}.el-input-number--small[data-v-33dd67e0]{width:10rem!important}.head .search>div[data-v-d3ca7ebe]{margin-right:1rem}.page[data-v-d3ca7ebe]{padding:2rem 0;display:inline-block}.el-form-item[data-v-d3ca7ebe]{margin-bottom:1rem}.el-input-number--small[data-v-d3ca7ebe]{width:10rem!important}.el-form-item[data-v-c2557c92]{margin-bottom:1rem}.el-input-number--small[data-v-c2557c92]{width:10rem!important}.blue[data-v-62bbb114]{color:#409eff}a.a-edit[data-v-62bbb114]{margin-left:1rem}a.a-edit .el-icon[data-v-62bbb114]{vertical-align:middle}.servers-wrap[data-v-60d7955e]{padding:1rem;font-size:1.3rem;color:#555}.servers-wrap a[data-v-60d7955e]{color:#333}
|
@@ -1 +1 @@
|
|||||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/><script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script><script defer="defer" src="js/chunk-vendors.81af7d4e.js"></script><script defer="defer" src="js/app.360c2592.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.f83ea0ab.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/><script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script><script defer="defer" src="js/chunk-vendors.81af7d4e.js"></script><script defer="defer" src="js/app.665d3555.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.f83ea0ab.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
File diff suppressed because one or more lines are too long
1
src/linker.app/public/web/js/159.d85691cc.js
Normal file
1
src/linker.app/public/web/js/159.d85691cc.js
Normal file
File diff suppressed because one or more lines are too long
1
src/linker.app/public/web/js/app.665d3555.js
Normal file
1
src/linker.app/public/web/js/app.665d3555.js
Normal file
File diff suppressed because one or more lines are too long
@@ -75,10 +75,10 @@ namespace linker.libs
|
|||||||
byte[] key = new byte[16];
|
byte[] key = new byte[16];
|
||||||
byte[] iv = new byte[16];
|
byte[] iv = new byte[16];
|
||||||
byte[] hash = SHA384.HashData(Encoding.UTF8.GetBytes(password));
|
byte[] hash = SHA384.HashData(Encoding.UTF8.GetBytes(password));
|
||||||
|
|
||||||
Array.Copy(hash, 0, key, 0, key.Length);
|
Array.Copy(hash, 0, key, 0, key.Length);
|
||||||
Array.Copy(hash, key.Length, iv, 0, iv.Length);
|
Array.Copy(hash, key.Length, iv, 0, iv.Length);
|
||||||
return (Key: key, IV: iv);
|
return (Key: key, IV: iv);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -20,8 +20,15 @@ namespace linker.messenger.store.file.relay
|
|||||||
{
|
{
|
||||||
this.dBfactory = dBfactory;
|
this.dBfactory = dBfactory;
|
||||||
liteCollection = dBfactory.GetCollection<CdkeyStoreInfo>("relayCdkey");
|
liteCollection = dBfactory.GetCollection<CdkeyStoreInfo>("relayCdkey");
|
||||||
this.crypto = CryptoFactory.CreateSymmetric(fileConfig.Data.Server.Relay.Cdkey.SecretKey, System.Security.Cryptography.PaddingMode.PKCS7);
|
|
||||||
this.fileConfig = fileConfig;
|
this.fileConfig = fileConfig;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(fileConfig.Data.Server.Relay.Cdkey.SecretKey) == false)
|
||||||
|
{
|
||||||
|
fileConfig.Data.Server.Cdkey.SecretKey = fileConfig.Data.Server.Relay.Cdkey.SecretKey;
|
||||||
|
fileConfig.Data.Server.Relay.Cdkey.SecretKey = string.Empty;
|
||||||
|
fileConfig.Data.Update();
|
||||||
|
}
|
||||||
|
this.crypto = CryptoFactory.CreateSymmetric(fileConfig.Data.Server.Cdkey.SecretKey, System.Security.Cryptography.PaddingMode.PKCS7);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ValidateSecretKey(string secretKey)
|
public bool ValidateSecretKey(string secretKey)
|
||||||
|
@@ -10,7 +10,7 @@ namespace linker.messenger.store.file
|
|||||||
public sealed partial class RunningConfigInfo
|
public sealed partial class RunningConfigInfo
|
||||||
{
|
{
|
||||||
public RelayInfo Relay { get; set; } = new RelayInfo();
|
public RelayInfo Relay { get; set; } = new RelayInfo();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class RelayInfo
|
public sealed class RelayInfo
|
||||||
@@ -49,7 +49,8 @@ namespace linker.messenger.store.file
|
|||||||
#else
|
#else
|
||||||
public string SecretKey { get; set; } = Guid.NewGuid().ToString().ToUpper();
|
public string SecretKey { get; set; } = Guid.NewGuid().ToString().ToUpper();
|
||||||
#endif
|
#endif
|
||||||
public CdkeyConfigInfo Cdkey { get; set; } = new CdkeyConfigInfo();
|
[SaveJsonIgnore]
|
||||||
|
public CdkeyConfigTempInfo Cdkey { get; set; } = new CdkeyConfigTempInfo();
|
||||||
|
|
||||||
public DistributedInfo Distributed { get; set; } = new DistributedInfo { };
|
public DistributedInfo Distributed { get; set; } = new DistributedInfo { };
|
||||||
}
|
}
|
||||||
@@ -59,4 +60,9 @@ namespace linker.messenger.store.file
|
|||||||
public RelayServerNodeInfo Node { get; set; } = new RelayServerNodeInfo { };
|
public RelayServerNodeInfo Node { get; set; } = new RelayServerNodeInfo { };
|
||||||
public RelayServerMasterInfo Master { get; set; } = new RelayServerMasterInfo { };
|
public RelayServerMasterInfo Master { get; set; } = new RelayServerMasterInfo { };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class CdkeyConfigTempInfo
|
||||||
|
{
|
||||||
|
public string SecretKey { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,6 @@ using System.Net;
|
|||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace linker.snat
|
namespace linker.snat
|
||||||
{
|
{
|
||||||
@@ -21,7 +20,7 @@ namespace linker.snat
|
|||||||
/// 4,改为 192.168.56.6(局域网IP)->10.18.18.23(客户端A的虚拟网卡IP)
|
/// 4,改为 192.168.56.6(局域网IP)->10.18.18.23(客户端A的虚拟网卡IP)
|
||||||
/// 5,回到客户端A,就完成了NAT
|
/// 5,回到客户端A,就完成了NAT
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class LinkerSrcNat
|
public sealed partial class LinkerSrcNat
|
||||||
{
|
{
|
||||||
public bool Running => winDivert != null;
|
public bool Running => winDivert != null;
|
||||||
|
|
||||||
@@ -30,13 +29,6 @@ namespace linker.snat
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private WinDivert winDivert;
|
private WinDivert winDivert;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 网卡IP,用来作为源地址
|
|
||||||
/// </summary>
|
|
||||||
private NetworkIPv4Addr interfaceAddr;
|
|
||||||
private HashSet<uint> interfaceAddrs;
|
|
||||||
|
|
||||||
|
|
||||||
private uint srcIp;
|
private uint srcIp;
|
||||||
private NetworkIPv4Addr srcAddr;
|
private NetworkIPv4Addr srcAddr;
|
||||||
|
|
||||||
@@ -54,11 +46,17 @@ namespace linker.snat
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 五元组NAT映射表
|
/// 五元组NAT映射表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private ConcurrentDictionary<(uint src, ushort srcPort, uint dst, ushort dstPort, ProtocolType pro), NatMapInfo> natMap = new ConcurrentDictionary<(uint src, ushort srcPort, uint dst, ushort dstPort, ProtocolType pro), NatMapInfo>();
|
private readonly ConcurrentDictionary<(uint src, ushort srcPort, uint dst, ushort dstPort, ProtocolType pro), NatMapInfo> natMap = new();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 分配端口表
|
/// 分配端口表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private ConcurrentDictionary<(uint src, ushort port), ushort> source2portMap = new ConcurrentDictionary<(uint src, ushort port), ushort>();
|
private readonly ConcurrentDictionary<(uint src, ushort port), ushort> source2portMap = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 网络接口
|
||||||
|
/// </summary>
|
||||||
|
private readonly LinkerSrcNatInterfaceHelper interfaceHelper = new();
|
||||||
|
|
||||||
|
|
||||||
public LinkerSrcNat()
|
public LinkerSrcNat()
|
||||||
{
|
{
|
||||||
@@ -70,10 +68,8 @@ namespace linker.snat
|
|||||||
/// <param name="info">启动参数</param>
|
/// <param name="info">启动参数</param>
|
||||||
/// <param name="error">false启动失败的时候会有报错信息</param>
|
/// <param name="error">false启动失败的时候会有报错信息</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool Setup(SetupInfo info, out string error)
|
public bool Setup(SetupInfo info, ref string error)
|
||||||
{
|
{
|
||||||
error = string.Empty;
|
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows() == false || (RuntimeInformation.ProcessArchitecture != Architecture.X86 && RuntimeInformation.ProcessArchitecture != Architecture.X64))
|
if (OperatingSystem.IsWindows() == false || (RuntimeInformation.ProcessArchitecture != Architecture.X86 && RuntimeInformation.ProcessArchitecture != Architecture.X64))
|
||||||
{
|
{
|
||||||
error = "only win x64 and win x86";
|
error = "only win x64 and win x86";
|
||||||
@@ -88,15 +84,6 @@ namespace linker.snat
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
IPAddress defaultInterfaceIP = GetDefaultInterface();
|
|
||||||
if (defaultInterfaceIP == null)
|
|
||||||
{
|
|
||||||
error = "SNAT get default interface id fail";
|
|
||||||
string routes = CommandHelper.Windows(string.Empty, new string[] { $"route print" });
|
|
||||||
LoggerHelper.Instance.Error(routes);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
interfaceAddrs = GetInterfaces();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -105,12 +92,11 @@ namespace linker.snat
|
|||||||
srcIp = NetworkHelper.ToValue(info.Src);
|
srcIp = NetworkHelper.ToValue(info.Src);
|
||||||
srcAddr = IPv4Addr.Parse(info.Src.ToString());
|
srcAddr = IPv4Addr.Parse(info.Src.ToString());
|
||||||
|
|
||||||
interfaceAddr = IPv4Addr.Parse(defaultInterfaceIP.ToString());
|
interfaceHelper.Setup();
|
||||||
string filters = BuildFilter(info.Dsts);
|
string filters = BuildFilter(info.Dsts);
|
||||||
winDivert = new WinDivert(filters, WinDivert.Layer.Network, 0, 0);
|
winDivert = new WinDivert(filters, WinDivert.Layer.Network, 0, 0);
|
||||||
|
|
||||||
cts = new CancellationTokenSource();
|
cts = new CancellationTokenSource();
|
||||||
|
|
||||||
Recv(cts);
|
Recv(cts);
|
||||||
ClearTask(cts);
|
ClearTask(cts);
|
||||||
|
|
||||||
@@ -122,34 +108,6 @@ namespace linker.snat
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
private static IPAddress GetDefaultInterface()
|
|
||||||
{
|
|
||||||
string[] lines = CommandHelper.Windows(string.Empty, new string[] { $"route print" }).Split(Environment.NewLine);
|
|
||||||
foreach (var item in lines)
|
|
||||||
{
|
|
||||||
if (item.Trim().StartsWith("0.0.0.0"))
|
|
||||||
{
|
|
||||||
string[] arr = Regex.Replace(item.Trim(), @"\s+", " ").Split(' ');
|
|
||||||
return IPAddress.Parse(arr[arr.Length - 2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
private static HashSet<uint> GetInterfaces()
|
|
||||||
{
|
|
||||||
return NetworkInterface.GetAllNetworkInterfaces().Select(c =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return c.GetIPProperties().UnicastAddresses.FirstOrDefault(c => c.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).Address;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}).Where(c => c != null).Select(NetworkHelper.ToValue).ToHashSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 过滤条件,只过滤一定的数据包
|
/// 过滤条件,只过滤一定的数据包
|
||||||
@@ -159,7 +117,6 @@ namespace linker.snat
|
|||||||
{
|
{
|
||||||
IEnumerable<string> ipRanges = dsts.Select(c => $"(ip.SrcAddr >= {c.NetworkIP} and ip.SrcAddr <= {c.BroadcastIP})");
|
IEnumerable<string> ipRanges = dsts.Select(c => $"(ip.SrcAddr >= {c.NetworkIP} and ip.SrcAddr <= {c.BroadcastIP})");
|
||||||
return $"inbound and ({string.Join(" or ", ipRanges)})";
|
return $"inbound and ({string.Join(" or ", ipRanges)})";
|
||||||
//return $"({string.Join(" or ", ipRanges)})";
|
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 开始接收数据包
|
/// 开始接收数据包
|
||||||
@@ -241,14 +198,14 @@ namespace linker.snat
|
|||||||
{
|
{
|
||||||
foreach (var (i, p) in new WinDivertIndexedPacketParser(packet))
|
foreach (var (i, p) in new WinDivertIndexedPacketParser(packet))
|
||||||
{
|
{
|
||||||
//本机网卡IP不需要改,直接注入就可以
|
NetworkIPv4Addr interfaceAddr = interfaceHelper.GetInterfaceAddr(ipv4.DstAddr);
|
||||||
if (interfaceAddrs.Contains(ipv4.DstAddr) == false)
|
if (interfaceAddr.Raw != 0)
|
||||||
{
|
{
|
||||||
bool result = (ProtocolType)p.IPv4Hdr->Protocol switch
|
bool result = (ProtocolType)p.IPv4Hdr->Protocol switch
|
||||||
{
|
{
|
||||||
ProtocolType.Icmp => InjectIcmp(p, ptr),
|
ProtocolType.Icmp => InjectIcmp(p, ptr, interfaceAddr),
|
||||||
ProtocolType.Tcp => InjectTcp(p, ptr),
|
ProtocolType.Tcp => InjectTcp(p, ptr, interfaceAddr),
|
||||||
ProtocolType.Udp => InjectUdp(p, ptr),
|
ProtocolType.Udp => InjectUdp(p, ptr, interfaceAddr),
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if (result == false) return false;
|
if (result == false) return false;
|
||||||
@@ -263,13 +220,14 @@ namespace linker.snat
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 注入ICMP
|
/// 注入ICMP
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="p"></param>
|
/// <param name="p"></param>
|
||||||
/// <param name="ptr"></param>
|
/// <param name="ptr"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private unsafe bool InjectIcmp(WinDivertParseResult p, byte* ptr)
|
private unsafe bool InjectIcmp(WinDivertParseResult p, byte* ptr, NetworkIPv4Addr interfaceAddr)
|
||||||
{
|
{
|
||||||
//只操作response 和 request
|
//只操作response 和 request
|
||||||
if (p.ICMPv4Hdr->Type != 0 && p.ICMPv4Hdr->Type != 8) return false;
|
if (p.ICMPv4Hdr->Type != 0 && p.ICMPv4Hdr->Type != 8) return false;
|
||||||
@@ -342,7 +300,7 @@ namespace linker.snat
|
|||||||
/// <param name="p"></param>
|
/// <param name="p"></param>
|
||||||
/// <param name="ptr"></param>
|
/// <param name="ptr"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private unsafe bool InjectTcp(WinDivertParseResult p, byte* ptr)
|
private unsafe bool InjectTcp(WinDivertParseResult p, byte* ptr, NetworkIPv4Addr interfaceAddr)
|
||||||
{
|
{
|
||||||
IPV4Packet ipv4 = new IPV4Packet(ptr);
|
IPV4Packet ipv4 = new IPV4Packet(ptr);
|
||||||
|
|
||||||
@@ -410,7 +368,7 @@ namespace linker.snat
|
|||||||
/// <param name="p"></param>
|
/// <param name="p"></param>
|
||||||
/// <param name="ptr"></param>
|
/// <param name="ptr"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private unsafe bool InjectUdp(WinDivertParseResult p, byte* ptr)
|
private unsafe bool InjectUdp(WinDivertParseResult p, byte* ptr, NetworkIPv4Addr interfaceAddr)
|
||||||
{
|
{
|
||||||
//新端口
|
//新端口
|
||||||
ValueTuple<uint, ushort> portKey = (p.IPv4Hdr->SrcAddr.Raw, p.UDPHdr->SrcPort);
|
ValueTuple<uint, ushort> portKey = (p.IPv4Hdr->SrcAddr.Raw, p.UDPHdr->SrcPort);
|
||||||
@@ -481,6 +439,8 @@ namespace linker.snat
|
|||||||
|
|
||||||
natMap.Clear();
|
natMap.Clear();
|
||||||
source2portMap.Clear();
|
source2portMap.Clear();
|
||||||
|
|
||||||
|
interfaceHelper.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearTask(CancellationTokenSource cts)
|
private void ClearTask(CancellationTokenSource cts)
|
||||||
@@ -663,16 +623,61 @@ namespace linker.snat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
}
|
||||||
/// SNAT回调
|
|
||||||
/// </summary>
|
public sealed class LinkerSrcNatInterfaceHelper
|
||||||
public interface ILinkerSNatRecvCallback
|
{
|
||||||
|
private uint[] interfaceMasks = [];
|
||||||
|
private readonly ConcurrentDictionary<uint, (uint, NetworkIPv4Addr)> network2ipMap = new();
|
||||||
|
private readonly ConcurrentDictionary<uint, NetworkIPv4Addr> ip2ipMap = new();
|
||||||
|
|
||||||
|
public void Setup()
|
||||||
{
|
{
|
||||||
/// <summary>
|
Shutdown();
|
||||||
/// 接收到的TCP/IP数据包
|
List<(IPAddress Address, IPAddress IPv4Mask)> interfaces = NetworkInterface.GetAllNetworkInterfaces()
|
||||||
/// </summary>
|
.Where(c => c.OperationalStatus == OperationalStatus.Up && c.NetworkInterfaceType != NetworkInterfaceType.Loopback && c.NetworkInterfaceType != NetworkInterfaceType.Tunnel)
|
||||||
/// <param name="packet"></param>
|
.Select(c => c.GetIPProperties()).SelectMany(c => c.UnicastAddresses.Where(c => c.Address.AddressFamily == AddressFamily.InterNetwork).Select(c => (c.Address, c.IPv4Mask))).ToList();
|
||||||
public void Recv(ReadOnlyMemory<byte> packet);
|
|
||||||
|
interfaceMasks = interfaces.Select(c => NetworkHelper.ToValue(c.IPv4Mask)).Distinct().ToArray();
|
||||||
|
foreach ((IPAddress Address, IPAddress IPv4Mask) in interfaces)
|
||||||
|
{
|
||||||
|
uint value = NetworkHelper.ToValue(Address);
|
||||||
|
uint network = NetworkHelper.ToNetworkValue(value, NetworkHelper.ToValue(IPv4Mask));
|
||||||
|
network2ipMap.TryAdd(network, (value, IPv4Addr.Parse(Address.ToString())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetworkIPv4Addr GetInterfaceAddr(uint dstAddr)
|
||||||
|
{
|
||||||
|
if (ip2ipMap.TryGetValue(dstAddr, out NetworkIPv4Addr interfaceAddr))
|
||||||
|
{
|
||||||
|
return interfaceAddr;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < interfaceMasks.Length; i++)
|
||||||
|
{
|
||||||
|
//找到匹配的网卡
|
||||||
|
if (network2ipMap.TryGetValue(interfaceMasks[i] & dstAddr, out (uint, NetworkIPv4Addr) info))
|
||||||
|
{
|
||||||
|
//目标ip与网卡ip相同,无需注入
|
||||||
|
if (info.Item1 == dstAddr)
|
||||||
|
{
|
||||||
|
ip2ipMap.TryAdd(dstAddr, default);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip2ipMap.TryAdd(dstAddr, info.Item2);
|
||||||
|
return info.Item2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Shutdown()
|
||||||
|
{
|
||||||
|
ip2ipMap.Clear();
|
||||||
|
network2ipMap.Clear();
|
||||||
|
interfaceMasks = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.301" ProductVersion="0.0.0.301" publishDir="/dist/" dstrip="false" local="false" ignored="false">
|
<project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.302" ProductVersion="0.0.0.302" publishDir="/dist/" dstrip="false" local="false" ignored="false">
|
||||||
<file name="main.aardio" path="main.aardio" comment="main.aardio"/>
|
<file name="main.aardio" path="main.aardio" comment="main.aardio"/>
|
||||||
<folder name="资源文件" path="res" embed="true" local="false" ignored="false">
|
<folder name="资源文件" path="res" embed="true" local="false" ignored="false">
|
||||||
<file name="favicon.ico" path="res\favicon.ico" comment="res\favicon.ico"/>
|
<file name="favicon.ico" path="res\favicon.ico" comment="res\favicon.ico"/>
|
||||||
|
BIN
src/linker.tray.win/dist/linker.tray.win.exe
vendored
BIN
src/linker.tray.win/dist/linker.tray.win.exe
vendored
Binary file not shown.
1
src/linker.tray.win/web/css/118.be8a94f0.css
Normal file
1
src/linker.tray.win/web/css/118.be8a94f0.css
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.el-radio-group[data-v-3927a588]{margin-right:.6rem}.wrap[data-v-3927a588]{padding-bottom:1rem}.el-form-item[data-v-8eed28d4]{margin-bottom:1rem}.el-input-number--small[data-v-8eed28d4]{width:10rem!important}.el-form-item[data-v-3afdc5d4]{margin-bottom:1rem}.el-input-number--small[data-v-3afdc5d4]{width:10rem!important}.head .search>div[data-v-33dd67e0]{margin-right:1rem}.page[data-v-33dd67e0]{padding:2rem 0;display:inline-block}.el-form-item[data-v-33dd67e0]{margin-bottom:1rem}.el-input-number--small[data-v-33dd67e0]{width:10rem!important}.head .search>div[data-v-d3ca7ebe]{margin-right:1rem}.page[data-v-d3ca7ebe]{padding:2rem 0;display:inline-block}.el-form-item[data-v-d3ca7ebe]{margin-bottom:1rem}.el-input-number--small[data-v-d3ca7ebe]{width:10rem!important}.el-form-item[data-v-c2557c92]{margin-bottom:1rem}.el-input-number--small[data-v-c2557c92]{width:10rem!important}.blue[data-v-62bbb114]{color:#409eff}a.a-edit[data-v-62bbb114]{margin-left:1rem}a.a-edit .el-icon[data-v-62bbb114]{vertical-align:middle}.servers-wrap[data-v-60d7955e]{padding:1rem;font-size:1.3rem;color:#555}.servers-wrap a[data-v-60d7955e]{color:#333}
|
@@ -1 +0,0 @@
|
|||||||
.el-radio-group[data-v-7061404c]{margin-right:.6rem}.wrap[data-v-7061404c]{padding-bottom:1rem}.el-form-item[data-v-2bef0d8e]{margin-bottom:1rem}.el-input-number--small[data-v-2bef0d8e]{width:10rem!important}.el-form-item[data-v-3d96703d]{margin-bottom:1rem}.el-input-number--small[data-v-3d96703d]{width:10rem!important}.head .search>div[data-v-5d11d068]{margin-right:1rem}.page[data-v-5d11d068]{padding:2rem 0;display:inline-block}.el-form-item[data-v-5d11d068]{margin-bottom:1rem}.el-input-number--small[data-v-5d11d068]{width:10rem!important}.head .search>div[data-v-22d5523e]{margin-right:1rem}.page[data-v-22d5523e]{padding:2rem 0;display:inline-block}.el-form-item[data-v-22d5523e]{margin-bottom:1rem}.el-input-number--small[data-v-22d5523e]{width:10rem!important}.el-form-item[data-v-c2557c92]{margin-bottom:1rem}.el-input-number--small[data-v-c2557c92]{width:10rem!important}.blue[data-v-1c91b9a3]{color:#409eff}a.a-edit[data-v-1c91b9a3]{margin-left:1rem}a.a-edit .el-icon[data-v-1c91b9a3]{vertical-align:middle}.servers-wrap[data-v-60d7955e]{padding:1rem;font-size:1.3rem;color:#555}.servers-wrap a[data-v-60d7955e]{color:#333}
|
|
@@ -1 +1 @@
|
|||||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/><script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script><script defer="defer" src="js/chunk-vendors.81af7d4e.js"></script><script defer="defer" src="js/app.360c2592.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.f83ea0ab.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/><script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script><script defer="defer" src="js/chunk-vendors.81af7d4e.js"></script><script defer="defer" src="js/app.665d3555.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.f83ea0ab.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
277
src/linker.tray.win/web/js/118.16573c08.js
Normal file
277
src/linker.tray.win/web/js/118.16573c08.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/linker.tray.win/web/js/159.d85691cc.js
Normal file
1
src/linker.tray.win/web/js/159.d85691cc.js
Normal file
File diff suppressed because one or more lines are too long
1
src/linker.tray.win/web/js/212.2cb1147b.js
Normal file
1
src/linker.tray.win/web/js/212.2cb1147b.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/linker.tray.win/web/js/app.665d3555.js
Normal file
1
src/linker.tray.win/web/js/app.665d3555.js
Normal file
File diff suppressed because one or more lines are too long
@@ -10,7 +10,7 @@ namespace linker.tun
|
|||||||
public bool Running => linkerSrcNat.Running;
|
public bool Running => linkerSrcNat.Running;
|
||||||
|
|
||||||
private LinkerSrcNat linkerSrcNat = new LinkerSrcNat();
|
private LinkerSrcNat linkerSrcNat = new LinkerSrcNat();
|
||||||
|
|
||||||
|
|
||||||
public LanSnat()
|
public LanSnat()
|
||||||
{
|
{
|
||||||
@@ -40,8 +40,9 @@ namespace linker.tun
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
LoggerHelper.Instance.Error(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Shutdown();
|
Shutdown();
|
||||||
@@ -49,7 +50,7 @@ namespace linker.tun
|
|||||||
{
|
{
|
||||||
Src = address,
|
Src = address,
|
||||||
Dsts = items.Select(c => new LinkerSrcNat.AddrInfo(c.IP, c.PrefixLength)).ToArray()
|
Dsts = items.Select(c => new LinkerSrcNat.AddrInfo(c.IP, c.PrefixLength)).ToArray()
|
||||||
}, out error);
|
}, ref error);
|
||||||
}
|
}
|
||||||
public void Shutdown()
|
public void Shutdown()
|
||||||
{
|
{
|
||||||
|
@@ -206,7 +206,9 @@ namespace linker.tun
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (linkerTunDevice.Running)
|
if (linkerTunDevice.Running)
|
||||||
|
{
|
||||||
lanSnat.Setup(address, prefixLength, items, ref natError);
|
lanSnat.Setup(address, prefixLength, items, ref natError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除NAT
|
/// 移除NAT
|
||||||
|
@@ -21,9 +21,10 @@
|
|||||||
<Authors>snltty</Authors>
|
<Authors>snltty</Authors>
|
||||||
<Company>snltty</Company>
|
<Company>snltty</Company>
|
||||||
<Description>1. 一些累计更新
|
<Description>1. 一些累计更新
|
||||||
2. 修复socks5,解决CPU爆满问题,增加域名解析和HTTP代理
|
2. 修复socks5,解决CPU爆满问题,增加本地域名解析,支持HTTP代理
|
||||||
3. 优化唤醒模块
|
3. 优化唤醒模块
|
||||||
5. 管理端口改为1804,一个端口托管Web+Websocket</Description>
|
4. 优化应用NAT,根据目标IP自动选择网卡
|
||||||
|
5. 分离cdkey,使其可作用于任意模块</Description>
|
||||||
<Copyright>snltty</Copyright>
|
<Copyright>snltty</Copyright>
|
||||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
v1.8.3
|
v1.8.3
|
||||||
2025-06-10 17:28:53
|
2025-06-13 10:47:48
|
||||||
1. 一些累计更新
|
1. 一些累计更新
|
||||||
2. 修复socks5,解决CPU爆满问题,增加域名解析和HTTP代理
|
2. 修复socks5,解决CPU爆满问题,增加本地域名解析,支持HTTP代理
|
||||||
3. 优化唤醒模块
|
3. 优化唤醒模块
|
||||||
5. 管理端口改为1804,一个端口托管Web+Websocket
|
4. 优化应用NAT,根据目标IP自动选择网卡
|
||||||
|
5. 分离cdkey,使其可作用于任意模块
|
Reference in New Issue
Block a user