diff --git a/common/mux/client.go b/common/mux/client.go index 55ad3138..b3b3ada3 100644 --- a/common/mux/client.go +++ b/common/mux/client.go @@ -28,9 +28,10 @@ type Client struct { maxConnections int minStreams int maxStreams int + paddingEnabled bool } -func NewClient(ctx context.Context, dialer N.Dialer, protocol Protocol, maxConnections int, minStreams int, maxStreams int) *Client { +func NewClient(ctx context.Context, dialer N.Dialer, protocol Protocol, maxConnections int, minStreams int, maxStreams int, paddingEnabled bool) (*Client, error) { return &Client{ ctx: ctx, dialer: dialer, @@ -38,7 +39,8 @@ func NewClient(ctx context.Context, dialer N.Dialer, protocol Protocol, maxConne maxConnections: maxConnections, minStreams: minStreams, maxStreams: maxStreams, - } + paddingEnabled: paddingEnabled, + }, nil } func NewClientWithOptions(ctx context.Context, dialer N.Dialer, options option.MultiplexOptions) (*Client, error) { @@ -52,7 +54,7 @@ func NewClientWithOptions(ctx context.Context, dialer N.Dialer, options option.M if err != nil { return nil, err } - return NewClient(ctx, dialer, protocol, options.MaxConnections, options.MinStreams, options.MaxStreams), nil + return NewClient(ctx, dialer, protocol, options.MaxConnections, options.MinStreams, options.MaxStreams, options.Padding) } func (c *Client) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { @@ -145,10 +147,19 @@ func (c *Client) offerNew() (abstractSession, error) { if err != nil { return nil, err } - if vectorisedWriter, isVectorised := bufio.CreateVectorisedWriter(conn); isVectorised { - conn = &vectorisedProtocolConn{protocolConn{Conn: conn, protocol: c.protocol}, vectorisedWriter} + var version byte + if c.paddingEnabled { + version = Version1 } else { - conn = &protocolConn{Conn: conn, protocol: c.protocol} + version = Version0 + } + conn = newProtocolConn(conn, Request{ + Version: version, + Protocol: c.protocol, + PaddingEnabled: c.paddingEnabled, + }) + if c.paddingEnabled { + conn = newPaddingConn(conn) } session, err := c.protocol.newClient(conn) if err != nil { @@ -213,7 +224,7 @@ func (c *ClientConn) Write(b []byte) (n int, err error) { Network: N.NetworkTCP, Destination: c.destination, } - _buffer := buf.StackNewSize(requestLen(request) + len(b)) + _buffer := buf.StackNewSize(streamRequestLen(request) + len(b)) defer common.KeepAlive(_buffer) buffer := common.Dup(_buffer) defer buffer.Release() @@ -307,7 +318,7 @@ func (c *ClientPacketConn) writeRequest(payload []byte) (n int, err error) { Network: N.NetworkUDP, Destination: c.destination, } - rLen := requestLen(request) + rLen := streamRequestLen(request) if len(payload) > 0 { rLen += 2 + len(payload) } @@ -452,7 +463,7 @@ func (c *ClientPacketAddrConn) writeRequest(payload []byte, destination M.Socksa Destination: c.destination, PacketAddr: true, } - rLen := requestLen(request) + rLen := streamRequestLen(request) if len(payload) > 0 { rLen += M.SocksaddrSerializer.AddrPortLen(destination) + 2 + len(payload) } diff --git a/common/mux/padding.go b/common/mux/padding.go new file mode 100644 index 00000000..850bf254 --- /dev/null +++ b/common/mux/padding.go @@ -0,0 +1,240 @@ +package mux + +import ( + "encoding/binary" + "io" + "math/rand" + "net" + + "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" + N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/common/rw" +) + +const kFirstPaddings = 16 + +type paddingConn struct { + N.ExtendedConn + writer N.VectorisedWriter + readPadding int + writePadding int + readRemaining int + paddingRemaining int +} + +func newPaddingConn(conn net.Conn) net.Conn { + writer, isVectorised := bufio.CreateVectorisedWriter(conn) + if isVectorised { + return &vectorisedPaddingConn{ + paddingConn{ + ExtendedConn: bufio.NewExtendedConn(conn), + writer: bufio.NewVectorisedWriter(conn), + }, + writer, + } + } else { + return &paddingConn{ + ExtendedConn: bufio.NewExtendedConn(conn), + writer: bufio.NewVectorisedWriter(conn), + } + } +} + +func (c *paddingConn) Read(p []byte) (n int, err error) { + if c.readRemaining > 0 { + if len(p) > c.readRemaining { + p = p[:c.readRemaining] + } + n, err = c.ExtendedConn.Read(p) + if err != nil { + return + } + c.readRemaining -= n + return + } + if c.paddingRemaining > 0 { + err = rw.SkipN(c.ExtendedConn, c.paddingRemaining) + if err != nil { + return + } + c.paddingRemaining = 0 + } + if c.readPadding < kFirstPaddings { + var paddingHdr []byte + if len(p) >= 4 { + paddingHdr = p[:4] + } else { + _paddingHdr := make([]byte, 4) + defer common.KeepAlive(_paddingHdr) + paddingHdr = common.Dup(_paddingHdr) + } + _, err = io.ReadFull(c.ExtendedConn, paddingHdr) + if err != nil { + return + } + originalDataSize := int(binary.BigEndian.Uint16(paddingHdr[:2])) + paddingLen := int(binary.BigEndian.Uint16(paddingHdr[2:])) + if len(p) > originalDataSize { + p = p[:originalDataSize] + } + n, err = c.ExtendedConn.Read(p) + if err != nil { + return + } + c.readPadding++ + c.readRemaining = originalDataSize - n + c.paddingRemaining = paddingLen + return + } + return c.ExtendedConn.Read(p) +} + +func (c *paddingConn) Write(p []byte) (n int, err error) { + for pLen := len(p); pLen > 0; { + var data []byte + if pLen > 65535 { + data = p[:65535] + p = p[65535:] + pLen -= 65535 + } else { + data = p + pLen = 0 + } + var writeN int + writeN, err = c.write(data) + n += writeN + if err != nil { + break + } + } + return n, err +} + +func (c *paddingConn) write(p []byte) (n int, err error) { + if c.writePadding < kFirstPaddings { + paddingLen := 256 + rand.Intn(512) + _buffer := buf.StackNewSize(4 + len(p) + paddingLen) + defer common.KeepAlive(_buffer) + buffer := common.Dup(_buffer) + defer buffer.Release() + header := buffer.Extend(4) + binary.BigEndian.PutUint16(header[:2], uint16(len(p))) + binary.BigEndian.PutUint16(header[2:], uint16(paddingLen)) + common.Must1(buffer.Write(p)) + buffer.Extend(paddingLen) + _, err = c.ExtendedConn.Write(buffer.Bytes()) + if err == nil { + n = len(p) + } + c.writePadding++ + return + } + return c.ExtendedConn.Write(p) +} + +func (c *paddingConn) ReadBuffer(buffer *buf.Buffer) error { + p := buffer.FreeBytes() + if c.readRemaining > 0 { + if len(p) > c.readRemaining { + p = p[:c.readRemaining] + } + n, err := c.ExtendedConn.Read(p) + if err != nil { + return err + } + c.readRemaining -= n + buffer.Truncate(n) + return nil + } + if c.paddingRemaining > 0 { + err := rw.SkipN(c.ExtendedConn, c.paddingRemaining) + if err != nil { + return err + } + c.paddingRemaining = 0 + } + if c.readPadding < kFirstPaddings { + var paddingHdr []byte + if len(p) >= 4 { + paddingHdr = p[:4] + } else { + _paddingHdr := make([]byte, 4) + defer common.KeepAlive(_paddingHdr) + paddingHdr = common.Dup(_paddingHdr) + } + _, err := io.ReadFull(c.ExtendedConn, paddingHdr) + if err != nil { + return err + } + originalDataSize := int(binary.BigEndian.Uint16(paddingHdr[:2])) + paddingLen := int(binary.BigEndian.Uint16(paddingHdr[2:])) + + if len(p) > originalDataSize { + p = p[:originalDataSize] + } + n, err := c.ExtendedConn.Read(p) + if err != nil { + return err + } + c.readPadding++ + c.readRemaining = originalDataSize - n + c.paddingRemaining = paddingLen + buffer.Truncate(n) + return nil + } + return c.ExtendedConn.ReadBuffer(buffer) +} + +func (c *paddingConn) WriteBuffer(buffer *buf.Buffer) error { + if c.writePadding < kFirstPaddings { + bufferLen := buffer.Len() + if bufferLen > 65535 { + return common.Error(c.Write(buffer.Bytes())) + } + paddingLen := 256 + rand.Intn(512) + header := buffer.ExtendHeader(4) + binary.BigEndian.PutUint16(header[:2], uint16(bufferLen)) + binary.BigEndian.PutUint16(header[2:], uint16(paddingLen)) + buffer.Extend(paddingLen) + c.writePadding++ + } + return c.ExtendedConn.WriteBuffer(buffer) +} + +func (c *paddingConn) FrontHeadroom() int { + return 4 + 256 + 1024 +} + +type vectorisedPaddingConn struct { + paddingConn + writer N.VectorisedWriter +} + +func (c *vectorisedPaddingConn) WriteVectorised(buffers []*buf.Buffer) error { + if c.writePadding < kFirstPaddings { + bufferLen := buf.LenMulti(buffers) + if bufferLen > 65535 { + defer buf.ReleaseMulti(buffers) + for _, buffer := range buffers { + _, err := c.Write(buffer.Bytes()) + if err != nil { + return err + } + } + return nil + } + paddingLen := 256 + rand.Intn(512) + header := buf.NewSize(4) + common.Must( + binary.Write(header, binary.BigEndian, uint16(bufferLen)), + binary.Write(header, binary.BigEndian, uint16(paddingLen)), + ) + c.writePadding++ + padding := buf.NewSize(paddingLen) + padding.Extend(paddingLen) + buffers = append(append([]*buf.Buffer{header}, buffers...), padding) + } + return c.writer.WriteVectorised(buffers) +} diff --git a/common/mux/protocol.go b/common/mux/protocol.go index 594d66ca..d48a92ee 100644 --- a/common/mux/protocol.go +++ b/common/mux/protocol.go @@ -3,6 +3,7 @@ package mux import ( "encoding/binary" "io" + "math/rand" "net" C "github.com/sagernet/sing-box/constant" @@ -113,11 +114,14 @@ func (p Protocol) String() string { } const ( - version0 = 0 + Version0 = iota + Version1 ) type Request struct { - Protocol Protocol + Version byte + Protocol Protocol + PaddingEnabled bool } func ReadRequest(reader io.Reader) (*Request, error) { @@ -125,19 +129,60 @@ func ReadRequest(reader io.Reader) (*Request, error) { if err != nil { return nil, err } - if version != version0 { + if version < Version0 || version > Version1 { return nil, E.New("unsupported version: ", version) } protocol, err := rw.ReadByte(reader) if err != nil { return nil, err } - return &Request{Protocol: Protocol(protocol)}, nil + var paddingEnabled bool + if version == Version1 { + err = binary.Read(reader, binary.BigEndian, &paddingEnabled) + if err != nil { + return nil, err + } + if paddingEnabled { + var paddingLen uint16 + err = binary.Read(reader, binary.BigEndian, &paddingLen) + if err != nil { + return nil, err + } + err = rw.SkipN(reader, int(paddingLen)) + if err != nil { + return nil, err + } + } + } + return &Request{Version: version, Protocol: Protocol(protocol), PaddingEnabled: paddingEnabled}, nil } -func EncodeRequest(buffer *buf.Buffer, request Request) { - buffer.WriteByte(version0) - buffer.WriteByte(byte(request.Protocol)) +func EncodeRequest(request Request, payload []byte) *buf.Buffer { + var requestLen int + requestLen += 2 + var paddingLen uint16 + if request.Version == Version1 { + requestLen += 1 + if request.PaddingEnabled { + requestLen += 2 + paddingLen = uint16(256 + rand.Intn(512)) + requestLen += int(paddingLen) + } + } + buffer := buf.NewSize(requestLen + len(payload)) + common.Must( + buffer.WriteByte(request.Version), + buffer.WriteByte(byte(request.Protocol)), + ) + if request.Version == Version1 { + common.Must(binary.Write(buffer, binary.BigEndian, request.PaddingEnabled)) + if request.PaddingEnabled { + common.Must(binary.Write(buffer, binary.BigEndian, paddingLen)) + buffer.Extend(int(paddingLen)) + } + } + common.Must1(buffer.Write(payload)) + return buffer } const ( @@ -174,7 +219,7 @@ func ReadStreamRequest(reader io.Reader) (*StreamRequest, error) { return &StreamRequest{network, destination, udpAddr}, nil } -func requestLen(request StreamRequest) int { +func streamRequestLen(request StreamRequest) int { var rLen int rLen += 1 // version rLen += 2 // flags diff --git a/common/mux/service.go b/common/mux/service.go index 19ec5bf0..eef7e1d7 100644 --- a/common/mux/service.go +++ b/common/mux/service.go @@ -22,6 +22,9 @@ func NewConnection(ctx context.Context, router adapter.Router, errorHandler E.Ha if err != nil { return err } + if request.PaddingEnabled { + conn = newPaddingConn(conn) + } session, err := request.Protocol.newServer(conn) if err != nil { return err diff --git a/common/mux/session.go b/common/mux/session.go index fa91dc44..db9b6ee4 100644 --- a/common/mux/session.go +++ b/common/mux/session.go @@ -4,7 +4,6 @@ import ( "io" "net" - "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" N "github.com/sagernet/sing/common/network" @@ -50,23 +49,35 @@ func (y *yamuxSession) CanTakeNewRequest() bool { type protocolConn struct { net.Conn - protocol Protocol + request Request protocolWritten bool } +func newProtocolConn(conn net.Conn, request Request) net.Conn { + writer, isVectorised := bufio.CreateVectorisedWriter(conn) + if isVectorised { + return &vectorisedProtocolConn{ + protocolConn{ + Conn: conn, + request: request, + }, + writer, + } + } else { + return &protocolConn{ + Conn: conn, + request: request, + } + } +} + func (c *protocolConn) Write(p []byte) (n int, err error) { if c.protocolWritten { return c.Conn.Write(p) } - _buffer := buf.StackNewSize(2 + len(p)) - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) - defer buffer.Release() - EncodeRequest(buffer, Request{ - Protocol: c.protocol, - }) - common.Must(common.Error(buffer.Write(p))) + buffer := EncodeRequest(c.request, p) n, err = c.Conn.Write(buffer.Bytes()) + buffer.Release() if err == nil { n-- } @@ -87,20 +98,14 @@ func (c *protocolConn) Upstream() any { type vectorisedProtocolConn struct { protocolConn - N.VectorisedWriter + writer N.VectorisedWriter } func (c *vectorisedProtocolConn) WriteVectorised(buffers []*buf.Buffer) error { if c.protocolWritten { - return c.VectorisedWriter.WriteVectorised(buffers) + return c.writer.WriteVectorised(buffers) } c.protocolWritten = true - _buffer := buf.StackNewSize(2) - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) - defer buffer.Release() - EncodeRequest(buffer, Request{ - Protocol: c.protocol, - }) - return c.VectorisedWriter.WriteVectorised(append([]*buf.Buffer{buffer}, buffers...)) + buffer := EncodeRequest(c.request, nil) + return c.writer.WriteVectorised(append([]*buf.Buffer{buffer}, buffers...)) } diff --git a/docs/configuration/shared/multiplex.md b/docs/configuration/shared/multiplex.md index e2962070..f6256d09 100644 --- a/docs/configuration/shared/multiplex.md +++ b/docs/configuration/shared/multiplex.md @@ -10,7 +10,8 @@ "protocol": "smux", "max_connections": 4, "min_streams": 4, - "max_streams": 0 + "max_streams": 0, + "padding": false } ``` @@ -49,3 +50,12 @@ Conflict with `max_streams`. Maximum multiplexed streams in a connection before opening a new connection. Conflict with `max_connections` and `min_streams`. + +#### padding + +!!! info + + Requires sing-box server version 1.3-beta9 or later. + +Enable padding. + diff --git a/docs/configuration/shared/multiplex.zh.md b/docs/configuration/shared/multiplex.zh.md index 0a9fa16f..aae78d41 100644 --- a/docs/configuration/shared/multiplex.zh.md +++ b/docs/configuration/shared/multiplex.zh.md @@ -48,4 +48,13 @@ 在打开新连接之前,连接中的最大多路复用流数量。 -与 `max_connections` 和 `min_streams` 冲突。 \ No newline at end of file +与 `max_connections` 和 `min_streams` 冲突。 + +#### padding + +!!! info + + 需要 sing-box 服务器版本 1.3-beta9 或更高。 + +启用填充。 + diff --git a/option/outbound.go b/option/outbound.go index abea81a0..6a394b74 100644 --- a/option/outbound.go +++ b/option/outbound.go @@ -150,4 +150,5 @@ type MultiplexOptions struct { MaxConnections int `json:"max_connections,omitempty"` MinStreams int `json:"min_streams,omitempty"` MaxStreams int `json:"max_streams,omitempty"` + Padding bool `json:"padding,omitempty"` } diff --git a/test/go.mod b/test/go.mod index bb338fd8..812d572f 100644 --- a/test/go.mod +++ b/test/go.mod @@ -10,7 +10,7 @@ require ( github.com/docker/docker v20.10.18+incompatible github.com/docker/go-connections v0.4.0 github.com/gofrs/uuid/v5 v5.0.0 - github.com/sagernet/sing v0.2.4-0.20230419153323-5fae6fa434c1 + github.com/sagernet/sing v0.2.4 github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507 github.com/spyzhov/ajson v0.7.1 github.com/stretchr/testify v1.8.2 @@ -21,7 +21,7 @@ require ( require ( berty.tech/go-libtor v1.0.385 // indirect github.com/Dreamacro/clash v1.15.0 // indirect - github.com/Microsoft/go-winio v0.5.1 // indirect + github.com/Microsoft/go-winio v0.6.0 // indirect github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/caddyserver/certmagic v0.17.2 // indirect @@ -72,13 +72,13 @@ require ( github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc // indirect github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b // indirect - github.com/sagernet/sing-tun v0.1.4-0.20230420014302-db67add64fae // indirect + github.com/sagernet/sing-tun v0.1.5-0.20230422121432-209ec123ca7b // indirect github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect - github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c // indirect + github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect @@ -92,13 +92,12 @@ require ( golang.org/x/mod v0.8.0 // indirect golang.org/x/sys v0.7.0 // indirect golang.org/x/text v0.9.0 // indirect - golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect golang.org/x/tools v0.6.0 // indirect google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect google.golang.org/grpc v1.54.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gotest.tools/v3 v3.4.0 // indirect - gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect + gvisor.dev/gvisor v0.0.0-20230415003630-3981d5d5e523 // indirect lukechampine.com/blake3 v1.1.7 // indirect ) diff --git a/test/go.sum b/test/go.sum index f345989a..1568f7b2 100644 --- a/test/go.sum +++ b/test/go.sum @@ -3,8 +3,8 @@ berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+f github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Dreamacro/clash v1.15.0 h1:mlpD950VEggXZBNahV66hyKDRxcczkj3vymoAt78KyE= github.com/Dreamacro/clash v1.15.0/go.mod h1:WNH69bN11LiAdgdSr4hpkEuXVMfBbWyhEKMCTx9BtNE= -github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= -github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= @@ -126,16 +126,16 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.4-0.20230419153323-5fae6fa434c1 h1:CdzNL25lzfVo0NMeghPqsupNsWvkzrbrUt5t8DoDPcQ= -github.com/sagernet/sing v0.2.4-0.20230419153323-5fae6fa434c1/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing v0.2.4 h1:gC8BR5sglbJZX23RtMyFa8EETP9YEUADhfbEzU1yVbo= +github.com/sagernet/sing v0.2.4/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc h1:hmbuqKv48SAjiKPoqtJGvS5pEHVPZjTHq9CPwQY2cZ4= github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc/go.mod h1:ZKuuqgsHRxDahYrzgSgy4vIAGGuKPlIf4hLcNzYzLkY= github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507 h1:bAHZCdWqJkb8LEW98+YsMVDXGRMUVjka8IC+St6ot88= github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507/go.mod h1:UJjvQGw0lyYaDGIDvUraL16fwaAEH1WFw1Y6sUcMPog= github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4= github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI= -github.com/sagernet/sing-tun v0.1.4-0.20230420014302-db67add64fae h1:yNKqOPKX9GnnEMvnm9ZVsIyMuMsU0x6uCJQMwAhGafA= -github.com/sagernet/sing-tun v0.1.4-0.20230420014302-db67add64fae/go.mod h1:F7hYqaFR7RRs0aLj3gHDt+v18mpD5apJwPUfTd4e5HQ= +github.com/sagernet/sing-tun v0.1.5-0.20230422121432-209ec123ca7b h1:9NsciSJGwzdkXwVvT2c2g+RvkTVkANeBLr2l+soJ7LM= +github.com/sagernet/sing-tun v0.1.5-0.20230422121432-209ec123ca7b/go.mod h1:DD7Ce2Gt0GFc6I/1+Uw4D/aUlBsGqrQsC52CMK/V818= github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3/go.mod h1:yKrAr+dqZd64DxBXCHWrYicp+n4qbqO73mtwv3dck8U= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= @@ -146,9 +146,8 @@ github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfI github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs= github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY= -github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= -github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2dKX7EQP++1JLNtw4C2TNxd4/ov8YUpOPOSo= +github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spyzhov/ajson v0.7.1 h1:1MDIlPc6x0zjNtpa7tDzRAyFAvRX+X8ZsvtYz5lZg6A= @@ -156,7 +155,6 @@ github.com/spyzhov/ajson v0.7.1/go.mod h1:63V+CGM6f1Bu/p4nLIN8885ojBdt88TbLoSFzy github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -216,13 +214,10 @@ golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -241,13 +236,12 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= @@ -270,8 +264,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= -gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= -gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4= -gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM= +gvisor.dev/gvisor v0.0.0-20230415003630-3981d5d5e523 h1:zUQYeyyPLnSR6yMvLSOmLH37xDWCZ7BqlpE69fE5K3Q= +gvisor.dev/gvisor v0.0.0-20230415003630-3981d5d5e523/go.mod h1:pzr6sy8gDLfVmDAg8OYrlKvGEHw5C3PGTiBXBTCx76Q= lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= diff --git a/test/mux_test.go b/test/mux_test.go index f77ac8c3..aff082fd 100644 --- a/test/mux_test.go +++ b/test/mux_test.go @@ -18,22 +18,40 @@ var muxProtocols = []mux.Protocol{ } func TestVMessSMux(t *testing.T) { - testVMessMux(t, mux.ProtocolSMux.String()) + testVMessMux(t, option.MultiplexOptions{ + Enabled: true, + Protocol: mux.ProtocolSMux.String(), + }) } func TestShadowsocksMux(t *testing.T) { for _, protocol := range muxProtocols { t.Run(protocol.String(), func(t *testing.T) { - testShadowsocksMux(t, protocol.String()) + testShadowsocksMux(t, option.MultiplexOptions{ + Enabled: true, + Protocol: protocol.String(), + }) }) } } func TestShadowsockH2Mux(t *testing.T) { - testShadowsocksMux(t, mux.ProtocolH2Mux.String()) + testShadowsocksMux(t, option.MultiplexOptions{ + Enabled: true, + Protocol: mux.ProtocolH2Mux.String(), + Padding: true, + }) } -func testShadowsocksMux(t *testing.T, protocol string) { +func TestShadowsockSMuxPadding(t *testing.T) { + testShadowsocksMux(t, option.MultiplexOptions{ + Enabled: true, + Protocol: mux.ProtocolSMux.String(), + Padding: true, + }) +} + +func testShadowsocksMux(t *testing.T, options option.MultiplexOptions) { method := shadowaead_2022.List[0] password := mkBase64(t, 16) startInstance(t, option.Options{ @@ -72,12 +90,9 @@ func testShadowsocksMux(t *testing.T, protocol string) { Server: "127.0.0.1", ServerPort: serverPort, }, - Method: method, - Password: password, - MultiplexOptions: &option.MultiplexOptions{ - Enabled: true, - Protocol: protocol, - }, + Method: method, + Password: password, + MultiplexOptions: &options, }, }, }, @@ -95,7 +110,7 @@ func testShadowsocksMux(t *testing.T, protocol string) { testSuit(t, clientPort, testPort) } -func testVMessMux(t *testing.T, protocol string) { +func testVMessMux(t *testing.T, options option.MultiplexOptions) { user, _ := uuid.NewV4() startInstance(t, option.Options{ Inbounds: []option.Inbound{ @@ -136,12 +151,9 @@ func testVMessMux(t *testing.T, protocol string) { Server: "127.0.0.1", ServerPort: serverPort, }, - Security: "auto", - UUID: user.String(), - Multiplex: &option.MultiplexOptions{ - Enabled: true, - Protocol: protocol, - }, + Security: "auto", + UUID: user.String(), + Multiplex: &options, }, }, },