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 {