This commit is contained in:
snltty
2025-08-31 01:38:16 +08:00
parent d49fa0cdd1
commit 155efd440e
26 changed files with 552 additions and 47 deletions

View File

@@ -37,7 +37,7 @@ jobs:
release_name: v1.9.1.${{ steps.date.outputs.today }}
draft: false
prerelease: false
body: "1. 一些累计更新\r\n2. 服务器转发多节点\r\n3. 虚拟网卡下伪造ACK为TCP-in-TCP隧道提速\r\n4. 一些代码优化、修复一些错误\r\n5. 优化打洞\r\n6. 其它一些小改变"
body: "1. 一些累计更新\r\n2. 服务器转发多节点\r\n3. 虚拟网卡下伪造ACK为TCP-in-TCP隧道提速\r\n4. 一些代码优化、修复一些错误\r\n5. 新增一个UDP同时打开的打洞协议优化了一下TCP同时打开的打洞协议\r\n6. 其它一些小改变"
- name: publish projects
run: ./publish.bat "C:\\Android\\android-sdk"
- name: upload-win-x86-oss

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.el-radio-group[data-v-72593913]{margin-right:.6rem}.wrap[data-v-72593913]{padding-bottom:1rem}.el-form-item[data-v-4af2067e]{margin-bottom:1rem}.el-input-number--small[data-v-4af2067e]{width:10rem!important}.el-form-item[data-v-7ea96748]{margin-bottom:1rem}.el-input-number--small[data-v-7ea96748]{width:10rem!important}.head .search>div[data-v-1fe12153]{margin-right:1rem}.page[data-v-1fe12153]{padding:2rem 0;display:inline-block}.el-form-item[data-v-1fe12153]{margin-bottom:1rem}.el-input-number--small[data-v-1fe12153]{width:10rem!important}.head .search>div[data-v-6a696afb]{margin-right:1rem}.page[data-v-6a696afb]{padding:2rem 0;display:inline-block}.el-form-item[data-v-6a696afb]{margin-bottom:1rem}.el-input-number--small[data-v-6a696afb]{width:10rem!important}.el-transfer.src-tranfer .el-transfer__buttons .el-button{display:block}.el-transfer.src-tranfer .el-transfer__buttons .el-button:nth-child(2){margin:1rem 0 0 0}.el-form-item[data-v-26eb3ac8]{margin-bottom:1rem}.el-input-number--small[data-v-26eb3ac8]{width:10rem!important}.blue[data-v-92ae2ca2]{color:#409eff}.el-checkbox[data-v-92ae2ca2]{font-weight:100}a.a-edit .el-icon[data-v-92ae2ca2]{vertical-align:middle}.el-form-item[data-v-70160c48]{margin-bottom:1rem}.el-input-number--small[data-v-70160c48]{width:10rem!important}.head .search>div[data-v-7977ca92]{margin-right:1rem}.page[data-v-7977ca92]{padding:2rem 0;display:inline-block}.el-form-item[data-v-7977ca92]{margin-bottom:1rem}.el-input-number--small[data-v-7977ca92]{width:10rem!important}.blue[data-v-e76dff3a]{color:#409eff}a.a-edit[data-v-e76dff3a]{margin-left:1rem}a.a-edit .el-icon[data-v-e76dff3a]{vertical-align:middle}.el-form-item[data-v-06530694]{margin-bottom:1rem}.el-input-number--small[data-v-06530694]{width:10rem!important}.el-checkbox[data-v-09d3b4fe]{font-weight:100}a.a-edit .el-icon[data-v-09d3b4fe]{vertical-align:middle}.servers-wrap[data-v-3b21a224]{padding:1rem;font-size:1.3rem;color:#555}.servers-wrap a[data-v-3b21a224]{color:#333}

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.3e624437.js"></script><script defer="defer" src="js/app.a82999c6.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.db9830c6.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.e9b4f2f4.js"></script><script defer="defer" src="js/app.d3e1d5d0.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.e16885f2.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

View File

@@ -0,0 +1 @@
"use strict";(self["webpackChunklinker_web"]=self["webpackChunklinker_web"]||[]).push([[276],{35377:function(e,s,t){t.d(s,{A:function(){return b}});var a=t(56768),n=t(24232);const l={class:"t-c"},c={class:"t-c w-100 mgt-1"};function o(e,s,t,o,r,d){const i=(0,a.g2)("Share"),u=(0,a.g2)("el-icon"),m=(0,a.g2)("el-button"),h=(0,a.g2)("el-transfer"),f=(0,a.g2)("el-dialog");return(0,a.uX)(),(0,a.CE)("div",null,[(0,a.RG)(e.$slots,"default",{},(()=>[(0,a.bF)(m,{class:"btn",size:"small",onClick:o.handleShowSync},{default:(0,a.k6)((()=>[(0,a.bF)(u,null,{default:(0,a.k6)((()=>[(0,a.bF)(i)])),_:1})])),_:1},8,["onClick"])])),(0,a.bF)(f,{class:"options-center",title:e.$t("server.sync"),"destroy-on-close":"",modelValue:o.state.showNames,"onUpdate:modelValue":s[2]||(s[2]=e=>o.state.showNames=e),width:"54rem",top:"2vh"},{default:(0,a.k6)((()=>[(0,a.Lk)("div",null,[(0,a.Lk)("div",l,(0,n.v_)(`${e.$t("server.sync")}${e.$t(`server.async${o.state.name}`)}${e.$t("server.asyncText")}`),1),(0,a.bF)(h,{class:"src-tranfer mgt-1",modelValue:o.state.srcIdValues,"onUpdate:modelValue":s[0]||(s[0]=e=>o.state.srcIdValues=e),filterable:"","filter-method":o.srcFilterMethod,data:o.state.srcIds,titles:[e.$t("firewall.unselect"),e.$t("firewall.selected")],props:{key:"MachineId",label:"MachineName"}},null,8,["modelValue","filter-method","data","titles"]),(0,a.Lk)("div",c,[(0,a.bF)(m,{onClick:s[1]||(s[1]=e=>o.state.showNames=!1)},{default:(0,a.k6)((()=>[(0,a.eW)((0,n.v_)(e.$t("common.cancel")),1)])),_:1}),(0,a.bF)(m,{type:"primary",onClick:o.handleConfirm},{default:(0,a.k6)((()=>[(0,a.eW)((0,n.v_)(e.$t("common.confirm")),1)])),_:1},8,["onClick"])])])])),_:1},8,["title","modelValue"])])}var r=t(69299),d=t(10004);const i=e=>(0,d.zG)("sync/Sync",e);var u=t(53830),m=t(57477),h=t(51219),f=t(90144),v=t(35931),k={props:["name"],components:{Share:m.SYj},setup(e){const{t:s}=(0,v.s9)(),t=(0,u.B)(),n=(0,a.EW)((()=>t.value.hasAccess("Sync"))),l=(0,f.Kh)({name:e.name,loading:!1,showNames:!1,srcIdValues:[],srcIds:[]}),c=()=>{i({names:[e.name],ids:l.srcIdValues}).then((e=>{h.nk.success(s("common.oper")),l.showNames=!1}))},o=()=>{n.value?(l.showNames=!0,d()):h.nk.success(s("common.access"))},d=()=>{l.loading=!0,(0,r.NT)().then((e=>{l.loading=!1,l.srcIds=e})).catch((e=>{l.loading=!1}))},m=(e,s)=>s.MachineName.toLowerCase().includes(e.toLowerCase());return{state:l,handleShowSync:o,srcFilterMethod:m,handleConfirm:c}}},w=t(71241);const p=(0,w.A)(k,[["render",o]]);var b=p},83384:function(e,s,t){t.r(s),t.d(s,{default:function(){return m}});var a=t(56768);const n={class:"firewall-setting-wrap flex flex-column h-100"},l={class:"inner"};function c(e,s,t,c,o,r){const d=(0,a.g2)("Firewall");return(0,a.uX)(),(0,a.CE)("div",n,[(0,a.Lk)("div",l,[(0,a.bF)(d)])])}var o=t(90144),r=t(63733),d={components:{Firewall:r.A},setup(e,{emit:s}){const t=(0,o.Kh)({});return{state:t}}},i=t(71241);const u=(0,i.A)(d,[["render",c],["__scopeId","data-v-101dd60e"]]);var m=u}}]);

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([[52],{96271:function(e,t,n){n.d(t,{A:function(){return b}});var a=n(56768),s=n(24232);const o={class:"flex"},c={class:"flex-1"},r={class:"t-c"};function l(e,t,n,l,d,i){const u=(0,a.g2)("Sync"),m=(0,a.g2)("el-input"),h=(0,a.g2)("el-button"),v=(0,a.g2)("el-card"),f=(0,a.gN)("trim");return(0,a.uX)(),(0,a.Wv)(v,{shadow:"never"},{header:(0,a.k6)((()=>[(0,a.Lk)("div",o,[(0,a.Lk)("span",c,(0,s.v_)(e.$t("action.text")),1),l.state.isSelf?((0,a.uX)(),(0,a.Wv)(u,{key:0,name:"ActionStatic"})):(0,a.Q3)("",!0)])])),footer:(0,a.k6)((()=>[(0,a.Lk)("div",r,[(0,a.bF)(h,{type:"success",onClick:l.handleSave},{default:(0,a.k6)((()=>[(0,a.eW)((0,s.v_)(e.$t("common.confirm")),1)])),_:1},8,["onClick"])])])),default:(0,a.k6)((()=>[(0,a.Lk)("div",null,[(0,a.bo)((0,a.bF)(m,{modelValue:l.state.data,"onUpdate:modelValue":t[0]||(t[0]=e=>l.state.data=e),rows:10,type:"textarea",resize:"none",onChange:l.handleSave},null,8,["modelValue","onChange"]),[[f]])])])),_:1})}var d=n(10004);const i=e=>(0,d.zG)("action/GetServerArgs",e),u=e=>(0,d.zG)("action/SetServerArgs",e);var m=n(53830),h=n(51219),v=n(90144),f=n(35931),k=n(35377),p={props:["machineId"],components:{Sync:k.A},setup(e){const{t:t}=(0,f.s9)(),n=(0,m.B)(),s=(0,v.Kh)({data:"",machineId:e.machineId||n.value.config.Client.Id,isSelf:(0,a.EW)((()=>s.machineId==n.value.config.Client.Id))}),o=()=>{i(s.machineId).then((e=>{s.data=e}))},c=()=>{try{if(s.data&&"object"!=typeof JSON.parse(s.data))return void h.nk.error(t("action.jsonError"))}catch(e){return void h.nk.error(t("action.jsonError"))}u({Key:s.machineId,Value:s.data}).then((()=>{h.nk.success(t("common.oper"))})).catch((e=>{console.log(e),h.nk.error(t("common.operFail"))}))};return(0,a.sV)((()=>{o()})),{state:s,handleSave:c}}},g=n(71241);const I=(0,g.A)(p,[["render",l]]);var b=I},35377:function(e,t,n){n.d(t,{A:function(){return I}});var a=n(56768),s=n(24232);const o={class:"t-c"},c={class:"t-c w-100 mgt-1"};function r(e,t,n,r,l,d){const i=(0,a.g2)("Share"),u=(0,a.g2)("el-icon"),m=(0,a.g2)("el-button"),h=(0,a.g2)("el-transfer"),v=(0,a.g2)("el-dialog");return(0,a.uX)(),(0,a.CE)("div",null,[(0,a.RG)(e.$slots,"default",{},(()=>[(0,a.bF)(m,{class:"btn",size:"small",onClick:r.handleShowSync},{default:(0,a.k6)((()=>[(0,a.bF)(u,null,{default:(0,a.k6)((()=>[(0,a.bF)(i)])),_:1})])),_:1},8,["onClick"])])),(0,a.bF)(v,{class:"options-center",title:e.$t("server.sync"),"destroy-on-close":"",modelValue:r.state.showNames,"onUpdate:modelValue":t[2]||(t[2]=e=>r.state.showNames=e),width:"54rem",top:"2vh"},{default:(0,a.k6)((()=>[(0,a.Lk)("div",null,[(0,a.Lk)("div",o,(0,s.v_)(`${e.$t("server.sync")}${e.$t(`server.async${r.state.name}`)}${e.$t("server.asyncText")}`),1),(0,a.bF)(h,{class:"src-tranfer mgt-1",modelValue:r.state.srcIdValues,"onUpdate:modelValue":t[0]||(t[0]=e=>r.state.srcIdValues=e),filterable:"","filter-method":r.srcFilterMethod,data:r.state.srcIds,titles:[e.$t("firewall.unselect"),e.$t("firewall.selected")],props:{key:"MachineId",label:"MachineName"}},null,8,["modelValue","filter-method","data","titles"]),(0,a.Lk)("div",c,[(0,a.bF)(m,{onClick:t[1]||(t[1]=e=>r.state.showNames=!1)},{default:(0,a.k6)((()=>[(0,a.eW)((0,s.v_)(e.$t("common.cancel")),1)])),_:1}),(0,a.bF)(m,{type:"primary",onClick:r.handleConfirm},{default:(0,a.k6)((()=>[(0,a.eW)((0,s.v_)(e.$t("common.confirm")),1)])),_:1},8,["onClick"])])])])),_:1},8,["title","modelValue"])])}var l=n(69299),d=n(10004);const i=e=>(0,d.zG)("sync/Sync",e);var u=n(53830),m=n(57477),h=n(51219),v=n(90144),f=n(35931),k={props:["name"],components:{Share:m.SYj},setup(e){const{t:t}=(0,f.s9)(),n=(0,u.B)(),s=(0,a.EW)((()=>n.value.hasAccess("Sync"))),o=(0,v.Kh)({name:e.name,loading:!1,showNames:!1,srcIdValues:[],srcIds:[]}),c=()=>{i({names:[e.name],ids:o.srcIdValues}).then((e=>{h.nk.success(t("common.oper")),o.showNames=!1}))},r=()=>{s.value?(o.showNames=!0,d()):h.nk.success(t("common.access"))},d=()=>{o.loading=!0,(0,l.NT)().then((e=>{o.loading=!1,o.srcIds=e})).catch((e=>{o.loading=!1}))},m=(e,t)=>t.MachineName.toLowerCase().includes(e.toLowerCase());return{state:o,handleShowSync:r,srcFilterMethod:m,handleConfirm:c}}},p=n(71241);const g=(0,p.A)(k,[["render",r]]);var I=g},5052:function(e,t,n){n.r(t),n.d(t,{default:function(){return u}});var a=n(56768);const s={class:"action-wrap"};function o(e,t,n,o,c,r){const l=(0,a.g2)("Action");return(0,a.uX)(),(0,a.CE)("div",s,[(0,a.bF)(l,{machineId:o.state.machineId},null,8,["machineId"])])}var c=n(90144),r=n(96271),l={props:["machineId"],components:{Action:r.A},setup(e){const t=(0,c.Kh)({machineId:e.machineId});return{state:t}}},d=n(71241);const i=(0,d.A)(l,[["render",o],["__scopeId","data-v-08c763b2"]]);var u=i}}]);

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

@@ -0,0 +1 @@
"use strict";(self["webpackChunklinker_web"]=self["webpackChunklinker_web"]||[]).push([[708],{87414:function(e,a,n){n.r(a),n.d(a,{default:function(){return J}});var t=n(56768);const s={class:"net-wrap app-wrap"},l={class:"inner absolute flex flex-column flex-nowrap"},i={class:"head"},u={class:"body flex-1 relative"},r={class:"status"};function c(e,a,n,c,d,o){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",u,[(0,t.bF)(p)]),(0,t.Lk)("div",r,[(0,t.bF)(v,{config:!1})])])])}n(44114);var d=n(24232);const o=e=>((0,t.Qi)("data-v-1cb47bd6"),e=e(),(0,t.jt)(),e),g={class:"head-wrap"},p={class:"tools flex"},v={class:"label"},h=o((()=>(0,t.Lk)("span",{class:"flex-1"},null,-1))),f={style:{"margin-left":"1rem"}};function k(e,a,n,s,l,i){const u=(0,t.g2)("Refresh"),r=(0,t.g2)("el-icon"),c=(0,t.g2)("el-button"),o=(0,t.g2)("Background");return(0,t.uX)(),(0,t.CE)("div",g,[(0,t.Lk)("div",p,[(0,t.Lk)("span",v,"分组 : "+(0,d.v_)(s.state.group),1),h,(0,t.bF)(c,{size:"small",onClick:s.handleRefresh},{default:(0,t.k6)((()=>[(0,t.eW)(" 刷新(F5)"),(0,t.bF)(r,null,{default:(0,t.k6)((()=>[(0,t.bF)(u)])),_:1})])),_:1},8,["onClick"]),(0,t.Lk)("div",f,[(0,t.bF)(o,{name:"net"})])])])}var b=n(53830),m=n(90144),C=n(57477),L=n(7199),_={components:{Edit:C.ffu,Refresh:C.C42,Background:L.A},setup(){const e=(0,b.B)(),a=(0,m.Kh)({server:(0,t.EW)((()=>e.value.config.Client.Server.Host)),group:(0,t.EW)((()=>e.value.config.Client.Group.Name))}),n=()=>{window.location.reload()};return{state:a,handleRefresh:n}}},w=n(71241);const S=(0,w.A)(_,[["render",k],["__scopeId","data-v-1cb47bd6"]]);var x=S;const F=e=>((0,t.Qi)("data-v-3c358101"),e=e(),(0,t.jt)(),e),z={class:"net-list-wrap flex flex-column absolute"},E={class:"flex-1 scrollbar"},T={class:"flex"},A=F((()=>(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,a,n,s,l,i){const u=(0,t.g2)("DeviceName"),r=(0,t.g2)("UpdaterBtn"),c=(0,t.g2)("TuntapShow"),d=(0,t.g2)("el-pagination");return(0,t.uX)(),(0,t.CE)("div",z,[(0,t.Lk)("div",E,[(0,t.Lk)("ul",null,[((0,t.uX)(!0),(0,t.CE)(t.FK,null,(0,t.pI)(s.devices.page.List,((e,a)=>((0,t.uX)(),(0,t.CE)("li",{key:a},[(0,t.Lk)("dl",null,[(0,t.Lk)("dt",T,[(0,t.Lk)("div",null,[(0,t.bF)(u,{item:e},null,8,["item"])]),A,(0,t.Lk)("div",null,[(0,t.bF)(r,{config:!1,item:e},null,8,["item"])])]),(0,t.Lk)("dd",I,[s.tuntap.list[e.MachineId]?((0,t.uX)(),(0,t.Wv)(c,{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)(d,{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 y=n(75234),X=n(54373),N=n(65304),U=n(31480),D=n(33200),Q=n(6564),W=n(73417),H=n(76978),K={components:{StarFilled:C.BQ2,UpdaterBtn:U.A,DeviceName:D.A,TuntapShow:Q.A},setup(e){(0,b.B)();const a=(0,m.Kh)({}),{devices:n,machineId:s,_getSignList:l,_getSignList1:i,handlePageChange:u,handlePageSizeChange:r,clearDevicesTimeout:c}=(0,X.r)(),{tuntap:d,_getTuntapInfo:o,handleTuntapRefresh:g,clearTuntapTimeout:p,handleTuntapEdit:v,sortTuntapIP:h}=(0,y.O)(),{_getUpdater:f,_subscribeUpdater:k,clearUpdaterTimeout:C}=(0,N.d)();(0,H.y)();(0,W.L2)();return(0,t.sV)((()=>{u(),g(),l(),i(),o(),f(),k()})),(0,t.hi)((()=>{c(),p(),C()})),{state:a,devices:n,machineId:s,handlePageChange:u,handlePageSizeChange:r,tuntap:d}}};const j=(0,w.A)(K,[["render",R],["__scopeId","data-v-3c358101"]]);var q=j,M=n(52417),V=n(81387),G={components:{Head:x,List:q,Status:M.A},setup(){document.addEventListener("contextmenu",(function(e){e.preventDefault()}));const e=(0,b.B)(),a=(0,V.rd)();return(0,t.sV)((()=>{0==e.value.hasAccess("NetManager")&&a.push({name:"NoPermission"})})),{}}};const O=(0,w.A)(G,[["render",c],["__scopeId","data-v-60d9820b"]]);var J=O}}]);

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

@@ -1,11 +1,7 @@
using linker.messenger.api;
using linker.messenger.decenter;
using linker.messenger.decenter;
using linker.messenger.exroute;
using linker.tunnel;
using Microsoft.Extensions.DependencyInjection;
using System.Text.Json.Serialization;
using System.Text.Json;
using linker.tunnel.connection;
using linker.messenger.signin.args;
using linker.messenger.sync;
using linker.libs.web;
@@ -15,9 +11,6 @@ namespace linker.messenger.tunnel
{
public static ServiceCollection AddTunnelClient(this ServiceCollection serviceCollection)
{
//SerialzeExtends.AddJsonConverter(new ITunnelConnectionConverter());
serviceCollection.AddSingleton<TunnelTransfer>();
serviceCollection.AddSingleton<TunnelClientExcludeIPTransfer>();
serviceCollection.AddSingleton<ITunnelMessengerAdapter, TunnelMessengerAdapter>();
@@ -75,8 +68,6 @@ namespace linker.messenger.tunnel
public static ServiceCollection AddTunnelServer(this ServiceCollection serviceCollection)
{
//SerialzeExtends.AddJsonConverter(new ITunnelConnectionConverter());
serviceCollection.AddSingleton<TunnelServerMessenger>();
serviceCollection.AddSingleton<TunnelServerExternalResolver>();
return serviceCollection;
@@ -92,17 +83,4 @@ namespace linker.messenger.tunnel
return serviceProvider;
}
}
public sealed class ITunnelConnectionConverter : JsonConverter<ITunnelConnection>
{
public override ITunnelConnection Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return null;
}
public override void Write(Utf8JsonWriter writer, ITunnelConnection value, JsonSerializerOptions options)
{
writer.WriteStringValue(string.Empty);
}
}
}

View File

@@ -35,6 +35,7 @@ namespace linker.tunnel
tunnelWanPortTransfer = new TunnelWanPortTransfer();
transports = new List<ITunnelTransport> {
new TransportUdp(tunnelMessengerAdapter),
new TransportUdpP2PNAT(tunnelMessengerAdapter),
new TransportTcpP2PNAT(tunnelMessengerAdapter),
new TransportTcpNutssb(tunnelMessengerAdapter),
transportUdpPortMap,
@@ -327,7 +328,7 @@ namespace linker.tunnel
/// <param name="tunnelTransportInfo"></param>
public async Task OnBegin(TunnelTransportInfo tunnelTransportInfo)
{
if (operating.StartOperation(BuildKey(tunnelTransportInfo.Remote.MachineId, tunnelTransportInfo.TransactionId)) == false)
{
return;

View File

@@ -123,28 +123,31 @@ namespace linker.tunnel.transport
&& tunnelTransportInfo.Local.LocalIps.Any(c => c.AddressFamily == AddressFamily.InterNetworkV6)
? new IPEndPoint(tunnelTransportInfo.Remote.LocalIps.FirstOrDefault(c => c.AddressFamily == AddressFamily.InterNetworkV6), tunnelTransportInfo.Remote.Remote.Port)
: tunnelTransportInfo.Remote.Remote;
Socket targetSocket = new(ep.AddressFamily, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
try
for (int i = 0; i < 5; i++)
{
targetSocket.KeepAlive();
targetSocket.IPv6Only(ep.AddressFamily, false);
targetSocket.ReuseBind(new IPEndPoint(ep.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, tunnelTransportInfo.Local.Local.Port));
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
Socket targetSocket = new(ep.AddressFamily, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
try
{
LoggerHelper.Instance.Warning($"{Name} connect to {tunnelTransportInfo.Remote.MachineId}->{tunnelTransportInfo.Remote.MachineName} {ep}");
}
await targetSocket.ConnectAsync(ep).WaitAsync(TimeSpan.FromMilliseconds(2000)).ConfigureAwait(false);
targetSocket.KeepAlive();
targetSocket.IPv6Only(ep.AddressFamily, false);
targetSocket.ReuseBind(new IPEndPoint(ep.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, tunnelTransportInfo.Local.Local.Port));
if (mode == TunnelMode.Client)
{
return await TcpClient(tunnelTransportInfo, targetSocket).ConfigureAwait(false);
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Warning($"{Name} connect to {tunnelTransportInfo.Remote.MachineId}->{tunnelTransportInfo.Remote.MachineName} {ep}");
}
await targetSocket.ConnectAsync(ep).WaitAsync(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false);
if (mode == TunnelMode.Client)
{
return await TcpClient(tunnelTransportInfo, targetSocket).ConfigureAwait(false);
}
return await TcpServer(tunnelTransportInfo, targetSocket).ConfigureAwait(false);
}
catch (Exception)
{
targetSocket.SafeClose();
}
return await TcpServer(tunnelTransportInfo, targetSocket).ConfigureAwait(false);
}
catch (Exception)
{
targetSocket.SafeClose();
}
return null;
}

View File

@@ -0,0 +1,168 @@

using linker.tunnel.connection;
using linker.libs;
using linker.libs.extends;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using linker.tunnel.wanport;
namespace linker.tunnel.transport
{
/// <summary>
/// UDP同时连接打洞
///
/// 大致原理
/// A 通知 B B立马连接AA也同时去连接B
/// </summary>
public sealed class TransportUdpP2PNAT : ITunnelTransport
{
public string Name => "UdpP2PNAT";
public string Label => "UDP、同时打开";
public TunnelProtocolType ProtocolType => TunnelProtocolType.Udp;
public TunnelWanPortProtocolType AllowWanPortProtocolType => TunnelWanPortProtocolType.Udp;
public bool Reverse => true;
public bool DisableReverse => false;
public bool SSL => true;
public bool DisableSSL => false;
public byte Order => 3;
/// <summary>
/// 连接成功
/// </summary>
public Action<ITunnelConnection> OnConnected { get; set; } = (state) => { };
private readonly byte[] authBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.ttl1");
private readonly byte[] endBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.end1");
private readonly ITunnelMessengerAdapter tunnelMessengerAdapter;
public TransportUdpP2PNAT(ITunnelMessengerAdapter tunnelMessengerAdapter)
{
this.tunnelMessengerAdapter = tunnelMessengerAdapter;
}
public void SetSSL(X509Certificate certificate)
{
}
/// <summary>
/// 连接对方
/// </summary>
/// <param name="tunnelTransportInfo"></param>
/// <returns></returns>
public async Task<ITunnelConnection> ConnectAsync(TunnelTransportInfo tunnelTransportInfo)
{
if (await tunnelMessengerAdapter.SendConnectBegin(tunnelTransportInfo).ConfigureAwait(false) == false)
{
return null;
}
if (tunnelTransportInfo.Direction == TunnelDirection.Reverse)
{
await Task.Delay(50).ConfigureAwait(false);
}
ITunnelConnection connection = await ConnectForward(tunnelTransportInfo, TunnelMode.Client).ConfigureAwait(false);
if (connection != null)
{
await tunnelMessengerAdapter.SendConnectSuccess(tunnelTransportInfo).ConfigureAwait(false);
return connection;
}
await tunnelMessengerAdapter.SendConnectFail(tunnelTransportInfo).ConfigureAwait(false);
return null;
}
/// <summary>
/// 收到对方开始连接的消息
/// </summary>
/// <param name="tunnelTransportInfo"></param>
public async Task OnBegin(TunnelTransportInfo tunnelTransportInfo)
{
ITunnelConnection connection = await ConnectForward(tunnelTransportInfo, TunnelMode.Server).ConfigureAwait(false);
if (connection != null)
{
OnConnected(connection);
await tunnelMessengerAdapter.SendConnectSuccess(tunnelTransportInfo).ConfigureAwait(false);
}
else
{
await tunnelMessengerAdapter.SendConnectFail(tunnelTransportInfo).ConfigureAwait(false);
}
}
public void OnFail(TunnelTransportInfo tunnelTransportInfo)
{
}
public void OnSuccess(TunnelTransportInfo tunnelTransportInfo)
{
}
private async Task<ITunnelConnection> ConnectForward(TunnelTransportInfo tunnelTransportInfo, TunnelMode mode)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Warning($"{Name} connect to {tunnelTransportInfo.Remote.MachineId}->{tunnelTransportInfo.Remote.MachineName} {string.Join("\r\n", tunnelTransportInfo.RemoteEndPoints.Select(c => c.ToString()))}");
}
IPEndPoint ep = tunnelTransportInfo.Remote.LocalIps.Any(c => c.AddressFamily == AddressFamily.InterNetworkV6)
&& tunnelTransportInfo.Local.LocalIps.Any(c => c.AddressFamily == AddressFamily.InterNetworkV6)
? new IPEndPoint(tunnelTransportInfo.Remote.LocalIps.FirstOrDefault(c => c.AddressFamily == AddressFamily.InterNetworkV6), tunnelTransportInfo.Remote.Remote.Port)
: tunnelTransportInfo.Remote.Remote;
byte[] buffer = new byte[1024];
IPEndPoint tempEP = new IPEndPoint(ep.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0);
Socket targetSocket = new(ep.AddressFamily, SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp);
targetSocket.IPv6Only(ep.AddressFamily, false);
targetSocket.WindowsUdpBug();
targetSocket.ReuseBind(new IPEndPoint(ep.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, tunnelTransportInfo.Local.Local.Port));
for (int i = 0; i < 5; i++)
{
try
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Warning($"{Name} connect to {tunnelTransportInfo.Remote.MachineId}->{tunnelTransportInfo.Remote.MachineName} {ep}");
}
targetSocket.SendTo(authBytes, ep);
recv:;
var result = await targetSocket.ReceiveFromAsync(buffer, tempEP).WaitAsync(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false);
if ((result.RemoteEndPoint as IPEndPoint).Equals(ep) == false)
{
goto recv;
}
ISymmetricCrypto crypto = mode == TunnelMode.Client ? CryptoFactory.CreateSymmetric(tunnelTransportInfo.Remote.MachineId) : CryptoFactory.CreateSymmetric(tunnelTransportInfo.Local.MachineId);
return new TunnelConnectionUdp
{
UdpClient = targetSocket,
RemoteMachineId = tunnelTransportInfo.Remote.MachineId,
RemoteMachineName = tunnelTransportInfo.Remote.MachineName,
Direction = tunnelTransportInfo.Direction,
ProtocolType = TunnelProtocolType.Udp,
Type = TunnelType.P2P,
Mode = mode,
TransactionId = tunnelTransportInfo.TransactionId,
TransactionTag = tunnelTransportInfo.TransactionTag,
TransportName = tunnelTransportInfo.TransportName,
IPEndPoint = NetworkHelper.TransEndpointFamily(ep),
Label = string.Empty,
Receive = true,
SSL = tunnelTransportInfo.SSL,
Crypto = crypto
};
}
catch (Exception)
{
}
}
targetSocket.SafeClose();
return null;
}
}
}

View File

@@ -24,7 +24,7 @@
2. 服务器转发多节点
3. 虚拟网卡下伪造ACK为TCP-in-TCP隧道提速
4. 一些代码优化、修复一些错误
5. 优化打洞
5. 新增一个UDP同时打开的打洞协议优化了一下TCP同时打开的打洞协议
6. 其它一些小改变</Description>
<Copyright>snltty</Copyright>
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>

View File

@@ -1,8 +1,8 @@
v1.9.1
2025-08-30 21:22:23
2025-08-31 01:38:15
1. 一些累计更新
2. 服务器转发多节点
3. 虚拟网卡下伪造ACK为TCP-in-TCP隧道提速
4. 一些代码优化、修复一些错误
5. 优化打洞
5. 新增一个UDP同时打开的打洞协议优化了一下TCP同时打开的打洞协议
6. 其它一些小改变