soheilhy/cmux

socks5 matcher not working

munding opened this issue · 2 comments

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())

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:

cmux/matchers.go

Lines 93 to 94 in 5ec6847

br := bufio.NewReader(&io.LimitedReader{R: r, N: maxHTTPRead})
l, part, err := br.ReadLine()

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
}