mirror of
https://github.com/snltty/linker.git
synced 2025-09-26 21:15:57 +08:00
177
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,6 +5,6 @@ obj
|
||||
node_modules
|
||||
/public/*
|
||||
/x64/*
|
||||
/src/linker.share.win/*
|
||||
|
||||
|
||||
TestResults
|
30
linker.sln
30
linker.sln
@@ -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
|
||||
|
@@ -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;
|
||||
|
1
src/linker.app/public/web/css/14.46b35329.css
Normal file
1
src/linker.app/public/web/css/14.46b35329.css
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.app/public/web/css/596.05fef871.css
Normal file
1
src/linker.app/public/web/css/596.05fef871.css
Normal file
File diff suppressed because one or more lines are too long
1
src/linker.app/public/web/css/app.09dcc3e8.css
Normal file
1
src/linker.app/public/web/css/app.09dcc3e8.css
Normal file
File diff suppressed because one or more lines are too long
@@ -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>
|
277
src/linker.app/public/web/js/123.c1ee077e.js
Normal file
277
src/linker.app/public/web/js/123.c1ee077e.js
Normal file
File diff suppressed because one or more lines are too long
1
src/linker.app/public/web/js/14.47d44c63.js
Normal file
1
src/linker.app/public/web/js/14.47d44c63.js
Normal file
File diff suppressed because one or more lines are too long
@@ -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}}]);
|
1
src/linker.app/public/web/js/32.c00f21cc.js
Normal file
1
src/linker.app/public/web/js/32.c00f21cc.js
Normal file
File diff suppressed because one or more lines are too long
1
src/linker.app/public/web/js/596.b9acb564.js
Normal file
1
src/linker.app/public/web/js/596.b9acb564.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.app/public/web/js/754.a7c56d93.js
Normal file
1
src/linker.app/public/web/js/754.a7c56d93.js
Normal file
File diff suppressed because one or more lines are too long
1
src/linker.app/public/web/js/898.0352a0a6.js
Normal file
1
src/linker.app/public/web/js/898.0352a0a6.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
@@ -13,7 +13,7 @@ sidebar_position: 11
|
||||
|
||||

|
||||
|
||||
先下载 <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`升级,重启
|
||||
|
||||
|
@@ -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"
|
||||
}
|
||||
}"
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
BIN
src/linker.doc.web/static/update-20241130.bin
Normal file
BIN
src/linker.doc.web/static/update-20241130.bin
Normal file
Binary file not shown.
@@ -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();
|
||||
|
7
src/linker.messenger.firewall/LinkerFirewall.cs
Normal file
7
src/linker.messenger.firewall/LinkerFirewall.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
namespace linker.messenger.firewall
|
||||
{
|
||||
internal sealed class LinkerFirewall
|
||||
{
|
||||
}
|
||||
}
|
@@ -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>
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -1,5 +0,0 @@
|
||||
namespace linker.messenger.serializer.aot
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class JsonAotAttribute : Attribute { }
|
||||
}
|
@@ -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);
|
||||
|
@@ -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>();
|
||||
|
@@ -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);
|
||||
|
@@ -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)
|
||||
|
@@ -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"/>
|
||||
|
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/14.46b35329.css
Normal file
1
src/linker.tray.win/web/css/14.46b35329.css
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/css/227.896b84cf.css
Normal file
1
src/linker.tray.win/web/css/227.896b84cf.css
Normal file
File diff suppressed because one or more lines are too long
@@ -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>
|
1
src/linker.tray.win/web/js/14.47d44c63.js
Normal file
1
src/linker.tray.win/web/js/14.47d44c63.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/227.47378724.js
Normal file
1
src/linker.tray.win/web/js/227.47378724.js
Normal 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}}]);
|
1
src/linker.tray.win/web/js/75.7740bcfe.js
Normal file
1
src/linker.tray.win/web/js/75.7740bcfe.js
Normal file
File diff suppressed because one or more lines are too long
1
src/linker.tray.win/web/js/app.6c05d4d4.js
Normal file
1
src/linker.tray.win/web/js/app.6c05d4d4.js
Normal file
File diff suppressed because one or more lines are too long
@@ -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
26
src/linker.tun/LanMap.cs
Normal 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
101
src/linker.tun/LanSnat.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -1,6 +1,5 @@
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace linker.tun
|
||||
{
|
||||
|
@@ -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>
|
@@ -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; /* 超出的文本隐藏 */
|
||||
|
95
src/linker.web/src/views/full/devices/TuntapIP.vue
Normal file
95
src/linker.web/src/views/full/devices/TuntapIP.vue
Normal 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>
|
@@ -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>
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
v1.7.7
|
||||
2025-05-05 11:08:59
|
||||
2025-05-06 14:14:16
|
||||
1. 一些累计更新
|
||||
2. 优化ssl证书,兼容安卓
|
||||
3. 打洞和中继优化,显示loading,增加手动尝试打洞
|
||||
|
Reference in New Issue
Block a user