soheilhy / cmux

Connection multiplexer for GoLang: serve different services on the same port!
Apache License 2.0
2.53k stars 197 forks source link

socks5 matcher not working #94

Closed munding closed 1 year ago

munding commented 1 year ago

I wrote a socks5 matcher like TLS,just match one byte

func SOCKS5(versions ...int) Matcher {
    if len(versions) == 0 {
        versions = []int{
            0x05,
        }
    }
    prefixes := [][]byte{}
    for _, v := range versions {
        prefixes = append(prefixes, []byte{byte(v)})
    }
    return prefixByteMatcher(prefixes...)
}

when I put socks5 matcher after HTTP1Fast matcher, it is not working, not reach the socks5 server handler but put it before http matcher, it's working

// failed!
httpL := m.Match(cmux.HTTP1FastOptions())
socksL := m.Match(cmux.SOCKS5())
iYarnFog commented 1 year ago

I also found this problem. After reading the code, I found this problem: HTTP1 Matcher tried to read a line and match it in the form of a newline character, while requests like socks did not contain a newline character.

This causes all HTTP1 Matchers to be blocked.

Related code: https://github.com/soheilhy/cmux/blob/5ec6847320e53b5fee0ab9a4757b56625a946c85/matchers.go#L93-L94

munding commented 1 year ago

I also read the code. HTTP1Fast use prefixByteMatcher, then use ReadAtLeast(r Reader, buf []byte, min int) min is the max length of HTTP method(CONNECT or OPTIONS, just 7 bytes), so it needs to read at least 7 bytes. but socks first payload usually less than 7 bytes,so it is blocked... socks5 proto fist payload at least 3 bytes, like below:

# +----+----------+----------+
# |VER | NMETHODS | METHODS  |
# +----+----------+----------+
# | 1  |    1     | 1 to 255 |
# +----+----------+----------+

so i change the defaultHTTPMethods like this (just 3 bytes):

var defaultSimpleHTTPMethods = []string{
    "OPT", //OPTIONS
    "GET", //GET
    "HEA", //HEAD
    "POS", //POST
    "PUT", //PUT
    "DEL", //DELETE
    "TRA", //TRACE
    "CON", //CONNECT
}