diff --git a/advLayer/grpcSimple/client.go b/advLayer/grpcSimple/client.go index 2b5b209..ac27469 100644 --- a/advLayer/grpcSimple/client.go +++ b/advLayer/grpcSimple/client.go @@ -1,8 +1,5 @@ package grpcSimple -// Modified from: https://github.com/Dreamacro/clash/blob/master/transport/gun/gun.go -// License: MIT - import ( "bufio" "crypto/tls" @@ -174,8 +171,6 @@ func (c *Client) GetCommonConn(underlay net.Conn) (any, error) { } -func (c *Client) ProcessWhenFull(underlay any) {} - func (c *Client) DialSubConn(underlay any) (net.Conn, error) { if underlay == nil { diff --git a/advLayer/grpcSimple/common.go b/advLayer/grpcSimple/common.go index 6e76321..31f86d6 100644 --- a/advLayer/grpcSimple/common.go +++ b/advLayer/grpcSimple/common.go @@ -11,6 +11,9 @@ import ( "github.com/e1732a364fed/v2ray_simple/utils" ) +// Modified from: https://github.com/Dreamacro/clash/blob/master/transport/gun/gun.go +// License: MIT + func commonWrite(b []byte) *bytes.Buffer { protobufHeader := [binary.MaxVarintLen64 + 1]byte{0x0A} varuintSize := binary.PutUvarint(protobufHeader[1:], uint64(len(b))) @@ -58,7 +61,7 @@ func (c *commonPart) Read(b []byte) (n int, err error) { protobufPayloadLen, err := binary.ReadUvarint(c.br) if err != nil { - return 0, utils.ErrInErr{ErrDesc: "binary.ReadUvarint failed", ErrDetail: err, ExtraIs: []error{utils.ErrInvalidData}} + return 0, utils.ErrInErr{ErrDesc: "grpc Read, binary.ReadUvarint failed", ErrDetail: err, ExtraIs: []error{utils.ErrInvalidData}} } size := int(protobufPayloadLen) diff --git a/advLayer/grpcSimple/server.go b/advLayer/grpcSimple/server.go index 1b53268..18356b6 100644 --- a/advLayer/grpcSimple/server.go +++ b/advLayer/grpcSimple/server.go @@ -122,7 +122,7 @@ func (s *Server) StartHandle(underlay net.Conn, newSubConnChan chan net.Conn, fa var buf *bytes.Buffer - sc := &netLayer.IOWrapper{ + respConn := &netLayer.IOWrapper{ Reader: rq.Body, Writer: rw, CloseChan: make(chan struct{}), @@ -130,7 +130,7 @@ func (s *Server) StartHandle(underlay net.Conn, newSubConnChan chan net.Conn, fa fm := httpLayer.FallbackMeta{ Path: p, - Conn: sc, + Conn: respConn, } // 如果使用 rq.Write, 那么实际上就是回落到 http1.1, 只有用 http2.Transport.RoundTrip 才是 h2 请求 @@ -141,9 +141,9 @@ func (s *Server) StartHandle(underlay net.Conn, newSubConnChan chan net.Conn, fa buf = utils.GetBuf() rq.Write(buf) - sc.FirstWriteChan = make(chan struct{}) + respConn.FirstWriteChan = make(chan struct{}) - fm.FirstBuffer = buf + fm.H1RequestBuf = buf } else { fm.IsH2 = true @@ -156,7 +156,7 @@ func (s *Server) StartHandle(underlay net.Conn, newSubConnChan chan net.Conn, fa fallbackConnChan <- fm - <-sc.CloseChan + <-respConn.CloseChan } diff --git a/advLayer/ws/server.go b/advLayer/ws/server.go index fd1bc7b..90da338 100644 --- a/advLayer/ws/server.go +++ b/advLayer/ws/server.go @@ -57,7 +57,7 @@ func (s *Server) Handshake(underlay net.Conn) (net.Conn, error) { //我们目前只支持 ws on http1.1 - var rp httpLayer.RequestParser + var rp httpLayer.H1RequestParser re := rp.ReadAndParse(underlay) if re != nil { if re == httpLayer.ErrNotHTTP_Request { @@ -77,10 +77,10 @@ func (s *Server) Handshake(underlay net.Conn) (net.Conn, error) { if rp.Method != "GET" || s.Thepath != rp.Path { return httpLayer.FallbackMeta{ - Conn: underlay, - FirstBuffer: optionalFirstBuffer, - Path: rp.Path, - Method: rp.Method, + Conn: underlay, + H1RequestBuf: optionalFirstBuffer, + Path: rp.Path, + Method: rp.Method, }, httpLayer.ErrShouldFallback } diff --git a/cmd/verysimple/main.go b/cmd/verysimple/main.go index 6a8a69a..bd24c19 100644 --- a/cmd/verysimple/main.go +++ b/cmd/verysimple/main.go @@ -354,12 +354,19 @@ func mainFunc() (result int) { } } + + //如果在非linux系统 上,仅设置了tproxy,则会遇到下面情况 + if len(tproxyList) == 0 { + if !(defaultInServer != nil || len(allServers) > 0) { + configFileQualifiedToRun = false + } + } } } } - //没配置可用的listen或者dial,而且还无法动态更改配置 + //没可用的listen或者dial,而且还无法动态更改配置 if !configFileQualifiedToRun && !isFlexible() { utils.Error("No valid proxy settings available, nor cli or apiServer feature enabled, exit now.") return -1 diff --git a/examples/quic.server.toml b/examples/quic.server.toml index 75ff915..ec8a761 100644 --- a/examples/quic.server.toml +++ b/examples/quic.server.toml @@ -5,7 +5,7 @@ host = "0.0.0.0" port = 4434 version = 0 insecure = true -fallback = ":80" +fallback = "udp://127.0.0.1:80" #试图回落到 nginx的 无tls 的 udp的 http3 服务端口 (目前尚未支持quic的回落功能,请期待) cert = "cert.pem" key = "cert.key" advancedLayer = "quic" diff --git a/examples/vlesss.server.toml b/examples/vlesss.server.toml index 7a42373..667a327 100644 --- a/examples/vlesss.server.toml +++ b/examples/vlesss.server.toml @@ -7,7 +7,7 @@ host = "0.0.0.0" port = 4433 version = 0 insecure = true -fallback = ":80" # 默认回落地址.ip必须是本机ip(可以省略ip而只写端口,程序会默认补全127.0.0.1), 或者unix domain socket的文件名/路径, 或者 udp://127.0.0.1:80 这种url格式。 (用udp以试图回落到 nginx的 无tls 的 http3 服务端口) +fallback = ":80" # 默认回落地址.ip必须是本机ip(可以省略ip而只写端口,程序会默认补全127.0.0.1), 或者unix domain socket的文件名/路径, 或者 udp://127.0.0.1:80 这种url格式。 (用udp以试图回落到 nginx的 无tls 的 udp的 http3 服务端口,适用于 quic的情况) #cert = "cert.pem" # 这里既可以默认放在程序本身目录下,也可以指定完整路径 #key = "cert.key" # 如果 cert和key中 有一项没给出, 或者文件不存在, 就会自动在内存中生成随机证书, diff --git a/httpLayer/header.go b/httpLayer/header.go index 57306a5..e9343ca 100644 --- a/httpLayer/header.go +++ b/httpLayer/header.go @@ -13,10 +13,13 @@ import ( "golang.org/x/exp/slices" ) -//观察v2ray的实现,在没有header时,还会添加一个 Date ,这个v2ray的文档里没提 -// https://www.v2fly.org/config/transport/tcp.html#noneheaderobject -// -// transport/internet/headers/http/http.go +/* +观察v2ray的实现,在没有header时,还会添加一个 Date ,这个v2ray的文档里没提 + +v2ray文档: https://www.v2fly.org/config/transport/tcp.html#noneheaderobject + +相关 v2ray代码: transport/internet/headers/http/http.go +*/ type RequestHeader struct { Version string `toml:"version"` //默认值为 "1.1" @@ -90,7 +93,7 @@ func (hh *HeaderPreset) AssignDefaultValue() { func (h *HeaderPreset) ReadRequest(underlay net.Conn) (err error, leftBuf *bytes.Buffer) { - var rp RequestParser + var rp H1RequestParser err = rp.ReadAndParse(underlay) if err != nil { return diff --git a/httpLayer/httpLayer.go b/httpLayer/httpLayer.go index 885ee3b..66e3ca5 100644 --- a/httpLayer/httpLayer.go +++ b/httpLayer/httpLayer.go @@ -16,6 +16,7 @@ import ( "errors" "io" "net" + "strings" "github.com/e1732a364fed/v2ray_simple/utils" @@ -72,13 +73,34 @@ type RequestErr struct { Method string } -func (pe *RequestErr) Error() string { - return "InvaidRequest " + pe.Method + "," + pe.Path +func (e *RequestErr) Is(err error) bool { + if err == nil { + return false + } + if re, ok := err.(*RequestErr); ok && re != nil { + return (e.Path == re.Path && e.Method == re.Path) + } + if err == utils.ErrInvalidData { + return true + } + return false } -// RequestParser被用于 预读一个链接,判断该连接是否是有效的http请求, +func (pe *RequestErr) Error() string { + var sb strings.Builder + sb.WriteString("InvaidRequest ") + sb.WriteString(pe.Method) + sb.WriteString(",") + sb.WriteString(pe.Path) + + return sb.String() +} + +// H1RequestParser被用于 预读一个链接,判断该连接是否是有效的http请求, // 并将Version,Path,Method 记录在结构中. -type RequestParser struct { +// +// 只能过滤 http 0.9, 1.0 和 1.1. 无法过滤h2和h3. +type H1RequestParser struct { Version string Path string Method string @@ -88,7 +110,7 @@ type RequestParser struct { // 尝试读取数据并解析HTTP请求, 解析道道 数据会存入 RequestParser 结构中. //如果读取错误,会返回该错误; 如果读到的不是HTTP请求,返回 ErrNotHTTP_Request; -func (rhr *RequestParser) ReadAndParse(r io.Reader) error { +func (rhr *H1RequestParser) ReadAndParse(r io.Reader) error { bs := utils.GetPacket() n, e := r.Read(bs) @@ -109,10 +131,10 @@ func (rhr *RequestParser) ReadAndParse(r io.Reader) error { // http level fallback metadata type FallbackMeta struct { net.Conn - FirstBuffer *bytes.Buffer - Path string - Method string - IsH2 bool + H1RequestBuf *bytes.Buffer + Path string + Method string + IsH2 bool H2Request *http.Request } diff --git a/main.go b/main.go index dc105a6..bb290ce 100644 --- a/main.go +++ b/main.go @@ -346,7 +346,7 @@ func handleNewIncomeConnection(inServer proxy.Server, defaultClientForThis proxy newiics := iics newiics.theRequestPath = fallbackMeta.Path - newiics.theFallbackFirstBuffer = fallbackMeta.FirstBuffer + newiics.theFallbackFirstBuffer = fallbackMeta.H1RequestBuf newiics.wrappedConn = fallbackMeta.Conn newiics.isFallbackH2 = fallbackMeta.IsH2 newiics.fallbackH2Request = fallbackMeta.H2Request @@ -383,7 +383,7 @@ func handleNewIncomeConnection(inServer proxy.Server, defaultClientForThis proxy meta := wsConn.(httpLayer.FallbackMeta) iics.theRequestPath = meta.Path - iics.theFallbackFirstBuffer = meta.FirstBuffer + iics.theFallbackFirstBuffer = meta.H1RequestBuf iics.wrappedConn = meta.Conn if ce := utils.CanLogDebug("Single AdvLayer Check failed, will fallback."); ce != nil { diff --git a/utils/io.go b/utils/io.go index 1dd876c..1318306 100644 --- a/utils/io.go +++ b/utils/io.go @@ -17,6 +17,7 @@ type ByteWriter interface { Write(p []byte) (n int, err error) } +//optionally read from OptionalReader type ReadWrapper struct { io.Reader OptionalReader io.Reader @@ -47,6 +48,7 @@ type DummyReadCloser struct { ReadCount int } +// ReadCount -= 1 at each call. //if ReadCount<0, return 0, io.EOF func (d *DummyReadCloser) Read(p []byte) (int, error) { d.ReadCount -= 1 @@ -68,6 +70,7 @@ type DummyWriteCloser struct { WriteCount int } +// WriteCount -= 1 at each call. //if WriteCount<0, return 0, io.EOF func (d *DummyWriteCloser) Write(p []byte) (int, error) { d.WriteCount -= 1 @@ -86,10 +89,12 @@ func (DummyWriteCloser) Close() error { return nil } +//先从Old读,若SwitchChan被关闭, 立刻改为从New读 type ReadSwitcher struct { - Old, New io.Reader + Old, New io.Reader //non-nil + SwitchChan chan struct{} //non-nil + io.Closer - SwitchChan chan struct{} readOnce sync.Once @@ -129,7 +134,6 @@ func (d *ReadSwitcher) Read(p []byte) (int, error) { } } -//return nil func (d *ReadSwitcher) Close() error { if d.Closer != nil { return d.Closer.Close() @@ -137,10 +141,11 @@ func (d *ReadSwitcher) Close() error { return nil } +//先向Old写,若SwitchChan被关闭, 改为向New写 type WriteSwitcher struct { - Old, New io.Writer + Old, New io.Writer //non-nil + SwitchChan chan struct{} //non-nil io.Closer - SwitchChan chan struct{} } func (d *WriteSwitcher) Write(p []byte) (int, error) { @@ -154,7 +159,6 @@ func (d *WriteSwitcher) Write(p []byte) (int, error) { } } -//return nil func (d *WriteSwitcher) Close() error { if d.Closer != nil { return d.Closer.Close()