From 49c25bf1e4eab98bc204afc7956f3fb591eb120c Mon Sep 17 00:00:00 2001 From: e1732a364fed <75717694+e1732a364fed@users.noreply.github.com> Date: Sat, 1 Jan 2000 00:00:00 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BB=A4trojan=E8=AF=BB=E5=88=B0crlf=E5=90=8E?= =?UTF-8?q?=E5=86=8D=E7=BB=93=E6=9D=9F;=E4=BF=AE=E8=AE=A2=E4=BB=A3?= =?UTF-8?q?=E7=A0=81,=E6=B7=BB=E5=8A=A0read=5Ftimeout=E7=9A=84app=E9=85=8D?= =?UTF-8?q?=E7=BD=AE;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根据 https://www.ihcblog.com/a-better-tls-obfs-proxy/ trojan的crlf是模仿http协议,令服务端具有和真实http服务器一样的响应特征 --- cmd/verysimple/config.go | 8 ++++++++ proxy/proxy.go | 4 +++- proxy/trojan/server.go | 32 ++++++++++++++++++++++++++------ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/cmd/verysimple/config.go b/cmd/verysimple/config.go index 42d01a1..cfd20c1 100644 --- a/cmd/verysimple/config.go +++ b/cmd/verysimple/config.go @@ -41,6 +41,7 @@ type AppConf struct { UDP_timeout *int `toml:"udp_timeout"` DialTimeoutSeconds *int `toml:"dial_timeout"` + ReadTimeoutSeconds *int `toml:"read_timeout"` GeoipFile *string `toml:"geoip_file"` GeositeFolder *string `toml:"geosite_folder"` @@ -75,6 +76,13 @@ func setupByAppConf(ac *AppConf) { } } + + if ac.ReadTimeoutSeconds != nil { + if s := *ac.ReadTimeoutSeconds; s > 0 { + proxy.CommonReadTimeout = time.Duration(s) * time.Second + } + } + if ac.GeoipFile != nil { netLayer.GeoipFileName = *ac.GeoipFile } diff --git a/proxy/proxy.go b/proxy/proxy.go index 146e90c..8617bfd 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -13,7 +13,9 @@ import ( ) // default recommended handshake read timeout -const CommonReadTimeout = time.Second * 4 +const DefaultCommonReadTimeout = time.Second * 4 + +var CommonReadTimeout = DefaultCommonReadTimeout // set read timeout after CommonReadTimeout func SetCommonReadTimeout(c net.Conn) error { diff --git a/proxy/trojan/server.go b/proxy/trojan/server.go index b4737d1..ede517e 100644 --- a/proxy/trojan/server.go +++ b/proxy/trojan/server.go @@ -90,14 +90,33 @@ func (s *Server) Handshake(underlay net.Conn) (result net.Conn, msgConn netLayer readbs := utils.GetBytes(utils.MTU) - wholeReadLen, err := underlay.Read(readbs) - if err != nil { - returnErr = utils.ErrInErr{ErrDesc: "read underlay failed", ErrDetail: err, Data: wholeReadLen} - return - } - //todo: 根据 https://www.ihcblog.com/a-better-tls-obfs-proxy/ + var wholeReadLen int + + //根据 https://www.ihcblog.com/a-better-tls-obfs-proxy/ //trojan的 CRLF 是为了模拟http服务器的行为, 所以此时不要一次性Read,而是要Read到CRLF为止 + // wholeReadLen, err := underlay.Read(readbs) + // if err != nil { + // returnErr = utils.ErrInErr{ErrDesc: "read underlay failed", ErrDetail: err, Data: wholeReadLen} + // return + // } + + for { + thislen, e := underlay.Read(readbs[wholeReadLen:]) + if e != nil { + returnErr = utils.ErrInErr{ErrDesc: "read underlay failed", ErrDetail: e, Data: wholeReadLen} + return + } + lastTail := wholeReadLen + wholeReadLen += thislen + + index_crlf := bytes.Index(readbs[lastTail:wholeReadLen], crlf) + + if index_crlf > 0 { + break + } + } + if wholeReadLen < 17 { //根据下面回答,HTTP的最小长度恰好是16字节,但是是0.9版本。1.0是18字节,1.1还要更长。总之我们可以直接不返回fallback地址 //https://stackoverflow.com/questions/25047905/http-request-minimum-size-in-bytes/25065089 @@ -173,6 +192,7 @@ realPart: //关于 trojan实现多路复用的方式,可参考 https://p4gefau1t.github.io/trojan-go/developer/mux/ (该链接只是泛泛提了一下而已,没有制定具体实现的标准) ismux = true } + var err error targetAddr, err = GetAddrFrom(readbuf, ismux) if err != nil {