From fc61624a0a623231177763bb8aedcbc10d1e84a0 Mon Sep 17 00:00:00 2001 From: Eric Rodrigues Pires Date: Tue, 1 Jul 2025 20:08:38 -0300 Subject: [PATCH] Adjustments to logs and book --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- book/src/technical_overview.md | 3 +-- book/theme/favicon.png | Bin 0 -> 40396 bytes src/http.rs | 22 +++++++++------------- src/lib.rs | 1 + src/tcp_alias.rs | 7 +++++++ src/telemetry.rs | 6 ++++++ 8 files changed, 27 insertions(+), 18 deletions(-) create mode 100644 book/theme/favicon.png diff --git a/Cargo.lock b/Cargo.lock index c1bc7c9..c596930 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3517,9 +3517,9 @@ dependencies = [ [[package]] name = "russh" -version = "0.53.0-beta.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8b4607282e06aa840b03da52d97b829865c1e0e992184bf4cb9aba28c773c72" +checksum = "9b71d6d784c75ab19c421b7c3df21b100c9643f8b2563ae345a495ee792e85e4" dependencies = [ "aes", "aws-lc-rs", diff --git a/Cargo.toml b/Cargo.toml index 0a3dce0..ce2092e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,7 +58,7 @@ reqwest = { version = "0.12.20", default-features = false, features = [ "json", "rustls-tls-manual-roots", ] } -russh = "0.53.0-beta.1" +russh = "0.53.0" rustls = "0.23.28" rustls-acme = { version = "0.14.0", default-features = false, features = [ "tokio", diff --git a/book/src/technical_overview.md b/book/src/technical_overview.md index ad092f9..2a4b816 100644 --- a/book/src/technical_overview.md +++ b/book/src/technical_overview.md @@ -65,8 +65,7 @@ sequenceDiagram SS ->> M: Register tunnel handler Note over SC, HC: Traffic routing HC ->>+ HS: HTTP request to assigned domain - HS ->>+ M: Look up tunnel for domain - M -->>- HS: Return tunnel handler + HS ->> M: Look up tunnel for domain HS ->>+ SS: Forward request via tunnel SS ->>+ SC: Relay to local service SC -->>- SS: Response from local service diff --git a/book/theme/favicon.png b/book/theme/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..1132ab673ef385ff2a439f3ac264067fc672d32b GIT binary patch literal 40396 zcmeAS@N?(olHy`uVBq!ia0y~yVE6^X9Bd2>3>|NxY#A6BSkfJR9T^xl_H+M9WMyDr zU@Q)DcVfJGQm3AQfk7eJBgmJ5p-PQ`p`it$x#0x^L#Y7+!>a@a2CEqi4B`cIb_Lon zFfgzsdAqwXSToo#*l$_NtjNH?z**oCS2OOQvuzp$G*)z#m60i0eUS#tzYG!=wV)CG8a*Fq~rD4x2 zKHC<)zdy^q?APCKH^Yl2ZH%hk`Q+Wchb^_=zHh(wYu(m;+*zyFZo4%|h<&VQ*6Taw z-ggjA@N~K5uz#P-)~jW?w;UhDDt+R6uuJ5})~jK+O;fxN)C*2*?BHp%7n=CmWeHn# z?$%i4Z5)5>nQ8?C9U28cs2||nn!bMRw&nZIGX8Jx_`(n?dQo}aa?JyvY31%GNb{ui70PVxNZ`sx=8YHm+--r^eZ(dOoh?_c*AGRcTeyzTnr zvQp8%*~$mW55v*%GRv7xbTS2;)4&}G@}1D&g)HPyEr|lwwV|o za&;-I;NOQ&Q+K}pQEDRH`zAeTK|kXRE@wW|S(|Jn3j9Pv@9Hb*hg{WXSe~`vy2JXn zor}L&2mIyd;%>L`uTQA-472I~deNg?QDh>sQqlU3JE}^BTtEI@XVMeo4Eg%?Kz&HW zT=9$V?{C*wzvrRF+cNHtLV5v#ZifXAi@cck+)$KFCd=f;JAR979+kVr`b=_6a%&I9 zG4I{BH<$5;t6(MLf$w^Hr}kc#efq4Gb>7_^FZI5iR#Gq5WjVX>Ew19{Of(moXnf#< zHtURz9|vkDO}W^2rfFa4eY?u9y~kgc+|rn3Gf73R)nV&uX zxyQ}7dd?k*Twip#KY!XK-FG?9R8Ual zs4%~$cFp659se>~vVuOJ_M5!Y?Zm{i$qy3_tUR*$eD{g&(63WEYF4sU^M1J%^WiSb zANPb*SC{%H7Zfcw<=e5(Rbbh7{!_{H=V#6q*>I>xxUX>)WX@o?&iuXW#AlZjaSMH= z(1z~~(;5DofADEAKY#92`TdGHdE1*i8r0%!KHp=wXtBs#hpBB%xLbptK*5r$NhT5n z*Cb3m51*ZT;HAlw^`L+@6P(HRZ~2ti@AoXs)%9(QIu3j<-oP38y+??RQTy`cJ2vL0 z3+)d`_eS(9$vSaYv~}#^s?gh@sU+@_GRIc*gVTd>mnW7C>))6C+$Vf|=Ioh{m;P7I zdy;qivrWjbmHgjx zkL3@~g?*+RU)Eliojfz|xE1G{GuDhV)tz4aUUQ~oXKCF$>B9jM{gK_tvX0R%^Emf# zRZQzx(|IEGLF57b?i0nKQ^QNGe(C$kOmE$J^NE6>W9a4Pr5!3EQ!V;#%6=*KpKnp8 zTKMKos(iz&w!dGwyx(y=GPMURR9O2Ycae!~Wbo zwe<0f)z;R3PQKjy=jFRR)eJ_yYPs#@RwYdh+n!(iWP59#|Kaa1elRwwZ>gET?7eV> z+&l)ilQKKB{P@;iQx$4?d$D8xuA0{GU#o5fiwf>svdUgt>3zUe$J*}NzhYOWKX`p^ zX7mC56|ZzYFbe)$vC2+OsrKxIPhaiZ+3zf0b$`8p-R19Jr?Q7FxtjAN;pC_I-~PMb zh#oZzl({V5dsB*M$Bp;JtFAu}*?-=-`5?=VT%osH4Cmaudv^cy+PnX5S_(FqxYT@o z!=oP^bt>r_%ZF1g=jQ$0EZtUf{FBhVr>8%OTkpQroGSQ}f7LCfd*>#v2~$>DbdvG$ z>a6CL{WDl=1b=Q?HB0J+e{t|tRl%L?I|3i{YA*a@_~5+j6J^a8?D6N%E?ULz@?^Pd zN}^k6{PsOMtGPc{T6!C^ojY~$c%VzYNz&r$&rc;BI2qS}d9U5`gl;P;Np0;wre_8Ia79-Fo07VlMoZUM$XspS3!-B6q48`m=v8vK4nc12!8Lty+B` zF?4U73*X9DK}DKRx>x-YOIXeJ>+iGu6Aos3-rZAgNc03I`TjR)D-?-z=#!LA zO-X7yw&6z3r5qL(#|}fbfMbC^BGPSv-#)k9$Pm26JlEjC)6>5>^t%7N{I)HxTZiHQ z;#Gc=rwE(RS7;TQG%10@#5Kh)^!erU&nK*sWA0;WZ}@v)O^46QEawC2FaK@k-*4#Y zx`6H1V7O)&x!l$VWlF83g1^R?NycDhhN>VocZ^SE#r&U zC4GPO8?PCjzZ@=Wp)fa1*tE;A?O(=`sdHoHZryqEIr_GZiOi;Dr`Cx^o$oGSv3O7^ z!^ONVe``eU_8ZspF6VB~_+hv2y>&|D%saQW>$exz&7K#qctO{DRpl3PhZirraPdj0 zwC@3XBhDYk3w_pjo&H{V@{*m6;Lpo%b?*i&Yuvu{;TL^|=**70EX!O{#3C5^Qs-H+ zeiqs=X`1qF72SjP=6$a@`a9&RnWs=jn8op*%p|5$-)n0Wc$lIz3s*>fSlkhqv!nXI z5U*h6_iNMEsptIhXE=RerpN{NhQF(<^p#>4JnZ~2tDOctexEUZT{NEe_#0S&Uaqad2FLXf))n{^L%Ok^+kUh|L)1M zm}H!tZL?wHNp*AK3-JNDi*{)#tzL0&@rHG){;Mdx7oNC3{3^R^ihHPSXzl8bI}2C& zbe_0o@o2kz)eQD3TfHNOucxs`i9Ve1{$uW3zVmO&EDbI%y`1A$k+o4{BPV~_{}9c3 z@s0Iy+6UIF`s?p}e(u#fwU>qE>lZ#(e98IH)Mi$q(JQOvy8BjNP5HM*egDpF>!u4Y z?3QOz3gvxcqGG)GRMUdsM=!TL->A>HS;tgL$IMAgiuYxkVsLLjRHDa&-#_LZ534`G z+&|ApssGDJc@_a6jnzBsS?cE#_;-vN82C;C3Pyy{oogRTShbB)f&1U}tvW;RFq zcL&FL9_GB)eua;}m~`LOdmCna@;+no6djKfr?OXxezn)MSr=tz>-q2K!V|&=ZpT_m zo?Ir(FLAu<`OzQy<~QHTTT_^oCn6_*;JeMTTe|No%VzW`ypOs6Wa1OUrbUtNJI{Tt zI9M`$>V|_k$|>tEPMGP|942uoi-l!g|MSkPZLi&onlEN+fLvz}jS=*-F3h~_aa+A>9=bn6d(oa%%x`$qxfAx>4bn*wA^Ndl~ zE+|(&{daPhcCWJ$?x2B?EaUknv)_I-8f|O%XegEPRv_9(pc-|o?B zujx-WmAYeNdX)EbvCsDCmc$ufrlrT`i#2fPAwL5vX1%ARbkO@&Zr-f<-g)c3Ec@h|VK&?Eb^5gBVky%E+8E!a zF&j%2|G#GTJlKC5!=39{pPaqDYo5R2(zn=f=wYknvRk=-6g+J5>Y}{kxHiWn#HE{C zCO&Jr{;jIobZgrE&o+hi*Ez4N|5-M5zxw_OhCf(Y7YMV@pKJ0&Vf()4m2#Ko@|~YE z|M9l8=BXBG=`w|`Q-hCvD7Utr6LbH7bni^wnpuf6>eL?1iF12+adq~eTRS(;G4bNw zVfo>veA|!A)9+d>rqz9_QhpG7po;g)^7*EX^I7KE^H$yev**qGE!^k1W>_q{n)USF z6=BEAHm18D_IB>vwC`ZN%`b`fI|>@v7cJTP``dx%?c(AUS2rGBbME}bEVB=``#+qC ze5tLxWClyD~%`u3{-9D%FhLSMPHe==V>cZzIJm%ldaN<%b+xGs+^VaWY z|G5i3dd$W=@A<{t?Ul#=$ee$@#bVW|a}{S&A2ezG-?001@@r`W8NHCLSBAaLKVPoDSZ4u4<_htI;#(H%n?{?e%>gi%j zgT;O$yz@ei*`?ne zH91u9X{NF2bQ}J&R%u=9t(9}EB!i#VUtLuYE4y94Y?1xM>E3=9rV45&ZGP1CyfSlD zV3&-GhPhh1@yCvJSO5657?q%aWU(9zpH+e@$2&WxK%|^Ay^Xk66*>bt-^=#jlQ4L!T zKfL>|A#Js*0E?xB+vASS)7O8RXPo}?!#lm{m-V(<&*I%z{9nlZyRJ}MIsBTeFImrB=yvW|>Agqwzm8W{ndRE5dFqwwfg%qp=N%TD zaymJ0Uw$!DYMb59xM>Hg=N;d7GxFWbvdVks_~!52bu2#r?T1#2XT^nQ($~j4jC}q2 zj-~bCr4Kv!dD>F;@~hACofRfE#kOjkr%2!Rb%vQgA>G_Gv*=`0-ZVdF~+s>WLh=* z-!8eGS9V2xT6I%$(IUPJBHJ0_ZBIU%R2O7u7j1IZBhG1d&Su?x&zTHzpLkBqnd9tz zqSNpE=NYg4K2GwR9bHwsZ^O28_w({TzAQXq<>`Dz@c#1Gm3g}+EDO`vV$&bclK4q# zoqu%RVyPGY^45+@2ajwtnDR61@=DL!ypmi;jukw6WwpQbolLwzo2B49ah96vpOnmX z-YWArFaMLu?fT?QDO*R-pLy4}TrQ|ubl$hSn7z74=lEp5c^s-u{+r#y!Vf5YUNl8j zPp4p-yj36XyyZXQ&Yj)8#-Xk#ll5o1yWyA1a;(&bgVq9+&nGkdoy-P2K89~%1q-8&KU zGiRP0nXJ2VN+p}%i#Eo!A7|XlIKhAJ{KsF5+bwq(%zyT7rd7}O^x)>;ai%}OyGCZC#pJy%4}*<4?fi1ukvTT?kD+UsrkcYucCg< zi&C0ub#eNA4kx}6E1t5lpEV+z=Q33)epvf_+bV9Qn4aXDp8s+~zJ6~!z16*5YR0N< zm;db9sB!3PaB#&V-+PlLP2Jj3CSY(o^RrRp!)-q!r@g7#{rJBqR@@R^(Sw=@KVhAX}ZL`KGf^Mw*#kBIuGo!ICezhv3hK?h+LF**UzK& zTbuY##I29sbR~${uTVhqtlJ6O-_t7|T#@{zX;x#|7ul60c37dmZ`1LQ4J(^IznI{2 z;_m;Dz2&b>x5dwu6`GjO9P!m=T9oeeTCqcXO5V@s+28KRs$qNcndwRj6iT zr?&snKLSC&6=r+fRln4ub?$)P=bP7yGk2Yq7Jn8Yc7t`Fh1})t3=PiQdwjz~98ROj^-6cy35rx~kXbC|qj# zE7qmYwc~Pv$lupb5394U39XyVwLa_AgDrWSVjHlCwX5+E2(}-S3x(?$$S$y zF65a^`d94V;d|(Scj~>|K%tw}o2xjlOu5(Ym*#M7=ChdjYi4b=)7s1dTO!KrJ$>cykD|!&-1;cc(gQ8!}u(lhJvYmqYKR?%{yu4@1uS2?ra+{`{e|1sx=f=yER$bNE5mn1{ zGrwQyaM=3e&aOU%FCSme{r&Z}S8A=pI zO}*Roef6;q6Ab^nwMeQb@Y;rSrAZ zSY{=ju=Vb?DflHb-;k4gzksVwo8p2Wne+C|v$-F`^)1-{s`QR+>f0h8q`N+O!S$lH zo7?Dm)}mEgnj3zuG)pv7{AwX~yioOI+U}*D0(X+`UHvD!byuR1gQZU0$@p&BZ&vz; zQrCDd-MZ>})^bVy_?@TfE$ch^`;Nr~stT3sZ2z--Ld&7)p+DbPIF*-K-g~LSZ1Yqo zn(NA*lj%)2Hgm~ZIckcWf9vA=uJonJ>@#kH-@mixbQ$y{Ppg@4pgTM7h+%m5_YaEm z79G|#mHa;Srl8=?z);I4zm4waEZ_=GJn<)FxrE}~#X6xA{I)6U|E-C9w6f{!c^1i% zq&>mh8;^f_UEt<*_mg1QPTx~LyO&z3KE0wmwW03Ar__6OFS+Iyr@gtkc9bKyV4`pIb6=YVMh)658n~D<=FSU@bf3TcX_Id6ra0V*vbi~ zb1Qa#zY=!!bwyX#)+-MGPp!M??NL@)yyxzsr|drFliVcke^<-en)=Dh+j&8?Y2%KB z+sOf1r|s7!PJZ;$E3om_o2^#MJ!eL4U);JUJ^s{tbw#;eE&kYjhi>b~K4mmMX_#{D zWr@sz>8E2SHP@clEoVJ-T~wJ>thRo`M)h}FY_hfcVy4QTyWMPHxqrQvF~^SbO8MwGVdu-TR0vlhh9z9uqpcj#72=Bme6L_WV2yR3QQb5sFmNov2EYQRd@ z2HT1IR$P{yu6aD8bLqAdhFedCG+DKNc>VR$y?>_eRSSFjJHJg?ZeNjT@}oQ6(@!3+ zIdJ^al+!xZXOA|_jCg?o0BnbG)mWTv}%5@0&UQ=gj$urKP49Pa3x+AMZ1i;Q8_P{=eKN z1%<9fopbKjtUvrzFunBo)9d^_nx-EtHnw<9YW@;c zcl(o2`PW~69P1BMCfu($)2Oh(b5ov|3*VC53wv)Zj#r+>w?T*D{>n~1>+`R-q-HLQ zW^#&jyc(q7``%!!#BrY`GfF2-DRwaLbX&gOn)~3}ow?eLy3@aPz1Vi>a7Qv z(#y&%GHdJa@2fp?{`~W-_4A$^+S;C#zW?J`%g3*Oy_DA9Is0v9;gRX<*X?{HA#A%o zjN`G1Xy#K#wIH!YTE53KFP2^4agN)#<%I7_hhx(p&yY>dQ0JCV415{8!ufkP!+n)5 zC37Zwwm%a){^%=Rn#sC1ch~ECTl`jZ1n)n~*ys0#tz2#2j5kTzd12dCb+RXH%+Fcw zv&`z|r>M9CKP(;=o2kDOC|YWw+?6bMI7Ya>}v3X)AOm{`=b1(Z+u&=FIPA-&?k? z(J{U|chxz=sh5^yRL-6FAY}RH_nwieD@7iic6oWDuJ6(J(~F9xaj;#T9eE^cQ=zN! znrpGIZt_OXk`A z*zorz^Sn20H7j|1x|Z^b6@;!8NexoperfaaQ&wx;PH0d2{_(-g&rf$=nYPN#xO74x z@0a}C?2Z$Tp?jq(=B~P@sPx&Pf#dS3TOtpOs?>ElK1|yg+4nwv+pevrWV0VJoK8HY zyTKzfv+?YoEV*}+`D>3H6PP{Y!1u|T7BO2p=e%5>weT#f%IXvumG=|RTff?HD)ijL zg`C%d&K>w}^Q>0hbLmRg76Ts1{^NVz=H@>>(kU#F{NvK}eN#B>Or&~_Cm-()U#fNU z^}Z#iu4O!t={kB|-8SbkvjZO;eq5^ zG56iEX}5K)Ugnvv+_CUZ6_ZLhOGs- zsq}Uu|CZa+rtes7|DeBJ`M2dd^_}@`rWf{`e#-N-pOC!j7uN$`mDEj{2d-a^I%(oM4 z6YnRNu{*!pUo>_9y*tk~2Of#C+#~CLLB1fNcCzxm&z0{zh(`_4(aiyKYcCY+AO|UU(8_pBaNp5S08eQsGZI#OFgLR zIjy3n>8QTB!Or>JwTiP7PiRm7_VL2a&v)Ww`q~?2H~KG0xGweLzt0h=lX7pTuYUE~ z^@*#}rb(+RE{R@TJa74S|MI8LZbtH*KkK#q?y=7;U*F2!t9@s~f6Q>T(w_sD?D%xw zdON47ok|l7GEb8Olb#;l7H+lv)K86P6Thac ze$~ytPKd2;=Be^;tELwJ-g`||-01R6=a(toc~)Obcic^@N}im1cenOBt^aj<-W_~% z$Y=GYI~i{#w)>y5vwm2+a{E2K?ULT>c4e%bf9KgM)paTVeWqW3<5QfMtQ{R(8{u+q zX5OA!^$(ttI0A$R$1*CLG|zT=@<97f)nwx1uZ`oivPSMg0||NgCq zuXbGuxEZ{fb%FMQ{M?*NA8hjCV--Ktrtb-PYx`tr;@g@^rUVbwNx7H2mWEX8`95Y` zZ5$g{qWYlu;=RnQrCr%4o5Q~fz7bBWU;cK9Vwp+O^s{dk7O%CExOCj?TG}j~kncxo zdxO+|U7F8tGyl21esP(_qx@gY=hXUZS$ z)^3Z={Ce;DWItmZqm0uMLuMOwo{GnZ_Uw83fN|&R3#(+JXDq**_0;-^vF(TRb9Nti zAG7lm--kvPfBQva{fjf( zW`-~xVLQ^t!TH@E^{NQBovfd?_fO!R-t9ZJ)^j92 zC{C)H_1sKq%W=Wkg==n~>@RhB(z0rw&<_3?lTwcVoz^i!>P38g#XYf!)h^p`Q?oo?_q=Rc{f+z zOp(4J$5;99i^*Aq0)|}wnrA+xM<0irU2p%0Ewp@hXvh_U}aQ%dt27{Tg0! z%ci(aZ{pKUrklM((w0WFzxg^VcGIQJuit!2oOH4xv~}OU<2k#J_TJTFcS%wGD3BxV ztRuvvtyDC9)xN$Z53|^JaP?#_sDJCQ-!HU2*ySDLx6D~hI^7>?KNr{Bf9PCv{1s!^ z^Ylz}sZN#6rsp!Vd*6Oz|MTwT@gKV%PGEh|F8*xC*9VO*)py=yUB1-Rw#syV>ddW^ zs(X?Tv&&l_egEdmjg1b4r**e~*f#%{X59z&`U#8O`#)XmuM%BNX8J*;KjYZhHU|1#Zr(v57jy?^4~ zyx*_!q4Mk}p}T3DC6=GvwyDF%Xtg^~g|~ z<<5<)!V8}>ju_U4$~q`06)SzJd0_4Oq)aeSa3_yvb1d(d_2=4@J_Uu=ZmZpF(pY&u z*^uK!3uCW>htoqRXU*&U%pH$r@Xxn9ET5le$Pjlw^W&@6eU~y!x-<=sZ{|F=u1V?l zypBp&FZO1K_4W_?^0#Ti?pYThKvCnqL0 z-o1O5)8R&(wosy$RPpCKI*!{U7B1Rb(!ZBacxQ=NrATz-nzu_;W4|9Qn|)Q|5qERq zvejmcKeQ6U_f8jQXZ)X(+B$XS%cT3i<=9(lXM}XdX1eXUxkN4RilXYh#WFLe-f#B3 zz&dY(bsxu(H@Ryo-wV1Ux!9)WrP2PXe>UQc;%s*IB~J`C z-_28ev>@-~Ny!M!w~EV6Y?ht#onQ0z%`L0?EpZ#JDjm}Qb4b77(UH!YImSHByYA|} zue!cFV`~%-8}s*L>o~g0dmggB6}y~y``P1H7edz z#q?U~la*j3k4wd}=Z3yUemi($f}YN2W47D6@!;XtuX(C#qp~u7G46Z6aogUr`EzWJ zK2JWZ^&vlO+K#-+OeOVcMz3?$#%YPp*RAO|%cD4H#k{&Fe^~7jzBYGr*ndm5KX&KN zoX^jG{k7ZwbM}7E{rA`3aZ*}3yVQH?^IvwWFW==-IN372l%H?T$6HJvCbvxEzR_bN zGR<0cUHH?9{~FG6`NutdDXnzpLFJxxm!EAteOl+dPqbjOv~R^y*|+`M<8H2#(0I3Q zr&3g6{seo+P=(!mjn6k`YhGONfV-rrVQSjs^ewlG99k|&sILjXD!x4N?`M}3mYAPu zEnoege!5lpK)yj*IrJMVW4jdZw#PHN1CQ*qc*a!_IMsWxq5Qt0R^{;ZMc%uQ7N@6G zCZx}#YYR3!*&6JbCZG~6Z*ubS4&TdRmsY6os?LA+RW0j`btZe< zw>yP0&krk9PhGZZ*Qu(TPAt0v^mkNc3ST-O87}81{r>UBzY#0F!;-$(K3w)xwJtBK zOFuvV^Ut_`|9-bQ;T^6YLOwFYPhI&XU|;dB)0>~A&CJ}+VN?I8pr}=DYf$`pjhJ0i zTjscys|N@2D9O!Qb>&BpZBmS#h-{nv({iT!$?F7*GA%YOOP@6Vlj{pMJ9FQ1%Zqa# zeJaq1fAzI8!{k!2QcvRiRr?%W_A&pM)A48Cs(-8nMqfisFRY!NzhYHA+aAstR^rEH z*uJ$YawnenT6kue;T-9H%Y2^fRW{2`t&E%h{mr*e($CKsJh;ujZWq_Oo4qREdi9si zWqZ}~V_R|H?TzU>w;1L~&*eCL|NFl0g)c5BTFvDP6e;}or}EyvZ`;-5lsP`xeKgu} z+PvPrPkq<@Nz&VGZX}u3PG>RxX62%0zBH=G^;M2-W9v#j?qJz@%TLX2SN6-#-z
;*Yey=UJ1GJ+l$l-Q$J};i5GU-s9^3Z)%JXD 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 LtDnm{r-UW|wQCfc literal 0 HcmV?d00001 diff --git a/src/http.rs b/src/http.rs index 3b06848..3783153 100644 --- a/src/http.rs +++ b/src/http.rs @@ -34,7 +34,7 @@ use tokio::{ io::{AsyncRead, AsyncWrite, copy_bidirectional_with_sizes}, time::timeout, }; -use tracing::{debug, warn}; +use tracing::{debug, info, warn}; const X_FORWARDED_FOR: &str = "X-Forwarded-For"; const X_FORWARDED_HOST: &str = "X-Forwarded-Host"; @@ -115,6 +115,7 @@ fn http_log(data: HttpLog, tx: Option, disable_http_logs: b uri, elapsed_time, } = data; + debug!(histogram.http_elapsed_time = elapsed_time.as_secs_f64(), %status, %method, %host, %uri, %ip); let status_escape_color = match status { 100..=199 => "37", 200..=299 => "34", @@ -135,21 +136,16 @@ fn http_log(data: HttpLog, tx: Option, disable_http_logs: b // GET or other _ => "44", }; + let duration = pretty_duration::pretty_duration(&elapsed_time, None); let line = format!( - "\x1b[2m{}\x1b[22m \x1b[{}m[{}] \x1b[0;1;30;{}m {} \x1b[0m {} => {} \x1b[2m({}) {}\x1b[0m\r\n", - chrono::Utc::now().to_rfc3339(), - status_escape_color, - status, - method_escape_color, - method, - host, - uri, - ip, - pretty_duration::pretty_duration(&elapsed_time, None) + "\x1b[{status_escape_color}m[{status}] \x1b[0;1;30;{method_escape_color}m {method} \x1b[0m {host} => {uri} \x1b[2m({ip}) {duration}\x1b[0m" ); - print!("{line}"); + info!("{line}"); if !disable_http_logs { - let _ = tx.map(|tx| tx.send(line.into_bytes())); + let _ = tx.map(|tx| { + let time = chrono::Utc::now().to_rfc3339(); + tx.send(format!("\x1b[2m{time}\x1b[22m {line}\r\n").into_bytes()) + }); } } diff --git a/src/lib.rs b/src/lib.rs index 7335bfa..81f9089 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ //! #![doc = include_str!("../README.md")] //! +#![doc(html_logo_url = "https://sandhole.com.br/favicon.png")] use std::{ collections::{BTreeMap, HashMap}, diff --git a/src/tcp_alias.rs b/src/tcp_alias.rs index 6ce117f..3ed6cda 100644 --- a/src/tcp_alias.rs +++ b/src/tcp_alias.rs @@ -2,6 +2,7 @@ use std::{ borrow::Borrow, + fmt::Display, hash::{Hash, Hasher}, }; @@ -9,6 +10,12 @@ use std::{ #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub(crate) struct TcpAlias(pub(crate) String, pub(crate) u16); +impl Display for TcpAlias { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:{}", self.0, self.1) + } +} + // A borrowed TCP alias, with references to an address and a port. Useful for accessing the TCP connection map. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub(crate) struct BorrowedTcpAlias<'a>(pub(crate) &'a str, pub(crate) &'a u16); diff --git a/src/telemetry.rs b/src/telemetry.rs index 735a2bd..d12d865 100644 --- a/src/telemetry.rs +++ b/src/telemetry.rs @@ -5,6 +5,7 @@ use std::{ use ahash::RandomState; use dashmap::DashMap; +use tracing::debug; use crate::tcp_alias::TcpAlias; @@ -146,6 +147,7 @@ impl Telemetry { // Take into account an SSH connection to the given hostname. pub(crate) fn add_ssh_connection(&self, alias: String) { + debug!(monotonic_counter.ssh_connections = 1, %alias); self.ssh_connections_per_minute .entry(alias) .or_insert_with(|| Counter::new(Duration::from_secs(120), Duration::from_secs(60))) @@ -155,6 +157,7 @@ impl Telemetry { // Take into account an HTTP request to the given hostname. pub(crate) fn add_http_request(&self, hostname: String) { + debug!(monotonic_counter.http_requests = 1, %hostname); self.http_requests_per_minute .entry(hostname) .or_insert_with(|| Counter::new(Duration::from_secs(120), Duration::from_secs(60))) @@ -164,6 +167,7 @@ impl Telemetry { // Take into account an SNI request to the given hostname. pub(crate) fn add_sni_connection(&self, hostname: String) { + debug!(monotonic_counter.sni_connections = 1, %hostname); self.sni_connections_per_minute .entry(hostname) .or_insert_with(|| Counter::new(Duration::from_secs(120), Duration::from_secs(60))) @@ -173,6 +177,7 @@ impl Telemetry { // Take into account a TCP connection to the given port. pub(crate) fn add_tcp_connection(&self, port: u16) { + debug!(monotonic_counter.tcp_connections = 1, %port); self.tcp_connections_per_minute .entry(port) .or_insert_with(|| Counter::new(Duration::from_secs(120), Duration::from_secs(60))) @@ -182,6 +187,7 @@ impl Telemetry { // Take into account a local-forwarded connection to the given alias. pub(crate) fn add_alias_connection(&self, alias: TcpAlias) { + debug!(monotonic_counter.alias_connections = 1, %alias); self.alias_connections_per_minute .entry(alias) .or_insert_with(|| Counter::new(Duration::from_secs(120), Duration::from_secs(60))) -- 2.51.2