mirror of
https://github.com/snltty/linker.git
synced 2025-10-05 01:02:44 +08:00
app
This commit is contained in:
@@ -92,6 +92,8 @@ namespace linker.app
|
|||||||
[Service(Label = "VpnServiceLinker", Name = "com.snltty.linker.app.VpnServiceLinker", Enabled = true, Permission = "android.permission.BIND_VPN_SERVICE")]
|
[Service(Label = "VpnServiceLinker", Name = "com.snltty.linker.app.VpnServiceLinker", Enabled = true, Permission = "android.permission.BIND_VPN_SERVICE")]
|
||||||
public class VpnServiceLinker : VpnService, ILinkerTunDeviceCallback, ITuntapProxyCallback
|
public class VpnServiceLinker : VpnService, ILinkerTunDeviceCallback, ITuntapProxyCallback
|
||||||
{
|
{
|
||||||
|
private static LinkerVpnDevice linkerVpnDevice = new LinkerVpnDevice();
|
||||||
|
|
||||||
TuntapConfigTransfer tuntapConfigTransfer;
|
TuntapConfigTransfer tuntapConfigTransfer;
|
||||||
TuntapProxy tuntapProxy;
|
TuntapProxy tuntapProxy;
|
||||||
TuntapDecenter tuntapDecenter;
|
TuntapDecenter tuntapDecenter;
|
||||||
@@ -105,7 +107,8 @@ namespace linker.app
|
|||||||
tuntapProxy.Callback = this;
|
tuntapProxy.Callback = this;
|
||||||
tuntapDecenter = LinkerMessengerEntry.GetService<TuntapDecenter>();
|
tuntapDecenter = LinkerMessengerEntry.GetService<TuntapDecenter>();
|
||||||
|
|
||||||
tuntapTransfer.Initialize(new LinkerVpnDevice(this), this);
|
linkerVpnDevice.SetVpnService(this);
|
||||||
|
tuntapTransfer.Initialize(linkerVpnDevice, this);
|
||||||
}
|
}
|
||||||
public override void OnCreate()
|
public override void OnCreate()
|
||||||
{
|
{
|
||||||
@@ -298,7 +301,13 @@ namespace linker.app
|
|||||||
FileInputStream vpnInput;
|
FileInputStream vpnInput;
|
||||||
FileOutputStream vpnOutput;
|
FileOutputStream vpnOutput;
|
||||||
|
|
||||||
public LinkerVpnDevice(VpnService vpnService)
|
LinkerTunDeviceRouteItem[] routes = [];
|
||||||
|
|
||||||
|
public LinkerVpnDevice()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetVpnService(VpnService vpnService)
|
||||||
{
|
{
|
||||||
this.vpnService = vpnService;
|
this.vpnService = vpnService;
|
||||||
}
|
}
|
||||||
@@ -317,6 +326,12 @@ namespace linker.app
|
|||||||
builder.SetMtu(1420)
|
builder.SetMtu(1420)
|
||||||
.AddAddress(address.ToString(), prefixLength)
|
.AddAddress(address.ToString(), prefixLength)
|
||||||
.AddDnsServer("8.8.8.8").SetBlocking(false);
|
.AddDnsServer("8.8.8.8").SetBlocking(false);
|
||||||
|
|
||||||
|
foreach (var item in routes)
|
||||||
|
{
|
||||||
|
builder.AddRoute(NetworkHelper.ToNetworkIP(item.Address, item.PrefixLength).ToString(), item.PrefixLength);
|
||||||
|
}
|
||||||
|
|
||||||
if (OperatingSystem.IsAndroidVersionAtLeast(29))
|
if (OperatingSystem.IsAndroidVersionAtLeast(29))
|
||||||
builder.SetMetered(false);
|
builder.SetMetered(false);
|
||||||
vpnInterface = builder.SetSession(name).Establish();
|
vpnInterface = builder.SetSession(name).Establish();
|
||||||
@@ -350,10 +365,11 @@ namespace linker.app
|
|||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
return buffer;
|
return Helper.EmptyArray;
|
||||||
}
|
}
|
||||||
public bool Write(ReadOnlyMemory<byte> buffer)
|
public bool Write(ReadOnlyMemory<byte> buffer)
|
||||||
{
|
{
|
||||||
|
if (fd == 0) return false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
buffer.CopyTo(bufferWrite);
|
buffer.CopyTo(bufferWrite);
|
||||||
@@ -409,6 +425,7 @@ namespace linker.app
|
|||||||
|
|
||||||
public void AddRoute(LinkerTunDeviceRouteItem[] ips)
|
public void AddRoute(LinkerTunDeviceRouteItem[] ips)
|
||||||
{
|
{
|
||||||
|
routes = ips.Select(c => new LinkerTunDeviceRouteItem { Address = c.Address, PrefixLength = c.PrefixLength }).ToArray();
|
||||||
}
|
}
|
||||||
public void RemoveRoute(LinkerTunDeviceRouteItem[] ips)
|
public void RemoveRoute(LinkerTunDeviceRouteItem[] ips)
|
||||||
{
|
{
|
||||||
|
@@ -296,7 +296,11 @@ namespace linker.libs
|
|||||||
|
|
||||||
public static IPAddress ToNetworkIP(IPAddress ip, uint prefixIP)
|
public static IPAddress ToNetworkIP(IPAddress ip, uint prefixIP)
|
||||||
{
|
{
|
||||||
return ToNetworkIP(BinaryPrimitives.ReadUInt32BigEndian(ip.GetAddressBytes()), prefixIP);
|
return ToNetworkIP(ToValue(ip), prefixIP);
|
||||||
|
}
|
||||||
|
public static IPAddress ToNetworkIP(IPAddress ip, byte prefixLength)
|
||||||
|
{
|
||||||
|
return ToNetworkIP(ToValue(ip), ToPrefixValue(prefixLength));
|
||||||
}
|
}
|
||||||
public static IPAddress ToNetworkIP(uint ip, uint prefixIP)
|
public static IPAddress ToNetworkIP(uint ip, uint prefixIP)
|
||||||
{
|
{
|
||||||
|
@@ -1,15 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<template v-if="tuntap.list[item.MachineId] && tuntap.list[item.MachineId].system">
|
|
||||||
<span :title="tuntap.list[item.MachineId].SystemInfo">
|
|
||||||
<img class="system":src="`./${tuntap.list[item.MachineId].system}.svg`" />
|
|
||||||
<img v-if="tuntap.list[item.MachineId].systemDocker" class="system" :src="`./docker.svg`" />
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<a href="javascript:;" @click="handleEdit" title="此客户端的设备名" class="a-line">
|
<a href="javascript:;" @click="handleEdit" title="此客户端的设备名" class="a-line">
|
||||||
<strong class="gateway" :class="{green:item.Connected}">{{item.MachineName || 'null' }}</strong>
|
<strong class="gateway" :class="{green:item.Connected}">{{item.MachineName || 'null' }}</strong>
|
||||||
</a>
|
</a>
|
||||||
<strong class="self gateway" v-if="item.isSelf">(<el-icon size="16"><StarFilled /></el-icon>) </strong>
|
<strong class="self gateway" v-if="item.isSelf">(<el-icon size="16"><StarFilled /></el-icon>) </strong>
|
||||||
|
<template v-if="tuntap.list[item.MachineId] && tuntap.list[item.MachineId].systems">
|
||||||
|
<template v-for="system in tuntap.list[item.MachineId].systems">
|
||||||
|
<span :title="tuntap.list[item.MachineId].SystemInfo">
|
||||||
|
<img class="system":src="`./${system}.svg`" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@ export default {
|
|||||||
img.system{
|
img.system{
|
||||||
height:1.6rem;
|
height:1.6rem;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-right:.4rem
|
margin-left:.4rem
|
||||||
}
|
}
|
||||||
.self{
|
.self{
|
||||||
color:#d400ff;
|
color:#d400ff;
|
||||||
|
@@ -15,15 +15,7 @@ export const provideTuntap = () => {
|
|||||||
});
|
});
|
||||||
provide(tuntapSymbol, tuntap);
|
provide(tuntapSymbol, tuntap);
|
||||||
|
|
||||||
const systems = {
|
const reg = /ios|android|windows|ubuntu|openwrt|armbian|archlinux|fedora|centos|rocky|alpine|debian|linux|docker/g;
|
||||||
linux: ['debian', 'ubuntu', 'alpine', 'rocky', 'centos', 'fedora', 'archlinux'],
|
|
||||||
armbian: ['armbian'],
|
|
||||||
openwrt: ['openwrt'],
|
|
||||||
ubuntu: ['ubuntu'],
|
|
||||||
windows: ['windows'],
|
|
||||||
android: ['android'],
|
|
||||||
ios: ['ios'],
|
|
||||||
}
|
|
||||||
|
|
||||||
const _getTuntapInfo = () => {
|
const _getTuntapInfo = () => {
|
||||||
clearTimeout(tuntap.value.timer);
|
clearTimeout(tuntap.value.timer);
|
||||||
@@ -31,29 +23,13 @@ export const provideTuntap = () => {
|
|||||||
tuntap.value.hashcode = res.HashCode;
|
tuntap.value.hashcode = res.HashCode;
|
||||||
if (res.List) {
|
if (res.List) {
|
||||||
for (let j in res.List) {
|
for (let j in res.List) {
|
||||||
let system = 'system';
|
|
||||||
const systemStr = res.List[j].SystemInfo.toLowerCase();
|
const systemStr = res.List[j].SystemInfo.toLowerCase();
|
||||||
for (let jj in systems) {
|
|
||||||
if (systemStr.indexOf(jj) >= 0) {
|
const match = systemStr.match(reg);
|
||||||
const items = systems[jj];
|
|
||||||
if (items.length == 1) {
|
|
||||||
system = items[0];
|
|
||||||
} else {
|
|
||||||
for (let i = 0; i < items.length; i++) {
|
|
||||||
if (systemStr.indexOf(items[i]) >= 0) {
|
|
||||||
system = items[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Object.assign(res.List[j], {
|
Object.assign(res.List[j], {
|
||||||
running: res.List[j].Status == 2,
|
running: res.List[j].Status == 2,
|
||||||
loading: res.List[j].Status == 1,
|
loading: res.List[j].Status == 1,
|
||||||
system: system,
|
systems: match
|
||||||
systemDocker: systemStr.indexOf('docker') >= 0,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
tuntap.value.list = res.List;
|
tuntap.value.list = res.List;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
v1.7.4
|
v1.7.4
|
||||||
2025-04-23 23:28:20
|
2025-04-24 00:55:37
|
||||||
1. 一些优化
|
1. 一些优化
|
||||||
2. 内置应用层SNAT,用于无法使用系统NetNat的windows系统
|
2. 内置应用层SNAT,用于无法使用系统NetNat的windows系统
|
||||||
3. 如果你设备很多,请尝试升级其中一个成功重启后再升级其它
|
3. 如果你设备很多,请尝试升级其中一个成功重启后再升级其它
|
Reference in New Issue
Block a user