stick all smux headers, disable smux keep alive

This commit is contained in:
Page Fault
2020-05-27 19:43:42 +00:00
parent d4bb967e13
commit f5d06aaad6
6 changed files with 86 additions and 21 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ require (
github.com/proullon/ramsql v0.0.0-20181213202341-817cee58a244
github.com/refraction-networking/utls v0.0.0-20190909200633-43c36d3c1f57
github.com/smartystreets/goconvey v1.6.4
github.com/xtaci/smux v1.5.14
github.com/xtaci/smux v1.5.15-0.20200523091831-637399ad4398
github.com/ziutek/mymysql v1.5.4 // indirect
go.starlark.net v0.0.0-20200519165436-0aa95694c768 // indirect
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
+2 -2
View File
@@ -292,8 +292,8 @@ github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP080
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xtaci/smux v1.5.14 h1:1j+zJYDZRv9FHaWqCJfH5RPizIm0fSzJIFbfVn8zsfg=
github.com/xtaci/smux v1.5.14/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
github.com/xtaci/smux v1.5.15-0.20200523091831-637399ad4398 h1:1nJafFt4SJPzJ5RbWBP2OUJ7Xcx7pdjyjldEdFrLfKs=
github.com/xtaci/smux v1.5.15-0.20200523091831-637399ad4398/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+67 -15
View File
@@ -19,23 +19,75 @@ import (
// HACK stick the smux 8 bytes header to the payload
type smuxStickyReadWriteCloser struct {
io.ReadWriteCloser
smuxHeader []byte
synQueue chan []byte
finQueue chan []byte
}
func (rwc *smuxStickyReadWriteCloser) stickToPayload(p []byte) []byte {
buf := make([]byte, 0, len(p)+16)
for {
select {
case header := <-rwc.synQueue:
buf = append(buf, header...)
default:
goto stick1
}
}
stick1:
buf = append(buf, p...)
for {
select {
case header := <-rwc.finQueue:
buf = append(buf, header...)
default:
goto stick2
}
}
stick2:
return buf
}
func (rwc *smuxStickyReadWriteCloser) Close() error {
const maxPaddingLength = 512
padding := [maxPaddingLength + 8]byte{0, 0, 'A', 'B', 'C', 'D', 'E', 'F'}
buf := rwc.stickToPayload(nil)
rwc.Write(append(buf, padding[:rand.Intn(maxPaddingLength)]...))
return rwc.ReadWriteCloser.Close()
}
func (rwc *smuxStickyReadWriteCloser) Write(p []byte) (int, error) {
if len(p) == 8 && rwc.smuxHeader == nil {
// check version and command, cmdPSH = 2
if (p[0] == 1 || p[0] == 2) && (p[1] == 2) {
rwc.smuxHeader = p
return 8, nil
if len(p) == 8 {
if p[0] == 1 || p[0] == 2 { //smux 8 bytes header
switch p[1] {
// THE CONTENT OF THE BUFFER MIGHT CHANGE
// NEVER STORE THE POINTER TO HEADER, COPY THE HEADER INSTEAD
case 0:
//cmdSYN
header := make([]byte, 8)
copy(header, p)
rwc.synQueue <- header
return 8, nil
case 1:
//cmdFIN
header := make([]byte, 8)
copy(header, p)
rwc.finQueue <- header
return 8, nil
}
} else {
log.Debug("Unknown 8 bytes")
}
}
if rwc.smuxHeader != nil {
_, err := rwc.ReadWriteCloser.Write(append(rwc.smuxHeader, p...))
rwc.smuxHeader = nil
return len(p), err
_, err := rwc.ReadWriteCloser.Write(rwc.stickToPayload(p))
return len(p), err
}
func newSmuxStickyReadWriteCloser(rwc io.ReadWriteCloser) *smuxStickyReadWriteCloser {
return &smuxStickyReadWriteCloser{
ReadWriteCloser: rwc,
synQueue: make(chan []byte, 128),
finQueue: make(chan []byte, 128),
}
return rwc.ReadWriteCloser.Write(p)
}
type muxID uint32
@@ -84,11 +136,11 @@ func (m *MuxManager) newMuxClient() (*muxClientInfo, error) {
return nil, err
}
smuxRWC := &smuxStickyReadWriteCloser{
ReadWriteCloser: trojanConn,
}
smuxRWC := newSmuxStickyReadWriteCloser(trojanConn)
client, err := smux.Client(smuxRWC, nil)
smuxConfig := smux.DefaultConfig()
smuxConfig.KeepAliveDisabled = true
client, err := smux.Client(smuxRWC, smuxConfig)
common.Must(err)
log.Info("Mux TLS tunnel established, client id:", id)
return &muxClientInfo{
+8
View File
@@ -17,6 +17,10 @@ type Buildable interface {
}
func RelayConn(ctx context.Context, a, b io.ReadWriter, bufferSize int) {
if a == nil || b == nil {
log.Debug("Empty RW")
return
}
errChan := make(chan error, 2)
copyConn := func(dst io.Writer, src io.Reader) {
buf := make([]byte, bufferSize)
@@ -36,6 +40,10 @@ func RelayConn(ctx context.Context, a, b io.ReadWriter, bufferSize int) {
}
func RelayPacket(ctx context.Context, a, b protocol.PacketReadWriter) {
if a == nil || b == nil {
log.Debug("Empty RW")
return
}
errChan := make(chan error, 2)
copyPacket := func(dst protocol.PacketWriter, src protocol.PacketReader) {
for {
+4 -2
View File
@@ -79,13 +79,15 @@ func (s *Server) handleConn(conn net.Conn) {
defer conn.Close()
if req.Command == protocol.Mux {
muxServer, err := smux.Server(inboundConn, nil)
smuxConfig := smux.DefaultConfig()
smuxConfig.KeepAliveDisabled = true
muxServer, err := smux.Server(inboundConn, smuxConfig)
common.Must(err)
defer muxServer.Close()
for {
stream, err := muxServer.AcceptStream()
if err != nil {
log.Debug("Mux conn from", conn.RemoteAddr(), "closed:", err)
log.Error(common.NewError("Failed to accpet mux conn from " + conn.RemoteAddr().String()).Base(err))
return
}
go s.handleMuxConn(stream)
+4 -1
View File
@@ -148,6 +148,9 @@ func getBasicClientConfig() *conf.GlobalConfig {
Passwords: getPasswords("trojanpassword"),
BufferSize: 512 * 1024,
}
file, err := os.OpenFile("keylog.txt", os.O_CREATE|os.O_WRONLY, 0600)
common.Must(err)
config.TLS.KeyLogger = file
return config
}
@@ -381,7 +384,7 @@ func TestRealProxy(t *testing.T) {
if os.Getenv("real_test") == "" {
t.Skip("skipping real proxy test")
}
clientConfig := getBasicClientConfig()
clientConfig := addMuxConfig(getBasicClientConfig())
serverConfig := getBasicServerConfig()
go RunClient(context.Background(), clientConfig)
go RunHelloHTTPServer(context.Background())