From b518dbfd58262c292e62dbac94670c464cad1927 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Mon, 29 May 2023 22:23:19 +0800 Subject: [PATCH 01/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=AE=98=E7=BD=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs/.vuepress/public/img/logo/xiaonuo.png | Bin 0 -> 48128 bytes neutrino-proxy-vuepress/docs/index.md | 5 ++++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 neutrino-proxy-vuepress/docs/.vuepress/public/img/logo/xiaonuo.png diff --git a/neutrino-proxy-vuepress/docs/.vuepress/public/img/logo/xiaonuo.png b/neutrino-proxy-vuepress/docs/.vuepress/public/img/logo/xiaonuo.png new file mode 100644 index 0000000000000000000000000000000000000000..b40e5deeb768c215099a2c53ff7c2a9e6f523673 GIT binary patch literal 48128 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

dw+Fg zZ^s&>unFua_&TdAw0>#Ye%i&8%vhgDtgZZV!DgdJb6L{;2c{kQcApId5H}EfWx*hV zBaNX(U#K^IMS=`=34NV149F|*_l&;#m<3hjAXh5`q2^}lNNhX)A}sz1o)76gr%5k; zF0M-z-gt)}(QABBf$*$HpC_K!=N71{pe!eoRs;zvwHscn)O*CMPxE~*kUa}58CWKB`~08+@VV)ze_&dIO^U-E+O_5__-DFk*}83h@xqSE(`(aEn%WNuv(BFP zx$yYtRRINz4~8saO$^W4Rcu`qVhjCN3z`e9Yp1fXH=YP%aX^6y654Oo%aHZO&0zR!3Db9cqbRCxL0Mt+W3fM` z>vB>y-sCq%Ku-QaW*>WmE8sYyr1Eh=8U z0;rezhe~&PZ197Rg>CA8SkO2|Z3uw}I1csL5VIkO`8tzBXRRPra92g8P18WA3jVpA z@~8M@(1mHNAUuS#0z5(*#NBqB!;1c#;ko&01B&Neu)#Xufd;i06XZn)Y}w$>FG`l)Ey9ngOvs{Rko^Z=7ns!FhS`;$xrb^gRv`StpDCiD9QgA&10Lk07? ze1pxHC!&F25?<5me&5RSRfksbuAEDF=BCxa&R$OvuV1we-8QPoEA3stmozAg$0moL_-d)#g!Zs z2R)Ej2>Kd`mgk@4yQjhVuKDb=NOsB^l>#urD9Pa)CFWSe{~Pp*)AAT4k3fOQZlYq) zh@5EKJTO{Y?Q(oWDDK@jO@;b1N1_ook9YMcZD(y73k{}Oq7y!Oz8>)+8xp}gwB}-$ zAf79?84&}YXJZ-i;U9Nz-`1<|^2QazS#DTj1HV4ZIf4XxVdDzKNM8qG7}3Ulw0FE& zyI(#UmElO50!+$wUs?&>R`?Pd3q3fF-;>TTm3l?dT|5A@sDfkHj($&)d33w27uH1b zfDw(w3^l<@c#nm!%uO7z!y-+{c%6(!xOkEJ5w}YC@itHRAt^LyT z+pXN_S0)ys?+%o01pJOK*E=}W3no0Ud`qmOf1eZ+%HL2%iMfcf=SVP@IGO+!>;7`j zh1m4n2p=}s&v&MySc3{)ZxSs2GS&=&_^5QjDqa*kVEH(h@OIbD%x+0atLFjY;ph0S zJ3oLubE9dlU99R+FchDW80JijGHMkQ+p>t;-5!csSi&ryX3NV?ZsxFS3c8PaD%viH zIu2kBlOzmeP`nhTy-ArjuDU-GQIn{!D8vGcF4UT*% zqxDQVYL&t;syVB-@xYs#@~=ErU%HRj(1FTPTvhK+(!V#H%X>Pfccx&G@h5DZQ48wB z>wKmz&167u6I*kdn;BjQ1s*EAI0KMR_@l+=vAZm-(X;xrO9*#9;u7CHnuWuptzR%+ z`jiB0Q=?K^K$bq|ONcH_%&!B}mIWUhJ$W3{E7MLGwT%C|LYvcc3<~_lv9)bCo zTTa)L4`?-RYZ{pS*b-|oPqQvL)9u7{fFuBGR)M}_PEDkzy`O$-vg7xiR(u%oN%gCG zp^d?j)#Ak9^H_be!N<8fQ-%`@fV(lE#~+LM?;>7}zb$qo8)cpg5?mt+ zY~p=@YnNETs#hg{YCya{ba?SZ8am=#-@N3Xy!01uzHN8Ac;cDqDK5@uCcr1A|Wn_tlQ6S#Qu zsEHZ4$ATNuOCchMBZs(P!;Q79BE@KYU{4XcX_`tk-tru(jPVx-D-VK|DA*Ug1a%;~ z7pnJxX8}ZK811e$p~864{Xr%o=eHzof1LKX4lz_E zJARILq5|AWxXd>(&$MS#twRl9R^i}?h5*;8pj_KHgqIT?F@A~P?*I;!QB%5(6A^Hj zPDF^&CTTx9zA0RvkmwBDSvt>>cL^1A@q<6Uc)0EF#RffafI#`O@nam!&!6LD%C0h@3qCYBiL+|ErTBaEo#){=O*y&^}xL>$2rs+_Jjo7l`L0`klwEak8?xkc{@rN)rRss?e_% zRD~3{aU8N*fr1r$kQs{Z=CltpL$LXrukF*3pLnjpf70S7%CC%TPZ5V}>Y?3_vYJ)k zlZ)1CxJDZgjz7DBySz&(fB`L=TXemL zr1ll?qSQZHE*+P8a?vNhnZ+bu%602WHV4-~&E@;pq3FR;IuXk?bp52;( z+_Z2iPM!QQY@1FX+N^``T)flnWa+zd_shIuvAo;Wq6Wrv=u+Rqs$x#lbciNrOsBf4 z3zJfydBmq)fHgrlieL_PwSYo`&jIuNk82YqM$H-CE40`JN`_1 z{TCX`9{m-6Bt|Ni`~~f{-!iA)T49Bt5T}o`;GK!t&Kh5r*eNyJVFvv0e!?g83;Z`N?858!oZnT%FpF?El@nvt4UM@qF${_M>W)LElL7@_UPF zX-wgfA7H&k{5)%9nY4eVR&Iui&GABmeHRVF8!{Dy>SN1 zk0Xs~6<*8LKc1iKyE~8@^fkh_-;Yp|9qhRjO)L$1&9{g5%uO~X_}u}Y3mWnfG*6sy zZvHN4g>Sk8Ofk~_H&!(*QGql(vtYi2f;_N17Z zD&VYLSD%+C^;lAgYDIHpu01|}cHEvk*bLUmvsdjTvL`g!Aqj15W#-7EQ(Ksnr3rJ`GcU)rpGDquFMV2oy(7T z3Yl-!KmqF15#Y0eYSO46V}rURr2&B8b=p1WrmJ51&^<2VNZBN`eAQ)aBU=+wiXo!S zSHil}E;tLo$waL-;cCstJ9UOQL;NV;n#lr`+y^oUUbh%diU6xBP(w-dQf)gf)D9Qu z-NDIn3)E)3}7S7Jn-zJG46mdJFh8JoOv%BrL|0Bn&QE-veuEL~f-(RhK3vgB3`!PwAl` z$4xnElYP0P@0j_=gP(X4Vrtm@AI-+NTk-J6B5z9s%kGTEpfluT*?IN!Ic(O-r;{Sz z*>DckLEhyS9WUfb?mlrj1;t+c$y==0Q3END?Y+^+XtX~(*kiZqcyBZbow=+?$1*jQ zG5bVi6z&oZu8A<5Oc7d84O~lIL}%%R{wVX&85WRW)Ak0>9Z<8JksEZVU}IKxn`k^B zA7#Pj-Xse#f3uE}>!wLsog zUL8=Q!+Ug=m}x-C@wd7e?N&!)-qeAm^ou#)3tG1_Sj$@=_sD6Qo6*bm1c6SAr{L~M zSP@RG=W+>(M}H+{*qL7LY7|~6 zl!Dy7i9(Q3jEu42bI&ezKL<zpFPjk-8^Y?xZPH&Ry6*7x7UC=u*z1ZmQ(iQzr5C=>%tYgEIplzz~@p@KZEI9Z^l+SoNr-k4kKAG{5oaOqb z?%Z6xsuQD~eg-%n+|YW^J?MN5)r8fS;jEqs@n|CIAei~0J zA1A@B-vC3`K)~TPkLy`u#-WU6b{mCe73{;p`W?6DrxKk-p05(DlP^yNSUjLA zOIztuiPkl}1&NoeD{|d$!_ybBVskXcUcEC7vm9X*?LZuH ze5u*pPmPqpb3IzF0Q_Pj>YQsyL^xZy8;2jJi62J0Eq07{_*-iLH6xtVH4HoLZnQuE zWR5uTp}O>hwLwGB_eoZ0hPdc>UdbY^hn?#egposW^bZKlV%nS)%O%4BQQX`3?O( z4Q8%ZFWXsbl9r?N?&BOEss>ovhmHR}Eehg-d@4jDts3%?4dS6@y6X>SkXw05M z4c!97^o8Ipzc?}gVRZk-Co!7;`_EIwEVdhOTDXVLbdA}g?uSqVvDd6SP(iyU?{zm3 zgF%fkr=5Z?o!ZXR3FqMde;Ey-D$|tFFW8ka1R!SGlYHxE@{IOK`dT6Vo!MISBn=#e zAiC%6=5d#m$NxLi|C-Q|cv0gPB-efK*tAMrTMd!OIQKJAsni0QY~4-KuKSe+_CEMF z(S4nL)j|Ewl@LeowEMeYE$dA?-Ke#VQVab5na%bvuTZLs&GeP`^?$KNmzeB3hQY*m z7qBRP-$_1Fv;I#73j-pPfF8P92Xmi)A+bsX;mt-8jm21j?pwHeVSm59!v3#_Xq4r0 z-21XCDMKHT+GHr)O?1LL_Ky(9(AchLRVMykMvn>Qo+I}EKk5F@n)UI;s#-;+48fi_ zZk1Y!NZ4J_<^Q5pby_c7T|}vJ2tacS><#`I??z$w&-`{_sQ_nm+u7ocJtE~p9?H-p zokQ{eXaD}!A3H%V)a<1UJ>yX1dGP#3@$r8FlyHACaCiOu{7CTrz6daC0;>}JKaPl3 zJpv*pNJrwhJt2tf+@ew zA_HviA=JX~V`RmgVbk)}y^?F>uEREu{z2!0L}&BH~Kc1`r^cM(>w*2~*TStL_p z$B?(-zW~I>p0QnvB<4VF31bBjQTS5sEK{&7;j{N()uUR-tp|nSzfy}z1>|4@j-{X1 z5|Q7FD-w*os zBdp&4oR|@Ow(DPVfhR9K6p%X#ibV@)m5rT^fZU=}$o~VO76UmD6$GDhAbNmDY5Yxm z{oq?fzvjei`owAaL~n}D`>!&Z66hR$!DiiJ46I=X!9RwD=)V1>Jv|Ywt9q2;_|OrT z{U61pNi_PB3b*O0I_-^SnsB{tFv2_Q`dYs-gQ4$B_BG11?Q``s1FJ;CwT_rELK z;74V<&c>ctyd#XgJKgz`oCP2gm)VOhxlSICzWVPzBTrs6vhLLG7J_B129yjFtIG$- zlGpkv9d*S;{Ijg##ZLxxlyc>C4e(X6+LYd&PUcK)mYrefRH3>f@>C|{?hskxe*VYl4|V^7-bEV5`mh>l z+hdTVX@AZ=ErU8}Q2P;d;27LGkQxH}>-?|n8^L0`c3DT*UYZ0ltex8f4uh4DHhb-2 z?q3r|f~9k~&{sHM68KK><=_8#ySEql`-FUCxF^lBga-e+#~bUV`O@@eFb0#*Sqn7- zcTg7KL;S1_ns*t?Dgx)NAAX}T4Z%MuE*?uBqnx&G=VMW zOOOs()1IY5aE{qdPhQfjWbw7lqv`)P5~&sNFpEG~ikKG+F7Oo0vF@NVN!4?>~uML?g*vsDNWDg;Q*=`}l*7&~CC?KP2U&Soo-}_rGR3y5u$TNSOD&Sw^nf zPsRD$lbdGmS^?{+4D)$!;@YLF-#=&4kvkX4#TLS5N~Cl&1CgLSL!54b5z0q7B|a;y zi~rvEeE*DxohP{&fz;XrBNo$Ul%7kD$4T8g_`hg{h@L)tMn$🤝 友情开源项目

- + + + +

From 7dda047d5177c7199c8eb1db794afbddf6fc3b95 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Mon, 29 May 2023 22:57:16 +0800 Subject: [PATCH 02/45] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=8A=A5=E4=B8=8D=E6=94=AF=E6=8C=81=E7=9A=84=E5=8D=8F=E8=AE=AE?= =?UTF-8?q?HTTPS=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../neutrinoproxy/server/constant/NetworkProtocolEnum.java | 7 +++++++ .../neutrinoproxy/server/service/PortMappingService.java | 3 +++ 2 files changed, 10 insertions(+) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/NetworkProtocolEnum.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/NetworkProtocolEnum.java index 25b4677b..be5d23c9 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/NetworkProtocolEnum.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/NetworkProtocolEnum.java @@ -2,6 +2,7 @@ package org.dromara.neutrinoproxy.server.constant; import lombok.AllArgsConstructor; import lombok.Getter; +import org.apache.commons.lang3.StringUtils; import java.util.Map; import java.util.function.Function; @@ -23,6 +24,12 @@ public enum NetworkProtocolEnum { private static final Map map = Stream.of(NetworkProtocolEnum.values()).collect(Collectors.toMap(NetworkProtocolEnum::getDesc, Function.identity())); public static NetworkProtocolEnum of(String desc) { + if (StringUtils.isBlank(desc)) { + return null; + } + if (desc.startsWith("HTTP")) { + return NetworkProtocolEnum.HTTP; + } return map.get(desc); } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java index 5867ece7..ee085e26 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java @@ -108,6 +108,9 @@ public class PortMappingService implements LifecycleBean { if (StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(item.getSubdomain())) { item.setDomain(item.getSubdomain() + "." + proxyConfig.getServer().getDomainName()); } + if (NetworkProtocolEnum.HTTP.getDesc().equals(item.getProtocal())) { + item.setProtocal("HTTP(S)"); + } }); //sorted [userId asc] [licenseId asc] [createTime asc] respList = respList.stream().sorted(Comparator.comparing(PortMappingListRes::getUserId) From ea67c2bce0c7f71162a116b9d3621c1dada6a353 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Wed, 31 May 2023 21:34:53 +0800 Subject: [PATCH 03/45] =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=AB=AF=E4=BB=A3?= =?UTF-8?q?=E7=90=86=E7=9B=B8=E5=85=B3=E5=91=BD=E5=90=8D=E8=B0=83=E6=95=B4?= =?UTF-8?q?=EF=BC=8C=E4=BD=BF=E5=BE=97=E8=A1=A8=E4=B9=89=E6=9B=B4=E5=8A=A0?= =?UTF-8?q?=E5=87=86=E7=A1=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dromara/neutrinoproxy/server/proxy/core/HttpProxy.java | 1 + .../dromara/neutrinoproxy/server/proxy/core/HttpsProxy.java | 1 + .../core/{ProxyServerRunner.java => ProxyTunnelServer.java} | 5 ++--- 3 files changed, 4 insertions(+), 3 deletions(-) rename neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/{ProxyServerRunner.java => ProxyTunnelServer.java} (97%) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpProxy.java index fbbe4e05..e58aa407 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpProxy.java @@ -14,6 +14,7 @@ import org.noear.solon.core.event.AppLoadEndEvent; import org.noear.solon.core.event.EventListener; /** + * HTTP代理 * @author: aoshiguchen * @date: 2023/4/2 */ diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpsProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpsProxy.java index bfac3abb..e2eb3ad3 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpsProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpsProxy.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.security.KeyStore; /** + * HTTPS代理 * @author: aoshiguchen * @date: 2023/4/2 */ diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyServerRunner.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelServer.java similarity index 97% rename from neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyServerRunner.java rename to neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelServer.java index 0e634d0e..e6d00a14 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyServerRunner.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelServer.java @@ -1,6 +1,5 @@ package org.dromara.neutrinoproxy.server.proxy.core; -import io.netty.handler.logging.LoggingHandler; import org.dromara.neutrinoproxy.core.ProxyMessageDecoder; import org.dromara.neutrinoproxy.core.ProxyMessageEncoder; import org.dromara.neutrinoproxy.core.util.FileUtil; @@ -27,13 +26,13 @@ import java.io.InputStream; import java.security.KeyStore; /** - * + * 代理隧道服务 * @author: aoshiguchen * @date: 2022/6/16 */ @Slf4j @Component -public class ProxyServerRunner implements EventListener { +public class ProxyTunnelServer implements EventListener { @Inject private ProxyConfig proxyConfig; @Inject("tunnelBossGroup") From 98737f0e9d5a9c12e5ecc8899a64b75bc3dd9cbd Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Wed, 31 May 2023 21:41:22 +0800 Subject: [PATCH 04/45] =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=AB=AF=E4=BB=A3?= =?UTF-8?q?=E7=90=86=E7=9B=B8=E5=85=B3=E5=91=BD=E5=90=8D=E8=B0=83=E6=95=B4?= =?UTF-8?q?=EF=BC=8C=E4=BD=BF=E5=BE=97=E8=A1=A8=E4=B9=89=E6=9B=B4=E5=8A=A0?= =?UTF-8?q?=E5=87=86=E7=A1=AE.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...rverChannelHandler.java => ProxyTunnelChannelHandler.java} | 4 ++-- .../neutrinoproxy/server/proxy/core/ProxyTunnelServer.java | 2 +- .../server/proxy/{core => enhance}/HttpProxy.java | 3 ++- .../proxy/{core => enhance}/HttpVisitorChannelHandler.java | 2 +- .../server/proxy/{core => enhance}/HttpsProxy.java | 3 ++- todolist.MD | 4 ++-- 6 files changed, 10 insertions(+), 8 deletions(-) rename neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/{ServerChannelHandler.java => ProxyTunnelChannelHandler.java} (97%) rename neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/{core => enhance}/HttpProxy.java (94%) rename neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/{core => enhance}/HttpVisitorChannelHandler.java (99%) rename neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/{core => enhance}/HttpsProxy.java (96%) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ServerChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java similarity index 97% rename from neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ServerChannelHandler.java rename to neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java index b0b68b00..6e78924a 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ServerChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java @@ -47,10 +47,10 @@ import java.util.Date; * @date: 2022/6/16 */ @Slf4j -public class ServerChannelHandler extends SimpleChannelInboundHandler { +public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler { private static volatile Dispatcher dispatcher; - public ServerChannelHandler() { + public ProxyTunnelChannelHandler() { dispatcher = Solon.context().getBean(Dispatcher.class); } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelServer.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelServer.java index e6d00a14..bd7e8c35 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelServer.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelServer.java @@ -117,6 +117,6 @@ public class ProxyTunnelServer implements EventListener { proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip())); ch.pipeline().addLast(new ProxyMessageEncoder()); ch.pipeline().addLast(new IdleStateHandler(proxyConfig.getProtocol().getReadIdleTime(), proxyConfig.getProtocol().getWriteIdleTime(), proxyConfig.getProtocol().getAllIdleTimeSeconds())); - ch.pipeline().addLast(new ServerChannelHandler()); + ch.pipeline().addLast(new ProxyTunnelChannelHandler()); } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java similarity index 94% rename from neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpProxy.java rename to neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java index e58aa407..b3f1f6ad 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java @@ -1,4 +1,4 @@ -package org.dromara.neutrinoproxy.server.proxy.core; +package org.dromara.neutrinoproxy.server.proxy.enhance; import cn.hutool.core.util.StrUtil; import io.netty.bootstrap.ServerBootstrap; @@ -8,6 +8,7 @@ import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import lombok.extern.slf4j.Slf4j; import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig; +import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler; import org.noear.solon.annotation.Component; import org.noear.solon.annotation.Inject; import org.noear.solon.core.event.AppLoadEndEvent; diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpVisitorChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java similarity index 99% rename from neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpVisitorChannelHandler.java rename to neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java index adf00073..40882d8e 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpVisitorChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java @@ -1,4 +1,4 @@ -package org.dromara.neutrinoproxy.server.proxy.core; +package org.dromara.neutrinoproxy.server.proxy.enhance; import cn.hutool.core.util.StrUtil; import io.netty.buffer.ByteBuf; diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpsProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java similarity index 96% rename from neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpsProxy.java rename to neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java index e2eb3ad3..0af8f0f2 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/HttpsProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java @@ -1,4 +1,4 @@ -package org.dromara.neutrinoproxy.server.proxy.core; +package org.dromara.neutrinoproxy.server.proxy.enhance; import cn.hutool.core.util.StrUtil; import io.netty.bootstrap.ServerBootstrap; @@ -11,6 +11,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.dromara.neutrinoproxy.core.util.FileUtil; import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig; +import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler; import org.noear.solon.annotation.Component; import org.noear.solon.annotation.Inject; import org.noear.solon.core.event.AppLoadEndEvent; diff --git a/todolist.MD b/todolist.MD index 07476287..9af5aa0c 100644 --- a/todolist.MD +++ b/todolist.MD @@ -2,7 +2,7 @@ - [ ] 增加针对https的支持 # Bug -- 指令通达被close的问题,org.dromara.neutrinoproxy.server.proxy.core.ServerChannelHandler.channelInactive +- 指令通达被close的问题,org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelChannelHandler.channelInactive - windows环境下直接运行发布版的jar包,日志输出乱码 - 代理mysql时,使用未开启远程访问的账号走代理访问mysql,代理客户端出现断开现象 @@ -26,4 +26,4 @@ # 3.x规划 - [ ] 支持针对用户限速、限流 - [ ] 支持P2P穿透 -- [ ] 支持原生编译 \ No newline at end of file +- [ ] 支持原生编译 From b52225937c94ba0f92f894ca4ac7f4b42d71a697 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Wed, 31 May 2023 22:23:12 +0800 Subject: [PATCH 05/45] =?UTF-8?q?http=E3=80=81https=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E7=BA=BF=E7=A8=8B=E6=B1=A0=E5=88=86=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../neutrinoproxy/server/proxy/enhance/HttpProxy.java | 6 +----- .../neutrinoproxy/server/proxy/enhance/HttpsProxy.java | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java index b3f1f6ad..bac549a6 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java @@ -22,10 +22,6 @@ import org.noear.solon.core.event.EventListener; @Slf4j @Component public class HttpProxy implements EventListener { - @Inject("serverBossGroup") - private NioEventLoopGroup serverBossGroup; - @Inject("serverWorkerGroup") - private NioEventLoopGroup serverWorkerGroup; @Inject private ProxyConfig proxyConfig; @Override @@ -40,7 +36,7 @@ public class HttpProxy implements EventListener { private void start() { try { ServerBootstrap bootstrap = new ServerBootstrap(); - bootstrap.group(serverBossGroup, serverWorkerGroup) + bootstrap.group(new NioEventLoopGroup(1), new NioEventLoopGroup()) .channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java index 0af8f0f2..c3d7dd14 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java @@ -29,10 +29,6 @@ import java.security.KeyStore; @Slf4j @Component public class HttpsProxy implements EventListener { - @Inject("serverBossGroup") - private NioEventLoopGroup serverBossGroup; - @Inject("serverWorkerGroup") - private NioEventLoopGroup serverWorkerGroup; @Inject private ProxyConfig proxyConfig; @Override @@ -48,7 +44,7 @@ public class HttpsProxy implements EventListener { private void start() { try { ServerBootstrap bootstrap = new ServerBootstrap(); - bootstrap.group(serverBossGroup, serverWorkerGroup) + bootstrap.group(new NioEventLoopGroup(1), new NioEventLoopGroup()) .channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { From a972e0f3093e5559884cea2f010c60827b7801bd Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Wed, 31 May 2023 22:29:44 +0800 Subject: [PATCH 06/45] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= =?UTF-8?q?=EF=BC=8C=E9=81=BF=E5=85=8D=E6=96=B0=E5=A2=9E=E7=AB=AF=E5=8F=A3?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E6=97=B6=E4=B8=8D=E6=96=AD=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E6=96=B0=E7=9A=84ServerBootstrap=E5=AE=9E=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/base/proxy/ProxyConfiguration.java | 9 +++++++++ .../server/service/VisitorChannelService.java | 20 ++++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java index a4c2ca6b..186ca59e 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java @@ -1,5 +1,6 @@ package org.dromara.neutrinoproxy.server.base.proxy; +import io.netty.bootstrap.ServerBootstrap; import org.dromara.neutrinoproxy.core.ProxyDataTypeEnum; import org.dromara.neutrinoproxy.core.ProxyMessage; import org.dromara.neutrinoproxy.core.ProxyMessageHandler; @@ -43,6 +44,14 @@ public class ProxyConfiguration implements LifecycleBean { return new NioEventLoopGroup(proxyConfig.getServer().getWorkThreadCount()); } + @Bean("tcpServerBootstrap") + public ServerBootstrap tcpServerBootstrap(@Inject("serverBossGroup") NioEventLoopGroup serverBossGroup, + @Inject("serverWorkerGroup") NioEventLoopGroup serverWorkerGroup) { + ServerBootstrap bootstrap = new ServerBootstrap(); + bootstrap.group(serverBossGroup, serverWorkerGroup); + return bootstrap; + } + @Bean("tunnelBossGroup") public NioEventLoopGroup tunnelBossGroup(@Inject ProxyConfig proxyConfig) { return new NioEventLoopGroup(proxyConfig.getTunnel().getBossThreadCount()); diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java index 6eb7c5aa..229780ba 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java @@ -41,10 +41,8 @@ import java.util.stream.Collectors; @Slf4j @Component public class VisitorChannelService { - @Inject("serverBossGroup") - private NioEventLoopGroup serverBossGroup; - @Inject("serverWorkerGroup") - private NioEventLoopGroup serverWorkerGroup; + @Inject("tcpServerBootstrap") + private ServerBootstrap tcpServerBootstrap; @Inject private ProxyMutualService proxyMutualService; @Db @@ -218,20 +216,18 @@ public class VisitorChannelService { if (CollectionUtil.isEmpty(portMappingList)) { return; } - ServerBootstrap bootstrap = new ServerBootstrap(); - bootstrap.group(serverBossGroup, serverWorkerGroup) - .channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() { + tcpServerBootstrap.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { - ch.pipeline().addFirst(new BytesMetricsHandler()); - ch.pipeline().addLast(new TcpVisitorChannelHandler()); - } - }); + ch.pipeline().addFirst(new BytesMetricsHandler()); + ch.pipeline().addLast(new TcpVisitorChannelHandler()); + } + }); for (PortMappingDO portMapping : portMappingList) { try { proxyMutualService.bindServerPort(cmdChannelAttachInfo, portMapping.getServerPort()); - bootstrap.bind(portMapping.getServerPort()).get(); + tcpServerBootstrap.bind(portMapping.getServerPort()).get(); log.info("绑定用户端口: {}", portMapping.getServerPort()); } catch (Exception ex) { // BindException表示该端口已经绑定过 From 5a502115b10ce2f0308f763ed5cd105661170de3 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Wed, 31 May 2023 22:32:22 +0800 Subject: [PATCH 07/45] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= =?UTF-8?q?=EF=BC=8C=E9=81=BF=E5=85=8D=E6=96=B0=E5=A2=9E=E7=AB=AF=E5=8F=A3?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E6=97=B6=E4=B8=8D=E6=96=AD=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E6=96=B0=E7=9A=84ServerBootstrap=E5=AE=9E=E4=BE=8B.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/base/proxy/ProxyConfiguration.java | 15 ++++++++++++++- .../server/service/VisitorChannelService.java | 7 ------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java index 186ca59e..7aa5a712 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java @@ -1,6 +1,9 @@ package org.dromara.neutrinoproxy.server.base.proxy; import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; import org.dromara.neutrinoproxy.core.ProxyDataTypeEnum; import org.dromara.neutrinoproxy.core.ProxyMessage; import org.dromara.neutrinoproxy.core.ProxyMessageHandler; @@ -8,6 +11,8 @@ import org.dromara.neutrinoproxy.core.dispatcher.DefaultDispatcher; import org.dromara.neutrinoproxy.core.dispatcher.Dispatcher; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.nio.NioEventLoopGroup; +import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler; +import org.dromara.neutrinoproxy.server.proxy.core.TcpVisitorChannelHandler; import org.noear.solon.Solon; import org.noear.solon.annotation.Bean; import org.noear.solon.annotation.Configuration; @@ -48,7 +53,15 @@ public class ProxyConfiguration implements LifecycleBean { public ServerBootstrap tcpServerBootstrap(@Inject("serverBossGroup") NioEventLoopGroup serverBossGroup, @Inject("serverWorkerGroup") NioEventLoopGroup serverWorkerGroup) { ServerBootstrap bootstrap = new ServerBootstrap(); - bootstrap.group(serverBossGroup, serverWorkerGroup); + bootstrap.group(serverBossGroup, serverWorkerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addFirst(new BytesMetricsHandler()); + ch.pipeline().addLast(new TcpVisitorChannelHandler()); + } + }); return bootstrap; } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java index 229780ba..1db3808e 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java @@ -216,13 +216,6 @@ public class VisitorChannelService { if (CollectionUtil.isEmpty(portMappingList)) { return; } - tcpServerBootstrap.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() { - @Override - public void initChannel(SocketChannel ch) throws Exception { - ch.pipeline().addFirst(new BytesMetricsHandler()); - ch.pipeline().addLast(new TcpVisitorChannelHandler()); - } - }); for (PortMappingDO portMapping : portMappingList) { try { From 2d0b9132e983566f90a9bf7d014438c4ac719ad2 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Wed, 31 May 2023 22:42:16 +0800 Subject: [PATCH 08/45] =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E6=9E=9A=E4=B8=BE?= =?UTF-8?q?=E8=B0=83=E6=95=B4=EF=BC=8C=E7=BB=B4=E6=8A=A4=E5=8D=8F=E8=AE=AE?= =?UTF-8?q?=E5=85=B3=E8=81=94=E7=9A=84=E4=B8=8B=E5=B1=82=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../neutrinoproxy/server/constant/NetworkProtocolEnum.java | 7 ++++--- .../server/service/VisitorChannelService.java | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/NetworkProtocolEnum.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/NetworkProtocolEnum.java index be5d23c9..7a053552 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/NetworkProtocolEnum.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/NetworkProtocolEnum.java @@ -16,11 +16,12 @@ import java.util.stream.Stream; @Getter @AllArgsConstructor public enum NetworkProtocolEnum { - TCP("TCP"), - UDP("UDP"), - HTTP("HTTP"), + TCP("TCP", "TCP"), + UDP("UDP", "UDP"), + HTTP("HTTP", "TCP"), ; private String desc; + private String baseProtocol; private static final Map map = Stream.of(NetworkProtocolEnum.values()).collect(Collectors.toMap(NetworkProtocolEnum::getDesc, Function.identity())); public static NetworkProtocolEnum of(String desc) { diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java index 1db3808e..bd409d69 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java @@ -218,6 +218,7 @@ public class VisitorChannelService { } for (PortMappingDO portMapping : portMappingList) { + // TODO 此处切入,TCP/UDP代理 try { proxyMutualService.bindServerPort(cmdChannelAttachInfo, portMapping.getServerPort()); tcpServerBootstrap.bind(portMapping.getServerPort()).get(); From e2195ab966904edcc58bff02ff42af9ab8a6a7ec Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Thu, 1 Jun 2023 22:34:41 +0800 Subject: [PATCH 09/45] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E9=87=8D?= =?UTF-8?q?=E8=BF=9E=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../neutrinoproxy/client/core/ProxyClientService.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java index 37561b7a..70186cb4 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java @@ -49,7 +49,7 @@ public class ProxyClientService { /** * 重连间隔(秒) */ - private static final long RECONNECT_INTERVAL_SECONDS = 5; + private static final long RECONNECT_INTERVAL_SECONDS = 8; /** * 重连次数 */ @@ -80,6 +80,14 @@ public class ProxyClientService { bootstrap.group(workerGroup); bootstrap.channel(NioSocketChannel.class); + bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000); + bootstrap.option(ChannelOption.SO_KEEPALIVE, true); + /** + * TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。 + * Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。 + */ + bootstrap.option(ChannelOption.TCP_NODELAY, true); + bootstrap.handler(new ChannelInitializer() { @Override From 8c2e1b8f6ce4c72e187c09531c4d723119054afb Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 2 Jun 2023 21:20:19 +0800 Subject: [PATCH 10/45] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E9=87=8D?= =?UTF-8?q?=E8=BF=9E=E4=BC=98=E5=8C=96.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../neutrinoproxy/client/core/ProxyClientService.java | 9 +++++---- neutrino-proxy-client/src/main/resources/app.yml | 8 ++++---- neutrino-proxy-server/src/main/resources/app.yml | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java index 70186cb4..cf138ffa 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java @@ -49,7 +49,7 @@ public class ProxyClientService { /** * 重连间隔(秒) */ - private static final long RECONNECT_INTERVAL_SECONDS = 8; + private static final long RECONNECT_INTERVAL_SECONDS = 5; /** * 重连次数 */ @@ -80,7 +80,7 @@ public class ProxyClientService { bootstrap.group(workerGroup); bootstrap.channel(NioSocketChannel.class); - bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000); + bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000); bootstrap.option(ChannelOption.SO_KEEPALIVE, true); /** * TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。 @@ -189,12 +189,13 @@ public class ProxyClientService { } protected synchronized void reconnect() { - if (!reconnectServiceEnable) { + if (!reconnectServiceEnable || null == channel) { return; } - if (null != channel && channel.isActive()) { + if (channel.isActive()) { return; } + channel.close(); log.info("客户端重连 seq:{}", ++reconnectCount); try { connectProxyServer(); diff --git a/neutrino-proxy-client/src/main/resources/app.yml b/neutrino-proxy-client/src/main/resources/app.yml index cef79537..db8bfaf2 100644 --- a/neutrino-proxy-client/src/main/resources/app.yml +++ b/neutrino-proxy-client/src/main/resources/app.yml @@ -9,9 +9,9 @@ neutrino: length-field-length: 4 initial-bytes-to-strip: 0 length-adjustment: 0 - read-idle-time: 40 - write-idle-time: 5 - all-idle-time-seconds: 45 + read-idle-time: 8 + write-idle-time: 3 + all-idle-time-seconds: 8 client: thread-count: 50 key-store-password: ${STORE_PASS:123456} @@ -20,4 +20,4 @@ neutrino: server-port: ${SERVER_PORT:9002} ssl-enable: ${SSL_ENABLE:true} obtain-license-interval: 5 - license-key: ${LICENSE_KEY:b0a907332b474b25897c4dcb31fc7eb6} + license-key: ${LICENSE_KEY:} diff --git a/neutrino-proxy-server/src/main/resources/app.yml b/neutrino-proxy-server/src/main/resources/app.yml index 76a68f1d..d144ea42 100644 --- a/neutrino-proxy-server/src/main/resources/app.yml +++ b/neutrino-proxy-server/src/main/resources/app.yml @@ -9,7 +9,7 @@ neutrino: length-field-length: 4 initial-bytes-to-strip: 0 length-adjustment: 0 - read-idle-time: 40 + read-idle-time: 30 write-idle-time: 5 all-idle-time-seconds: 0 tunnel: From 2ec87abda973c5bbcc3974f5682dc21dc11860c8 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 2 Jun 2023 22:09:01 +0800 Subject: [PATCH 11/45] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E9=87=8D?= =?UTF-8?q?=E8=BF=9E=E6=9C=BA=E5=88=B6=E8=B0=83=E6=95=B4=EF=BC=8C=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E9=A6=96=E6=AC=A1=E8=BF=9E=E6=8E=A5=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E4=B9=9F=E8=BF=9B=E8=A1=8C=E9=87=8D=E8=BF=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/core/ProxyClientService.java | 199 +++++++++--------- 1 file changed, 104 insertions(+), 95 deletions(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java index cf138ffa..48430cb6 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java @@ -49,15 +49,15 @@ public class ProxyClientService { /** * 重连间隔(秒) */ - private static final long RECONNECT_INTERVAL_SECONDS = 5; + private static final long RECONNECT_INTERVAL_SECONDS = 8; /** * 重连次数 */ private volatile int reconnectCount = 0; - /** - * 启用重连服务 - */ - private volatile boolean reconnectServiceEnable = false; +// /** +// * 启用重连服务 +// */ +// private volatile boolean reconnectServiceEnable = false; /** * 重连服务执行器 */ @@ -80,7 +80,7 @@ public class ProxyClientService { bootstrap.group(workerGroup); bootstrap.channel(NioSocketChannel.class); - bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000); + bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000); bootstrap.option(ChannelOption.SO_KEEPALIVE, true); /** * TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。 @@ -104,103 +104,112 @@ public class ProxyClientService { ch.pipeline().addLast(new ClientChannelHandler()); } }); - this.start(); - } - public void start() { - if (StrUtil.isEmpty(proxyConfig.getClient().getServerIp())) { - log.error("not found server-ip config."); - Solon.stop(); - return; + try { + this.start(); + } catch (Exception e) { + // 启动连不上也做一下重连,因此先catch异常 + log.error("启动异常", e); + } } - if (null == proxyConfig.getClient().getServerPort()) { - log.error("not found server-port config."); - Solon.stop(); - return; + + public void start() { + if (StrUtil.isEmpty(proxyConfig.getClient().getServerIp())) { + log.error("not found server-ip config."); + Solon.stop(); + return; + } + if (null == proxyConfig.getClient().getServerPort()) { + log.error("not found server-port config."); + Solon.stop(); + return; + } + if (null != proxyConfig.getClient().getSslEnable() && proxyConfig.getClient().getSslEnable() + && StrUtil.isEmpty(proxyConfig.getClient().getJksPath())) { + log.error("not found jks-path config."); + Solon.stop(); + return; + } + if (StrUtil.isEmpty(proxyConfig.getClient().getLicenseKey())) { + log.error("not found license-key config."); + Solon.stop(); + return; + } + if (null == channel || !channel.isActive()) { + try { + connectProxyServer(); + } catch (Exception e) { + log.error("client start error", e); + } + } else { + channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey())); + } } - if (null != proxyConfig.getClient().getSslEnable() && proxyConfig.getClient().getSslEnable() - && StrUtil.isEmpty(proxyConfig.getClient().getJksPath())) { - log.error("not found jks-path config."); - Solon.stop(); - return; + + /** + * 连接代理服务器 + */ + private void connectProxyServer() throws InterruptedException { + bootstrap.connect(proxyConfig.getClient().getServerIp(), proxyConfig.getClient().getServerPort()) + .addListener(new ChannelFutureListener() { + + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (future.isSuccess()) { + channel = future.channel(); + // 连接成功,向服务器发送客户端认证信息(licenseKey) + ProxyUtil.setCmdChannel(future.channel()); + future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey())); + log.info("连接代理服务成功. channelId:{}", future.channel().id().asLongText()); + +// reconnectServiceEnable = true; + reconnectCount = 0; + } else { + log.info("连接代理服务失败!"); + } + } + }).sync(); } - if (StrUtil.isEmpty(proxyConfig.getClient().getLicenseKey())) { - log.error("not found license-key config."); - Solon.stop(); - return; + + private ChannelHandler createSslHandler() { + try { + InputStream jksInputStream = FileUtil.getInputStream(proxyConfig.getClient().getJksPath()); + + SSLContext clientContext = SSLContext.getInstance("TLS"); + final KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(jksInputStream, proxyConfig.getClient().getKeyStorePassword().toCharArray()); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(ks); + TrustManager[] trustManagers = tmf.getTrustManagers(); + clientContext.init(null, trustManagers, null); + + SSLEngine sslEngine = clientContext.createSSLEngine(); + sslEngine.setUseClientMode(true); + + return new SslHandler(sslEngine); + } catch (Exception e) { + log.error("创建SSL处理器失败", e); + e.printStackTrace(); + } + return null; } - if (null == channel || !channel.isActive()) { + + protected synchronized void reconnect() { +// if (!reconnectServiceEnable) { +// return; +// } + if (null != channel) { + if (channel.isActive()) { + return; + } + channel.close(); + } + + log.info("客户端重连 seq:{}", ++reconnectCount); try { connectProxyServer(); } catch (Exception e) { - log.error("client start error", e); + log.error("重连异常", e); } - } else { - channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey())); } - } - - /** - * 连接代理服务器 - */ - private void connectProxyServer() throws InterruptedException { - bootstrap.connect(proxyConfig.getClient().getServerIp(), proxyConfig.getClient().getServerPort()) - .addListener(new ChannelFutureListener() { - - @Override - public void operationComplete(ChannelFuture future) throws Exception { - if (future.isSuccess()) { - channel = future.channel(); - // 连接成功,向服务器发送客户端认证信息(licenseKey) - ProxyUtil.setCmdChannel(future.channel()); - future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey())); - log.info("连接代理服务成功. channelId:{}", future.channel().id().asLongText()); - - reconnectServiceEnable = true; - reconnectCount = 0; - } else { - log.info("连接代理服务失败!"); - } - } - }).sync(); - } - - private ChannelHandler createSslHandler() { - try { - InputStream jksInputStream = FileUtil.getInputStream(proxyConfig.getClient().getJksPath()); - - SSLContext clientContext = SSLContext.getInstance("TLS"); - final KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(jksInputStream, proxyConfig.getClient().getKeyStorePassword().toCharArray()); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - tmf.init(ks); - TrustManager[] trustManagers = tmf.getTrustManagers(); - clientContext.init(null, trustManagers, null); - - SSLEngine sslEngine = clientContext.createSSLEngine(); - sslEngine.setUseClientMode(true); - - return new SslHandler(sslEngine); - } catch (Exception e) { - log.error("创建SSL处理器失败", e); - e.printStackTrace(); - } - return null; - } - - protected synchronized void reconnect() { - if (!reconnectServiceEnable || null == channel) { - return; - } - if (channel.isActive()) { - return; - } - channel.close(); - log.info("客户端重连 seq:{}", ++reconnectCount); - try { - connectProxyServer(); - } catch (Exception e) { - log.error("重连异常", e); - } - } } From bcd429d54fae0f6a730c1baad5a0321349466f60 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 2 Jun 2023 22:24:20 +0800 Subject: [PATCH 12/45] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E6=97=B6=E8=AE=A4=E8=AF=81=E5=A4=B1=E8=B4=A5=EF=BC=8C?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E6=96=AD=E5=BC=80=E8=BF=9E=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/handler/ProxyMessageAuthHandler.java | 4 ++++ .../server/proxy/handler/ProxyMessageAuthHandler.java | 5 +++++ todolist.MD | 4 +--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java index 3972f55e..a042c816 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java @@ -2,6 +2,7 @@ package org.dromara.neutrinoproxy.client.handler; import com.alibaba.fastjson.JSONObject; import org.dromara.neutrinoproxy.core.Constants; +import org.dromara.neutrinoproxy.core.ExceptionEnum; import org.dromara.neutrinoproxy.core.ProxyMessage; import org.dromara.neutrinoproxy.core.ProxyMessageHandler; import org.dromara.neutrinoproxy.core.dispatcher.Match; @@ -24,5 +25,8 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { JSONObject data = JSONObject.parseObject(info); Integer code = data.getInteger("code"); log.info("认证结果:{}", info); + if (!ExceptionEnum.SUCCESS.getCode().equals(code)) { + context.channel().close(); + } } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java index a43584da..49d28299 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java @@ -82,6 +82,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { String licenseKey = proxyMessage.getInfo(); if (StrUtil.isEmpty(licenseKey)) { ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不能为空!", licenseKey)); + ctx.channel().close(); clientConnectRecordService.add(new ClientConnectRecordDO() .setIp(ip) .setType(ClientConnectTypeEnum.CONNECT.getType()) @@ -95,6 +96,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { LicenseDO licenseDO = licenseService.findByKey(licenseKey); if (null == licenseDO) { ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不存在!", licenseKey)); + ctx.channel().close(); clientConnectRecordService.add(new ClientConnectRecordDO() .setIp(ip) .setType(ClientConnectTypeEnum.CONNECT.getType()) @@ -107,6 +109,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { } if (EnableStatusEnum.DISABLE.getStatus().equals(licenseDO.getEnable())) { ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "当前license已被禁用!", licenseKey)); + ctx.channel().close(); clientConnectRecordService.add(new ClientConnectRecordDO() .setIp(ip) .setLicenseId(licenseDO.getId()) @@ -120,6 +123,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { UserDO userDO = userService.findById(licenseDO.getUserId()); if (null == userDO || EnableStatusEnum.DISABLE.getStatus().equals(userDO.getEnable())) { ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "当前license无效!", licenseKey)); + ctx.channel().close(); clientConnectRecordService.add(new ClientConnectRecordDO() .setIp(ip) .setLicenseId(licenseDO.getId()) @@ -133,6 +137,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { Channel cmdChannel = ProxyUtil.getCmdChannelByLicenseId(licenseDO.getId()); if (null != cmdChannel) { ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "当前license已被另一节点使用!", licenseKey)); + ctx.channel().close(); clientConnectRecordService.add(new ClientConnectRecordDO() .setIp(ip) .setLicenseId(licenseDO.getId()) diff --git a/todolist.MD b/todolist.MD index 9af5aa0c..a967f1b6 100644 --- a/todolist.MD +++ b/todolist.MD @@ -1,10 +1,8 @@ -# 1.x剩余规划 -- [ ] 增加针对https的支持 - # Bug - 指令通达被close的问题,org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelChannelHandler.channelInactive - windows环境下直接运行发布版的jar包,日志输出乱码 - 代理mysql时,使用未开启远程访问的账号走代理访问mysql,代理客户端出现断开现象 +- 客户端连接映射某个端口以后,如果在服务器端禁用了,没有立刻反映出来,要灯客户端重连以后才会屏蔽被禁用的端口。 # 2.x规划 - 插件开发 From 32504d33af2b53eaf9a0b93430b9c52fceba2681 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 2 Jun 2023 22:36:39 +0800 Subject: [PATCH 13/45] =?UTF-8?q?1=E3=80=81=E6=9C=8D=E5=8A=A1=E7=AB=AF?= =?UTF-8?q?=E3=80=81=E5=AE=A2=E6=88=B7=E7=AB=AF=E8=AE=A4=E8=AF=81=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E8=B0=83=E6=95=B4.=202=E3=80=81=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E7=AB=AF=E5=8F=A3=E6=98=A0=E5=B0=84=E8=A2=AB=E7=A6=81=E7=94=A8?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E5=AE=A2=E6=88=B7=E7=AB=AF=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E4=BE=9D=E7=84=B6=E8=83=BD=E8=AE=BF=E9=97=AE=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/handler/ProxyMessageAuthHandler.java | 8 +++++++- .../server/service/VisitorChannelService.java | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java index a042c816..4cdd240a 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java @@ -8,6 +8,7 @@ import org.dromara.neutrinoproxy.core.ProxyMessageHandler; import org.dromara.neutrinoproxy.core.dispatcher.Match; import io.netty.channel.ChannelHandlerContext; import lombok.extern.slf4j.Slf4j; +import org.noear.solon.Solon; import org.noear.solon.annotation.Component; /** @@ -25,8 +26,13 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { JSONObject data = JSONObject.parseObject(info); Integer code = data.getInteger("code"); log.info("认证结果:{}", info); - if (!ExceptionEnum.SUCCESS.getCode().equals(code)) { + if (ExceptionEnum.CONNECT_FAILED.getCode().equals(code)) { context.channel().close(); + } else if (ExceptionEnum.AUTH_FAILED.getCode().equals(code)) { + // 客户端认证失败,直接停止服务 + log.info("client auth failed , client stop."); + context.channel().close(); + Solon.stop(); } } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java index bd409d69..fe550954 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java @@ -218,6 +218,10 @@ public class VisitorChannelService { } for (PortMappingDO portMapping : portMappingList) { + if (EnableStatusEnum.DISABLE.getStatus().equals(portMapping.getEnable())) { + // 端口映射被禁用了,忽略 TODO 端口被禁用了也需要处理 + continue; + } // TODO 此处切入,TCP/UDP代理 try { proxyMutualService.bindServerPort(cmdChannelAttachInfo, portMapping.getServerPort()); From 375687aa5f17886598658d93aaca10578ba3583d Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 2 Jun 2023 22:46:15 +0800 Subject: [PATCH 14/45] =?UTF-8?q?1=E3=80=81=E6=9C=8D=E5=8A=A1=E7=AB=AF?= =?UTF-8?q?=E3=80=81=E5=AE=A2=E6=88=B7=E7=AB=AF=E8=AE=A4=E8=AF=81=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E8=B0=83=E6=95=B4.=202=E3=80=81=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E7=AB=AF=E5=8F=A3=E6=98=A0=E5=B0=84=E8=A2=AB=E7=A6=81=E7=94=A8?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E5=AE=A2=E6=88=B7=E7=AB=AF=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E4=BE=9D=E7=84=B6=E8=83=BD=E8=AE=BF=E9=97=AE=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dromara/neutrinoproxy/client/core/ProxyClientService.java | 2 +- .../java/org/dromara/neutrinoproxy/core/ExceptionEnum.java | 4 +++- .../server/proxy/handler/ProxyMessageAuthHandler.java | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java index 48430cb6..d79a01b9 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java @@ -65,7 +65,7 @@ public class ProxyClientService { @Init public void init() { - this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 0, RECONNECT_INTERVAL_SECONDS, TimeUnit.SECONDS); + this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 15, RECONNECT_INTERVAL_SECONDS, TimeUnit.SECONDS); NioEventLoopGroup workerGroup = new NioEventLoopGroup(proxyConfig.getClient().getThreadCount()); realServerBootstrap.group(workerGroup); diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ExceptionEnum.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ExceptionEnum.java index d3315d7a..ca02fb37 100644 --- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ExceptionEnum.java +++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ExceptionEnum.java @@ -35,7 +35,9 @@ import lombok.Getter; public enum ExceptionEnum { SUCCESS(0, "成功"), AUTH_FAILED(1, "认证失败"), - CONNECT_FAILED(2, "连接失败"); + CONNECT_FAILED(2, "连接失败"), + LICENSE_CANNOT_REPEAT_CONNECT(3, "license不能多个客户端同时使用"), + ; private Integer code; private String msg; diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java index 49d28299..5d387243 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java @@ -136,7 +136,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { } Channel cmdChannel = ProxyUtil.getCmdChannelByLicenseId(licenseDO.getId()); if (null != cmdChannel) { - ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "当前license已被另一节点使用!", licenseKey)); + ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.LICENSE_CANNOT_REPEAT_CONNECT.getCode(), "当前license已被另一节点使用!", licenseKey)); ctx.channel().close(); clientConnectRecordService.add(new ClientConnectRecordDO() .setIp(ip) From fc4097529ff5de7c8bdbbf81a4e4f0e63eb9cdd8 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 2 Jun 2023 23:26:13 +0800 Subject: [PATCH 15/45] =?UTF-8?q?1=E3=80=81=E6=9C=8D=E5=8A=A1=E7=AB=AF?= =?UTF-8?q?=E3=80=81=E5=AE=A2=E6=88=B7=E7=AB=AF=E8=AE=A4=E8=AF=81=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E8=B0=83=E6=95=B4.=202=E3=80=81=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E7=AB=AF=E5=8F=A3=E6=98=A0=E5=B0=84=E8=A2=AB=E7=A6=81=E7=94=A8?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E5=AE=A2=E6=88=B7=E7=AB=AF=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E4=BE=9D=E7=84=B6=E8=83=BD=E8=AE=BF=E9=97=AE=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/handler/ProxyMessageAuthHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java index 4cdd240a..e6259caa 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java @@ -26,13 +26,13 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { JSONObject data = JSONObject.parseObject(info); Integer code = data.getInteger("code"); log.info("认证结果:{}", info); - if (ExceptionEnum.CONNECT_FAILED.getCode().equals(code)) { - context.channel().close(); - } else if (ExceptionEnum.AUTH_FAILED.getCode().equals(code)) { + if (ExceptionEnum.AUTH_FAILED.getCode().equals(code)) { // 客户端认证失败,直接停止服务 log.info("client auth failed , client stop."); context.channel().close(); Solon.stop(); + } else { + context.channel().close(); } } } From eb277b414a835528361000734435fbafc7683c0a Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Sat, 3 Jun 2023 00:47:30 +0800 Subject: [PATCH 16/45] =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=AB=AF=E3=80=81?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E8=AE=A4=E8=AF=81=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E8=B0=83=E6=95=B4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- .../client/config/CustomConfig.java | 37 --------------- .../client/config/ProxyConfig.java | 1 + .../client/core/ProxyClientService.java | 4 +- .../handler/ProxyMessageAuthHandler.java | 4 +- .../neutrinoproxy/client/util/ProxyUtil.java | 27 +++++++++++ .../src/main/resources/app.yml | 1 + .../neutrinoproxy/core/ExceptionEnum.java | 1 + .../neutrinoproxy/core/ProxyMessage.java | 4 +- .../proxy/core/ProxyTunnelChannelHandler.java | 2 + .../handler/ProxyMessageAuthHandler.java | 45 ++++++++++++++----- .../neutrinoproxy/server/util/ProxyUtil.java | 30 +++++++++++++ 12 files changed, 104 insertions(+), 55 deletions(-) delete mode 100644 neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/CustomConfig.java diff --git a/.gitignore b/.gitignore index 993208fd..b204d46d 100644 --- a/.gitignore +++ b/.gitignore @@ -54,4 +54,5 @@ hs_err_pid* **/memo/** -neutrino-proxy-vuepress/deploy.sh \ No newline at end of file +neutrino-proxy-vuepress/deploy.sh +.NEUTRINO_PROXY_CLIENT_ID diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/CustomConfig.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/CustomConfig.java deleted file mode 100644 index 6f8de075..00000000 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/CustomConfig.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2022 aoshiguchen - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package org.dromara.neutrinoproxy.client.config; - -import lombok.Data; - -/** - * @author: aoshiguchen - * @date: 2022/10/18 - */ -@Data -public class CustomConfig { - private String jksPath; - private String serverIp; - private Integer serverPort; - private Boolean sslEnable; - private String licenseKey; -} diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java index 20f48a18..ebe8376d 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java @@ -39,5 +39,6 @@ public class ProxyConfig { private Integer obtainLicenseInterval; private String licenseKey; private Integer threadCount; + private String clientId; } } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java index d79a01b9..27759491 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java @@ -142,7 +142,7 @@ public class ProxyClientService { log.error("client start error", e); } } else { - channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey())); + channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey(), ProxyUtil.getClientId())); } } @@ -159,7 +159,7 @@ public class ProxyClientService { channel = future.channel(); // 连接成功,向服务器发送客户端认证信息(licenseKey) ProxyUtil.setCmdChannel(future.channel()); - future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey())); + future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey(), ProxyUtil.getClientId())); log.info("连接代理服务成功. channelId:{}", future.channel().id().asLongText()); // reconnectServiceEnable = true; diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java index e6259caa..9acdcc01 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java @@ -31,7 +31,9 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { log.info("client auth failed , client stop."); context.channel().close(); Solon.stop(); - } else { + } else if (ExceptionEnum.CONNECT_FAILED.getCode().equals(code) || + ExceptionEnum.LICENSE_CANNOT_REPEAT_CONNECT.getCode().equals(code) + ){ context.channel().close(); } } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java index 1bbb711d..897b139b 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java @@ -21,6 +21,8 @@ */ package org.dromara.neutrinoproxy.client.util; +import org.apache.commons.lang3.StringUtils; +import org.dromara.neutrinoproxy.client.config.ProxyConfig; import org.dromara.neutrinoproxy.client.core.ProxyChannelBorrowListener; import org.dromara.neutrinoproxy.core.Constants; import io.netty.bootstrap.Bootstrap; @@ -29,10 +31,12 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelOption; import io.netty.util.AttributeKey; +import org.dromara.neutrinoproxy.core.util.FileUtil; import org.noear.solon.Solon; import java.util.Iterator; import java.util.Map; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; @@ -54,6 +58,9 @@ public class ProxyUtil { private static volatile Channel cmdChannel; + private static String clientId; + private static final String CLIENT_ID_FILE = ".NEUTRINO_PROXY_CLIENT_ID"; + public static void borrowProxyChanel(Bootstrap bootstrap, final ProxyChannelBorrowListener borrowListener) { Channel channel = proxyChannelPool.poll(); if (null != channel) { @@ -129,4 +136,24 @@ public class ProxyUtil { realServerChannels.clear(); } + + public static String getClientId() { + if (StringUtils.isNotBlank(clientId)) { + return clientId; + } + ProxyConfig proxyConfig = Solon.context().getBean(ProxyConfig.class); + if (StringUtils.isNotBlank(proxyConfig.getClient().getClientId())) { + clientId = proxyConfig.getClient().getClientId(); + return clientId; + } + String id = FileUtil.readContentAsString(CLIENT_ID_FILE); + if (StringUtils.isNotBlank(id)) { + clientId = id; + return id; + } + id = UUID.randomUUID().toString().replace("-", ""); + FileUtil.write(CLIENT_ID_FILE, id); + clientId = id; + return id; + } } diff --git a/neutrino-proxy-client/src/main/resources/app.yml b/neutrino-proxy-client/src/main/resources/app.yml index db8bfaf2..386790ee 100644 --- a/neutrino-proxy-client/src/main/resources/app.yml +++ b/neutrino-proxy-client/src/main/resources/app.yml @@ -21,3 +21,4 @@ neutrino: ssl-enable: ${SSL_ENABLE:true} obtain-license-interval: 5 license-key: ${LICENSE_KEY:} + client-id: ${CLIENT_ID:} diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ExceptionEnum.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ExceptionEnum.java index ca02fb37..71cdc7a9 100644 --- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ExceptionEnum.java +++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ExceptionEnum.java @@ -36,6 +36,7 @@ public enum ExceptionEnum { SUCCESS(0, "成功"), AUTH_FAILED(1, "认证失败"), CONNECT_FAILED(2, "连接失败"), + @Deprecated LICENSE_CANNOT_REPEAT_CONNECT(3, "license不能多个客户端同时使用"), ; diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java index b4b0e299..5470565e 100644 --- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java +++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java @@ -100,9 +100,9 @@ public class ProxyMessage { return create().setType(TYPE_HEARTBEAT); } - public static ProxyMessage buildAuthMessage(String info) { + public static ProxyMessage buildAuthMessage(String info, String clientId) { return create().setType(TYPE_AUTH) - .setInfo(info); + .setInfo(info + "," + clientId); } public static ProxyMessage buildAuthResultMessage(Integer code, String msg, String licenseKey) { diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java index 6e78924a..8636b74f 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java @@ -99,6 +99,8 @@ public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler subdomainToServerPort = new HashMap<>(); + /** + * licenseId - 客户端Id映射 + */ + private static Map licenseIdToClientIdMap = new HashMap<>(); /** * 初始化代理信息 @@ -387,4 +391,30 @@ public class ProxyUtil { // ignore } } + + /** + * 设置licenseId - clientId映射 + * @param licenseId + * @param clientId + */ + public static void setLicenseIdToClientIdMap(Integer licenseId, String clientId) { + licenseIdToClientIdMap.put(licenseId, clientId); + } + + /** + * 根据licenseId获取clientId + * @param licenseId + * @return + */ + public static String getClientIdByLicenseId(Integer licenseId) { + return licenseIdToClientIdMap.get(licenseId); + } + + /** + * 根据licenseId删除clientId + * @param licenseId + */ + public static void removeClientIdByLicenseId(Integer licenseId) { + licenseIdToClientIdMap.remove(licenseId); + } } From 5a3375ce80280a49bf4c00b2b5cc8901fe5fa893 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Sat, 3 Jun 2023 01:30:52 +0800 Subject: [PATCH 17/45] =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=AB=AF=E3=80=81?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E8=AE=A4=E8=AF=81=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E8=B0=83=E6=95=B4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/core/ProxyClientService.java | 6 ++-- .../proxy/core/ProxyTunnelChannelHandler.java | 28 +++++++++++-------- .../handler/ProxyMessageAuthHandler.java | 2 +- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java index 27759491..d7c6d5f5 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java @@ -49,7 +49,7 @@ public class ProxyClientService { /** * 重连间隔(秒) */ - private static final long RECONNECT_INTERVAL_SECONDS = 8; + private static final long RECONNECT_INTERVAL_SECONDS = 6; /** * 重连次数 */ @@ -65,7 +65,7 @@ public class ProxyClientService { @Init public void init() { - this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 15, RECONNECT_INTERVAL_SECONDS, TimeUnit.SECONDS); + this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 10, RECONNECT_INTERVAL_SECONDS, TimeUnit.SECONDS); NioEventLoopGroup workerGroup = new NioEventLoopGroup(proxyConfig.getClient().getThreadCount()); realServerBootstrap.group(workerGroup); @@ -80,7 +80,7 @@ public class ProxyClientService { bootstrap.group(workerGroup); bootstrap.channel(NioSocketChannel.class); - bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000); + bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000); bootstrap.option(ChannelOption.SO_KEEPALIVE, true); /** * TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。 diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java index 8636b74f..c56c0abd 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java @@ -89,18 +89,22 @@ public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler Date: Sat, 3 Jun 2023 01:34:22 +0800 Subject: [PATCH 18/45] =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=AB=AF=E3=80=81?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E8=AE=A4=E8=AF=81=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../proxy/core/ProxyTunnelChannelHandler.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java index c56c0abd..5d32ff52 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java @@ -93,19 +93,20 @@ public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler Date: Sat, 3 Jun 2023 03:19:45 +0800 Subject: [PATCH 19/45] =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=AB=AF=E3=80=81?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E8=AE=A4=E8=AF=81=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/config/ProxyConfiguration.java | 9 +- .../client/core/CmdChannelHandler.java | 77 ++++++ ...lHandler.java => ProxyChannelHandler.java} | 35 +-- .../client/core/ProxyClientService.java | 250 ++++++++++-------- .../client/core/RealServerChannelHandler.java | 4 +- .../handler/ProxyMessageConnectHandler.java | 6 +- .../neutrinoproxy/client/util/ProxyUtil.java | 6 +- 7 files changed, 242 insertions(+), 145 deletions(-) create mode 100644 neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java rename neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/{ClientChannelHandler.java => ProxyChannelHandler.java} (73%) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java index ebc761ef..ca206083 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java @@ -31,8 +31,13 @@ public class ProxyConfiguration implements LifecycleBean { Solon.context().wrapAndPut(Dispatcher.class, dispatcher); } - @Bean("bootstrap") - public Bootstrap bootstrap() { + @Bean("cmdTunnelBootstrap") + public Bootstrap cmdTunnelBootstrap() { + return new Bootstrap(); + } + + @Bean("proxyTunnelBootstrap") + public Bootstrap proxyTunnelBootstrap() { return new Bootstrap(); } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java new file mode 100644 index 00000000..6db7fdb5 --- /dev/null +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java @@ -0,0 +1,77 @@ +package org.dromara.neutrinoproxy.client.core; + +import org.dromara.neutrinoproxy.client.util.ProxyUtil; +import org.dromara.neutrinoproxy.core.Constants; +import org.dromara.neutrinoproxy.core.ProxyMessage; +import org.dromara.neutrinoproxy.core.dispatcher.Dispatcher; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOption; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.timeout.IdleStateEvent; +import lombok.extern.slf4j.Slf4j; +import org.noear.solon.Solon; + +/** + * 处理与服务端之间的数据传输 + * @author: aoshiguchen + * @date: 2022/6/16 + */ +@Slf4j +public class CmdChannelHandler extends SimpleChannelInboundHandler { + + + @Override + protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception { + if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) { + log.info("Client CmdChannel recieved proxy message, type is {}", proxyMessage.getType()); + } + Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage); + } + + @Override + public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { + Channel realServerChannel = ctx.channel().attr(Constants.NEXT_CHANNEL).get(); + if (realServerChannel != null) { + realServerChannel.config().setOption(ChannelOption.AUTO_READ, ctx.channel().isWritable()); + } + + super.channelWritabilityChanged(ctx); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + log.info("Client CmdChannel 与服务端断开连接"); + ProxyUtil.setCmdChannel(null); + ProxyUtil.clearRealServerChannels(); + + super.channelInactive(ctx); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + log.error("Client CmdChannel Error channelId:{}", ctx.channel().id().asLongText(), cause); + ctx.close(); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if(evt instanceof IdleStateEvent) { + IdleStateEvent event = (IdleStateEvent)evt; + switch (event.state()) { + case READER_IDLE: + // 读超时,断开连接 +// log.info("读超时"); +// ctx.channel().close(); + break; + case WRITER_IDLE: + ctx.channel().writeAndFlush(ProxyMessage.buildHeartbeatMessage()); + break; + case ALL_IDLE: + log.info("Client CmdChannel 读写超时"); + ctx.close(); + break; + } + } + } +} diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ClientChannelHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java similarity index 73% rename from neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ClientChannelHandler.java rename to neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java index b6d85001..ebe217f6 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ClientChannelHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java @@ -1,15 +1,15 @@ package org.dromara.neutrinoproxy.client.core; -import org.dromara.neutrinoproxy.client.util.ProxyUtil; -import org.dromara.neutrinoproxy.core.Constants; -import org.dromara.neutrinoproxy.core.ProxyMessage; -import org.dromara.neutrinoproxy.core.dispatcher.Dispatcher; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelOption; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.timeout.IdleStateEvent; import lombok.extern.slf4j.Slf4j; +import org.dromara.neutrinoproxy.client.util.ProxyUtil; +import org.dromara.neutrinoproxy.core.Constants; +import org.dromara.neutrinoproxy.core.ProxyMessage; +import org.dromara.neutrinoproxy.core.dispatcher.Dispatcher; import org.noear.solon.Solon; /** @@ -18,13 +18,13 @@ import org.noear.solon.Solon; * @date: 2022/6/16 */ @Slf4j -public class ClientChannelHandler extends SimpleChannelInboundHandler { +public class ProxyChannelHandler extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception { if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) { - log.info("recieved proxy message, type is {}", proxyMessage.getType()); + log.info("Client ProxyChannel recieved proxy message, type is {}", proxyMessage.getType()); } Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage); } @@ -41,17 +41,10 @@ public class ClientChannelHandler extends SimpleChannelInboundHandler() { @@ -78,17 +81,10 @@ public class ProxyClientService { } }); - bootstrap.group(workerGroup); - bootstrap.channel(NioSocketChannel.class); - bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000); - bootstrap.option(ChannelOption.SO_KEEPALIVE, true); - /** - * TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。 - * Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。 - */ - bootstrap.option(ChannelOption.TCP_NODELAY, true); - - bootstrap.handler(new ChannelInitializer() { + proxyTunnelBootstrap.group(workerGroup); + proxyTunnelBootstrap.channel(NioSocketChannel.class); + proxyTunnelBootstrap.remoteAddress(InetSocketAddress.createUnresolved(proxyConfig.getClient().getServerIp(), proxyConfig.getClient().getServerPort())); + proxyTunnelBootstrap.handler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { @@ -101,115 +97,143 @@ public class ProxyClientService { proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip())); ch.pipeline().addLast(new ProxyMessageEncoder()); ch.pipeline().addLast(new IdleStateHandler(proxyConfig.getProtocol().getReadIdleTime(), proxyConfig.getProtocol().getWriteIdleTime(), proxyConfig.getProtocol().getAllIdleTimeSeconds())); - ch.pipeline().addLast(new ClientChannelHandler()); + ch.pipeline().addLast(new ProxyChannelHandler()); } }); - try { - this.start(); - } catch (Exception e) { - // 启动连不上也做一下重连,因此先catch异常 - log.error("启动异常", e); - } - } + cmdTunnelBootstrap.group(workerGroup); + cmdTunnelBootstrap.channel(NioSocketChannel.class); +// cmdTunnelBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000); +// cmdTunnelBootstrap.option(ChannelOption.SO_KEEPALIVE, true); +// /** +// * TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。 +// * Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。 +// */ +// cmdTunnelBootstrap.option(ChannelOption.TCP_NODELAY, true); + cmdTunnelBootstrap.remoteAddress(InetSocketAddress.createUnresolved(proxyConfig.getClient().getServerIp(), proxyConfig.getClient().getServerPort())); - public void start() { - if (StrUtil.isEmpty(proxyConfig.getClient().getServerIp())) { - log.error("not found server-ip config."); - Solon.stop(); - return; - } - if (null == proxyConfig.getClient().getServerPort()) { - log.error("not found server-port config."); - Solon.stop(); - return; - } - if (null != proxyConfig.getClient().getSslEnable() && proxyConfig.getClient().getSslEnable() - && StrUtil.isEmpty(proxyConfig.getClient().getJksPath())) { - log.error("not found jks-path config."); - Solon.stop(); - return; - } - if (StrUtil.isEmpty(proxyConfig.getClient().getLicenseKey())) { - log.error("not found license-key config."); - Solon.stop(); - return; - } - if (null == channel || !channel.isActive()) { - try { - connectProxyServer(); - } catch (Exception e) { - log.error("client start error", e); + cmdTunnelBootstrap.handler(new ChannelInitializer() { + + @Override + public void initChannel(SocketChannel ch) throws Exception { + if (proxyConfig.getClient().getSslEnable()) { + ch.pipeline().addLast(createSslHandler()); } - } else { - channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey(), ProxyUtil.getClientId())); +// ch.pipeline().addFirst(new LoggingHandler(ProxyClientService.class)); + ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(), + proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(), + proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip())); + ch.pipeline().addLast(new ProxyMessageEncoder()); + ch.pipeline().addLast(new IdleStateHandler(proxyConfig.getProtocol().getReadIdleTime(), proxyConfig.getProtocol().getWriteIdleTime(), proxyConfig.getProtocol().getAllIdleTimeSeconds())); + ch.pipeline().addLast(new CmdChannelHandler()); } + }); + + try { + this.start(); + } catch (Exception e) { + // 启动连不上也做一下重连,因此先catch异常 + log.error("[客户端指令隧道] 启动异常", e); } + } - /** - * 连接代理服务器 - */ - private void connectProxyServer() throws InterruptedException { - bootstrap.connect(proxyConfig.getClient().getServerIp(), proxyConfig.getClient().getServerPort()) - .addListener(new ChannelFutureListener() { - - @Override - public void operationComplete(ChannelFuture future) throws Exception { - if (future.isSuccess()) { - channel = future.channel(); - // 连接成功,向服务器发送客户端认证信息(licenseKey) - ProxyUtil.setCmdChannel(future.channel()); - future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey(), ProxyUtil.getClientId())); - log.info("连接代理服务成功. channelId:{}", future.channel().id().asLongText()); - -// reconnectServiceEnable = true; - reconnectCount = 0; - } else { - log.info("连接代理服务失败!"); - } - } - }).sync(); + public void start() { + if (StrUtil.isEmpty(proxyConfig.getClient().getServerIp())) { + log.error("not found server-ip config."); + Solon.stop(); + return; } - - private ChannelHandler createSslHandler() { - try { - InputStream jksInputStream = FileUtil.getInputStream(proxyConfig.getClient().getJksPath()); - - SSLContext clientContext = SSLContext.getInstance("TLS"); - final KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(jksInputStream, proxyConfig.getClient().getKeyStorePassword().toCharArray()); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - tmf.init(ks); - TrustManager[] trustManagers = tmf.getTrustManagers(); - clientContext.init(null, trustManagers, null); - - SSLEngine sslEngine = clientContext.createSSLEngine(); - sslEngine.setUseClientMode(true); - - return new SslHandler(sslEngine); - } catch (Exception e) { - log.error("创建SSL处理器失败", e); - e.printStackTrace(); - } - return null; + if (null == proxyConfig.getClient().getServerPort()) { + log.error("not found server-port config."); + Solon.stop(); + return; } - - protected synchronized void reconnect() { -// if (!reconnectServiceEnable) { -// return; -// } - if (null != channel) { - if (channel.isActive()) { - return; - } - channel.close(); - } - - log.info("客户端重连 seq:{}", ++reconnectCount); + if (null != proxyConfig.getClient().getSslEnable() && proxyConfig.getClient().getSslEnable() + && StrUtil.isEmpty(proxyConfig.getClient().getJksPath())) { + log.error("not found jks-path config."); + Solon.stop(); + return; + } + if (StrUtil.isEmpty(proxyConfig.getClient().getLicenseKey())) { + log.error("not found license-key config."); + Solon.stop(); + return; + } + if (null == channel || !channel.isActive()) { try { connectProxyServer(); } catch (Exception e) { - log.error("重连异常", e); + log.error("client start error", e); } + } else { + channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey(), ProxyUtil.getClientId())); } + } + + /** + * 连接代理服务器 + */ + private void connectProxyServer() throws InterruptedException { + cmdTunnelBootstrap.connect() + .addListener(new ChannelFutureListener() { + + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (future.isSuccess()) { + channel = future.channel(); + // 连接成功,向服务器发送客户端认证信息(licenseKey) + ProxyUtil.setCmdChannel(future.channel()); + future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey(), ProxyUtil.getClientId())); + log.info("[客户端指令隧道] 连接代理服务成功. channelId:{}", future.channel().id().asLongText()); + +// reconnectServiceEnable = true; + reconnectCount = 0; + } else { + log.info("[客户端指令隧道] 连接代理服务失败!"); + } + } + }).sync(); + } + + private ChannelHandler createSslHandler() { + try { + InputStream jksInputStream = FileUtil.getInputStream(proxyConfig.getClient().getJksPath()); + + SSLContext clientContext = SSLContext.getInstance("TLS"); + final KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(jksInputStream, proxyConfig.getClient().getKeyStorePassword().toCharArray()); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(ks); + TrustManager[] trustManagers = tmf.getTrustManagers(); + clientContext.init(null, trustManagers, null); + + SSLEngine sslEngine = clientContext.createSSLEngine(); + sslEngine.setUseClientMode(true); + + return new SslHandler(sslEngine); + } catch (Exception e) { + log.error("创建SSL处理器失败", e); + e.printStackTrace(); + } + return null; + } + + protected synchronized void reconnect() { +// if (!reconnectServiceEnable) { +// return; +// } + if (null != channel) { + if (channel.isActive()) { + return; + } + channel.close(); + } + + log.info("[客户端指令隧道] 客户端重连 seq:{}", ++reconnectCount); + try { + connectProxyServer(); + } catch (Exception e) { + log.error("[客户端指令隧道] 重连异常", e); + } + } } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/RealServerChannelHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/RealServerChannelHandler.java index 0506217b..69c47d45 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/RealServerChannelHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/RealServerChannelHandler.java @@ -22,6 +22,7 @@ package org.dromara.neutrinoproxy.client.core; +import lombok.extern.slf4j.Slf4j; import org.dromara.neutrinoproxy.client.util.ProxyUtil; import org.dromara.neutrinoproxy.core.Constants; import org.dromara.neutrinoproxy.core.ProxyMessage; @@ -36,6 +37,7 @@ import io.netty.channel.SimpleChannelInboundHandler; * @author: aoshiguchen * @date: 2022/6/16 */ +@Slf4j public class RealServerChannelHandler extends SimpleChannelInboundHandler { @@ -85,6 +87,6 @@ public class RealServerChannelHandler extends SimpleChannelInboundHandler { + proxyTunnelBootstrap.connect().addListener((ChannelFutureListener) future -> { if (future.isSuccess()) { borrowListener.success(future.channel()); } else { From c959ce13a3f656a9cbf890014b5ef3b02da1bf78 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Mon, 5 Jun 2023 10:00:59 +0800 Subject: [PATCH 20/45] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E7=AB=AF=E5=8F=A3?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E9=80=89=E6=8B=A9https=EF=BC=8C=E5=9F=9F?= =?UTF-8?q?=E5=90=8D=E8=BE=93=E5=85=A5=E6=A1=86=E6=B2=A1=E5=87=BA=E6=9D=A5?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- neutrino-proxy-admin/src/views/proxy/portMapping.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neutrino-proxy-admin/src/views/proxy/portMapping.vue b/neutrino-proxy-admin/src/views/proxy/portMapping.vue index 285cca59..32d517e1 100644 --- a/neutrino-proxy-admin/src/views/proxy/portMapping.vue +++ b/neutrino-proxy-admin/src/views/proxy/portMapping.vue @@ -154,7 +154,7 @@ - + From a3b324c72bb738a718bff5d0645f7546dc9384e1 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Mon, 5 Jun 2023 17:48:33 +0800 Subject: [PATCH 21/45] =?UTF-8?q?http=E4=BB=A3=E7=90=86=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E8=B0=83=E6=95=B4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/proxy/enhance/HttpVisitorChannelHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java index 40882d8e..50fe8c56 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java @@ -68,11 +68,11 @@ public class HttpVisitorChannelHandler extends SimpleChannelInboundHandler Date: Mon, 5 Jun 2023 18:02:03 +0800 Subject: [PATCH 22/45] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=AB=AF=E3=80=81=E6=97=A5=E5=BF=97=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dromara/neutrinoproxy/client/config/ProxyConfig.java | 1 + .../neutrinoproxy/client/core/ProxyClientService.java | 5 ++++- neutrino-proxy-client/src/main/resources/app.yml | 1 + .../neutrinoproxy/server/base/proxy/ProxyConfig.java | 2 ++ .../server/base/proxy/ProxyConfiguration.java | 9 ++++++++- .../server/proxy/core/ProxyTunnelServer.java | 5 ++++- .../neutrinoproxy/server/proxy/enhance/HttpProxy.java | 5 +++++ .../neutrinoproxy/server/proxy/enhance/HttpsProxy.java | 5 +++++ neutrino-proxy-server/src/main/resources/app.yml | 2 ++ 9 files changed, 32 insertions(+), 3 deletions(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java index ebe8376d..9f81668f 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java @@ -40,5 +40,6 @@ public class ProxyConfig { private String licenseKey; private Integer threadCount; private String clientId; + private Boolean transferLogEnable; } } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java index a039983b..8953184e 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java @@ -1,6 +1,7 @@ package org.dromara.neutrinoproxy.client.core; import cn.hutool.core.util.StrUtil; +import io.netty.handler.logging.LoggingHandler; import org.dromara.neutrinoproxy.client.config.ProxyConfig; import org.dromara.neutrinoproxy.client.util.ProxyUtil; import org.dromara.neutrinoproxy.core.ProxyMessage; @@ -119,7 +120,9 @@ public class ProxyClientService { if (proxyConfig.getClient().getSslEnable()) { ch.pipeline().addLast(createSslHandler()); } -// ch.pipeline().addFirst(new LoggingHandler(ProxyClientService.class)); + if (null != proxyConfig.getClient().getTransferLogEnable() && proxyConfig.getClient().getTransferLogEnable()) { + ch.pipeline().addFirst(new LoggingHandler(ProxyClientService.class)); + } ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(), proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(), proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip())); diff --git a/neutrino-proxy-client/src/main/resources/app.yml b/neutrino-proxy-client/src/main/resources/app.yml index 386790ee..4ebc28dd 100644 --- a/neutrino-proxy-client/src/main/resources/app.yml +++ b/neutrino-proxy-client/src/main/resources/app.yml @@ -22,3 +22,4 @@ neutrino: obtain-license-interval: 5 license-key: ${LICENSE_KEY:} client-id: ${CLIENT_ID:} + transfer-log-enable: ${CLIENT_LOG:false} diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfig.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfig.java index 0ec22f42..e3176b03 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfig.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfig.java @@ -49,6 +49,7 @@ public class ProxyConfig { private Integer httpsProxyPort; private String keyStorePassword; private String jksPath; + private Boolean transferLogEnable; } @Data @@ -60,6 +61,7 @@ public class ProxyConfig { private String keyStorePassword; private String keyManagerPassword; private String jksPath; + private Boolean transferLogEnable; } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java index 7aa5a712..b7537641 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java @@ -4,6 +4,7 @@ import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.logging.LoggingHandler; import org.dromara.neutrinoproxy.core.ProxyDataTypeEnum; import org.dromara.neutrinoproxy.core.ProxyMessage; import org.dromara.neutrinoproxy.core.ProxyMessageHandler; @@ -12,6 +13,7 @@ import org.dromara.neutrinoproxy.core.dispatcher.Dispatcher; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.nio.NioEventLoopGroup; import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler; +import org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelServer; import org.dromara.neutrinoproxy.server.proxy.core.TcpVisitorChannelHandler; import org.noear.solon.Solon; import org.noear.solon.annotation.Bean; @@ -51,13 +53,18 @@ public class ProxyConfiguration implements LifecycleBean { @Bean("tcpServerBootstrap") public ServerBootstrap tcpServerBootstrap(@Inject("serverBossGroup") NioEventLoopGroup serverBossGroup, - @Inject("serverWorkerGroup") NioEventLoopGroup serverWorkerGroup) { + @Inject("serverWorkerGroup") NioEventLoopGroup serverWorkerGroup, + @Inject ProxyConfig proxyConfig + ) { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(serverBossGroup, serverWorkerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { + if (null != proxyConfig.getServer().getTransferLogEnable() && proxyConfig.getServer().getTransferLogEnable()) { + ch.pipeline().addFirst(new LoggingHandler(ProxyTunnelServer.class)); + } ch.pipeline().addFirst(new BytesMetricsHandler()); ch.pipeline().addLast(new TcpVisitorChannelHandler()); } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelServer.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelServer.java index bd7e8c35..bb510d1a 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelServer.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelServer.java @@ -1,5 +1,6 @@ package org.dromara.neutrinoproxy.server.proxy.core; +import io.netty.handler.logging.LoggingHandler; import org.dromara.neutrinoproxy.core.ProxyMessageDecoder; import org.dromara.neutrinoproxy.core.ProxyMessageEncoder; import org.dromara.neutrinoproxy.core.util.FileUtil; @@ -111,7 +112,9 @@ public class ProxyTunnelServer implements EventListener { } private void proxyServerCommonInitHandler(SocketChannel ch) { -// ch.pipeline().addFirst(new LoggingHandler(ProxyServerRunner.class)); + if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) { + ch.pipeline().addFirst(new LoggingHandler(ProxyTunnelServer.class)); + } ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(), proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(), proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip())); diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java index bac549a6..fb00568b 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java @@ -6,9 +6,11 @@ import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.logging.LoggingHandler; import lombok.extern.slf4j.Slf4j; import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig; import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler; +import org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelServer; import org.noear.solon.annotation.Component; import org.noear.solon.annotation.Inject; import org.noear.solon.core.event.AppLoadEndEvent; @@ -40,6 +42,9 @@ public class HttpProxy implements EventListener { .channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { + if (null != proxyConfig.getServer().getTransferLogEnable() && proxyConfig.getServer().getTransferLogEnable()) { + ch.pipeline().addFirst(new LoggingHandler(ProxyTunnelServer.class)); + } ch.pipeline().addFirst(new BytesMetricsHandler()); ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getDomainName())); } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java index c3d7dd14..57edda35 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java @@ -6,12 +6,14 @@ import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.logging.LoggingHandler; import io.netty.handler.ssl.SslHandler; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.dromara.neutrinoproxy.core.util.FileUtil; import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig; import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler; +import org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelServer; import org.noear.solon.annotation.Component; import org.noear.solon.annotation.Inject; import org.noear.solon.core.event.AppLoadEndEvent; @@ -48,6 +50,9 @@ public class HttpsProxy implements EventListener { .channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { + if (null != proxyConfig.getServer().getTransferLogEnable() && proxyConfig.getServer().getTransferLogEnable()) { + ch.pipeline().addFirst(new LoggingHandler(ProxyTunnelServer.class)); + } ch.pipeline().addLast(createSslHandler()); ch.pipeline().addFirst(new BytesMetricsHandler()); ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getDomainName())); diff --git a/neutrino-proxy-server/src/main/resources/app.yml b/neutrino-proxy-server/src/main/resources/app.yml index d144ea42..fc9fdd02 100644 --- a/neutrino-proxy-server/src/main/resources/app.yml +++ b/neutrino-proxy-server/src/main/resources/app.yml @@ -20,6 +20,7 @@ neutrino: key-store-password: ${STORE_PASS:123456} key-manager-password: ${MGR_PASS:123456} jks-path: ${JKS_PATH:classpath:/test.jks} + transfer-log-enable: ${TUNNEL_LOG:false} server: boss-thread-count: 5 work-thread-count: 20 @@ -29,6 +30,7 @@ neutrino: domain-name: ${DOMAIN_NAME:} key-store-password: ${HTTPS_STORE_PASS:} jks-path: ${HTTPS_JKS_PATH:} + transfer-log-enable: ${SERVER_LOG:false} data: db: type: ${DB_TYPE:sqlite} From aa131b07056fedb527f8e60f7bf29870024ae7b2 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Tue, 6 Jun 2023 10:11:12 +0800 Subject: [PATCH 23/45] =?UTF-8?q?=E8=A7=A3=E5=86=B3http=E5=9F=9F=E5=90=8D?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/constant/NetworkProtocolEnum.java | 5 +++++ .../server/controller/PortMappingController.java | 2 ++ .../neutrinoproxy/server/service/PortMappingService.java | 8 ++++---- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/NetworkProtocolEnum.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/NetworkProtocolEnum.java index 7a053552..9c1fb245 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/NetworkProtocolEnum.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/NetworkProtocolEnum.java @@ -33,4 +33,9 @@ public enum NetworkProtocolEnum { } return map.get(desc); } + + public static Boolean isHttp(String desc) { + NetworkProtocolEnum networkProtocolEnum = of(desc); + return NetworkProtocolEnum.HTTP == networkProtocolEnum; + } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/PortMappingController.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/PortMappingController.java index 773b264e..5a52640c 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/PortMappingController.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/PortMappingController.java @@ -51,6 +51,7 @@ public class PortMappingController { // 目前仅HTTP支持绑定域名 req.setSubdomain(null); } + req.setProtocal(networkProtocolEnum.getDesc()); return portMappingService.create(req); } @@ -74,6 +75,7 @@ public class PortMappingController { // 目前仅HTTP支持绑定域名 req.setSubdomain(null); } + req.setProtocal(networkProtocolEnum.getDesc()); return portMappingService.update(req); } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java index ee085e26..aa8004f7 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java @@ -149,7 +149,7 @@ public class PortMappingService implements LifecycleBean { // 更新VisitorChannel visitorChannelService.addVisitorChannelByPortMapping(portMappingDO); // 更新域名映射 - if (NetworkProtocolEnum.HTTP.getDesc().equals(portMappingDO.getProtocal()) && + if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort()); @@ -188,12 +188,12 @@ public class PortMappingService implements LifecycleBean { // 更新VisitorChannel visitorChannelService.updateVisitorChannelByPortMapping(oldPortMappingDO, portMappingDO); // 删除老的域名映射 - if (NetworkProtocolEnum.HTTP.getDesc().equals(oldPortMappingDO.getProtocal()) && + if (NetworkProtocolEnum.isHttp(oldPortMappingDO.getProtocal()) && StrUtil.isNotBlank(oldPortMappingDO.getSubdomain())) { ProxyUtil.removeSubdomainToServerPort(oldPortMappingDO.getSubdomain()); } // 更新域名映射 - if (NetworkProtocolEnum.HTTP.getDesc().equals(portMappingDO.getProtocal()) && + if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort()); @@ -268,7 +268,7 @@ public class PortMappingService implements LifecycleBean { // 更新VisitorChannel visitorChannelService.removeVisitorChannelByPortMapping(portMappingDO); // 更新域名映射 - if (NetworkProtocolEnum.HTTP.getDesc().equals(portMappingDO.getProtocal()) && + if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { ProxyUtil.removeSubdomainToServerPort(portMappingDO.getSubdomain()); } From 62bbd48b33dd641067630d03ccca8aff1268bc75 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Wed, 7 Jun 2023 20:37:26 +0800 Subject: [PATCH 24/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0TODOLIST?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- todolist.MD | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/todolist.MD b/todolist.MD index a967f1b6..a47c1be4 100644 --- a/todolist.MD +++ b/todolist.MD @@ -1,3 +1,15 @@ +# 1.x规划 +- Bug +- 优化 + - 心跳日志开关 + - 客户端启动无限重连开关 +- UDP支持 +- 官网文档完善 + - 常见问题汇总 + - HTTPS配置说明 +- 协议重构 +- 代码重构 + # Bug - 指令通达被close的问题,org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelChannelHandler.channelInactive - windows环境下直接运行发布版的jar包,日志输出乱码 From 2ae32670491b73f2a24353f02ee8c06e3c74006e Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Wed, 7 Jun 2023 20:41:33 +0800 Subject: [PATCH 25/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0logback=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + neutrino-proxy-client/src/main/resources/logback.xml | 2 +- neutrino-proxy-server/src/main/resources/logback.xml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b204d46d..950efd68 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,4 @@ hs_err_pid* neutrino-proxy-vuepress/deploy.sh .NEUTRINO_PROXY_CLIENT_ID +logs diff --git a/neutrino-proxy-client/src/main/resources/logback.xml b/neutrino-proxy-client/src/main/resources/logback.xml index e7178e77..76953690 100644 --- a/neutrino-proxy-client/src/main/resources/logback.xml +++ b/neutrino-proxy-client/src/main/resources/logback.xml @@ -1,6 +1,6 @@ - + diff --git a/neutrino-proxy-server/src/main/resources/logback.xml b/neutrino-proxy-server/src/main/resources/logback.xml index 380f20ed..005ce00d 100644 --- a/neutrino-proxy-server/src/main/resources/logback.xml +++ b/neutrino-proxy-server/src/main/resources/logback.xml @@ -1,6 +1,6 @@ - + From f88bbb53cb3733c0bd70aee10829db589773f800 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Wed, 7 Jun 2023 21:35:02 +0800 Subject: [PATCH 26/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0TODOLIST?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- todolist.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/todolist.MD b/todolist.MD index a47c1be4..ac39da8b 100644 --- a/todolist.MD +++ b/todolist.MD @@ -9,6 +9,7 @@ - HTTPS配置说明 - 协议重构 - 代码重构 +- 适配mariadb # Bug - 指令通达被close的问题,org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelChannelHandler.channelInactive From 0d997bbe9214ca1370d9a600da1b9aedbf86c7a4 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Thu, 8 Jun 2023 21:58:39 +0800 Subject: [PATCH 27/45] =?UTF-8?q?=E9=80=82=E9=85=8Dmariadb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- neutrino-proxy-server/pom.xml | 4 + .../server/base/db/DbConfiguration.java | 29 +-- .../server/constant/DbTypeEnum.java | 4 +- .../resources/sql/mariadb/init-structure.sql | 207 ++++++++++++++++++ .../resources/sql/mariadb/job_info.data.sql | 13 ++ .../resources/sql/mariadb/license.data.sql | 3 + .../resources/sql/mariadb/port_group.data.sql | 3 + .../sql/mariadb/port_mapping.data.sql | 7 + .../resources/sql/mariadb/port_pool.data.sql | 41 ++++ .../main/resources/sql/mariadb/user.data.sql | 5 + pom.xml | 5 + 11 files changed, 306 insertions(+), 15 deletions(-) create mode 100644 neutrino-proxy-server/src/main/resources/sql/mariadb/init-structure.sql create mode 100644 neutrino-proxy-server/src/main/resources/sql/mariadb/job_info.data.sql create mode 100644 neutrino-proxy-server/src/main/resources/sql/mariadb/license.data.sql create mode 100644 neutrino-proxy-server/src/main/resources/sql/mariadb/port_group.data.sql create mode 100644 neutrino-proxy-server/src/main/resources/sql/mariadb/port_mapping.data.sql create mode 100644 neutrino-proxy-server/src/main/resources/sql/mariadb/port_pool.data.sql create mode 100644 neutrino-proxy-server/src/main/resources/sql/mariadb/user.data.sql diff --git a/neutrino-proxy-server/pom.xml b/neutrino-proxy-server/pom.xml index 5f93a05a..6056881b 100644 --- a/neutrino-proxy-server/pom.xml +++ b/neutrino-proxy-server/pom.xml @@ -51,6 +51,10 @@ mysql mysql-connector-java + + org.mariadb.jdbc + mariadb-java-client + com.zaxxer HikariCP diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/db/DbConfiguration.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/db/DbConfiguration.java index 55f86cca..d30ece9b 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/db/DbConfiguration.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/db/DbConfiguration.java @@ -31,7 +31,6 @@ public class DbConfiguration { dataSource.setJournalMode(SQLiteConfig.JournalMode.WAL.getValue()); return dataSource; } else if (DbTypeEnum.MYSQL == dbTypeEnum) { - HikariDataSource dataSource = new HikariDataSource(); String driver = "com.mysql.cj.jdbc.Driver"; try { Class.forName(driver); @@ -39,24 +38,26 @@ public class DbConfiguration { // 对类名的判断,异常则说明不存在: driver = "com.mysql.jdbc.Driver"; } - dataSource.setDriverClassName(driver); - dataSource.setJdbcUrl(dbConfig.getUrl()); - dataSource.setMinimumIdle(5); - dataSource.setMaximumPoolSize(20); - dataSource.setMaxLifetime(60000); -// dataSource.setInitialSize(5); -// dataSource.setMinIdle(5); -// dataSource.setMaxActive(20); -// dataSource.setMaxWait(60000); -// dataSource.setPoolPreparedStatements(true); - dataSource.setUsername(dbConfig.getUsername()); - dataSource.setPassword(dbConfig.getPassword()); - return dataSource; + return newHikariDataSource(dbConfig, driver); + } else if (DbTypeEnum.MARIADB == dbTypeEnum) { + return newHikariDataSource(dbConfig, "org.mariadb.jdbc.Driver"); } return null; } + private HikariDataSource newHikariDataSource(DbConfig dbConfig, String driverClass) { + HikariDataSource dataSource = new HikariDataSource(); + dataSource.setDriverClassName(driverClass); + dataSource.setJdbcUrl(dbConfig.getUrl()); + dataSource.setMinimumIdle(5); + dataSource.setMaximumPoolSize(20); + dataSource.setMaxLifetime(60000); + dataSource.setUsername(dbConfig.getUsername()); + dataSource.setPassword(dbConfig.getPassword()); + return dataSource; + } + @Bean public void db1_ext(@Db("db") GlobalConfig globalConfig) { MetaObjectHandler metaObjectHandler = new MetaObjectHandlerImpl(); diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/DbTypeEnum.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/DbTypeEnum.java index f61ccdab..cef27e46 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/DbTypeEnum.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/DbTypeEnum.java @@ -38,7 +38,9 @@ import java.util.stream.Stream; @AllArgsConstructor public enum DbTypeEnum { SQLITE("sqlite"), - MYSQL("mysql"); + MYSQL("mysql"), + MARIADB("mariadb"), + ; private String type; diff --git a/neutrino-proxy-server/src/main/resources/sql/mariadb/init-structure.sql b/neutrino-proxy-server/src/main/resources/sql/mariadb/init-structure.sql new file mode 100644 index 00000000..af02f159 --- /dev/null +++ b/neutrino-proxy-server/src/main/resources/sql/mariadb/init-structure.sql @@ -0,0 +1,207 @@ +#############################系统管理相关表############################# +#用户表 +CREATE TABLE IF NOT EXISTS `user` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `name` varchar(50) NOT NULL COMMENT '用户名', + `login_name` varchar(50) NOT NULL COMMENT '登录名', + `login_password` varchar(255) NOT NULL COMMENT '登录密码', + `enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + `update_time` datetime(3) NOT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `I_user_login_name` (`login_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +#用户token表 +CREATE TABLE IF NOT EXISTS `user_token` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `token` varchar(50) NOT NULL COMMENT 'token', + `user_id` int NOT NULL COMMENT '用户ID', + `expiration_time` datetime(3) NOT NULL COMMENT '过期时间', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + `update_time` datetime(3) NOT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `I_user_token_user_id` (`user_id`), + KEY `I_user_token_token` (`token`), + KEY `I_user_token_expiration_time` (`expiration_time`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +#端口池 +CREATE TABLE IF NOT EXISTS `port_pool` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `group_id` int NOT NULL DEFAULT 1 COMMENT '分组ID', + `port` int NOT NULL COMMENT '端口', + `enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + `update_time` datetime(3) NOT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `I_port_pool_port` (`port`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +#端口分组 +CREATE TABLE IF NOT EXISTS `port_group` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `name` varchar(255) NOT NULL COMMENT '分组名称', + `possessor_type` int NOT NULL DEFAULT '0' COMMENT '所有者类型 (0、全局共享 1、用户所有 2License所有) ', + `possessor_id` int NOT NULL DEFAULT '-1' COMMENT '所有者id(当type为0时 固定为-1、当type为1时为用户id 、当type为2时为licenseid)', + `enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + `update_time` datetime(3) NOT NULL COMMENT '更新时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4; + +#############################代理配置相关表############################# +#license表 +CREATE TABLE IF NOT EXISTS `license` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `name` varchar(50) NOT NULL COMMENT 'license名称', + `key` varchar(100) NOT NULL COMMENT 'license key', + `user_id` int NOT NULL COMMENT '用户ID', + `is_online` int NOT NULL COMMENT '是否在线(1、在线 2、离线)', + `enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + `update_time` datetime(3) NOT NULL COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + KEY `I_license_key` (`key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +#端口映射表 +CREATE TABLE IF NOT EXISTS `port_mapping` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `license_id` int NOT NULL COMMENT 'licenseID', + `protocal` varchar(10) NOT NULL DEFAULT 'TCP' COMMENT '协议', + `subdomain` varchar(50) DEFAULT NULL COMMENT '子域名(仅HTTP时有效)', + `server_port` int NOT NULL COMMENT '服务端端口', + `client_ip` varchar(20) NOT NULL COMMENT '客户端IP', + `client_port` int NOT NULL COMMENT '客户端端口', + `is_online` int NOT NULL COMMENT '是否在线(1、在线 2、离线)', + `description` varchar(100) DEFAULT NULL COMMENT '描述', + `enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + `update_time` datetime(3) NOT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `I_port_mapping_server_port` (`server_port`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +#############################日志管理相关表############################# +#用户登录记录表 +CREATE TABLE IF NOT EXISTS `user_login_record` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `user_id` int NOT NULL COMMENT '用户ID', + `ip` varchar(50) NOT NULL COMMENT 'IP', + `token` varchar(100) NOT NULL COMMENT 'token', + `type` int NOT NULL COMMENT '类型(1、登录 2、登出)', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +#客户端连接记录表 +CREATE TABLE IF NOT EXISTS `client_connect_record` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `ip` varchar(50) NOT NULL COMMENT 'IP', + `license_id` int NOT NULL COMMENT 'licenseId', + `type` int NOT NULL COMMENT '类型(1、连接 2、断开连接)', + `msg` varchar(512) DEFAULT NULL COMMENT '消息', + `code` int NOT NULL COMMENT '结果 (1、成功 2、失败)', + `err` text DEFAULT NULL COMMENT '异常信息', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +#############################调度管理相关表############################# +#触发器信息表 +CREATE TABLE IF NOT EXISTS `job_info` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `desc` varchar(255) NOT NULL COMMENT '描述', + `handler` varchar(255) NOT NULL COMMENT '处理器', + `cron` varchar(128) NOT NULL COMMENT 'cron', + `param` varchar(512) DEFAULT NULL COMMENT '参数', + `alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮箱', + `alarm_ding` varchar(255) DEFAULT NULL COMMENT '报警钉钉配置', + `enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + `update_time` datetime(3) NOT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `I_job_info_handler` (`handler`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +#触发器日志表 +CREATE TABLE IF NOT EXISTS `job_log` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `job_id` int NOT NULL COMMENT 'JobId', + `handler` varchar(255) NOT NULL COMMENT '处理器', + `param` varchar(512) DEFAULT NULL COMMENT '参数', + `code` int NOT NULL COMMENT '结果(1、成功 2、失败)', + `msg` text COMMENT '消息', + `alarm_status` int NOT NULL COMMENT '报警状态(1、未报警 2、已报警)', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE, + KEY `I_job_log_create_time` (`create_time`) USING BTREE, + KEY `I_job_log_code` (`code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +#############################报表管理相关表############################# +#流量统计报表-分钟(保留24小时) +CREATE TABLE IF NOT EXISTS `flow_report_minute` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `user_id` int NOT NULL COMMENT '用户ID', + `license_id` int NOT NULL COMMENT 'licenseId', + `write_bytes` int NOT NULL COMMENT '写入流量', + `read_bytes` int NOT NULL COMMENT '读取流量', + `date` datetime(3) NOT NULL COMMENT '时间', + `date_str` varchar(20) NOT NULL COMMENT '时间 yyyy-MM-dd HH:mm', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `I_flow_report_minute_create_time` (`create_time`) USING BTREE, + KEY `I_flow_report_minute_date` (`date`) USING BTREE, + KEY `I_flow_report_minute_user_id` (`user_id`), + KEY `I_flow_report_minute_license_id` (`license_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +#流量统计报表-小时(保留60天) +CREATE TABLE IF NOT EXISTS `flow_report_hour` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `user_id` int NOT NULL COMMENT '用户ID', + `license_id` int NOT NULL COMMENT 'licenseId', + `write_bytes` int NOT NULL COMMENT '写入流量', + `read_bytes` int NOT NULL COMMENT '读取流量', + `date` datetime(3) NOT NULL COMMENT '时间', + `date_str` varchar(20) NOT NULL COMMENT '时间 yyyy-MM-dd HH', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `I_flow_report_hour_create_time` (`create_time`) USING BTREE, + KEY `I_flow_report_hour_date` (`date`) USING BTREE, + KEY `I_flow_report_hour_user_id` (`user_id`), + KEY `I_flow_report_hour_license_id` (`license_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +#流量统计报表-天(保留1年) +CREATE TABLE IF NOT EXISTS `flow_report_day` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `user_id` int NOT NULL COMMENT '用户ID', + `license_id` int NOT NULL COMMENT 'licenseId', + `write_bytes` int NOT NULL COMMENT '写入流量', + `read_bytes` int NOT NULL COMMENT '读取流量', + `date` datetime(3) NOT NULL COMMENT '时间', + `date_str` varchar(20) NOT NULL COMMENT '时间 yyyy-MM-dd', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `I_flow_report_day_create_time` (`create_time`) USING BTREE, + KEY `I_flow_report_day_date` (`date`) USING BTREE, + KEY `I_flow_report_day_user_id` (`user_id`), + KEY `I_flow_report_day_license_id` (`license_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +#流量统计报表-月(全量保留) +CREATE TABLE IF NOT EXISTS `flow_report_month` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `user_id` int NOT NULL COMMENT '用户ID', + `license_id` int NOT NULL COMMENT 'licenseId', + `write_bytes` int NOT NULL COMMENT '写入流量', + `read_bytes` int NOT NULL COMMENT '读取流量', + `date` datetime(3) NOT NULL COMMENT '时间', + `date_str` varchar(20) NOT NULL COMMENT '时间 yyyy-MM', + `create_time` datetime(3) NOT NULL COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `I_flow_report_month_create_time` (`create_time`) USING BTREE, + KEY `I_flow_report_month_date` (`date`) USING BTREE, + KEY `I_flow_report_month_user_id` (`user_id`), + KEY `I_flow_report_month_license_id` (`license_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ No newline at end of file diff --git a/neutrino-proxy-server/src/main/resources/sql/mariadb/job_info.data.sql b/neutrino-proxy-server/src/main/resources/sql/mariadb/job_info.data.sql new file mode 100644 index 00000000..278387ba --- /dev/null +++ b/neutrino-proxy-server/src/main/resources/sql/mariadb/job_info.data.sql @@ -0,0 +1,13 @@ +#job_qrtz_trigger_info +INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES +(1, '示例Job', 'DemoJob', '0/10 * * * * ?', '{"a":101}', 1, now(), now()); +INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES +(2, '数据清理任务', 'DataCleanJob', '0 0 1 * * ?', '', 1, now(), now()); +INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES +(3, '流量统计报表-分钟', 'FlowReportForMinuteJob', '0 */1 * * * ?', '', 1, now(), now()); +INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES +(4, '流量统计报表-小时', 'FlowReportForHourJob', '0 0 */1 * * ?', '', 1, now(), now()); +INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES +(5, '流量统计报表-天', 'FlowReportForDayJob', '0 0 1 * * ?', '', 1, now(), now()); +INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES +(6, '流量统计报表-月', 'FlowReportForMonthJob', '0 30 1 1 * ?', '', 1, now(), now()); \ No newline at end of file diff --git a/neutrino-proxy-server/src/main/resources/sql/mariadb/license.data.sql b/neutrino-proxy-server/src/main/resources/sql/mariadb/license.data.sql new file mode 100644 index 00000000..f7e239a2 --- /dev/null +++ b/neutrino-proxy-server/src/main/resources/sql/mariadb/license.data.sql @@ -0,0 +1,3 @@ +#license +INSERT INTO license(`id`, `name`, `key`, `user_id`, `is_online`, `enable`, `create_time`, `update_time`) VALUES +(1, '我的mac', 'b0a907332b474b25897c4dcb31fc7eb6', 1, 2, 1, now(), now()); diff --git a/neutrino-proxy-server/src/main/resources/sql/mariadb/port_group.data.sql b/neutrino-proxy-server/src/main/resources/sql/mariadb/port_group.data.sql new file mode 100644 index 00000000..65cdaebf --- /dev/null +++ b/neutrino-proxy-server/src/main/resources/sql/mariadb/port_group.data.sql @@ -0,0 +1,3 @@ +#port_group +INSERT INTO `port_group`(`id`,`name`,`possessor_type`,`possessor_id`,`enable`,`create_time`,`update_time`) VALUES +(1, '全局(默认)', 0, -1, 1, now(), now()); diff --git a/neutrino-proxy-server/src/main/resources/sql/mariadb/port_mapping.data.sql b/neutrino-proxy-server/src/main/resources/sql/mariadb/port_mapping.data.sql new file mode 100644 index 00000000..9063ecea --- /dev/null +++ b/neutrino-proxy-server/src/main/resources/sql/mariadb/port_mapping.data.sql @@ -0,0 +1,7 @@ +#port_mapping +INSERT INTO port_mapping(`id`, `license_id`, `server_port`, `protocal`, `subdomain`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) VALUES +(1, 1, 9101, 'HTTP', 'test1', '127.0.0.1', 8080, 2, 1, now(), now()); +INSERT INTO port_mapping(`id`, `license_id`, `server_port`, `protocal`, `subdomain`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) VALUES +(2, 1, 9102, 'TCP', '', '127.0.0.1', 3306, 2, 1, now(), now()); +INSERT INTO port_mapping(`id`, `license_id`, `server_port`, `protocal`, `subdomain`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) VALUES +(3, 1, 9103, 'HTTP', 'test2', '127.0.0.1', 8081, 2, 1, now(), now()); diff --git a/neutrino-proxy-server/src/main/resources/sql/mariadb/port_pool.data.sql b/neutrino-proxy-server/src/main/resources/sql/mariadb/port_pool.data.sql new file mode 100644 index 00000000..e4288b13 --- /dev/null +++ b/neutrino-proxy-server/src/main/resources/sql/mariadb/port_pool.data.sql @@ -0,0 +1,41 @@ +#端口池 +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(1, 1, 9101, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(2, 1, 9102, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(3, 1, 9103, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(4, 1, 9104, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(5, 1, 9105, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(6, 1, 9106, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(7, 1, 9107, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(8, 1, 9108, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(9, 1, 9109, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(10, 1, 9110, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(11, 1, 9111, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(12, 1, 9112, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(13, 1, 9113, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(14, 1, 9114, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(15, 1, 9115, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(16, 1, 9116, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(17, 1, 9117, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(18, 1, 9118, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(19, 1, 9119, 1, now(), now()); +INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES +(20, 1, 9120, 1, now(), now()); diff --git a/neutrino-proxy-server/src/main/resources/sql/mariadb/user.data.sql b/neutrino-proxy-server/src/main/resources/sql/mariadb/user.data.sql new file mode 100644 index 00000000..1be853ba --- /dev/null +++ b/neutrino-proxy-server/src/main/resources/sql/mariadb/user.data.sql @@ -0,0 +1,5 @@ +#用户表 6613b92b77056faeb72068f184ed4c4f +INSERT INTO `user`(`id`, `name`,`login_name`,`login_password`,`enable`,`create_time`, `update_time`) VALUES +(1, '管理员', 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, now(), now()); +INSERT INTO `user`(`id`, `name`,`login_name`,`login_password`,`enable`,`create_time`, `update_time`) VALUES +(2, '游客', 'visitor', 'e10adc3949ba59abbe56e057f20f883e', 1, now(), now()); diff --git a/pom.xml b/pom.xml index 57a840a7..aa92a35b 100644 --- a/pom.xml +++ b/pom.xml @@ -97,6 +97,11 @@ mysql-connector-java 5.1.49 + + org.mariadb.jdbc + mariadb-java-client + 2.7.4 + com.zaxxer HikariCP From 2dc8965cdb194f82939a93773a13ab01d75fb014 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Thu, 8 Jun 2023 22:00:11 +0800 Subject: [PATCH 28/45] =?UTF-8?q?=E9=80=82=E9=85=8Dmariadb.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- todolist.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/todolist.MD b/todolist.MD index ac39da8b..08b18c26 100644 --- a/todolist.MD +++ b/todolist.MD @@ -9,7 +9,7 @@ - HTTPS配置说明 - 协议重构 - 代码重构 -- 适配mariadb +- [x] 适配mariadb # Bug - 指令通达被close的问题,org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelChannelHandler.channelInactive From 70e6d2ab45ef25ea76fbe4f0482acce7ebfe45ce Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Thu, 8 Jun 2023 22:13:52 +0800 Subject: [PATCH 29/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=AE=98=E7=BD=91?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs/01.使用教程/01.开始使用/01.快速上手.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/01.快速上手.md b/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/01.快速上手.md index 7e7ef65d..6f181256 100644 --- a/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/01.快速上手.md +++ b/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/01.快速上手.md @@ -7,7 +7,7 @@ article: false ## 1、 部署服务端 ### 1.1、 Docker一键部署 -> 当前最新版本为1.8.2,下面的脚本中,可以使用:`registry.cn-hangzhou.aliyuncs.com/asgc/neutrino-proxy:1.8.2` 指定版本安装,推荐使用`latest`直接安装最新版。 +> 当前最新版本为1.8.4,下面的脚本中,可以使用:`registry.cn-hangzhou.aliyuncs.com/asgc/neutrino-proxy:1.8.4` 指定版本安装,推荐使用`latest`直接安装最新版。 #### 使用默认sqlite数据库 ```shell From 5a36c888757b01ecacfd655e0fc14091472a0e88 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 9 Jun 2023 12:55:24 +0800 Subject: [PATCH 30/45] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=9F=9F=E5=90=8D?= =?UTF-8?q?=E5=B8=A6=E7=AB=AF=E5=8F=A3=E8=AE=BF=E9=97=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/proxy/enhance/HttpVisitorChannelHandler.java | 3 ++- todolist.MD | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java index 50fe8c56..b17ec7bb 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java @@ -163,7 +163,8 @@ public class HttpVisitorChannelHandler extends SimpleChannelInboundHandler Date: Fri, 9 Jun 2023 13:07:25 +0800 Subject: [PATCH 31/45] =?UTF-8?q?=E6=97=A5=E5=BF=97=E8=B0=83=E6=95=B4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java | 2 +- .../dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java index fb00568b..78d2c376 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java @@ -50,7 +50,7 @@ public class HttpProxy implements EventListener { } }); bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpProxyPort()).sync(); - log.info("Http代理服务启动成功!"); + log.info("Http代理服务启动成功!port:{}", proxyConfig.getServer().getHttpProxyPort()); } catch (Exception e) { log.error("http proxy start err!", e); } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java index 57edda35..f31b4160 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java @@ -59,7 +59,7 @@ public class HttpsProxy implements EventListener { } }); bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpsProxyPort()).sync(); - log.info("Https代理服务启动成功!"); + log.info("Https代理服务启动成功!port:{}", proxyConfig.getServer().getHttpsProxyPort()); } catch (Exception e) { log.error("https proxy start err!", e); } From 2ceacc69160a9e80e0e6fe35a4e856b1f31607d3 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 9 Jun 2023 20:41:11 +0800 Subject: [PATCH 32/45] =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E3=80=81=E5=90=AF=E5=8A=A8=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E6=97=A5=E5=BF=97=E7=BA=A7=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../neutrinoproxy/client/ProxyClient.java | 27 +++++++++++++++++ .../client/core/CmdChannelHandler.java | 2 +- .../client/core/ProxyChannelHandler.java | 4 +-- .../src/main/resources/app.yml | 2 ++ .../neutrinoproxy/server/ProxyServer.java | 29 +++++++++++++++++++ .../rest/interceptor/VisitLogInterceptor.java | 2 +- .../neutrinoproxy/server/job/DemoJob.java | 2 +- .../proxy/core/ProxyTunnelChannelHandler.java | 2 +- .../server/service/JobLogService.java | 2 +- .../src/main/resources/app.yml | 2 ++ 10 files changed, 67 insertions(+), 7 deletions(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/ProxyClient.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/ProxyClient.java index c47f7a61..c01f343a 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/ProxyClient.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/ProxyClient.java @@ -1,14 +1,22 @@ package org.dromara.neutrinoproxy.client; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.noear.solon.Solon; +import org.noear.solon.SolonApp; import org.noear.solon.annotation.SolonMain; +import org.slf4j.LoggerFactory; /** * * @author: aoshiguchen * @date: 2022/6/16 */ +@Slf4j @SolonMain public class ProxyClient { @@ -20,6 +28,8 @@ public class ProxyClient { setAlias("neutrino.proxy.client.jksPath", "jksPath"); setAlias("neutrino.proxy.client.keyStorePassword", "keyStorePassword"); setAlias("neutrino.proxy.client.licenseKey", "licenseKey"); + // 设置日志级别 + setLogLevel(app); }); } @@ -34,4 +44,21 @@ public class ProxyClient { Solon.cfg().put(key, val); } } + + private static void setLogLevel(SolonApp app) { + String loggerLevel = app.cfg().get("neutrino.proxy.logger.level"); + if (StringUtils.isBlank(loggerLevel)) { + return; + } + + try { + Level level = Level.toLevel(loggerLevel); + LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); + for (Logger logger : loggerContext.getLoggerList()) { + logger.setLevel(level); + } + } catch (Exception e) { + log.error("日志级别设置失败", e); + } + } } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java index 6db7fdb5..31fb1a9f 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java @@ -24,7 +24,7 @@ public class CmdChannelHandler extends SimpleChannelInboundHandler @Override protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception { if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) { - log.info("Client CmdChannel recieved proxy message, type is {}", proxyMessage.getType()); + log.debug("Client CmdChannel recieved proxy message, type is {}", proxyMessage.getType()); } Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage); } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java index ebe217f6..85e7b0f0 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java @@ -24,7 +24,7 @@ public class ProxyChannelHandler extends SimpleChannelInboundHandler { // 跨域支持。加-1 优先级更高 app.filter(-1, new CrossFilter().allowedOrigins("*")); + // 设置日志级别 + setLogLevel(app); }); } + + private static void setLogLevel(SolonApp app) { + String loggerLevel = app.cfg().get("neutrino.proxy.logger.level"); + if (StringUtils.isBlank(loggerLevel)) { + return; + } + + try { + Level level = Level.toLevel(loggerLevel); + LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); + for (Logger logger : loggerContext.getLoggerList()) { + logger.setLevel(level); + } + } catch (Exception e) { + log.error("日志级别设置失败", e); + } + } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/VisitLogInterceptor.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/VisitLogInterceptor.java index 97d46072..181289da 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/VisitLogInterceptor.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/VisitLogInterceptor.java @@ -31,7 +31,7 @@ public class VisitLogInterceptor implements RouterInterceptor { } finally { Date now = new Date(); long elapsedTime = now.getTime() - startTime.getTime(); - log.info("\n-----------------------------------------------------------------接口请求日志:\n{} url:{} 执行耗时:{}\n请求体参数:{}\n响应结果:{}\n客户端IP:{}\n", + log.debug("\n-----------------------------------------------------------------接口请求日志:\n{} url:{} 执行耗时:{}\n请求体参数:{}\n响应结果:{}\n客户端IP:{}\n", ctx.method(), ctx.path(), getElapsedTimeStr(elapsedTime), JSONObject.toJSONString(ctx.paramMap()), JSONObject.toJSONString(JSONObject.toJSONString(ctx.result)), diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/job/DemoJob.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/job/DemoJob.java index 687e623b..4696dca2 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/job/DemoJob.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/job/DemoJob.java @@ -17,6 +17,6 @@ public class DemoJob implements IJobHandler { @Override public void execute(String param) throws Exception { - System.out.println("DemoJob execute param:" + param); + log.debug("DemoJob execute param: {}", param); } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java index 5d32ff52..0f3d9363 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java @@ -127,7 +127,7 @@ public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler Date: Fri, 9 Jun 2023 20:54:15 +0800 Subject: [PATCH 33/45] =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=8C=87=E5=AE=9A?= =?UTF-8?q?=E9=87=8D=E8=BF=9E=E9=97=B4=E9=9A=94=E3=80=81=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E6=97=A0=E9=99=90=E9=87=8D=E8=BF=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../neutrinoproxy/client/config/ProxyConfig.java | 7 +++++++ .../neutrinoproxy/client/core/ProxyClientService.java | 10 +++++----- .../client/handler/ProxyMessageAuthHandler.java | 8 +++++++- neutrino-proxy-client/src/main/resources/app.yml | 5 ++++- neutrino-proxy-server/src/main/resources/app.yml | 2 +- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java index 9f81668f..ceb5a195 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java @@ -41,5 +41,12 @@ public class ProxyConfig { private Integer threadCount; private String clientId; private Boolean transferLogEnable; + private Reconnection reconnection; + } + + @Data + public static class Reconnection { + private Integer intervalSeconds; + private Boolean unlimited; } } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java index 8953184e..48b92fce 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java @@ -49,10 +49,10 @@ public class ProxyClientService { @Inject("realServerBootstrap") private Bootstrap realServerBootstrap; private volatile Channel channel; - /** - * 重连间隔(秒) - */ - private static final long RECONNECT_INTERVAL_SECONDS = 5; +// /** +// * 重连间隔(秒) +// */ +// private static final long RECONNECT_INTERVAL_SECONDS = 5; /** * 重连次数 */ @@ -69,7 +69,7 @@ public class ProxyClientService { @Init public void init() { - this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 10, RECONNECT_INTERVAL_SECONDS, TimeUnit.SECONDS); + this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 10, proxyConfig.getClient().getReconnection().getIntervalSeconds(), TimeUnit.SECONDS); this.workerGroup = new NioEventLoopGroup(proxyConfig.getClient().getThreadCount()); realServerBootstrap.group(workerGroup); diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java index 9acdcc01..e0a05f17 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java @@ -1,6 +1,7 @@ package org.dromara.neutrinoproxy.client.handler; import com.alibaba.fastjson.JSONObject; +import org.dromara.neutrinoproxy.client.config.ProxyConfig; import org.dromara.neutrinoproxy.core.Constants; import org.dromara.neutrinoproxy.core.ExceptionEnum; import org.dromara.neutrinoproxy.core.ProxyMessage; @@ -10,6 +11,7 @@ import io.netty.channel.ChannelHandlerContext; import lombok.extern.slf4j.Slf4j; import org.noear.solon.Solon; import org.noear.solon.annotation.Component; +import org.noear.solon.annotation.Inject; /** * 认证信息处理器 @@ -20,6 +22,8 @@ import org.noear.solon.annotation.Component; @Match(type = Constants.ProxyDataTypeName.AUTH) @Component public class ProxyMessageAuthHandler implements ProxyMessageHandler { + @Inject + private ProxyConfig proxyConfig; @Override public void handle(ChannelHandlerContext context, ProxyMessage proxyMessage) { String info = proxyMessage.getInfo(); @@ -30,7 +34,9 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { // 客户端认证失败,直接停止服务 log.info("client auth failed , client stop."); context.channel().close(); - Solon.stop(); + if (!proxyConfig.getClient().getReconnection().getUnlimited()) { + Solon.stop(); + } } else if (ExceptionEnum.CONNECT_FAILED.getCode().equals(code) || ExceptionEnum.LICENSE_CANNOT_REPEAT_CONNECT.getCode().equals(code) ){ diff --git a/neutrino-proxy-client/src/main/resources/app.yml b/neutrino-proxy-client/src/main/resources/app.yml index 5eddcde7..01a69240 100644 --- a/neutrino-proxy-client/src/main/resources/app.yml +++ b/neutrino-proxy-client/src/main/resources/app.yml @@ -4,7 +4,7 @@ neutrino: proxy: logger: - level: info + level: ${LOG_LEVEL:info} protocol: max-frame-length: 2097152 length-field-offset: 0 @@ -25,3 +25,6 @@ neutrino: license-key: ${LICENSE_KEY:} client-id: ${CLIENT_ID:} transfer-log-enable: ${CLIENT_LOG:false} + reconnection: + interval-seconds: 10 + unlimited: false diff --git a/neutrino-proxy-server/src/main/resources/app.yml b/neutrino-proxy-server/src/main/resources/app.yml index f638242b..a2b4ec2c 100644 --- a/neutrino-proxy-server/src/main/resources/app.yml +++ b/neutrino-proxy-server/src/main/resources/app.yml @@ -4,7 +4,7 @@ server: neutrino: proxy: logger: - level: info + level: ${LOG_LEVEL:info} protocol: max-frame-length: ${MAX_FRAME_LENGTH:2097152} length-field-offset: 0 From e547895a9c13b3fc048d38b1f2f2a243d6678088 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 9 Jun 2023 21:27:23 +0800 Subject: [PATCH 34/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/app.yml | 17 +++++++-- .../src/main/resources/app.yml | 21 +++++++++- .../01.使用教程/01.开始使用/06.服务端配置.md | 10 ++++- .../01.使用教程/01.开始使用/07.客户端配置.md | 38 +++++++++++++++++++ 4 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/07.客户端配置.md diff --git a/neutrino-proxy-client/src/main/resources/app.yml b/neutrino-proxy-client/src/main/resources/app.yml index 01a69240..86eb7ef3 100644 --- a/neutrino-proxy-client/src/main/resources/app.yml +++ b/neutrino-proxy-client/src/main/resources/app.yml @@ -3,8 +3,6 @@ neutrino: name: neutrino-proxy-client proxy: - logger: - level: ${LOG_LEVEL:info} protocol: max-frame-length: 2097152 length-field-offset: 0 @@ -14,17 +12,30 @@ neutrino: read-idle-time: 8 write-idle-time: 3 all-idle-time-seconds: 8 + logger: + # 日志级别 + level: ${LOG_LEVEL:info} client: + # 线程池相关配置,用于技术调优,可忽略 thread-count: 50 + # 隧道SSL证书配置 key-store-password: ${STORE_PASS:123456} jks-path: ${JKS_PATH:classpath:/test.jks} + # 服务端IP server-ip: ${SERVER_IP:localhost} + # 服务端端口(对应服务端app.yml中的tunnel.port、tunnel.ssl-port) server-port: ${SERVER_PORT:9002} + # 是否启用SSL(注意:该配置必须和server-port对应上) ssl-enable: ${SSL_ENABLE:true} - obtain-license-interval: 5 + # 客户端连接唯一凭证 license-key: ${LICENSE_KEY:} + # 客户端唯一身份标识(可忽略,若不设置首次启动会自动生成) client-id: ${CLIENT_ID:} + # 是否开启隧道传输报文日志(日志级别为debug时开启才有效) transfer-log-enable: ${CLIENT_LOG:false} + # 重连设置 reconnection: + # 重连间隔(秒) interval-seconds: 10 + # 是否开启无限重连(未开启时,客户端license不合法会自动停止应用,开启了则不会,请谨慎开启) unlimited: false diff --git a/neutrino-proxy-server/src/main/resources/app.yml b/neutrino-proxy-server/src/main/resources/app.yml index a2b4ec2c..8da747a5 100644 --- a/neutrino-proxy-server/src/main/resources/app.yml +++ b/neutrino-proxy-server/src/main/resources/app.yml @@ -1,10 +1,9 @@ server: + # 服务端web端口,用于支持HTTP接口,管理后台页面访问 port: ${WEB_PORT:8888} neutrino: proxy: - logger: - level: ${LOG_LEVEL:info} protocol: max-frame-length: ${MAX_FRAME_LENGTH:2097152} length-field-offset: 0 @@ -14,30 +13,48 @@ neutrino: read-idle-time: 30 write-idle-time: 5 all-idle-time-seconds: 0 + logger: + # 日志级别 + level: ${LOG_LEVEL:info} + # 隧道相关配置-用于维持服务端与客户端的通信 tunnel: + # 线程池相关配置,用于技术调优,可忽略 boss-thread-count: 2 work-thread-count: 10 + # 隧道非SSL端口 port: ${OPEN_PORT:9000} + # 隧道SSL端口 ssl-port: ${SSL_PORT:9002} + # 隧道SSL证书配置 key-store-password: ${STORE_PASS:123456} key-manager-password: ${MGR_PASS:123456} jks-path: ${JKS_PATH:classpath:/test.jks} + # 是否开启隧道传输报文日志(日志级别为debug时开启才有效) transfer-log-enable: ${TUNNEL_LOG:false} server: + # 线程池相关配置,用于技术调优,可忽略 boss-thread-count: 5 work-thread-count: 20 + # http代理端口,默认80 http-proxy-port: ${HTTP_PROXY_PORT:80} + # https代理端口,默认443 (需要配置域名、证书) https-proxy-port: ${HTTPS_PROXY_PORT:443} # 如果不配置,则不支持域名映射 domain-name: ${DOMAIN_NAME:} + # https证书配置 key-store-password: ${HTTPS_STORE_PASS:} jks-path: ${HTTPS_JKS_PATH:} + # 是否开启代理服务报文日志(日志级别为debug时开启才有效) transfer-log-enable: ${SERVER_LOG:false} data: db: + # 数据库类型,目前支持sqlite、mysql、mariadb type: ${DB_TYPE:sqlite} + # 数据库连接URL url: ${DB_URL:jdbc:sqlite:data.db} + # 数据库用户名 username: ${DB_USER:} + # 数据库密码 password: ${DB_PASSWORD:} #添加MIME印射(如果有需要?) diff --git a/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/06.服务端配置.md b/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/06.服务端配置.md index 5f4c249b..dafff141 100644 --- a/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/06.服务端配置.md +++ b/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/06.服务端配置.md @@ -19,6 +19,9 @@ server: neutrino: proxy: + logger: + # 日志级别 + level: ${LOG_LEVEL:info} # 隧道相关配置-用于维持服务端与客户端的通信 tunnel: # 线程池相关配置,用于技术调优,可忽略 @@ -32,7 +35,8 @@ neutrino: key-store-password: ${STORE_PASS:123456} key-manager-password: ${MGR_PASS:123456} jks-path: ${JKS_PATH:classpath:/test.jks} - # 代理服务相关配置 + # 是否开启隧道传输报文日志(日志级别为debug时开启才有效) + transfer-log-enable: ${TUNNEL_LOG:false} server: # 线程池相关配置,用于技术调优,可忽略 boss-thread-count: 5 @@ -46,9 +50,11 @@ neutrino: # https证书配置 key-store-password: ${HTTPS_STORE_PASS:} jks-path: ${HTTPS_JKS_PATH:} + # 是否开启代理服务报文日志(日志级别为debug时开启才有效) + transfer-log-enable: ${SERVER_LOG:false} data: db: - # 数据库类型,目前支持sqlite、mysql两种 + # 数据库类型,目前支持sqlite、mysql、mariadb type: ${DB_TYPE:sqlite} # 数据库连接URL url: ${DB_URL:jdbc:sqlite:data.db} diff --git a/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/07.客户端配置.md b/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/07.客户端配置.md new file mode 100644 index 00000000..c9514f00 --- /dev/null +++ b/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/07.客户端配置.md @@ -0,0 +1,38 @@ +--- +title: 客户端配置 +date: 2023-06-09 21:15:35 +permalink: /pages/50ce10/ +--- + +# 以下是最新的客户端配置格式(app.yml) +```yml +neutrino: + proxy: + logger: + # 日志级别 + level: ${LOG_LEVEL:info} + client: + # 线程池相关配置,用于技术调优,可忽略 + thread-count: 50 + # 隧道SSL证书配置 + key-store-password: ${STORE_PASS:123456} + jks-path: ${JKS_PATH:classpath:/test.jks} + # 服务端IP + server-ip: ${SERVER_IP:localhost} + # 服务端端口(对应服务端app.yml中的tunnel.port、tunnel.ssl-port) + server-port: ${SERVER_PORT:9002} + # 是否启用SSL(注意:该配置必须和server-port对应上) + ssl-enable: ${SSL_ENABLE:true} + # 客户端连接唯一凭证 + license-key: ${LICENSE_KEY:} + # 客户端唯一身份标识(可忽略,若不设置首次启动会自动生成) + client-id: ${CLIENT_ID:} + # 是否开启隧道传输报文日志(日志级别为debug时开启才有效) + transfer-log-enable: ${CLIENT_LOG:false} + # 重连设置 + reconnection: + # 重连间隔(秒) + interval-seconds: 10 + # 是否开启无限重连(未开启时,客户端license不合法会自动停止应用,开启了则不会,请谨慎开启) + unlimited: false +``` From 533675b3677063fce14b26cb0048f3cdc9377240 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 9 Jun 2023 21:43:32 +0800 Subject: [PATCH 35/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3.?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=89=93=E8=B5=8F=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../01.使用教程/05.赞赏记录/100.2023年.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md diff --git a/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md b/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md new file mode 100644 index 00000000..a56a5419 --- /dev/null +++ b/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md @@ -0,0 +1,19 @@ +--- +title: 2023年 +date: 2023-06-09 21:33:17 +permalink: /pages/cded59/ +--- + +| 日期 | 渠道 |金额|昵称| 备注 | +|:-----------|:---|:-|:-|:--------| +| 2023-06-09 |微信红包|50|李阳| 开源无限好 | +| 2023-06-09 |Gitee捐助|50|罗宾| 感谢您的开源项目!| +| 2023-06-07 |Gitee捐助|50|罗宾| 感谢您的开源项目!| +| 2023-06-03 |Gitee捐助|50|Admin| 感谢您的开源项目!| +| 2023-05-29 |微信红包|20|TYY| | +| 2023-05-29 |Gitee捐助|10|笑看| 感谢您的开源项目!| +| 2023-05-26 |微信红包|50|至少还有满天星光照耀你| | +| 2023-02-23 |Gitee捐助|10|Yohanes|感谢您的开源项目! | +| 2023-02-23 |Gitee捐助|20|jam_lee|感谢您的开源项目!希望能支持域名映射| +| 2023-02-10 |Gitee捐助|5|实习两年半|感谢您的开源项目!| +| 2023-02-02 |Gitee捐助|10|阳光很暖|感谢您的开源项目!| From 5daec7195f1a43df37d21c16ef74001849a0f394 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 9 Jun 2023 23:22:56 +0800 Subject: [PATCH 36/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs/01.使用教程/05.赞赏记录/100.2023年.md | 1 + 1 file changed, 1 insertion(+) diff --git a/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md b/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md index a56a5419..1893f340 100644 --- a/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md +++ b/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md @@ -6,6 +6,7 @@ permalink: /pages/cded59/ | 日期 | 渠道 |金额|昵称| 备注 | |:-----------|:---|:-|:-|:--------| +| 2023-06-09 |Gitee捐助|50|Admin| 感谢您的开源项目! | | 2023-06-09 |微信红包|50|李阳| 开源无限好 | | 2023-06-09 |Gitee捐助|50|罗宾| 感谢您的开源项目!| | 2023-06-07 |Gitee捐助|50|罗宾| 感谢您的开源项目!| From c48404e3bb9a1136e3c1ba7c8780df4ad55ba0a6 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Mon, 12 Jun 2023 21:19:50 +0800 Subject: [PATCH 37/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=AE=98=E7=BD=91?= =?UTF-8?q?=E8=B5=9E=E5=8A=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../01.使用教程/05.赞赏记录/100.2023年.md | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md b/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md index 1893f340..56508ff2 100644 --- a/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md +++ b/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md @@ -4,17 +4,18 @@ date: 2023-06-09 21:33:17 permalink: /pages/cded59/ --- -| 日期 | 渠道 |金额|昵称| 备注 | -|:-----------|:---|:-|:-|:--------| -| 2023-06-09 |Gitee捐助|50|Admin| 感谢您的开源项目! | -| 2023-06-09 |微信红包|50|李阳| 开源无限好 | -| 2023-06-09 |Gitee捐助|50|罗宾| 感谢您的开源项目!| -| 2023-06-07 |Gitee捐助|50|罗宾| 感谢您的开源项目!| -| 2023-06-03 |Gitee捐助|50|Admin| 感谢您的开源项目!| -| 2023-05-29 |微信红包|20|TYY| | -| 2023-05-29 |Gitee捐助|10|笑看| 感谢您的开源项目!| -| 2023-05-26 |微信红包|50|至少还有满天星光照耀你| | -| 2023-02-23 |Gitee捐助|10|Yohanes|感谢您的开源项目! | -| 2023-02-23 |Gitee捐助|20|jam_lee|感谢您的开源项目!希望能支持域名映射| -| 2023-02-10 |Gitee捐助|5|实习两年半|感谢您的开源项目!| -| 2023-02-02 |Gitee捐助|10|阳光很暖|感谢您的开源项目!| +| 日期 | 渠道 | 金额 |昵称| 备注 | +|:-----------|:---|:---|:-|:--------| +| 2023-06-09 |Gitee捐助| 10 |失败女神| 感谢您的开源项目! | +| 2023-06-09 |Gitee捐助| 50 |Admin| 感谢您的开源项目! | +| 2023-06-09 |微信红包| 50 |李阳| 开源无限好 | +| 2023-06-09 |Gitee捐助| 50 |罗宾| 感谢您的开源项目!| +| 2023-06-07 |Gitee捐助| 50 |罗宾| 感谢您的开源项目!| +| 2023-06-03 |Gitee捐助| 50 |Admin| 感谢您的开源项目!| +| 2023-05-29 |微信红包| 20 |TYY| | +| 2023-05-29 |Gitee捐助| 10 |笑看| 感谢您的开源项目!| +| 2023-05-26 |微信红包| 50 |至少还有满天星光照耀你| | +| 2023-02-23 |Gitee捐助| 10 |Yohanes|感谢您的开源项目! | +| 2023-02-23 |Gitee捐助| 20 |jam_lee|感谢您的开源项目!希望能支持域名映射| +| 2023-02-10 |Gitee捐助| 5 |实习两年半|感谢您的开源项目!| +| 2023-02-02 |Gitee捐助| 10 |阳光很暖|感谢您的开源项目!| From fe86d786f4374058b587aa5e61ae81c745095c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=B5=A9=E6=9D=B0?= <897546244@qq.com> Date: Thu, 22 Jun 2023 15:51:50 +0800 Subject: [PATCH 38/45] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=AB=AF?= =?UTF-8?q?=E5=8F=A3=E6=98=A0=E5=B0=84=E6=9F=A5=E8=AF=A2BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/PortMappingService.java | 84 ++++++++----------- 1 file changed, 34 insertions(+), 50 deletions(-) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java index aa8004f7..76a5e881 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java @@ -8,6 +8,8 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.google.common.collect.Sets; +import ma.glasnost.orika.MapperFacade; +import org.apache.ibatis.solon.annotation.Db; import org.dromara.neutrinoproxy.server.base.db.DBInitialize; import org.dromara.neutrinoproxy.server.base.page.PageInfo; import org.dromara.neutrinoproxy.server.base.page.PageQuery; @@ -31,14 +33,10 @@ import org.dromara.neutrinoproxy.server.dal.entity.PortMappingDO; import org.dromara.neutrinoproxy.server.dal.entity.PortPoolDO; import org.dromara.neutrinoproxy.server.dal.entity.UserDO; import org.dromara.neutrinoproxy.server.util.ParamCheckUtil; -import ma.glasnost.orika.MapperFacade; -import org.apache.ibatis.solon.annotation.Db; -import org.dromara.neutrinoproxy.server.controller.res.proxy.*; import org.dromara.neutrinoproxy.server.util.ProxyUtil; import org.noear.solon.annotation.Component; import org.noear.solon.annotation.Init; import org.noear.solon.annotation.Inject; -import org.noear.solon.core.Lifecycle; import org.noear.solon.core.bean.LifecycleBean; import java.util.*; @@ -51,25 +49,25 @@ import java.util.stream.Collectors; */ @Component public class PortMappingService implements LifecycleBean { - @Inject - private MapperFacade mapperFacade; - @Db - private PortMappingMapper portMappingMapper; - @Db - private LicenseMapper licenseMapper; - @Db - private UserMapper userMapper; - @Db - private PortPoolMapper portPoolMapper; - @Inject - private VisitorChannelService visitorChannelService; + @Inject + private MapperFacade mapperFacade; + @Db + private PortMappingMapper portMappingMapper; + @Db + private LicenseMapper licenseMapper; + @Db + private UserMapper userMapper; + @Db + private PortPoolMapper portPoolMapper; + @Inject + private VisitorChannelService visitorChannelService; - @Inject - private PortPoolService portPoolService; - @Inject - private ProxyConfig proxyConfig; - @Inject - private DBInitialize dbInitialize; + @Inject + private PortPoolService portPoolService; + @Inject + private ProxyConfig proxyConfig; + @Inject + private DBInitialize dbInitialize; public PageInfo page(PageQuery pageQuery, PortMappingListReq req) { Page result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize()); @@ -77,6 +75,13 @@ public class PortMappingService implements LifecycleBean { //描述字段为模糊查询,在应用层处理,否则sqlite不支持 req.setDescription("%" + req.getDescription() + "%"); } + + // 协议名称转换 + if (StringUtils.isNotBlank(req.getProtocal())) { + NetworkProtocolEnum networkProtocolEnum = NetworkProtocolEnum.of(req.getProtocal()); + req.setProtocal(networkProtocolEnum.getDesc()); + } + List list = portMappingMapper.selectPortMappingByCondition(req); List respList = mapperFacade.mapAsList(list, PortMappingListRes.class); if (CollectionUtils.isEmpty(list)) { @@ -113,10 +118,7 @@ public class PortMappingService implements LifecycleBean { } }); //sorted [userId asc] [licenseId asc] [createTime asc] - respList = respList.stream().sorted(Comparator.comparing(PortMappingListRes::getUserId) - .thenComparing(PortMappingListRes::getLicenseId) - .thenComparing(PortMappingListRes::getCreateTime)) - .collect(Collectors.toList()); + respList = respList.stream().sorted(Comparator.comparing(PortMappingListRes::getUserId).thenComparing(PortMappingListRes::getLicenseId).thenComparing(PortMappingListRes::getCreateTime)).collect(Collectors.toList()); return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize()); } @@ -149,9 +151,7 @@ public class PortMappingService implements LifecycleBean { // 更新VisitorChannel visitorChannelService.addVisitorChannelByPortMapping(portMappingDO); // 更新域名映射 - if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && - StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && - StrUtil.isNotBlank(portMappingDO.getSubdomain())) { + if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort()); } return new PortMappingCreateRes(); @@ -188,14 +188,11 @@ public class PortMappingService implements LifecycleBean { // 更新VisitorChannel visitorChannelService.updateVisitorChannelByPortMapping(oldPortMappingDO, portMappingDO); // 删除老的域名映射 - if (NetworkProtocolEnum.isHttp(oldPortMappingDO.getProtocal()) && - StrUtil.isNotBlank(oldPortMappingDO.getSubdomain())) { + if (NetworkProtocolEnum.isHttp(oldPortMappingDO.getProtocal()) && StrUtil.isNotBlank(oldPortMappingDO.getSubdomain())) { ProxyUtil.removeSubdomainToServerPort(oldPortMappingDO.getSubdomain()); } // 更新域名映射 - if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && - StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && - StrUtil.isNotBlank(portMappingDO.getSubdomain())) { + if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort()); } return new PortMappingUpdateRes(); @@ -206,16 +203,7 @@ public class PortMappingService implements LifecycleBean { if (null == portMappingDO) { return null; } - PortMappingDetailRes res = new PortMappingDetailRes() - .setId(portMappingDO.getId()) - .setLicenseId(portMappingDO.getLicenseId()) - .setServerPort(portMappingDO.getServerPort()) - .setClientIp(portMappingDO.getClientIp()) - .setClientPort(portMappingDO.getClientPort()) - .setIsOnline(portMappingDO.getIsOnline()) - .setEnable(portMappingDO.getEnable()) - .setCreateTime(portMappingDO.getCreateTime()) - .setUpdateTime(portMappingDO.getUpdateTime()); + PortMappingDetailRes res = new PortMappingDetailRes().setId(portMappingDO.getId()).setLicenseId(portMappingDO.getLicenseId()).setServerPort(portMappingDO.getServerPort()).setClientIp(portMappingDO.getClientIp()).setClientPort(portMappingDO.getClientPort()).setIsOnline(portMappingDO.getIsOnline()).setEnable(portMappingDO.getEnable()).setCreateTime(portMappingDO.getCreateTime()).setUpdateTime(portMappingDO.getUpdateTime()); LicenseDO license = licenseMapper.findById(portMappingDO.getLicenseId()); if (null != license) { @@ -268,8 +256,7 @@ public class PortMappingService implements LifecycleBean { // 更新VisitorChannel visitorChannelService.removeVisitorChannelByPortMapping(portMappingDO); // 更新域名映射 - if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && - StrUtil.isNotBlank(portMappingDO.getSubdomain())) { + if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { ProxyUtil.removeSubdomainToServerPort(portMappingDO.getSubdomain()); } } @@ -295,10 +282,7 @@ public class PortMappingService implements LifecycleBean { if (StrUtil.isBlank(proxyConfig.getServer().getDomainName())) { return; } - List portMappingDOList = portMappingMapper.selectList(new LambdaQueryWrapper() - .eq(PortMappingDO::getProtocal, NetworkProtocolEnum.HTTP.getDesc()) - .isNotNull(PortMappingDO::getSubdomain) - ); + List portMappingDOList = portMappingMapper.selectList(new LambdaQueryWrapper().eq(PortMappingDO::getProtocal, NetworkProtocolEnum.HTTP.getDesc()).isNotNull(PortMappingDO::getSubdomain)); if (CollectionUtil.isEmpty(portMappingDOList)) { return; } From 48c8df15e7b81e4d4e6440242da27c186934298c Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Mon, 26 Jun 2023 10:30:44 +0800 Subject: [PATCH 39/45] =?UTF-8?q?1=E3=80=81=E5=8D=87=E7=BA=A7solon?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E4=B8=BA2.3.6=202=E3=80=81=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=90=8E=E5=8F=B0=E6=94=AF=E6=8C=81=E5=B8=A6context-path?= =?UTF-8?q?=E8=AE=BF=E9=97=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- neutrino-proxy-admin/config/docker.env.js | 2 +- .../dromara/neutrinoproxy/server/service/LicenseService.java | 2 -- neutrino-proxy-server/src/main/resources/app.yml | 1 + pom.xml | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/neutrino-proxy-admin/config/docker.env.js b/neutrino-proxy-admin/config/docker.env.js index 33aca667..3793cee6 100644 --- a/neutrino-proxy-admin/config/docker.env.js +++ b/neutrino-proxy-admin/config/docker.env.js @@ -1,5 +1,5 @@ module.exports = { NODE_ENV: '"development"', ENV_CONFIG: '"docker"', - BASE_API: '"/"' + BASE_API: '"/neutrino-proxy-server"' } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/LicenseService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/LicenseService.java index e1a66a03..7b96fda3 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/LicenseService.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/LicenseService.java @@ -26,7 +26,6 @@ import org.dromara.neutrinoproxy.server.util.ParamCheckUtil; import ma.glasnost.orika.MapperFacade; import org.apache.ibatis.solon.annotation.Db; import org.dromara.neutrinoproxy.server.controller.res.proxy.*; -import org.jetbrains.annotations.Nullable; import org.noear.solon.annotation.Component; import org.noear.solon.annotation.Init; import org.noear.solon.annotation.Inject; @@ -90,7 +89,6 @@ public class LicenseService implements LifecycleBean { return licenseList; } - @Nullable private List assembleConvertLicenses(List list) { List licenseList = mapperFacade.mapAsList(list, LicenseListRes.class); if (!CollectionUtil.isEmpty(licenseList)) { diff --git a/neutrino-proxy-server/src/main/resources/app.yml b/neutrino-proxy-server/src/main/resources/app.yml index 8da747a5..b11d0448 100644 --- a/neutrino-proxy-server/src/main/resources/app.yml +++ b/neutrino-proxy-server/src/main/resources/app.yml @@ -1,6 +1,7 @@ server: # 服务端web端口,用于支持HTTP接口,管理后台页面访问 port: ${WEB_PORT:8888} + context-path: /neutrino-proxy-server neutrino: proxy: diff --git a/pom.xml b/pom.xml index aa92a35b..b1ce1798 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.noear solon-parent - 2.2.8 + 2.3.6 From b28d4760812722f23f40772c2c7b1b1fcdac08fa Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Mon, 26 Jun 2023 18:00:25 +0800 Subject: [PATCH 40/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=B5=9E=E8=B5=8F?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs/01.使用教程/05.赞赏记录/100.2023年.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md b/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md index 56508ff2..368ae7b3 100644 --- a/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md +++ b/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md @@ -6,6 +6,8 @@ permalink: /pages/cded59/ | 日期 | 渠道 | 金额 |昵称| 备注 | |:-----------|:---|:---|:-|:--------| +| 2023-06-25 |Gitee捐助| 10 |zhujue888| 感谢您的开源项目! | +| 2023-06-16 |微信红包| 50 |小跟班| | | 2023-06-09 |Gitee捐助| 10 |失败女神| 感谢您的开源项目! | | 2023-06-09 |Gitee捐助| 50 |Admin| 感谢您的开源项目! | | 2023-06-09 |微信红包| 50 |李阳| 开源无限好 | From 86a3cf92b5347e341673bc6e8fa1cf8fa630d39c Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Mon, 26 Jun 2023 18:04:40 +0800 Subject: [PATCH 41/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=B5=9E=E8=B5=8F?= =?UTF-8?q?=E8=AE=B0=E5=BD=95.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs/01.使用教程/05.赞赏记录/100.2023年.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md b/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md index 368ae7b3..cdcfde6f 100644 --- a/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md +++ b/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md @@ -8,7 +8,7 @@ permalink: /pages/cded59/ |:-----------|:---|:---|:-|:--------| | 2023-06-25 |Gitee捐助| 10 |zhujue888| 感谢您的开源项目! | | 2023-06-16 |微信红包| 50 |小跟班| | -| 2023-06-09 |Gitee捐助| 10 |失败女神| 感谢您的开源项目! | +| 2023-06-10 |Gitee捐助| 10 |失败女神| 感谢您的开源项目! | | 2023-06-09 |Gitee捐助| 50 |Admin| 感谢您的开源项目! | | 2023-06-09 |微信红包| 50 |李阳| 开源无限好 | | 2023-06-09 |Gitee捐助| 50 |罗宾| 感谢您的开源项目!| @@ -19,5 +19,5 @@ permalink: /pages/cded59/ | 2023-05-26 |微信红包| 50 |至少还有满天星光照耀你| | | 2023-02-23 |Gitee捐助| 10 |Yohanes|感谢您的开源项目! | | 2023-02-23 |Gitee捐助| 20 |jam_lee|感谢您的开源项目!希望能支持域名映射| -| 2023-02-10 |Gitee捐助| 5 |实习两年半|感谢您的开源项目!| +| 2023-02-10 |Gitee捐助| 5 |实习两年半|感谢您的开源项目!| | 2023-02-02 |Gitee捐助| 10 |阳光很暖|感谢您的开源项目!| From f423056361d2f7a519ef5e5257afe3b2700c88da Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 30 Jun 2023 14:05:09 +0800 Subject: [PATCH 42/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=B5=9E=E8=B5=8F?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- neutrino-proxy-client/pom.xml | 6 ++-- .../01.使用教程/05.赞赏记录/100.2023年.md | 36 ++++++++++--------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/neutrino-proxy-client/pom.xml b/neutrino-proxy-client/pom.xml index f624979f..e9da2873 100644 --- a/neutrino-proxy-client/pom.xml +++ b/neutrino-proxy-client/pom.xml @@ -32,9 +32,9 @@ ${project.basedir}/src/main/resources false - - app-*.yml - + + + diff --git a/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md b/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md index cdcfde6f..8176aecf 100644 --- a/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md +++ b/neutrino-proxy-vuepress/docs/01.使用教程/05.赞赏记录/100.2023年.md @@ -4,20 +4,22 @@ date: 2023-06-09 21:33:17 permalink: /pages/cded59/ --- -| 日期 | 渠道 | 金额 |昵称| 备注 | -|:-----------|:---|:---|:-|:--------| -| 2023-06-25 |Gitee捐助| 10 |zhujue888| 感谢您的开源项目! | -| 2023-06-16 |微信红包| 50 |小跟班| | -| 2023-06-10 |Gitee捐助| 10 |失败女神| 感谢您的开源项目! | -| 2023-06-09 |Gitee捐助| 50 |Admin| 感谢您的开源项目! | -| 2023-06-09 |微信红包| 50 |李阳| 开源无限好 | -| 2023-06-09 |Gitee捐助| 50 |罗宾| 感谢您的开源项目!| -| 2023-06-07 |Gitee捐助| 50 |罗宾| 感谢您的开源项目!| -| 2023-06-03 |Gitee捐助| 50 |Admin| 感谢您的开源项目!| -| 2023-05-29 |微信红包| 20 |TYY| | -| 2023-05-29 |Gitee捐助| 10 |笑看| 感谢您的开源项目!| -| 2023-05-26 |微信红包| 50 |至少还有满天星光照耀你| | -| 2023-02-23 |Gitee捐助| 10 |Yohanes|感谢您的开源项目! | -| 2023-02-23 |Gitee捐助| 20 |jam_lee|感谢您的开源项目!希望能支持域名映射| -| 2023-02-10 |Gitee捐助| 5 |实习两年半|感谢您的开源项目!| -| 2023-02-02 |Gitee捐助| 10 |阳光很暖|感谢您的开源项目!| +| 日期 | 渠道 | 金额 |昵称| 备注 | +|:-----------|:---|:---|:-|:-----------------| +| 2023-06-29 |微信红包| 16.8 |迟迟🌱| 加油 | +| 2023-06-27 |微信红包| 30 |Arno| | +| 2023-06-25 |Gitee捐助| 10 |zhujue888| 感谢您的开源项目! | +| 2023-06-16 |微信红包| 50 |小跟班| | +| 2023-06-10 |Gitee捐助| 10 |失败女神| 感谢您的开源项目! | +| 2023-06-09 |Gitee捐助| 50 |Admin| 感谢您的开源项目! | +| 2023-06-09 |微信红包| 50 |李阳| 开源无限好 | +| 2023-06-09 |Gitee捐助| 50 |罗宾| 感谢您的开源项目! | +| 2023-06-07 |Gitee捐助| 50 |罗宾| 感谢您的开源项目! | +| 2023-06-03 |Gitee捐助| 50 |Admin| 感谢您的开源项目! | +| 2023-05-29 |微信红包| 20 |TYY| | +| 2023-05-29 |Gitee捐助| 10 |笑看| 感谢您的开源项目! | +| 2023-05-26 |微信红包| 50 |至少还有满天星光照耀你| | +| 2023-02-23 |Gitee捐助| 10 |Yohanes| 感谢您的开源项目! | +| 2023-02-23 |Gitee捐助| 20 |jam_lee| 感谢您的开源项目!希望能支持域名映射| +| 2023-02-10 |Gitee捐助| 5 |实习两年半| 感谢您的开源项目! | +| 2023-02-02 |Gitee捐助| 10 |阳光很暖| 感谢您的开源项目! | From c20a6db44a6ba89ed9788304b789a464dbc15881 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 30 Jun 2023 18:06:03 +0800 Subject: [PATCH 43/45] =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=AB=AF=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=EF=BC=8Ccmd=E9=80=9A=E9=81=93=E8=AF=BB?= =?UTF-8?q?=E5=86=99=E8=B6=85=E6=97=B6=E5=A4=84=E7=90=86=E8=B0=83=E6=95=B4?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../neutrinoproxy/client/core/CmdChannelHandler.java | 6 +++--- .../server/proxy/core/ProxyTunnelChannelHandler.java | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java index 31fb1a9f..b6bceee0 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java @@ -61,14 +61,14 @@ public class CmdChannelHandler extends SimpleChannelInboundHandler switch (event.state()) { case READER_IDLE: // 读超时,断开连接 -// log.info("读超时"); -// ctx.channel().close(); + log.error("Client CmdChannel 读超时,断开连接"); + ctx.channel().close(); break; case WRITER_IDLE: ctx.channel().writeAndFlush(ProxyMessage.buildHeartbeatMessage()); break; case ALL_IDLE: - log.info("Client CmdChannel 读写超时"); + log.error("Client CmdChannel 读写超时,断开连接"); ctx.close(); break; } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java index 0f3d9363..ba7e19b0 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java @@ -131,6 +131,7 @@ public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler Date: Fri, 30 Jun 2023 18:16:52 +0800 Subject: [PATCH 44/45] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=BF=83=E8=B7=B3?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=BC=80=E5=85=B3=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- neutrino-proxy-client/pom.xml | 6 +++--- .../neutrinoproxy/client/config/ProxyConfig.java | 1 + .../neutrinoproxy/client/core/CmdChannelHandler.java | 10 +++++++++- neutrino-proxy-client/src/main/resources/app.yml | 2 ++ .../neutrinoproxy/server/base/proxy/ProxyConfig.java | 1 + .../server/proxy/core/ProxyTunnelChannelHandler.java | 9 +++++++++ neutrino-proxy-server/src/main/resources/app.yml | 2 ++ 7 files changed, 27 insertions(+), 4 deletions(-) diff --git a/neutrino-proxy-client/pom.xml b/neutrino-proxy-client/pom.xml index e9da2873..f624979f 100644 --- a/neutrino-proxy-client/pom.xml +++ b/neutrino-proxy-client/pom.xml @@ -32,9 +32,9 @@ ${project.basedir}/src/main/resources false - - - + + app-*.yml + diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java index ceb5a195..68aa435b 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java @@ -41,6 +41,7 @@ public class ProxyConfig { private Integer threadCount; private String clientId; private Boolean transferLogEnable; + private Boolean heartbeatLogEnable; private Reconnection reconnection; } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java index b6bceee0..decd5c0b 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java @@ -1,5 +1,6 @@ package org.dromara.neutrinoproxy.client.core; +import org.dromara.neutrinoproxy.client.config.ProxyConfig; import org.dromara.neutrinoproxy.client.util.ProxyUtil; import org.dromara.neutrinoproxy.core.Constants; import org.dromara.neutrinoproxy.core.ProxyMessage; @@ -19,11 +20,18 @@ import org.noear.solon.Solon; */ @Slf4j public class CmdChannelHandler extends SimpleChannelInboundHandler { + private static volatile Boolean transferLogEnable = Boolean.FALSE; + public CmdChannelHandler() { + ProxyConfig proxyConfig = Solon.context().getBean(ProxyConfig.class); + if (null != proxyConfig.getClient() && null != proxyConfig.getClient().getHeartbeatLogEnable()) { + transferLogEnable = proxyConfig.getClient().getHeartbeatLogEnable(); + } + } @Override protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception { - if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) { + if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType() || transferLogEnable) { log.debug("Client CmdChannel recieved proxy message, type is {}", proxyMessage.getType()); } Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage); diff --git a/neutrino-proxy-client/src/main/resources/app.yml b/neutrino-proxy-client/src/main/resources/app.yml index 86eb7ef3..23072516 100644 --- a/neutrino-proxy-client/src/main/resources/app.yml +++ b/neutrino-proxy-client/src/main/resources/app.yml @@ -33,6 +33,8 @@ neutrino: client-id: ${CLIENT_ID:} # 是否开启隧道传输报文日志(日志级别为debug时开启才有效) transfer-log-enable: ${CLIENT_LOG:false} + # 是否开启心跳日志 + heartbeat-log-enable: ${HEARTBEAT_LOG:false} # 重连设置 reconnection: # 重连间隔(秒) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfig.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfig.java index e3176b03..928db99f 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfig.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfig.java @@ -62,6 +62,7 @@ public class ProxyConfig { private String keyManagerPassword; private String jksPath; private Boolean transferLogEnable; + private Boolean heartbeatLogEnable; } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java index ba7e19b0..21c800d5 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java @@ -25,6 +25,7 @@ package org.dromara.neutrinoproxy.server.proxy.core; import org.dromara.neutrinoproxy.core.Constants; import org.dromara.neutrinoproxy.core.ProxyMessage; import org.dromara.neutrinoproxy.core.dispatcher.Dispatcher; +import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig; import org.dromara.neutrinoproxy.server.constant.ClientConnectTypeEnum; import org.dromara.neutrinoproxy.server.constant.SuccessCodeEnum; import org.dromara.neutrinoproxy.server.dal.entity.ClientConnectRecordDO; @@ -49,13 +50,21 @@ import java.util.Date; @Slf4j public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler { private static volatile Dispatcher dispatcher; + private static volatile Boolean transferLogEnable = Boolean.FALSE; public ProxyTunnelChannelHandler() { dispatcher = Solon.context().getBean(Dispatcher.class); + ProxyConfig proxyConfig = Solon.context().getBean(ProxyConfig.class); + if (null != proxyConfig.getTunnel() && null != proxyConfig.getTunnel().getHeartbeatLogEnable()) { + transferLogEnable = proxyConfig.getTunnel().getHeartbeatLogEnable(); + } } @Override protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception { + if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType() || transferLogEnable) { + log.debug("Server CmdChannel recieved proxy message, type is {}", proxyMessage.getType()); + } dispatcher.dispatch(ctx, proxyMessage); } diff --git a/neutrino-proxy-server/src/main/resources/app.yml b/neutrino-proxy-server/src/main/resources/app.yml index b11d0448..99082f24 100644 --- a/neutrino-proxy-server/src/main/resources/app.yml +++ b/neutrino-proxy-server/src/main/resources/app.yml @@ -32,6 +32,8 @@ neutrino: jks-path: ${JKS_PATH:classpath:/test.jks} # 是否开启隧道传输报文日志(日志级别为debug时开启才有效) transfer-log-enable: ${TUNNEL_LOG:false} + # 是否开启心跳日志 + heartbeat-log-enable: ${HEARTBEAT_LOG:false} server: # 线程池相关配置,用于技术调优,可忽略 boss-thread-count: 5 From c385030fc458f164df61c12f32e9652622dce3d3 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Sat, 1 Jul 2023 14:04:53 +0800 Subject: [PATCH 45/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=AE=98=E7=BD=91?= =?UTF-8?q?=E6=96=87=E6=A1=A3=EF=BC=8C=E9=A1=B9=E7=9B=AEREADME?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 133 +----------------- .../01.开始使用/100.常见问题汇总.md | 32 +++++ 2 files changed, 36 insertions(+), 129 deletions(-) create mode 100644 neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/100.常见问题汇总.md diff --git a/README.md b/README.md index f00a9a1f..52e49b47 100644 --- a/README.md +++ b/README.md @@ -34,144 +34,19 @@ ![License管理](assets/run-example/license1.png) ![端口映射管理](assets/run-example/port-mapping1.png) -# 4、项目结构 -- neutrino-proxy - - neutrino-proxy-core 与代理相关的公共常量、编解码器 - - neutrino-proxy-client 代理客户端项目 - - neutrino-proxy-server 代理服务端项目 - - neutrino-proxy-admin 代理监控项目(基于vue-element-admin开发) - -# 5、运行 -## 5.1、使用keytool工具生成ssl证书, 若不需要ssl加密可跳过 -```shell -keytool -genkey -alias test1 -keyalg RSA -keysize 1024 -validity 3650 -keypass 123456 -storepass 123456 -keystore "./test.jks" -``` - -## 5.2、修改服务端配置(app.yml) -```yml -application: - name: neutrino-proxy-server - -neutrino: - proxy: - protocol: - max-frame-length: 2097152 - length-field-offset: 0 - length-field-length: 4 - initial-bytes-to-strip: 0 - length-adjustment: 0 - read-idle-time: 60 - write-idle-time: 40 - all-idle-time-seconds: 0 - tunnel: - boss-thread-count: 2 - work-thread-count: 10 - # 服务端端口,用于保持与客户端的连接,非SSL - port: ${OPEN_PORT:9000} - # 服务端端口,用于保持与客户端的连接,SSL,需要jks证书文件,若不需要ssl支持,可不配置 - ssl-port: ${SSL_PORT:9002} - # 证书配置,用于隧道通信SSL加密 - key-store-password: ${STORE_PASS:123456} - key-manager-password: ${MGR_PASS:123456} - jks-path: ${JKS_PATH:classpath:/test.jks} - server: - boss-thread-count: 5 - work-thread-count: 20 - # HTTP代理端口,默认80,也可以用其他端口,走nginx转发 - http-proxy-port: ${HTTP_PROXY_PORT:80} - # HTTPS代理端口,默认443,也可以用其他端口,走nginx转发 - https-proxy-port: ${HTTPS_PROXY_PORT:443} - # 如果不配置,则不支持域名映射 - domain-name: ${DOMAIN_NAME:} - # 证书配置,用于支持HTTPS - key-store-password: ${HTTPS_STORE_PASS:} - jks-path: ${HTTPS_JKS_PATH:} - data: - # 数据库配置(支持mysql) - type: sqlite - url: jdbc:sqlite:data.db - driver-class: org.sqlite.JDBC - username: - password: -``` - -## 5.3、启动服务端 -> java -jar neutrino-proxy-server.jar - -## 5.4、修改客户端配置 -```yml -application: - name: neutrino-proxy-client - -proxy: - protocol: - max-frame-length: 2097152 - length-field-offset: 0 - length-field-length: 4 - initial-bytes-to-strip: 0 - length-adjustment: 0 - read-idle-time: 60 - write-idle-time: 30 - all-idle-time-seconds: 0 - client: - # ssl证书密码 - key-store-password: 123456 - # ssl证书存放位置 - jks-path: classpath:/test.jks - # 服务端ip,若部署到服务器,则配置服务器的ip - server-ip: localhost - # 服务端端口,若使用ssl,则需要配置为服务端的"ssl-port" - server-port: 9000 - # 是否启用ssl,启用则必须配置ssl相关参数 - ssl-enable: false -``` -## 5.5、代理示意图 +# 4、代理示意图 ![代理流程](assets/design/neutrino-proxy-process.jpg) -## 5.6、启动客户端 -### 5.6.1、启动参数直接指定配置 -> java -jar neutrino-proxy-client.jar serverIp=localhost serverPort=9000 licenseKey=b0a907332b474b25897c4dcb31fc7eb6 - -### 5.6.2、启动参数指定外部配置文件 -> java -jar neutrino-proxy-client.jar config=app.properties - -配置文件格式如下: -``` -neutrino.proxy.client.server-ip=localhost -neutrino.proxy.client.server-port=9002 -neutrino.proxy.client.ssl-enable=true -neutrino.proxy.client.key-store-password=123456 -neutrino.proxy.client.jks-path=classpath:/test.jks -neutrino.proxy.client.license-key=b0a907332b474b25897c4dcb31fc7eb6 -``` - -## 5.7、Docker快速启动 -```shell script - # 一键部署前端和后端,客户端按上方部署即可 - docker run -it -p 9000-9200:9000-9200/tcp -p 8888:8888 -d --name neutrino registry.cn-hangzhou.aliyuncs.com/asgc/aoshiguchen-docker-images:1.64 - # 如没docker环境,可以一键部署docker环境(centos 7.8)系统 - curl http://www.wangke666.cn/static/createDocker.sh | bash -``` - -# 6、演示环境 +# 5、演示环境 > 可使用分配好的游客license试用。服务器带宽较低,仅供学习使用! - 管理后台地址:http://103.163.47.16:9527 - 游客账号:visitor/123456 -# 7、未来迭代方向 -- 优化代码、增强稳定性 -- 服务端增加管理页面,提供报表、授权、限流等功能 -- 从项目中分离、孵化出另一个开源项目(neutrino-framework) - -# 8、技术文档 -- [Aop](./docs/Aop.MD) -- [Channel](./docs/Channel.MD) - -# 9、联系我们 +# 6、联系我们 - 微信: yuyunshize - Gitee: https://gitee.com/asgc/neutrino-proxy -# 10、贡献者列表 +# 7、贡献者列表

diff --git a/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/100.常见问题汇总.md b/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/100.常见问题汇总.md new file mode 100644 index 00000000..06062e45 --- /dev/null +++ b/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/100.常见问题汇总.md @@ -0,0 +1,32 @@ +--- +title: 常见问题汇总 +date: 2023-07-01 13:35:00 +permalink: /pages/a00001/ +--- + +# 1、客户端启动后连不上服务端,一直在重连 + +## 1.1、启动日志包含`not found license-key config`相关字样 +出现这种情况,说明客户端没获取到配置的license,可按如下检查: +- 客户端是否有配置app.yml,app.yml中是否有配置`license-key` +- 客户端启动参数是否指定app.yml配置,若未指定客户端不会加载任何jar外部的配置文件 +- 客户端启动参数指定的配置文件路径是否正确?如:`java -jar neutrino-proxy-client.jar config=app.yml`,代表`app.yml`文件与jar在同级别目录下,如果不在同级别目录,请使用绝对/相对路径指定 +- 除此之外license还可以用以下方法直接在启动参数中指定: + - `java -jar -DLICENSE_KEY=xxxx -DSERVER_IP=x.x.x.x -DSERVER_PORT=9000 -DSSL_ENABLE=false neutrino-proxy-client.jar` + - `java -jar neutrino-proxy-client.jar serverIp=x.x.x.x serverPort=9000 sslEnable=false licenseKey=xxxx` + +## 1.1、配置文件确定都已经配置,且启动参数正确指定了,但是没有出现`认证成功日志` +- 确认客户端配置的`server-ip`,必须是服务端所在机器的ip,且保证客户端所在机器能正常ping通 +- 确认客户端配置的`server-port`与`ssl-enable`,默认情况应配置为9000、false或9002、true,除非服务端app.yml有改动隧道对外端口 +- 确认服务端对外的9000、9002端口是否已经放开 +- 服务端如果采用docker部署,需要确保容器的9000、9002端口映射到宿主机 + +# 2、关于中微子代理涉及的2类SSL证书 +## 2.1、HTTPS证书 +该证书用于服务端支持HTTPS,若需要在服务端`app.yml`中配置即可 + +## 2.2、隧道SSL证书 +该证书用于对客户端-服务端之间的数据通信进行加密,因此客户端/服务端均需要配置该证书。可参考如下命令生成: +``` +keytool -genkey -alias test1 -keyalg RSA -keysize 1024 -validity 3650 -keypass 123456 -storepass 123456 -keystore "./test.jks" +```