This commit is contained in:
snltty
2025-05-06 14:14:16 +08:00
parent 6251141b1c
commit 06f3ee4256
54 changed files with 748 additions and 306 deletions

2
.gitignore vendored
View File

@@ -5,6 +5,6 @@ obj
node_modules
/public/*
/x64/*
/src/linker.share.win/*
TestResults

View File

@@ -57,15 +57,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "linker.messenger.flow", "sr
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "linker.messenger.tuntap", "src\linker.messenger.tuntap\linker.messenger.tuntap.csproj", "{172C6E79-B47C-49E0-9731-6C12CCA071F7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "linker.messenger.serializer.aot", "src\linker.messenger.serializer.aot\linker.messenger.serializer.aot.csproj", "{0538DDF8-346F-48DE-84DF-AEF3EEBE03EA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "linker.app", "src\linker.app\linker.app.csproj", "{60FFFE21-C8F2-4B3A-BB49-7FA2AE31C2B0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "linker.ics", "src\linker.ics\linker.ics.csproj", "{BBE91688-7734-4BEF-B957-54F8C17F47CE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "linker.messenger.plan", "src\linker.messenger.plan\linker.messenger.plan.csproj", "{5649D02E-200B-45E0-A82F-8EBE76CF96C6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "linker.snat", "src\linker.snat\linker.snat.csproj", "{A1EA64AA-8C30-4616-B65D-8AF07641807E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "linker.snat", "src\linker.snat\linker.snat.csproj", "{A1EA64AA-8C30-4616-B65D-8AF07641807E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "linker.messenger.firewall", "src\linker.messenger.firewall\linker.messenger.firewall.csproj", "{F97DB5A9-3807-4441-A520-7B1211C1CE8A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -401,18 +401,6 @@ Global
{172C6E79-B47C-49E0-9731-6C12CCA071F7}.Release|x64.Build.0 = Release|Any CPU
{172C6E79-B47C-49E0-9731-6C12CCA071F7}.Release|x86.ActiveCfg = Release|Any CPU
{172C6E79-B47C-49E0-9731-6C12CCA071F7}.Release|x86.Build.0 = Release|Any CPU
{0538DDF8-346F-48DE-84DF-AEF3EEBE03EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0538DDF8-346F-48DE-84DF-AEF3EEBE03EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0538DDF8-346F-48DE-84DF-AEF3EEBE03EA}.Debug|x64.ActiveCfg = Debug|Any CPU
{0538DDF8-346F-48DE-84DF-AEF3EEBE03EA}.Debug|x64.Build.0 = Debug|Any CPU
{0538DDF8-346F-48DE-84DF-AEF3EEBE03EA}.Debug|x86.ActiveCfg = Debug|Any CPU
{0538DDF8-346F-48DE-84DF-AEF3EEBE03EA}.Debug|x86.Build.0 = Debug|Any CPU
{0538DDF8-346F-48DE-84DF-AEF3EEBE03EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0538DDF8-346F-48DE-84DF-AEF3EEBE03EA}.Release|Any CPU.Build.0 = Release|Any CPU
{0538DDF8-346F-48DE-84DF-AEF3EEBE03EA}.Release|x64.ActiveCfg = Release|Any CPU
{0538DDF8-346F-48DE-84DF-AEF3EEBE03EA}.Release|x64.Build.0 = Release|Any CPU
{0538DDF8-346F-48DE-84DF-AEF3EEBE03EA}.Release|x86.ActiveCfg = Release|Any CPU
{0538DDF8-346F-48DE-84DF-AEF3EEBE03EA}.Release|x86.Build.0 = Release|Any CPU
{60FFFE21-C8F2-4B3A-BB49-7FA2AE31C2B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{60FFFE21-C8F2-4B3A-BB49-7FA2AE31C2B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60FFFE21-C8F2-4B3A-BB49-7FA2AE31C2B0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
@@ -467,6 +455,18 @@ Global
{A1EA64AA-8C30-4616-B65D-8AF07641807E}.Release|x64.Build.0 = Release|Any CPU
{A1EA64AA-8C30-4616-B65D-8AF07641807E}.Release|x86.ActiveCfg = Release|Any CPU
{A1EA64AA-8C30-4616-B65D-8AF07641807E}.Release|x86.Build.0 = Release|Any CPU
{F97DB5A9-3807-4441-A520-7B1211C1CE8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F97DB5A9-3807-4441-A520-7B1211C1CE8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F97DB5A9-3807-4441-A520-7B1211C1CE8A}.Debug|x64.ActiveCfg = Debug|Any CPU
{F97DB5A9-3807-4441-A520-7B1211C1CE8A}.Debug|x64.Build.0 = Debug|Any CPU
{F97DB5A9-3807-4441-A520-7B1211C1CE8A}.Debug|x86.ActiveCfg = Debug|Any CPU
{F97DB5A9-3807-4441-A520-7B1211C1CE8A}.Debug|x86.Build.0 = Debug|Any CPU
{F97DB5A9-3807-4441-A520-7B1211C1CE8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F97DB5A9-3807-4441-A520-7B1211C1CE8A}.Release|Any CPU.Build.0 = Release|Any CPU
{F97DB5A9-3807-4441-A520-7B1211C1CE8A}.Release|x64.ActiveCfg = Release|Any CPU
{F97DB5A9-3807-4441-A520-7B1211C1CE8A}.Release|x64.Build.0 = Release|Any CPU
{F97DB5A9-3807-4441-A520-7B1211C1CE8A}.Release|x86.ActiveCfg = Release|Any CPU
{F97DB5A9-3807-4441-A520-7B1211C1CE8A}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -296,7 +296,6 @@ namespace linker.app
private string name = string.Empty;
public string Name => name;
public bool Running => fd != 0;
public bool AppNat => false;
private IPAddress address;
private byte prefixLength = 24;
@@ -416,13 +415,10 @@ namespace linker.app
public void SetMtu(int value)
{
}
public void SetSystemNat(out string error)
public void SetNat(out string error)
{
error = string.Empty;
}
public void SetAppNat(LinkerTunAppNatItemInfo[] items, ref string error)
{
}
public void RemoveNat(out string error)
{
error = string.Empty;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -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.cfba5739.js"></script><script defer="defer" src="js/app.ff827304.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.046a563b.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.cfba5739.js"></script><script defer="defer" src="js/app.6c05d4d4.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.09dcc3e8.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

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
"use strict";(self["webpackChunklinker_web"]=self["webpackChunklinker_web"]||[]).push([[239],{7332:function(e,n,a){a.r(n),a.d(n,{default:function(){return O}});var t=a(6768);const s={class:"net-wrap app-wrap"},l={class:"inner absolute flex flex-column flex-nowrap"},i={class:"head"},o={class:"body flex-1 relative"},c={class:"status"};function r(e,n,a,r,u,d){const g=(0,t.g2)("Head"),p=(0,t.g2)("List"),v=(0,t.g2)("Status");return(0,t.uX)(),(0,t.CE)("div",s,[(0,t.Lk)("div",l,[(0,t.Lk)("div",i,[(0,t.bF)(g)]),(0,t.Lk)("div",o,[(0,t.bF)(p)]),(0,t.Lk)("div",c,[(0,t.bF)(v,{config:!1})])])])}a(4114);var u=a(4232);const d=e=>((0,t.Qi)("data-v-6bfe19a3"),e=e(),(0,t.jt)(),e),g={class:"head-wrap"},p={class:"tools flex"},v={class:"label"},h=d((()=>(0,t.Lk)("span",{class:"flex-1"},null,-1))),f={style:{"margin-left":"1rem"}};function k(e,n,a,s,l,i){const o=(0,t.g2)("Refresh"),c=(0,t.g2)("el-icon"),r=(0,t.g2)("el-button"),d=(0,t.g2)("Background");return(0,t.uX)(),(0,t.CE)("div",g,[(0,t.Lk)("div",p,[(0,t.Lk)("span",v,"分组 : "+(0,u.v_)(s.state.group),1),h,(0,t.bF)(r,{size:"small",onClick:s.handleRefresh},{default:(0,t.k6)((()=>[(0,t.eW)(" 刷新(F5)"),(0,t.bF)(c,null,{default:(0,t.k6)((()=>[(0,t.bF)(o)])),_:1})])),_:1},8,["onClick"]),(0,t.Lk)("div",f,[(0,t.bF)(d,{name:"net"})])])])}var C=a(3830),m=a(144),b=a(7477),L=a(5096),_={components:{Edit:b.ffu,Refresh:b.C42,Background:L.A},setup(){const e=(0,C.B)(),n=(0,m.Kh)({server:(0,t.EW)((()=>e.value.config.Client.Server.Host)),group:(0,t.EW)((()=>e.value.config.Client.Group.Name))}),a=()=>{window.location.reload()};return{state:n,handleRefresh:a}}},w=a(1241);const S=(0,w.A)(_,[["render",k],["__scopeId","data-v-6bfe19a3"]]);var F=S;const x=e=>((0,t.Qi)("data-v-68d1c30a"),e=e(),(0,t.jt)(),e),T={class:"net-list-wrap flex flex-column absolute"},z={class:"flex-1 scrollbar"},E={class:"flex"},A=x((()=>(0,t.Lk)("div",{class:"flex-1"},null,-1))),I={class:"tuntap"},P={class:"page t-c"},B={class:"page-wrap t-c"};function R(e,n,a,s,l,i){const o=(0,t.g2)("DeviceName"),c=(0,t.g2)("UpdaterBtn"),r=(0,t.g2)("TuntapShow"),u=(0,t.g2)("el-pagination");return(0,t.uX)(),(0,t.CE)("div",T,[(0,t.Lk)("div",z,[(0,t.Lk)("ul",null,[((0,t.uX)(!0),(0,t.CE)(t.FK,null,(0,t.pI)(s.devices.page.List,((e,n)=>((0,t.uX)(),(0,t.CE)("li",{key:n},[(0,t.Lk)("dl",null,[(0,t.Lk)("dt",E,[(0,t.Lk)("div",null,[(0,t.bF)(o,{item:e},null,8,["item"])]),A,(0,t.Lk)("div",null,[(0,t.bF)(c,{config:!1,item:e},null,8,["item"])])]),(0,t.Lk)("dd",I,[s.tuntap.list[e.MachineId]?((0,t.uX)(),(0,t.Wv)(r,{key:0,item:e},null,8,["item"])):(0,t.Q3)("",!0)])])])))),128))])]),(0,t.Lk)("div",P,[(0,t.Lk)("div",B,[(0,t.bF)(u,{size:"small",background:"",layout:"prev,pager, next","pager-count":5,total:s.devices.page.Count,"page-size":s.devices.page.Request.Size,"current-page":s.devices.page.Request.Page,onCurrentChange:s.handlePageChange,onSizeChange:s.handlePageSizeChange,"page-sizes":[10,20,50,100,255]},null,8,["total","page-size","current-page","onCurrentChange","onSizeChange"])])])])}var D=a(8104),X=a(7985),y=a(9383),N=a(7115),U=a(263),Q=a(3691),W=a(9983),H={components:{StarFilled:b.BQ2,UpdaterBtn:N.A,DeviceName:U.A,TuntapShow:Q.A},setup(e){(0,C.B)();const n=(0,m.Kh)({}),{devices:a,machineId:s,_getSignList:l,_getSignList1:i,handleDeviceEdit:o,handlePageChange:c,handlePageSizeChange:r,handleDel:u,clearDevicesTimeout:d}=(0,X.r)(),{tuntap:g,_getTuntapInfo:p,handleTuntapRefresh:v,clearTuntapTimeout:h,handleTuntapEdit:f,sortTuntapIP:k}=(0,D.O)(),{_getUpdater:b,_subscribeUpdater:L,clearUpdaterTimeout:_}=(0,y.d)(),{connections:w,forwardConnections:S,_getForwardConnections:F,tuntapConnections:x,_getTuntapConnections:T,socks5Connections:z,_getSocks5Connections:E,handleTunnelConnections:A,clearConnectionsTimeout:I}=(0,W.L2)();return(0,t.sV)((()=>{c(),v(),l(),i(),p(),b(),L()})),(0,t.hi)((()=>{d(),h(),_()})),{state:n,devices:a,machineId:s,handlePageChange:c,handlePageSizeChange:r,tuntap:g}}};const K=(0,w.A)(H,[["render",R],["__scopeId","data-v-68d1c30a"]]);var j=K,q=a(5317),M=a(1387),V={components:{Head:F,List:j,Status:q.A},setup(){document.addEventListener("contextmenu",(function(e){e.preventDefault()}));const e=(0,C.B)(),n=(0,M.rd)();return(0,t.sV)((()=>{0==e.value.hasAccess("NetManager")&&n.push({name:"NoPermission"})})),{}}};const G=(0,w.A)(V,[["render",r],["__scopeId","data-v-6a3f3b43"]]);var O=G}}]);
"use strict";(self["webpackChunklinker_web"]=self["webpackChunklinker_web"]||[]).push([[227],{7332:function(e,n,a){a.r(n),a.d(n,{default:function(){return O}});var t=a(6768);const s={class:"net-wrap app-wrap"},l={class:"inner absolute flex flex-column flex-nowrap"},i={class:"head"},o={class:"body flex-1 relative"},c={class:"status"};function r(e,n,a,r,u,d){const g=(0,t.g2)("Head"),p=(0,t.g2)("List"),v=(0,t.g2)("Status");return(0,t.uX)(),(0,t.CE)("div",s,[(0,t.Lk)("div",l,[(0,t.Lk)("div",i,[(0,t.bF)(g)]),(0,t.Lk)("div",o,[(0,t.bF)(p)]),(0,t.Lk)("div",c,[(0,t.bF)(v,{config:!1})])])])}a(4114);var u=a(4232);const d=e=>((0,t.Qi)("data-v-6bfe19a3"),e=e(),(0,t.jt)(),e),g={class:"head-wrap"},p={class:"tools flex"},v={class:"label"},h=d((()=>(0,t.Lk)("span",{class:"flex-1"},null,-1))),f={style:{"margin-left":"1rem"}};function k(e,n,a,s,l,i){const o=(0,t.g2)("Refresh"),c=(0,t.g2)("el-icon"),r=(0,t.g2)("el-button"),d=(0,t.g2)("Background");return(0,t.uX)(),(0,t.CE)("div",g,[(0,t.Lk)("div",p,[(0,t.Lk)("span",v,"分组 : "+(0,u.v_)(s.state.group),1),h,(0,t.bF)(r,{size:"small",onClick:s.handleRefresh},{default:(0,t.k6)((()=>[(0,t.eW)(" 刷新(F5)"),(0,t.bF)(c,null,{default:(0,t.k6)((()=>[(0,t.bF)(o)])),_:1})])),_:1},8,["onClick"]),(0,t.Lk)("div",f,[(0,t.bF)(d,{name:"net"})])])])}var C=a(3830),m=a(144),b=a(7477),L=a(5096),_={components:{Edit:b.ffu,Refresh:b.C42,Background:L.A},setup(){const e=(0,C.B)(),n=(0,m.Kh)({server:(0,t.EW)((()=>e.value.config.Client.Server.Host)),group:(0,t.EW)((()=>e.value.config.Client.Group.Name))}),a=()=>{window.location.reload()};return{state:n,handleRefresh:a}}},w=a(1241);const S=(0,w.A)(_,[["render",k],["__scopeId","data-v-6bfe19a3"]]);var F=S;const x=e=>((0,t.Qi)("data-v-68d1c30a"),e=e(),(0,t.jt)(),e),T={class:"net-list-wrap flex flex-column absolute"},z={class:"flex-1 scrollbar"},E={class:"flex"},A=x((()=>(0,t.Lk)("div",{class:"flex-1"},null,-1))),I={class:"tuntap"},P={class:"page t-c"},B={class:"page-wrap t-c"};function R(e,n,a,s,l,i){const o=(0,t.g2)("DeviceName"),c=(0,t.g2)("UpdaterBtn"),r=(0,t.g2)("TuntapShow"),u=(0,t.g2)("el-pagination");return(0,t.uX)(),(0,t.CE)("div",T,[(0,t.Lk)("div",z,[(0,t.Lk)("ul",null,[((0,t.uX)(!0),(0,t.CE)(t.FK,null,(0,t.pI)(s.devices.page.List,((e,n)=>((0,t.uX)(),(0,t.CE)("li",{key:n},[(0,t.Lk)("dl",null,[(0,t.Lk)("dt",E,[(0,t.Lk)("div",null,[(0,t.bF)(o,{item:e},null,8,["item"])]),A,(0,t.Lk)("div",null,[(0,t.bF)(c,{config:!1,item:e},null,8,["item"])])]),(0,t.Lk)("dd",I,[s.tuntap.list[e.MachineId]?((0,t.uX)(),(0,t.Wv)(r,{key:0,item:e},null,8,["item"])):(0,t.Q3)("",!0)])])])))),128))])]),(0,t.Lk)("div",P,[(0,t.Lk)("div",B,[(0,t.bF)(u,{size:"small",background:"",layout:"prev,pager, next","pager-count":5,total:s.devices.page.Count,"page-size":s.devices.page.Request.Size,"current-page":s.devices.page.Request.Page,onCurrentChange:s.handlePageChange,onSizeChange:s.handlePageSizeChange,"page-sizes":[10,20,50,100,255]},null,8,["total","page-size","current-page","onCurrentChange","onSizeChange"])])])])}var D=a(8104),X=a(7985),y=a(9383),N=a(7115),U=a(263),Q=a(4109),W=a(9983),H={components:{StarFilled:b.BQ2,UpdaterBtn:N.A,DeviceName:U.A,TuntapShow:Q.A},setup(e){(0,C.B)();const n=(0,m.Kh)({}),{devices:a,machineId:s,_getSignList:l,_getSignList1:i,handleDeviceEdit:o,handlePageChange:c,handlePageSizeChange:r,handleDel:u,clearDevicesTimeout:d}=(0,X.r)(),{tuntap:g,_getTuntapInfo:p,handleTuntapRefresh:v,clearTuntapTimeout:h,handleTuntapEdit:f,sortTuntapIP:k}=(0,D.O)(),{_getUpdater:b,_subscribeUpdater:L,clearUpdaterTimeout:_}=(0,y.d)(),{connections:w,forwardConnections:S,_getForwardConnections:F,tuntapConnections:x,_getTuntapConnections:T,socks5Connections:z,_getSocks5Connections:E,handleTunnelConnections:A,clearConnectionsTimeout:I}=(0,W.L2)();return(0,t.sV)((()=>{c(),v(),l(),i(),p(),b(),L()})),(0,t.hi)((()=>{d(),h(),_()})),{state:n,devices:a,machineId:s,handlePageChange:c,handlePageSizeChange:r,tuntap:g}}};const K=(0,w.A)(H,[["render",R],["__scopeId","data-v-68d1c30a"]]);var j=K,q=a(5317),M=a(1387),V={components:{Head:F,List:j,Status:q.A},setup(){document.addEventListener("contextmenu",(function(e){e.preventDefault()}));const e=(0,C.B)(),n=(0,M.rd)();return(0,t.sV)((()=>{0==e.value.hasAccess("NetManager")&&n.push({name:"NoPermission"})})),{}}};const G=(0,w.A)(V,[["render",r],["__scopeId","data-v-6a3f3b43"]]);var O=G}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -13,7 +13,7 @@ sidebar_position: 11
![](./img/ikuai-ssh1.jpg)
先下载 <a href="/update-20241130.bin" target="_blank">update-20241130.bin</a><a href="/iKuai-3.7.16-base.bin" target="_blank">iKuai-3.7.16-base.bin</a>如果ikuai版本不是`3.7.16`,还需要先升级为`3.7.16`
先下载 <a href="/update-20241130.bin" target="_blank">update-20241130.bin</a><a href="https://www.ikuaios.com:555/i/%E5%8E%86%E5%8F%B2%E5%9B%BA%E4%BB%B6" target="_blank">iKuai-3.7.16</a>如果ikuai版本不是`3.7.16`,还需要先升级为`3.7.16`
然后依次上传`iKuai-3.7.16-base.bin`升级,重启,再上传`update-20241130.bin`升级,重启

View File

@@ -9,23 +9,25 @@ sidebar_position: 9
:::tip[v1.7.0+]
1. 如果你使用第三方程序启动linker可以传入参数进行初始化
2. 填写了哪些字段,哪些字段就会强制覆盖原有配置
1. 即使是null值也会覆盖所以不想覆盖的就把整个key都去掉而不是给null值
2. key一定要双引号标准json格式
3. 将json转为base64后传入 `linker.exe base64`
```
{
"Client":"{}", //对应client.json
"Server":"{}", //对应server.json
"Common":"{}", //对应common.json
"Action":"{}", //对应action.json
"Tuntap":"{
"Client":{}, //对应client.json
"Server":{}, //对应server.json
"Common":{}, //对应common.json
"Action":{}, //对应action.json
"Tuntap":{
"IP":"10.18.18.2", 网卡IP
"PrefixLength":24, 网卡掩码
局域网IP列表
"Lans":[{
IP:"10.18.18.1", 局域网IP
PrefixLength:24, 掩码
Disabled:false, 禁用
MapIP:"10.18.18.1", //路由IP
MapPrefixLength:24, //路由掩码
"IP":"10.18.18.1", 局域网IP
"PrefixLength":24, 掩码
"Disabled":false, 禁用
"MapIP":"10.18.18.1", //路由IP
"MapPrefixLength":24, //路由掩码
}],
"Name":"linker", 网卡名
"Running":true, 是否运行true则启动后自动运行网卡
@@ -34,20 +36,20 @@ sidebar_position: 9
端口转发列表
"Forwards":[
{
ListenAddr:"0.0.0.0"
ListenPort:33890
ConnectAddr:"192.168.1.1"
ConnectPort:3389,
Remark:"33890 转发到 3389",
"ListenAddr":"0.0.0.0"
"ListenPort":33890
"ConnectAddr":"192.168.1.1"
"ConnectPort":3389,
"Remark":"33890 转发到 3389",
}
],
//本组网络配置
"Lease":{
IP : "10.18.18.0"
PrefixLength:24,
Name:"linker"
"IP" : "10.18.18.0"
"PrefixLength":24,
"Name":"linker"
}
}"
}
}
```
:::

Binary file not shown.

View File

@@ -19,6 +19,7 @@ using linker.messenger.store.file;
using linker.messenger.serializer.memorypack;
using linker.libs;
using linker.messenger.plan;
using System.Text.Json;
namespace linker.messenger.entry
{
@@ -136,7 +137,7 @@ namespace linker.messenger.entry
/// 开始运行
/// </summary>
/// <param name="modules">排除哪些模块,默认无</param>
public static void Setup(ExcludeModule modules = ExcludeModule.None, Dictionary<string, string> configDic = null)
public static void Setup(ExcludeModule modules = ExcludeModule.None, JsonDocument config = null)
{
if (setuped.StartOperation() == false) return;
@@ -148,7 +149,7 @@ namespace linker.messenger.entry
serviceProvider.UseMessenger();
if ((modules & ExcludeModule.StoreFile) != ExcludeModule.StoreFile)
serviceProvider.UseStoreFile(configDic);
serviceProvider.UseStoreFile(config);
if ((modules & ExcludeModule.SerializerMemoryPack) != ExcludeModule.SerializerMemoryPack)
serviceProvider.UseSerializerMemoryPack();
@@ -189,7 +190,7 @@ namespace linker.messenger.entry
if ((modules & ExcludeModule.Socks5) != ExcludeModule.Socks5)
serviceProvider.UseSocks5Client();
if ((modules & ExcludeModule.Tuntap) != ExcludeModule.Tuntap)
serviceProvider.UseTuntapClient(configDic);
serviceProvider.UseTuntapClient(config);
if ((modules & ExcludeModule.Updater) != ExcludeModule.Updater)
serviceProvider.UseUpdaterClient();
serviceProvider.UseExRoute().UseAccessClient().UseDecenterClient().UsePcpClient().UseRelayClient().UseSyncClient().UseTunnelClient().UseFlowClient();

View File

@@ -0,0 +1,7 @@

namespace linker.messenger.firewall
{
internal sealed class LinkerFirewall
{
}
}

View File

@@ -1,5 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
@@ -8,14 +9,14 @@
<PublishAot>false</PublishAot>
<JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault>
<EnablePreviewFeatures>True</EnablePreviewFeatures>
<Title>linker messenger serializer aot</Title>
<Title>linker messenger firewall</Title>
<Authors>snltty</Authors>
<Company>snltty</Company>
<Description>linker messenger serializer aot</Description>
<Description>linker messenger firewall</Description>
<Copyright>snltty</Copyright>
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
<PackageReleaseNotes>linker messenger serializer aot</PackageReleaseNotes>
<PackageReleaseNotes>linker messenger firewall</PackageReleaseNotes>
<Version>1.7.7</Version>
<AssemblyVersion>1.7.7</AssemblyVersion>
<FileVersion>1.7.7</FileVersion>
@@ -36,4 +37,5 @@
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>
</Project>

View File

@@ -8,11 +8,12 @@ namespace linker.messenger.logger
{
public static ServiceCollection AddLogger(this ServiceCollection serviceCollection)
{
LoggerConsole();
return serviceCollection;
}
public static ServiceProvider UseLogger(this ServiceProvider serviceProvider)
{
LoggerConsole();
return serviceProvider;
}

View File

@@ -1,5 +0,0 @@
namespace linker.messenger.serializer.aot
{
[AttributeUsage(AttributeTargets.Class)]
public class JsonAotAttribute : Attribute { }
}

View File

@@ -6,6 +6,7 @@ using linker.messenger.signin;
using linker.messenger.api;
using System.Text;
using linker.messenger.relay.client.transport;
using System.Text.Json;
namespace linker.messenger.store.file
{
public sealed class ConfigApiController : IApiController
@@ -87,8 +88,8 @@ namespace linker.messenger.store.file
{
try
{
Dictionary<string, string> dic = Encoding.UTF8.GetString(Convert.FromBase64String(param.Content)).DeJson<Dictionary<string, string>>();
config.Save(dic);
using JsonDocument json = JsonDocument.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(param.Content)));
config.Save(json);
return true;
}
catch (Exception)
@@ -103,8 +104,8 @@ namespace linker.messenger.store.file
InstallSaveInfo info = param.Content.DeJson<InstallSaveInfo>();
string value = await exportResolver.Get(info.Server, info.Value);
Dictionary<string, string> dic = Encoding.UTF8.GetString(Convert.FromBase64String(value)).DeJson<Dictionary<string, string>>();
config.Save(dic);
using JsonDocument json = JsonDocument.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(value)));
config.Save(json);
return true;
}
catch (Exception)
@@ -123,8 +124,8 @@ namespace linker.messenger.store.file
var (client, clientObject, common, commonObject) = await GetConfig(configExportInfo).ConfigureAwait(false);
Dictionary<string, object> dic = new Dictionary<string, object>
{
{"Client",clientObject.ToJson()},
{"Common",commonObject.ToJson()},
{"Client",clientObject},
{"Common",commonObject},
};
return Convert.ToBase64String(Encoding.UTF8.GetBytes(dic.ToJson()));
@@ -145,8 +146,8 @@ namespace linker.messenger.store.file
var (client, clientObject, common, commonObject) = await GetConfig(configExportInfo).ConfigureAwait(false);
Dictionary<string, object> dic = new Dictionary<string, object>
{
{"Client",clientObject.ToJson()},
{"Common",commonObject.ToJson()},
{"Client",clientObject},
{"Common",commonObject},
};
string value = Convert.ToBase64String(Encoding.UTF8.GetBytes(dic.ToJson()));
return await exportResolver.Save(signInClientState.Connection.Address, value);

View File

@@ -34,6 +34,7 @@ using linker.messenger.tuntap;
using linker.messenger.tuntap.lease;
using linker.messenger.updater;
using Microsoft.Extensions.DependencyInjection;
using System.Text.Json;
namespace linker.messenger.store.file
{
public static class Entry
@@ -104,12 +105,12 @@ namespace linker.messenger.store.file
return serviceCollection;
}
public static ServiceProvider UseStoreFile(this ServiceProvider serviceProvider,Dictionary<string,string> configDic)
public static ServiceProvider UseStoreFile(this ServiceProvider serviceProvider,JsonDocument config = default)
{
LoggerHelper.Instance.Info("use store file");
FileConfig fileConfig = serviceProvider.GetService<FileConfig>();
fileConfig.Save(configDic);
fileConfig.Save(config);
RunningConfig runningConfig = serviceProvider.GetService<RunningConfig>();
IApiServer apiServer = serviceProvider.GetService<IApiServer>();

View File

@@ -94,7 +94,7 @@ namespace linker.messenger.store.file
}
}
public void Save(Dictionary<string, string> dic = null)
public void Save(JsonDocument json = null)
{
slim.Wait();
try
@@ -109,10 +109,11 @@ namespace linker.messenger.store.file
continue;
}
string text = item.Value.PropertyMethod.Serialize(item.Value.Property.GetValue(Data));
if (dic != null && dic.TryGetValue(item.Value.Property.Name, out string text2))
if (json != null && json.RootElement.TryGetProperty(item.Value.Property.Name, out JsonElement import))
{
text = item.Value.PropertyMethod.Deserialize(text).ToJson();
text = MergeJson(text, text2);
text = MergeJson(text, import.ToJson());
object value = item.Value.PropertyMethod.Deserialize(text);
text = item.Value.PropertyMethod.Serialize(value);

View File

@@ -9,6 +9,7 @@ using linker.messenger.tuntap.lease;
using linker.messenger.tuntap.messenger;
using linker.tun;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Net;
using System.Text;
using System.Text.Json;
@@ -41,57 +42,9 @@ namespace linker.messenger.tuntap
return serviceCollection;
}
public static ServiceProvider UseTuntapClient(this ServiceProvider serviceProvider, Dictionary<string, string> configDic)
public static ServiceProvider UseTuntapClient(this ServiceProvider serviceProvider, JsonDocument json = default)
{
if (configDic.TryGetValue("Tuntap", out string value))
{
ITuntapClientStore tuntapClientStore = serviceProvider.GetService<ITuntapClientStore>();
ILeaseClientStore leaseClientStore = serviceProvider.GetService<ILeaseClientStore>();
ISignInClientStore signInClientStore = serviceProvider.GetService<ISignInClientStore>();
try
{
JsonElement doc = JsonDocument.Parse(value).RootElement;
if (doc.TryGetProperty("IP", out JsonElement ip))
{
tuntapClientStore.Info.IP = IPAddress.Parse(ip.GetString());
}
if (doc.TryGetProperty("PrefixLength", out JsonElement prefixLength))
{
tuntapClientStore.Info.PrefixLength = prefixLength.GetByte();
}
if (doc.TryGetProperty("Lans", out JsonElement lans))
{
tuntapClientStore.Info.Lans = lans.GetRawText().DeJson<List<TuntapLanInfo>>();
}
if (doc.TryGetProperty("Name", out JsonElement name))
{
tuntapClientStore.Info.Name = name.GetString();
}
if (doc.TryGetProperty("Running", out JsonElement running))
{
tuntapClientStore.Info.Running = running.GetBoolean();
}
if (doc.TryGetProperty("Switch", out JsonElement _switch))
{
tuntapClientStore.Info.Switch = (TuntapSwitch)_switch.GetInt32();
}
if (doc.TryGetProperty("Forwards", out JsonElement forwards))
{
tuntapClientStore.Info.Forwards = forwards.GetRawText().DeJson<List<TuntapForwardInfo>>();
}
if (doc.TryGetProperty("Lease", out JsonElement lease))
{
leaseClientStore.Set(signInClientStore.Group.Id, lease.GetRawText().DeJson<LeaseInfo>());
}
}
catch (Exception ex)
{
LoggerHelper.Instance.Error(ex);
}
tuntapClientStore.Confirm();
leaseClientStore.Confirm();
}
InportConfig(serviceProvider, json);
TuntapProxy tuntapProxy = serviceProvider.GetService<TuntapProxy>();
TuntapTransfer tuntapTransfer = serviceProvider.GetService<TuntapTransfer>();
@@ -119,10 +72,61 @@ namespace linker.messenger.tuntap
DecenterClientTransfer decenterClientTransfer = serviceProvider.GetService<DecenterClientTransfer>();
decenterClientTransfer.AddDecenters(new List<IDecenter> { serviceProvider.GetService<TuntapDecenter>() });
return serviceProvider;
}
private static void InportConfig(ServiceProvider serviceProvider, JsonDocument json = default)
{
if (json != null && json.RootElement.TryGetProperty("Tuntap", out JsonElement tuntap))
{
ITuntapClientStore tuntapClientStore = serviceProvider.GetService<ITuntapClientStore>();
ILeaseClientStore leaseClientStore = serviceProvider.GetService<ILeaseClientStore>();
ISignInClientStore signInClientStore = serviceProvider.GetService<ISignInClientStore>();
try
{
if (tuntap.TryGetProperty("IP", out JsonElement ip))
{
tuntapClientStore.Info.IP = IPAddress.Parse(ip.GetString());
}
if (tuntap.TryGetProperty("PrefixLength", out JsonElement prefixLength))
{
tuntapClientStore.Info.PrefixLength = prefixLength.GetByte();
}
if (tuntap.TryGetProperty("Lans", out JsonElement lans))
{
tuntapClientStore.Info.Lans = lans.GetRawText().DeJson<List<TuntapLanInfo>>();
}
if (tuntap.TryGetProperty("Name", out JsonElement name))
{
tuntapClientStore.Info.Name = name.GetString();
}
if (tuntap.TryGetProperty("Running", out JsonElement running))
{
tuntapClientStore.Info.Running = running.GetBoolean();
}
if (tuntap.TryGetProperty("Switch", out JsonElement _switch))
{
tuntapClientStore.Info.Switch = (TuntapSwitch)_switch.GetInt32();
}
if (tuntap.TryGetProperty("Forwards", out JsonElement forwards))
{
tuntapClientStore.Info.Forwards = forwards.GetRawText().DeJson<List<TuntapForwardInfo>>();
}
if (tuntap.TryGetProperty("Lease", out JsonElement lease))
{
leaseClientStore.Set(signInClientStore.Group.Id, lease.GetRawText().DeJson<LeaseInfo>());
}
}
catch (Exception ex)
{
LoggerHelper.Instance.Error(ex);
}
tuntapClientStore.Confirm();
leaseClientStore.Confirm();
}
}
public static ServiceCollection AddTuntapServer(this ServiceCollection serviceCollection)

View File

@@ -1,5 +1,5 @@
<?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.258" ProductVersion="0.0.0.258" 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.260" ProductVersion="0.0.0.260" publishDir="/dist/" dstrip="false" local="false" ignored="false">
<file name="main.aardio" path="main.aardio" comment="main.aardio"/>
<folder name="资源文件" path="res" embed="true" local="false" ignored="false">
<file name="favicon.ico" path="res\favicon.ico" comment="res\favicon.ico"/>

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -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.cfba5739.js"></script><script defer="defer" src="js/app.ee325789.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.09dcc3e8.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.cfba5739.js"></script><script defer="defer" src="js/app.6c05d4d4.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.09dcc3e8.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

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
"use strict";(self["webpackChunklinker_web"]=self["webpackChunklinker_web"]||[]).push([[227],{7332:function(e,n,a){a.r(n),a.d(n,{default:function(){return O}});var t=a(6768);const s={class:"net-wrap app-wrap"},l={class:"inner absolute flex flex-column flex-nowrap"},i={class:"head"},o={class:"body flex-1 relative"},c={class:"status"};function r(e,n,a,r,u,d){const g=(0,t.g2)("Head"),p=(0,t.g2)("List"),v=(0,t.g2)("Status");return(0,t.uX)(),(0,t.CE)("div",s,[(0,t.Lk)("div",l,[(0,t.Lk)("div",i,[(0,t.bF)(g)]),(0,t.Lk)("div",o,[(0,t.bF)(p)]),(0,t.Lk)("div",c,[(0,t.bF)(v,{config:!1})])])])}a(4114);var u=a(4232);const d=e=>((0,t.Qi)("data-v-6bfe19a3"),e=e(),(0,t.jt)(),e),g={class:"head-wrap"},p={class:"tools flex"},v={class:"label"},h=d((()=>(0,t.Lk)("span",{class:"flex-1"},null,-1))),f={style:{"margin-left":"1rem"}};function k(e,n,a,s,l,i){const o=(0,t.g2)("Refresh"),c=(0,t.g2)("el-icon"),r=(0,t.g2)("el-button"),d=(0,t.g2)("Background");return(0,t.uX)(),(0,t.CE)("div",g,[(0,t.Lk)("div",p,[(0,t.Lk)("span",v,"分组 : "+(0,u.v_)(s.state.group),1),h,(0,t.bF)(r,{size:"small",onClick:s.handleRefresh},{default:(0,t.k6)((()=>[(0,t.eW)(" 刷新(F5)"),(0,t.bF)(c,null,{default:(0,t.k6)((()=>[(0,t.bF)(o)])),_:1})])),_:1},8,["onClick"]),(0,t.Lk)("div",f,[(0,t.bF)(d,{name:"net"})])])])}var C=a(3830),m=a(144),b=a(7477),L=a(5096),_={components:{Edit:b.ffu,Refresh:b.C42,Background:L.A},setup(){const e=(0,C.B)(),n=(0,m.Kh)({server:(0,t.EW)((()=>e.value.config.Client.Server.Host)),group:(0,t.EW)((()=>e.value.config.Client.Group.Name))}),a=()=>{window.location.reload()};return{state:n,handleRefresh:a}}},w=a(1241);const S=(0,w.A)(_,[["render",k],["__scopeId","data-v-6bfe19a3"]]);var F=S;const x=e=>((0,t.Qi)("data-v-68d1c30a"),e=e(),(0,t.jt)(),e),T={class:"net-list-wrap flex flex-column absolute"},z={class:"flex-1 scrollbar"},E={class:"flex"},A=x((()=>(0,t.Lk)("div",{class:"flex-1"},null,-1))),I={class:"tuntap"},P={class:"page t-c"},B={class:"page-wrap t-c"};function R(e,n,a,s,l,i){const o=(0,t.g2)("DeviceName"),c=(0,t.g2)("UpdaterBtn"),r=(0,t.g2)("TuntapShow"),u=(0,t.g2)("el-pagination");return(0,t.uX)(),(0,t.CE)("div",T,[(0,t.Lk)("div",z,[(0,t.Lk)("ul",null,[((0,t.uX)(!0),(0,t.CE)(t.FK,null,(0,t.pI)(s.devices.page.List,((e,n)=>((0,t.uX)(),(0,t.CE)("li",{key:n},[(0,t.Lk)("dl",null,[(0,t.Lk)("dt",E,[(0,t.Lk)("div",null,[(0,t.bF)(o,{item:e},null,8,["item"])]),A,(0,t.Lk)("div",null,[(0,t.bF)(c,{config:!1,item:e},null,8,["item"])])]),(0,t.Lk)("dd",I,[s.tuntap.list[e.MachineId]?((0,t.uX)(),(0,t.Wv)(r,{key:0,item:e},null,8,["item"])):(0,t.Q3)("",!0)])])])))),128))])]),(0,t.Lk)("div",P,[(0,t.Lk)("div",B,[(0,t.bF)(u,{size:"small",background:"",layout:"prev,pager, next","pager-count":5,total:s.devices.page.Count,"page-size":s.devices.page.Request.Size,"current-page":s.devices.page.Request.Page,onCurrentChange:s.handlePageChange,onSizeChange:s.handlePageSizeChange,"page-sizes":[10,20,50,100,255]},null,8,["total","page-size","current-page","onCurrentChange","onSizeChange"])])])])}var D=a(8104),X=a(7985),y=a(9383),N=a(7115),U=a(263),Q=a(4109),W=a(9983),H={components:{StarFilled:b.BQ2,UpdaterBtn:N.A,DeviceName:U.A,TuntapShow:Q.A},setup(e){(0,C.B)();const n=(0,m.Kh)({}),{devices:a,machineId:s,_getSignList:l,_getSignList1:i,handleDeviceEdit:o,handlePageChange:c,handlePageSizeChange:r,handleDel:u,clearDevicesTimeout:d}=(0,X.r)(),{tuntap:g,_getTuntapInfo:p,handleTuntapRefresh:v,clearTuntapTimeout:h,handleTuntapEdit:f,sortTuntapIP:k}=(0,D.O)(),{_getUpdater:b,_subscribeUpdater:L,clearUpdaterTimeout:_}=(0,y.d)(),{connections:w,forwardConnections:S,_getForwardConnections:F,tuntapConnections:x,_getTuntapConnections:T,socks5Connections:z,_getSocks5Connections:E,handleTunnelConnections:A,clearConnectionsTimeout:I}=(0,W.L2)();return(0,t.sV)((()=>{c(),v(),l(),i(),p(),b(),L()})),(0,t.hi)((()=>{d(),h(),_()})),{state:n,devices:a,machineId:s,handlePageChange:c,handlePageSizeChange:r,tuntap:g}}};const K=(0,w.A)(H,[["render",R],["__scopeId","data-v-68d1c30a"]]);var j=K,q=a(5317),M=a(1387),V={components:{Head:F,List:j,Status:q.A},setup(){document.addEventListener("contextmenu",(function(e){e.preventDefault()}));const e=(0,C.B)(),n=(0,M.rd)();return(0,t.sV)((()=>{0==e.value.hasAccess("NetManager")&&n.push({name:"NoPermission"})})),{}}};const G=(0,w.A)(V,[["render",r],["__scopeId","data-v-6a3f3b43"]]);var O=G}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -19,10 +19,6 @@ namespace linker.tun
/// 是否正在运行
/// </summary>
public bool Running { get; }
/// <summary>
/// 是否应用层NAT
/// </summary>
public bool AppNat { get; }
/// <summary>
/// 启动
@@ -51,12 +47,7 @@ namespace linker.tun
/// <summary>
/// 设置系统NAT转发
/// </summary>
public void SetSystemNat(out string error);
/// <summary>
/// 设置应用层NAT转发
/// </summary>
/// <param name="error"></param>
public void SetAppNat(LinkerTunAppNatItemInfo[] items, ref string error);
public void SetNat(out string error);
/// <summary>
/// 移除NAT转发
/// </summary>
@@ -122,6 +113,25 @@ namespace linker.tun
public Task Callback(LinkerTunDevicPacket packet);
}
/// <summary>
/// 数据包钩子
/// </summary>
public interface ILinkerTunPacketHook
{
/// <summary>
/// 从网卡读取到数据包后
/// </summary>
/// <param name="packet"></param>
/// <returns></returns>
public bool ReadAfter(ReadOnlyMemory<byte> packet);
/// <summary>
/// 写入网卡前
/// </summary>
/// <param name="packet"></param>
/// <returns></returns>
public bool WriteBefore(ReadOnlyMemory<byte> packet);
}
/// <summary>
/// 网卡端口转发
/// </summary>

26
src/linker.tun/LanMap.cs Normal file
View File

@@ -0,0 +1,26 @@
using linker.snat;
using static linker.snat.LinkerDstMapping;
namespace linker.tun
{
internal sealed class LanMap : ILinkerTunPacketHook
{
private readonly LinkerDstMapping linkerDstMapping = new LinkerDstMapping();
public void SetMap(DstMapInfo[] maps)
{
linkerDstMapping.SetDsts(maps);
}
public bool ReadAfter(ReadOnlyMemory<byte> packet)
{
linkerDstMapping.ToFakeDst(packet);
return true;
}
public bool WriteBefore(ReadOnlyMemory<byte> packet)
{
linkerDstMapping.ToRealDst(packet);
return true;
}
}
}

101
src/linker.tun/LanSnat.cs Normal file
View File

@@ -0,0 +1,101 @@
using linker.libs;
using linker.snat;
using System.Net;
using System.Net.NetworkInformation;
using System.Text.RegularExpressions;
namespace linker.tun
{
internal sealed class LanSnat : ILinkerTunPacketHook
{
private LinkerSrcNat linkerSrcNat = new LinkerSrcNat();
public bool Running => linkerSrcNat.Running;
public LanSnat()
{
}
public void Setup(IPAddress address, byte prefixLength, LinkerTunAppNatItemInfo[] items, ref string error)
{
if (OperatingSystem.IsWindows() == false) return;
Shutdown();
if (address == null || address.Equals(IPAddress.Any) || prefixLength == 0)
{
error = "SNAT need CIDR,like 10.18.18.0/24";
return;
}
IPAddress defaultInterfaceIP = GetDefaultInterface();
if (defaultInterfaceIP == null)
{
error = "SNAT get default interface id fail";
return;
}
IPAddress network = NetworkHelper.ToNetworkIP(address, NetworkHelper.ToPrefixValue(prefixLength));
string result = CommandHelper.PowerShell($"Get-NetNat", [], out string e);
if (string.IsNullOrWhiteSpace(result) == false && result.Contains($"{network}/{prefixLength}"))
{
return;
}
linkerSrcNat.Setup(new LinkerSrcNat.SetupInfo
{
Src = address,
Dsts = items.Select(c => new LinkerSrcNat.AddrInfo(c.IP, c.PrefixLength)).ToArray(),
InterfaceIp = defaultInterfaceIP
}, out error);
}
public void Shutdown()
{
try
{
linkerSrcNat.Shutdown();
}
catch (Exception)
{
}
}
public bool ReadAfter(ReadOnlyMemory<byte> packet)
{
return false;
}
public bool WriteBefore(ReadOnlyMemory<byte> packet)
{
if (linkerSrcNat.Running == false) return true;
return linkerSrcNat.Inject(packet) == false;
}
private 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(' ');
IPAddress ip = IPAddress.Parse(arr[arr.Length - 2]);
foreach (var inter in NetworkInterface.GetAllNetworkInterfaces())
{
try
{
if (ip.Equals(inter.GetIPProperties().UnicastAddresses.FirstOrDefault(c => c.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).Address))
{
return ip;
}
}
catch (Exception)
{
}
}
}
}
return null;
}
}
}

View File

@@ -14,7 +14,6 @@ namespace linker.tun
private string name = string.Empty;
public string Name => name;
public bool Running => safeFileHandle != null;
public bool AppNat => false;
private string interfaceLinux = string.Empty;
private FileStream fsRead = null;
@@ -150,7 +149,7 @@ namespace linker.tun
{
return CommandHelper.Linux(string.Empty, ["ip route show default | awk '{print $5}'"]);
}
public void SetSystemNat(out string error)
public void SetNat(out string error)
{
error = string.Empty;
if (address == null || address.Equals(IPAddress.Any)) return;
@@ -183,9 +182,7 @@ namespace linker.tun
error = ex.Message;
}
}
public void SetAppNat(LinkerTunAppNatItemInfo[] items,ref string error)
{
}
public void RemoveNat(out string error)
{
error = string.Empty;

View File

@@ -15,7 +15,6 @@ namespace linker.tun
private string name = string.Empty;
public string Name => name;
public bool Running => safeFileHandle != null;
public bool AppNat => false;
private FileStream fsRead = null;
private FileStream fsWrite = null;
@@ -137,7 +136,7 @@ namespace linker.tun
CommandHelper.Osx(string.Empty, new string[] { $"ifconfig {Name} mtu {value} up" });
}
public void SetSystemNat(out string error)
public void SetNat(out string error)
{
error = string.Empty;
/*
@@ -155,9 +154,6 @@ namespace linker.tun
});
*/
}
public void SetAppNat(LinkerTunAppNatItemInfo[] items, ref string error)
{
}
public void RemoveNat(out string error)
{
error = string.Empty;

View File

@@ -1,6 +1,5 @@
using linker.libs;
using linker.libs.timer;
using linker.snat;
using System.Net;
using static linker.snat.LinkerDstMapping;
@@ -20,9 +19,13 @@ namespace linker.tun
private string natError = string.Empty;
public string NatError => natError;
public bool AppNat => lanSnat.Running;
private IPAddress address;
private byte prefixLength;
private readonly LanMap lanMap = new LanMap();
private readonly LanSnat lanSnat = new LanSnat();
public bool AppNat => linkerTunDevice?.AppNat ?? false;
private readonly LinkerDstMapping linkerDstMapping = new LinkerDstMapping();
private readonly OperatingManager operatingManager = new OperatingManager();
public LinkerTunDeviceStatus Status
@@ -39,9 +42,14 @@ namespace linker.tun
}
}
private ILinkerTunPacketHook[] hooks = [];
public LinkerTunDeviceAdapter()
{
hooks = new ILinkerTunPacketHook[]
{
lanMap,lanSnat
};
}
/// <summary>
@@ -106,6 +114,8 @@ namespace linker.tun
setupError = $"{System.Runtime.InteropServices.RuntimeInformation.OSDescription} not support";
return false;
}
this.address = address;
this.prefixLength = prefixLength;
linkerTunDevice.Setup(deviceName, address, prefixLength, out setupError);
if (string.IsNullOrWhiteSpace(setupError) == false)
{
@@ -179,7 +189,7 @@ namespace linker.tun
return;
}
if (linkerTunDevice.Running)
linkerTunDevice.SetSystemNat(out natError);
linkerTunDevice.SetNat(out natError);
}
/// <summary>
/// 设置应用层NAT仅Windows
@@ -195,7 +205,7 @@ namespace linker.tun
return;
}
if (linkerTunDevice.Running)
linkerTunDevice.SetAppNat(items, ref natError);
lanSnat.Setup(address, prefixLength, items, ref natError);
}
/// <summary>
/// 移除NAT
@@ -207,6 +217,7 @@ namespace linker.tun
return;
}
linkerTunDevice.RemoveNat(out string error);
lanSnat.Shutdown();
}
/// <summary>
@@ -273,6 +284,14 @@ namespace linker.tun
linkerTunDevice.RemoveRoute(ips);
}
public void AddHooks(List<ILinkerTunPacketHook> hooks)
{
List<ILinkerTunPacketHook> list = this.hooks.ToList();
list.AddRange(hooks);
this.hooks = list.Distinct().ToArray();
}
private void Read()
{
TimerHelper.Async(async () =>
@@ -294,7 +313,10 @@ namespace linker.tun
LinkerTunDevicPacket packet = new LinkerTunDevicPacket(buffer, 0, length);
if (packet.DistIPAddress.Length == 0) continue;
linkerDstMapping.ToFakeDst(buffer.AsMemory(4, length - 4));
for (int i = 0; i < hooks.Length; i++)
{
if (hooks[i].ReadAfter(buffer.AsMemory(4, length - 4)) == false) continue;
}
await linkerTunDeviceCallback.Callback(packet).ConfigureAwait(false);
}
catch (Exception ex)
@@ -316,7 +338,10 @@ namespace linker.tun
{
if (linkerTunDevice == null || Status != LinkerTunDeviceStatus.Running) return false;
linkerDstMapping.ToRealDst(buffer, AppNat == false);
for (int i = 0; i < hooks.Length; i++)
{
if (hooks[i].WriteBefore(buffer) == false) return false;
}
return linkerTunDevice.Write(buffer);
}
@@ -326,7 +351,7 @@ namespace linker.tun
/// <param name="maps"></param>
public void SetMap(DstMapInfo[] maps)
{
linkerDstMapping.SetDsts(maps);
lanMap.SetMap(maps);
}
public async Task<bool> CheckAvailable(bool order = false)

View File

@@ -1,6 +1,5 @@
using linker.libs;
using linker.libs.extends;
using linker.snat;
using System.Buffers.Binary;
using System.Net;
using System.Net.NetworkInformation;
@@ -16,7 +15,6 @@ namespace linker.tun
private string name = string.Empty;
public string Name => name;
public bool Running => session != 0;
public bool AppNat => winDivertNAT != null && winDivertNAT.Running;
private IntPtr waitHandle = IntPtr.Zero, adapter = IntPtr.Zero, session = IntPtr.Zero;
private int interfaceNumber = 0;
@@ -31,7 +29,7 @@ namespace linker.tun
private CancellationTokenSource tokenSource;
private LinkerSrcNat winDivertNAT = new LinkerSrcNat();
public LinkerWinTunDevice()
{
@@ -194,7 +192,7 @@ namespace linker.tun
});
}
public void SetSystemNat(out string error)
public void SetNat(out string error)
{
error = string.Empty;
try
@@ -224,30 +222,7 @@ namespace linker.tun
error = ex.Message;
}
}
public void SetAppNat(LinkerTunAppNatItemInfo[] items, ref string error)
{
winDivertNAT.Shutdown();
if (address == null || address.Equals(IPAddress.Any) || prefixLength == 0)
{
error = "SNAT need CIDR,like 10.18.18.0/24";
return;
}
IPAddress network = NetworkHelper.ToNetworkIP(this.address, NetworkHelper.ToPrefixValue(prefixLength));
string result = CommandHelper.PowerShell($"Get-NetNat", [], out string e);
if (string.IsNullOrWhiteSpace(result) == false && result.Contains($"{network}/{prefixLength}"))
{
return;
}
winDivertNAT.Setup(new LinkerSrcNat.SetupInfo
{
Src = address,
Dsts = items.Select(c => new LinkerSrcNat.AddrInfo(c.IP, c.PrefixLength)).ToArray(),
InterfaceIp = defaultInterfaceIP
}, out error);
}
public void RemoveNat(out string error)
{
error = string.Empty;
@@ -261,14 +236,6 @@ namespace linker.tun
{
error = ex.Message;
}
try
{
winDivertNAT.Shutdown();
}
catch (Exception)
{
}
}
@@ -382,8 +349,6 @@ namespace linker.tun
{
if (session == 0 || tokenSource.IsCancellationRequested) return false;
if (winDivertNAT.Inject(packet)) return true;
IntPtr packetPtr = WinTun.WintunAllocateSendPacket(session, (uint)packet.Length);
if (packetPtr != 0)
{

View File

@@ -1,6 +1,5 @@
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Text;
namespace linker.tun
{

View File

@@ -2,91 +2,43 @@
<el-dialog v-model="state.show" :close-on-click-modal="false" append-to=".app-wrap"
:title="`设置[${state.machineName}]组网`" top="1vh" width="780">
<div>
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-width="8rem">
<el-form-item label="网卡名" prop="Name">
<el-input v-model="state.ruleForm.Name" style="width:14rem" /> <span>留空则使用本组网络的设置</span>
</el-form-item>
<el-form-item label="网卡IP" prop="IP" class="mgb-0">
<el-input v-model="state.ruleForm.IP" style="width:14rem" />
<span>/</span>
<el-input @change="handlePrefixLengthChange" v-model="state.ruleForm.PrefixLength" style="width:4rem" />
</el-form-item>
<el-form-item label="" class="mgb-0">
<el-checkbox class="mgr-1" v-model="state.ruleForm.ShowDelay" label="显示延迟" size="large" />
<el-checkbox class="mgr-1" v-model="state.ruleForm.AutoConnect" label="自动连接" size="large" />
<el-checkbox class="mgr-1" v-model="state.ruleForm.Multicast" label="禁用广播" size="large" />
<el-checkbox class="mgr-1" v-model="state.ruleForm.Nat" label="禁用NAT" size="large" />
<el-checkbox class="mgr-1" v-model="state.ruleForm.TcpMerge" label="TCP包合并" size="large" />
<el-checkbox v-model="state.ruleForm.InterfaceOrder" label="调整网卡顺序" size="large" />
</el-form-item>
<el-form-item prop="upgrade" class="mgb-0">
<el-checkbox v-model="state.ruleForm.Upgrade" label="我很懂,我要使用高级功能(点对网和网对网)" size="large" />
</el-form-item>
<div class="upgrade-wrap" v-if="state.ruleForm.Upgrade">
<el-form-item label="局域网IP" prop="LanIP" class="m-b-0" style="border-bottom: 1px solid #ddd;">
<TuntapLan ref="lanDom"></TuntapLan>
</el-form-item>
<el-form-item label="端口转发" prop="forwards">
<TuntapForward ref="forwardDom"></TuntapForward>
</el-form-item>
</div>
<el-form-item label="" prop="Btns" label-width="0">
<div class="w-100 t-c">
<el-button @click="state.show = false">取消</el-button>
<el-button type="primary" @click="handleSave">确认</el-button>
</div>
</el-form-item>
</el-form>
<el-tabs type="border-card">
<el-tab-pane label="网卡">
<TuntapIP ref="ipDom"></TuntapIP>
</el-tab-pane>
<el-tab-pane label="点/网对网">
<TuntapLan ref="lanDom"></TuntapLan>
</el-tab-pane>
<el-tab-pane label="端口转发">
<TuntapForward ref="forwardDom"></TuntapForward>
</el-tab-pane>
</el-tabs>
<div class="foot t-c">
<el-button @click="state.show = false" :loading="state.loading">取消</el-button>
<el-button type="primary" @click="handleSave" :loading="state.loading">确定保存</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import { updateTuntap } from '@/apis/tuntap';
import { injectGlobalData } from '@/provide';
import { ElMessage } from 'element-plus';
import { reactive, ref, watch} from 'vue';
import { useTuntap } from './tuntap';
import TuntapForward from './TuntapForward.vue'
import TuntapLan from './TuntapLan.vue'
import { Delete, Plus, Warning, Refresh } from '@element-plus/icons-vue'
import TuntapIP from './TuntapIP.vue'
export default {
props: ['modelValue'],
emits: ['change', 'update:modelValue'],
components: { Delete, Plus, Warning, Refresh,TuntapForward ,TuntapLan},
components: { TuntapForward ,TuntapLan,TuntapIP},
setup(props, { emit }) {
const globalData = injectGlobalData();
const tuntap = useTuntap();
const ruleFormRef = ref(null);
const state = reactive({
show: true,
machineName: tuntap.value.current.device.MachineName,
bufferSize: globalData.value.bufferSize,
ruleForm: {
IP: tuntap.value.current.IP,
PrefixLength: tuntap.value.current.PrefixLength || 24,
Gateway: tuntap.value.current.Gateway,
ShowDelay: tuntap.value.current.ShowDelay,
AutoConnect: tuntap.value.current.AutoConnect,
Upgrade: tuntap.value.current.Upgrade,
Multicast: tuntap.value.current.Multicast,
Nat: tuntap.value.current.Nat,
TcpMerge: tuntap.value.current.TcpMerge,
InterfaceOrder: tuntap.value.current.InterfaceOrder,
Forwards: tuntap.value.current.Forwards,
Name: tuntap.value.current.Name,
},
rules: {
Name: {
type: 'string',
pattern: /^$|^[A-Za-z][A-Za-z0-9]{0,31}$/,
message:'请输入正确的网卡名',
transform(value) {
return value.trim();
},
}
}
loading:false
});
watch(() => state.show, (val) => {
@@ -96,54 +48,37 @@ export default {
}, 300);
}
});
const handlePrefixLengthChange = () => {
var value = +state.ruleForm.PrefixLength;
if (value > 32 || value < 16 || isNaN(value)) {
value = 24;
}
state.ruleForm.PrefixLength = value;
}
const ipDom = ref(null);
const lanDom = ref(null);
const forwardDom = ref(null);
const handleSave = () => {
const json = JSON.parse(JSON.stringify(tuntap.value.current));
json.IP = state.ruleForm.IP.replace(/\s/g, '') || '0.0.0.0';
state.loading = true;
const json = ipDom.value.getData();
json.Lans = lanDom.value ? lanDom.value.getData() : tuntap.value.current.Lans;
json.PrefixLength = +state.ruleForm.PrefixLength;
json.Gateway = state.ruleForm.Gateway;
json.ShowDelay = state.ruleForm.ShowDelay;
json.AutoConnect = state.ruleForm.AutoConnect;
json.Upgrade = state.ruleForm.Upgrade;
json.Multicast = state.ruleForm.Multicast;
json.Nat = state.ruleForm.Nat;
json.TcpMerge = state.ruleForm.TcpMerge;
json.InterfaceOrder = state.ruleForm.InterfaceOrder;
json.Forwards = forwardDom.value ? forwardDom.value.getData() : tuntap.value.current.Forwards;
json.Name = state.ruleForm.Name;
updateTuntap(json).then(() => {
state.show = false;
state.loading = false;
ElMessage.success('已操作!');
emit('change')
emit('change');
}).catch((err) => {
state.loading = false;
console.log(err);
ElMessage.error('操作失败!');
});
}
return {
state, ruleFormRef, handlePrefixLengthChange, handleSave,
lanDom,forwardDom
state, handleSave,
ipDom,lanDom,forwardDom
}
}
}
</script>
<style lang="stylus" scoped>
.el-switch.is-disabled{opacity :1;}
.upgrade-wrap{
border:1px solid #ddd;
margin-bottom:2rem
.foot{
padding-top:2rem;
}
</style>

View File

@@ -5,7 +5,7 @@
<span class="green" v-if="state.testing">testing</span>
</div>
<div class="wrap">
<el-table stripe :data="state.forwards" border size="small" width="100%" height="200px" @cell-dblclick="handleCellClick">
<el-table stripe :data="state.forwards" border size="small" width="100%" height="400px" @cell-dblclick="handleCellClick">
<el-table-column prop="ListenPort" label="源端口" width="60">
<template #default="scope">
<template v-if="scope.row.ListenPortEditing">
@@ -191,9 +191,6 @@ export default {
}
</script>
<style lang="stylus" scoped>
.wrap{
padding:0 1rem 1rem 0;
}
.remark{
white-space: nowrap; /* 文本不换行 */
overflow: hidden; /* 超出的文本隐藏 */

View File

@@ -0,0 +1,95 @@
<template>
<div class="wrap">
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-width="8rem">
<el-form-item label="网卡名" prop="Name">
<el-input v-model="state.ruleForm.Name" style="width:14rem" /> <span>留空则使用本组网络的设置</span>
</el-form-item>
<el-form-item label="网卡IP" prop="IP" class="mgb-0">
<el-input v-model="state.ruleForm.IP" style="width:14rem" />
<span>/</span>
<el-input @change="handlePrefixLengthChange" v-model="state.ruleForm.PrefixLength" style="width:4rem" />
</el-form-item>
<el-form-item label="" class="mgb-0">
<el-checkbox class="mgr-1" v-model="state.ruleForm.ShowDelay" label="显示延迟" size="large" />
<el-checkbox class="mgr-1" v-model="state.ruleForm.AutoConnect" label="自动连接" size="large" />
<el-checkbox class="mgr-1" v-model="state.ruleForm.Multicast" label="禁用广播" size="large" />
<el-checkbox class="mgr-1" v-model="state.ruleForm.Nat" label="禁用NAT" size="large" />
<el-checkbox class="mgr-1" v-model="state.ruleForm.TcpMerge" label="TCP包合并" size="large" />
<el-checkbox v-model="state.ruleForm.InterfaceOrder" label="调整网卡顺序" size="large" />
</el-form-item>
</el-form>
</div>
</template>
<script>
import { reactive, ref} from 'vue';
import { useTuntap } from './tuntap';
import TuntapForward from './TuntapForward.vue'
import TuntapLan from './TuntapLan.vue'
import { Delete, Plus, Warning, Refresh } from '@element-plus/icons-vue'
export default {
emits: ['change'],
components: { Delete, Plus, Warning, Refresh,TuntapForward ,TuntapLan},
setup(props, { emit }) {
const tuntap = useTuntap();
const ruleFormRef = ref(null);
const state = reactive({
ruleForm: {
IP: tuntap.value.current.IP,
PrefixLength: tuntap.value.current.PrefixLength || 24,
Gateway: tuntap.value.current.Gateway,
ShowDelay: tuntap.value.current.ShowDelay,
AutoConnect: tuntap.value.current.AutoConnect,
Upgrade: tuntap.value.current.Upgrade,
Multicast: tuntap.value.current.Multicast,
Nat: tuntap.value.current.Nat,
TcpMerge: tuntap.value.current.TcpMerge,
InterfaceOrder: tuntap.value.current.InterfaceOrder,
Forwards: tuntap.value.current.Forwards,
Name: tuntap.value.current.Name,
},
rules: {
Name: {
type: 'string',
pattern: /^$|^[A-Za-z][A-Za-z0-9]{0,31}$/,
message:'请输入正确的网卡名',
transform(value) {
return value.trim();
},
}
}
});
const handlePrefixLengthChange = () => {
var value = +state.ruleForm.PrefixLength;
if (value > 32 || value < 16 || isNaN(value)) {
value = 24;
}
state.ruleForm.PrefixLength = value;
}
const getData = ()=>{
const json = JSON.parse(JSON.stringify(tuntap.value.current));
json.IP = state.ruleForm.IP.replace(/\s/g, '') || '0.0.0.0';
json.PrefixLength = +state.ruleForm.PrefixLength;
json.Gateway = state.ruleForm.Gateway;
json.ShowDelay = state.ruleForm.ShowDelay;
json.AutoConnect = state.ruleForm.AutoConnect;
json.Upgrade = state.ruleForm.Upgrade;
json.Multicast = state.ruleForm.Multicast;
json.Nat = state.ruleForm.Nat;
json.TcpMerge = state.ruleForm.TcpMerge;
json.InterfaceOrder = state.ruleForm.InterfaceOrder;
json.Name = state.ruleForm.Name;
return json;
}
return {
state, ruleFormRef, handlePrefixLengthChange,getData
}
}
}
</script>
<style lang="stylus" scoped>
.el-switch.is-disabled{opacity :1;}
.wrap{min-height:40rem;}
</style>

View File

@@ -4,7 +4,7 @@
<span class="yellow">使用系统NAT或应用层SNAT</span>
</div>
<div class="wrap">
<el-table stripe :data="state.lans" border size="small" width="100%" height="200px" @cell-dblclick="handleCellClick">
<el-table stripe :data="state.lans" border size="small" width="100%" height="400px" @cell-dblclick="handleCellClick">
<el-table-column prop="IP" label="路由IP" width="120">
<template #default="scope">
<template v-if="scope.row.IPEditing">
@@ -150,7 +150,4 @@ export default {
}
</script>
<style lang="stylus" scoped>
.wrap{
padding:0 1rem 1rem 0;
}
</style>

View File

@@ -4,6 +4,7 @@ using System.Diagnostics;
using linker.messenger.entry;
using linker.libs.extends;
using System.Text;
using System.Text.Json;
namespace linker
{
@@ -50,13 +51,11 @@ namespace linker
public static void Run(string[] args)
{
LinkerMessengerEntry.Initialize();
LinkerMessengerEntry.Build();
Dictionary<string, string> configDic = ParseArgs(args);
LinkerMessengerEntry.Setup(ExcludeModule.None, configDic);
using JsonDocument json = ParseArgs(args);
LinkerMessengerEntry.Setup(ExcludeModule.None, json);
LoggerHelper.Instance.Warning($"current version : {VersionHelper.version}");
LoggerHelper.Instance.Warning($"linker env is docker : {Environment.GetEnvironmentVariable("SNLTTY_LINKER_IS_DOCKER")}");
@@ -66,18 +65,18 @@ namespace linker
GCHelper.FlushMemory();
}
private static Dictionary<string, string> ParseArgs(string[] args)
private static JsonDocument ParseArgs(string[] args)
{
Dictionary<string, string> configDic = new Dictionary<string, string>();
JsonDocument json = null;
try
{
configDic = Encoding.UTF8.GetString(Convert.FromBase64String(args[0])).DeJson<Dictionary<string, string>>();
json = JsonDocument.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(args[0])));
}
catch (Exception ex)
{
LoggerHelper.Instance.Error(ex);
LoggerHelper.Instance.Error($"args parse fail {ex}");
}
return configDic;
return json;
}
}

View File

@@ -1,5 +1,5 @@
v1.7.7
2025-05-05 11:08:59
2025-05-06 14:14:16
1. 一些累计更新
2. 优化ssl证书兼容安卓
3. 打洞和中继优化显示loading增加手动尝试打洞