diff --git a/common/mux/client.go b/common/mux/client.go index c66dd7ae..36dd3137 100644 --- a/common/mux/client.go +++ b/common/mux/client.go @@ -1,535 +1,21 @@ package mux import ( - "context" - "encoding/binary" - "io" - "net" - "sync" - "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing/common" - "github.com/sagernet/sing/common/buf" - "github.com/sagernet/sing/common/bufio" - E "github.com/sagernet/sing/common/exceptions" - M "github.com/sagernet/sing/common/metadata" + "github.com/sagernet/sing-mux" N "github.com/sagernet/sing/common/network" - "github.com/sagernet/sing/common/x/list" ) -var _ N.Dialer = (*Client)(nil) - -type Client struct { - access sync.Mutex - connections list.List[abstractSession] - ctx context.Context - dialer N.Dialer - protocol Protocol - maxConnections int - minStreams int - maxStreams int -} - -func NewClient(ctx context.Context, dialer N.Dialer, protocol Protocol, maxConnections int, minStreams int, maxStreams int) *Client { - return &Client{ - ctx: ctx, - dialer: dialer, - protocol: protocol, - maxConnections: maxConnections, - minStreams: minStreams, - maxStreams: maxStreams, - } -} - -func NewClientWithOptions(ctx context.Context, dialer N.Dialer, options option.MultiplexOptions) (N.Dialer, error) { +func NewClientWithOptions(dialer N.Dialer, options option.MultiplexOptions) (*Client, error) { if !options.Enabled { return nil, nil } - if options.MaxConnections == 0 && options.MaxStreams == 0 { - options.MinStreams = 8 - } - protocol, err := ParseProtocol(options.Protocol) - if err != nil { - return nil, err - } - return NewClient(ctx, dialer, protocol, options.MaxConnections, options.MinStreams, options.MaxStreams), nil -} - -func (c *Client) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - switch N.NetworkName(network) { - case N.NetworkTCP: - stream, err := c.openStream() - if err != nil { - return nil, err - } - return &ClientConn{Conn: stream, destination: destination}, nil - case N.NetworkUDP: - stream, err := c.openStream() - if err != nil { - return nil, err - } - return bufio.NewUnbindPacketConn(&ClientPacketConn{ExtendedConn: bufio.NewExtendedConn(stream), destination: destination}), nil - default: - return nil, E.Extend(N.ErrUnknownNetwork, network) - } -} - -func (c *Client) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - stream, err := c.openStream() - if err != nil { - return nil, err - } - return &ClientPacketAddrConn{ExtendedConn: bufio.NewExtendedConn(stream), destination: destination}, nil -} - -func (c *Client) openStream() (net.Conn, error) { - var ( - session abstractSession - stream net.Conn - err error - ) - for attempts := 0; attempts < 2; attempts++ { - session, err = c.offer() - if err != nil { - continue - } - stream, err = session.Open() - if err != nil { - continue - } - break - } - if err != nil { - return nil, err - } - return &wrapStream{stream}, nil -} - -func (c *Client) offer() (abstractSession, error) { - c.access.Lock() - defer c.access.Unlock() - - sessions := make([]abstractSession, 0, c.maxConnections) - for element := c.connections.Front(); element != nil; { - if element.Value.IsClosed() { - nextElement := element.Next() - c.connections.Remove(element) - element = nextElement - continue - } - sessions = append(sessions, element.Value) - element = element.Next() - } - sLen := len(sessions) - if sLen == 0 { - return c.offerNew() - } - session := common.MinBy(sessions, abstractSession.NumStreams) - numStreams := session.NumStreams() - if numStreams == 0 { - return session, nil - } - if c.maxConnections > 0 { - if sLen >= c.maxConnections || numStreams < c.minStreams { - return session, nil - } - } else { - if c.maxStreams > 0 && numStreams < c.maxStreams { - return session, nil - } - } - return c.offerNew() -} - -func (c *Client) offerNew() (abstractSession, error) { - conn, err := c.dialer.DialContext(c.ctx, N.NetworkTCP, Destination) - if err != nil { - return nil, err - } - if vectorisedWriter, isVectorised := bufio.CreateVectorisedWriter(conn); isVectorised { - conn = &vectorisedProtocolConn{protocolConn{Conn: conn, protocol: c.protocol}, vectorisedWriter} - } else { - conn = &protocolConn{Conn: conn, protocol: c.protocol} - } - session, err := c.protocol.newClient(conn) - if err != nil { - return nil, err - } - c.connections.PushBack(session) - return session, nil -} - -func (c *Client) Close() error { - c.access.Lock() - defer c.access.Unlock() - for _, session := range c.connections.Array() { - session.Close() - } - return nil -} - -type ClientConn struct { - net.Conn - destination M.Socksaddr - requestWrite bool - responseRead bool -} - -func (c *ClientConn) readResponse() error { - response, err := ReadStreamResponse(c.Conn) - if err != nil { - return err - } - if response.Status == statusError { - return E.New("remote error: ", response.Message) - } - return nil -} - -func (c *ClientConn) Read(b []byte) (n int, err error) { - if !c.responseRead { - err = c.readResponse() - if err != nil { - return - } - c.responseRead = true - } - return c.Conn.Read(b) -} - -func (c *ClientConn) Write(b []byte) (n int, err error) { - if c.requestWrite { - return c.Conn.Write(b) - } - request := StreamRequest{ - Network: N.NetworkTCP, - Destination: c.destination, - } - _buffer := buf.StackNewSize(requestLen(request) + len(b)) - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) - defer buffer.Release() - EncodeStreamRequest(request, buffer) - buffer.Write(b) - _, err = c.Conn.Write(buffer.Bytes()) - if err != nil { - return - } - c.requestWrite = true - return len(b), nil -} - -func (c *ClientConn) ReadFrom(r io.Reader) (n int64, err error) { - if !c.requestWrite { - return bufio.ReadFrom0(c, r) - } - return bufio.Copy(c.Conn, r) -} - -func (c *ClientConn) WriteTo(w io.Writer) (n int64, err error) { - if !c.responseRead { - return bufio.WriteTo0(c, w) - } - return bufio.Copy(w, c.Conn) -} - -func (c *ClientConn) LocalAddr() net.Addr { - return c.Conn.LocalAddr() -} - -func (c *ClientConn) RemoteAddr() net.Addr { - return c.destination.TCPAddr() -} - -func (c *ClientConn) ReaderReplaceable() bool { - return c.responseRead -} - -func (c *ClientConn) WriterReplaceable() bool { - return c.requestWrite -} - -func (c *ClientConn) NeedAdditionalReadDeadline() bool { - return true -} - -func (c *ClientConn) Upstream() any { - return c.Conn -} - -type ClientPacketConn struct { - N.ExtendedConn - destination M.Socksaddr - requestWrite bool - responseRead bool -} - -func (c *ClientPacketConn) readResponse() error { - response, err := ReadStreamResponse(c.ExtendedConn) - if err != nil { - return err - } - if response.Status == statusError { - return E.New("remote error: ", response.Message) - } - return nil -} - -func (c *ClientPacketConn) Read(b []byte) (n int, err error) { - if !c.responseRead { - err = c.readResponse() - if err != nil { - return - } - c.responseRead = true - } - var length uint16 - err = binary.Read(c.ExtendedConn, binary.BigEndian, &length) - if err != nil { - return - } - if cap(b) < int(length) { - return 0, io.ErrShortBuffer - } - return io.ReadFull(c.ExtendedConn, b[:length]) -} - -func (c *ClientPacketConn) writeRequest(payload []byte) (n int, err error) { - request := StreamRequest{ - Network: N.NetworkUDP, - Destination: c.destination, - } - rLen := requestLen(request) - if len(payload) > 0 { - rLen += 2 + len(payload) - } - _buffer := buf.StackNewSize(rLen) - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) - defer buffer.Release() - EncodeStreamRequest(request, buffer) - if len(payload) > 0 { - common.Must( - binary.Write(buffer, binary.BigEndian, uint16(len(payload))), - common.Error(buffer.Write(payload)), - ) - } - _, err = c.ExtendedConn.Write(buffer.Bytes()) - if err != nil { - return - } - c.requestWrite = true - return len(payload), nil -} - -func (c *ClientPacketConn) Write(b []byte) (n int, err error) { - if !c.requestWrite { - return c.writeRequest(b) - } - err = binary.Write(c.ExtendedConn, binary.BigEndian, uint16(len(b))) - if err != nil { - return - } - return c.ExtendedConn.Write(b) -} - -func (c *ClientPacketConn) ReadBuffer(buffer *buf.Buffer) (err error) { - if !c.responseRead { - err = c.readResponse() - if err != nil { - return - } - c.responseRead = true - } - var length uint16 - err = binary.Read(c.ExtendedConn, binary.BigEndian, &length) - if err != nil { - return - } - _, err = buffer.ReadFullFrom(c.ExtendedConn, int(length)) - return -} - -func (c *ClientPacketConn) WriteBuffer(buffer *buf.Buffer) error { - if !c.requestWrite { - defer buffer.Release() - return common.Error(c.writeRequest(buffer.Bytes())) - } - bLen := buffer.Len() - binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(bLen)) - return c.ExtendedConn.WriteBuffer(buffer) -} - -func (c *ClientPacketConn) FrontHeadroom() int { - return 2 -} - -func (c *ClientPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { - err = c.ReadBuffer(buffer) - return -} - -func (c *ClientPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { - return c.WriteBuffer(buffer) -} - -func (c *ClientPacketConn) LocalAddr() net.Addr { - return c.ExtendedConn.LocalAddr() -} - -func (c *ClientPacketConn) RemoteAddr() net.Addr { - return c.destination.UDPAddr() -} - -func (c *ClientPacketConn) NeedAdditionalReadDeadline() bool { - return true -} - -func (c *ClientPacketConn) Upstream() any { - return c.ExtendedConn -} - -var _ N.NetPacketConn = (*ClientPacketAddrConn)(nil) - -type ClientPacketAddrConn struct { - N.ExtendedConn - destination M.Socksaddr - requestWrite bool - responseRead bool -} - -func (c *ClientPacketAddrConn) readResponse() error { - response, err := ReadStreamResponse(c.ExtendedConn) - if err != nil { - return err - } - if response.Status == statusError { - return E.New("remote error: ", response.Message) - } - return nil -} - -func (c *ClientPacketAddrConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { - if !c.responseRead { - err = c.readResponse() - if err != nil { - return - } - c.responseRead = true - } - destination, err := M.SocksaddrSerializer.ReadAddrPort(c.ExtendedConn) - if err != nil { - return - } - if destination.IsFqdn() { - addr = destination - } else { - addr = destination.UDPAddr() - } - var length uint16 - err = binary.Read(c.ExtendedConn, binary.BigEndian, &length) - if err != nil { - return - } - if cap(p) < int(length) { - return 0, nil, io.ErrShortBuffer - } - n, err = io.ReadFull(c.ExtendedConn, p[:length]) - return -} - -func (c *ClientPacketAddrConn) writeRequest(payload []byte, destination M.Socksaddr) (n int, err error) { - request := StreamRequest{ - Network: N.NetworkUDP, - Destination: c.destination, - PacketAddr: true, - } - rLen := requestLen(request) - if len(payload) > 0 { - rLen += M.SocksaddrSerializer.AddrPortLen(destination) + 2 + len(payload) - } - _buffer := buf.StackNewSize(rLen) - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) - defer buffer.Release() - EncodeStreamRequest(request, buffer) - if len(payload) > 0 { - common.Must( - M.SocksaddrSerializer.WriteAddrPort(buffer, destination), - binary.Write(buffer, binary.BigEndian, uint16(len(payload))), - common.Error(buffer.Write(payload)), - ) - } - _, err = c.ExtendedConn.Write(buffer.Bytes()) - if err != nil { - return - } - c.requestWrite = true - return len(payload), nil -} - -func (c *ClientPacketAddrConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { - if !c.requestWrite { - return c.writeRequest(p, M.SocksaddrFromNet(addr)) - } - err = M.SocksaddrSerializer.WriteAddrPort(c.ExtendedConn, M.SocksaddrFromNet(addr)) - if err != nil { - return - } - err = binary.Write(c.ExtendedConn, binary.BigEndian, uint16(len(p))) - if err != nil { - return - } - return c.ExtendedConn.Write(p) -} - -func (c *ClientPacketAddrConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { - if !c.responseRead { - err = c.readResponse() - if err != nil { - return - } - c.responseRead = true - } - destination, err = M.SocksaddrSerializer.ReadAddrPort(c.ExtendedConn) - if err != nil { - return - } - var length uint16 - err = binary.Read(c.ExtendedConn, binary.BigEndian, &length) - if err != nil { - return - } - _, err = buffer.ReadFullFrom(c.ExtendedConn, int(length)) - return -} - -func (c *ClientPacketAddrConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { - if !c.requestWrite { - defer buffer.Release() - return common.Error(c.writeRequest(buffer.Bytes(), destination)) - } - bLen := buffer.Len() - header := buf.With(buffer.ExtendHeader(M.SocksaddrSerializer.AddrPortLen(destination) + 2)) - common.Must( - M.SocksaddrSerializer.WriteAddrPort(header, destination), - binary.Write(header, binary.BigEndian, uint16(bLen)), - ) - return c.ExtendedConn.WriteBuffer(buffer) -} - -func (c *ClientPacketAddrConn) LocalAddr() net.Addr { - return c.ExtendedConn.LocalAddr() -} - -func (c *ClientPacketAddrConn) FrontHeadroom() int { - return 2 + M.MaxSocksaddrLength -} - -func (c *ClientPacketAddrConn) NeedAdditionalReadDeadline() bool { - return true -} - -func (c *ClientPacketAddrConn) Upstream() any { - return c.ExtendedConn + return mux.NewClient(mux.Options{ + Dialer: dialer, + Protocol: options.Protocol, + MaxConnections: options.MaxConnections, + MinStreams: options.MinStreams, + MaxStreams: options.MaxStreams, + Padding: options.Padding, + }) } diff --git a/common/mux/protocol.go b/common/mux/protocol.go index 26abebb1..abb0e268 100644 --- a/common/mux/protocol.go +++ b/common/mux/protocol.go @@ -1,240 +1,14 @@ package mux import ( - "encoding/binary" - "io" - "net" - - C "github.com/sagernet/sing-box/constant" - "github.com/sagernet/sing/common" - "github.com/sagernet/sing/common/buf" - E "github.com/sagernet/sing/common/exceptions" - M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" - "github.com/sagernet/sing/common/rw" - "github.com/sagernet/smux" - - "github.com/hashicorp/yamux" + "github.com/sagernet/sing-mux" ) -var Destination = M.Socksaddr{ - Fqdn: "sp.mux.sing-box.arpa", - Port: 444, -} - -const ( - ProtocolSMux Protocol = iota - ProtocolYAMux +type ( + Client = mux.Client ) -type Protocol byte - -func ParseProtocol(name string) (Protocol, error) { - switch name { - case "", "smux": - return ProtocolSMux, nil - case "yamux": - return ProtocolYAMux, nil - default: - return ProtocolYAMux, E.New("unknown multiplex protocol: ", name) - } -} - -func (p Protocol) newServer(conn net.Conn) (abstractSession, error) { - switch p { - case ProtocolSMux: - session, err := smux.Server(conn, smuxConfig()) - if err != nil { - return nil, err - } - return &smuxSession{session}, nil - case ProtocolYAMux: - return yamux.Server(conn, yaMuxConfig()) - default: - panic("unknown protocol") - } -} - -func (p Protocol) newClient(conn net.Conn) (abstractSession, error) { - switch p { - case ProtocolSMux: - session, err := smux.Client(conn, smuxConfig()) - if err != nil { - return nil, err - } - return &smuxSession{session}, nil - case ProtocolYAMux: - return yamux.Client(conn, yaMuxConfig()) - default: - panic("unknown protocol") - } -} - -func smuxConfig() *smux.Config { - config := smux.DefaultConfig() - config.KeepAliveDisabled = true - return config -} - -func yaMuxConfig() *yamux.Config { - config := yamux.DefaultConfig() - config.LogOutput = io.Discard - config.StreamCloseTimeout = C.TCPTimeout - config.StreamOpenTimeout = C.TCPTimeout - return config -} - -func (p Protocol) String() string { - switch p { - case ProtocolSMux: - return "smux" - case ProtocolYAMux: - return "yamux" - default: - return "unknown" - } -} - -const ( - version0 = 0 +var ( + Destination = mux.Destination + HandleConnection = mux.HandleConnection ) - -type Request struct { - Protocol Protocol -} - -func ReadRequest(reader io.Reader) (*Request, error) { - version, err := rw.ReadByte(reader) - if err != nil { - return nil, err - } - if version != version0 { - return nil, E.New("unsupported version: ", version) - } - protocol, err := rw.ReadByte(reader) - if err != nil { - return nil, err - } - if protocol > byte(ProtocolYAMux) { - return nil, E.New("unsupported protocol: ", protocol) - } - return &Request{Protocol: Protocol(protocol)}, nil -} - -func EncodeRequest(buffer *buf.Buffer, request Request) { - buffer.WriteByte(version0) - buffer.WriteByte(byte(request.Protocol)) -} - -const ( - flagUDP = 1 - flagAddr = 2 - statusSuccess = 0 - statusError = 1 -) - -type StreamRequest struct { - Network string - Destination M.Socksaddr - PacketAddr bool -} - -func ReadStreamRequest(reader io.Reader) (*StreamRequest, error) { - var flags uint16 - err := binary.Read(reader, binary.BigEndian, &flags) - if err != nil { - return nil, err - } - destination, err := M.SocksaddrSerializer.ReadAddrPort(reader) - if err != nil { - return nil, err - } - var network string - var udpAddr bool - if flags&flagUDP == 0 { - network = N.NetworkTCP - } else { - network = N.NetworkUDP - udpAddr = flags&flagAddr != 0 - } - return &StreamRequest{network, destination, udpAddr}, nil -} - -func requestLen(request StreamRequest) int { - var rLen int - rLen += 1 // version - rLen += 2 // flags - rLen += M.SocksaddrSerializer.AddrPortLen(request.Destination) - return rLen -} - -func EncodeStreamRequest(request StreamRequest, buffer *buf.Buffer) { - destination := request.Destination - var flags uint16 - if request.Network == N.NetworkUDP { - flags |= flagUDP - } - if request.PacketAddr { - flags |= flagAddr - if !destination.IsValid() { - destination = Destination - } - } - common.Must( - binary.Write(buffer, binary.BigEndian, flags), - M.SocksaddrSerializer.WriteAddrPort(buffer, destination), - ) -} - -type StreamResponse struct { - Status uint8 - Message string -} - -func ReadStreamResponse(reader io.Reader) (*StreamResponse, error) { - var response StreamResponse - status, err := rw.ReadByte(reader) - if err != nil { - return nil, err - } - response.Status = status - if status == statusError { - response.Message, err = rw.ReadVString(reader) - if err != nil { - return nil, err - } - } - return &response, nil -} - -type wrapStream struct { - net.Conn -} - -func (w *wrapStream) Read(p []byte) (n int, err error) { - n, err = w.Conn.Read(p) - err = wrapError(err) - return -} - -func (w *wrapStream) Write(p []byte) (n int, err error) { - n, err = w.Conn.Write(p) - err = wrapError(err) - return -} - -func (w *wrapStream) WriteIsThreadUnsafe() { -} - -func (w *wrapStream) Upstream() any { - return w.Conn -} - -func wrapError(err error) error { - switch err { - case yamux.ErrStreamClosed: - return io.EOF - default: - return err - } -} diff --git a/common/mux/service.go b/common/mux/service.go deleted file mode 100644 index 19ec5bf0..00000000 --- a/common/mux/service.go +++ /dev/null @@ -1,269 +0,0 @@ -package mux - -import ( - "context" - "encoding/binary" - "net" - - "github.com/sagernet/sing-box/adapter" - "github.com/sagernet/sing-box/log" - "github.com/sagernet/sing/common" - "github.com/sagernet/sing/common/buf" - "github.com/sagernet/sing/common/bufio" - E "github.com/sagernet/sing/common/exceptions" - M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" - "github.com/sagernet/sing/common/rw" - "github.com/sagernet/sing/common/task" -) - -func NewConnection(ctx context.Context, router adapter.Router, errorHandler E.Handler, logger log.ContextLogger, conn net.Conn, metadata adapter.InboundContext) error { - request, err := ReadRequest(conn) - if err != nil { - return err - } - session, err := request.Protocol.newServer(conn) - if err != nil { - return err - } - var group task.Group - group.Append0(func(ctx context.Context) error { - var stream net.Conn - for { - stream, err = session.Accept() - if err != nil { - return err - } - go newConnection(ctx, router, errorHandler, logger, stream, metadata) - } - }) - group.Cleanup(func() { - session.Close() - }) - return group.Run(ctx) -} - -func newConnection(ctx context.Context, router adapter.Router, errorHandler E.Handler, logger log.ContextLogger, stream net.Conn, metadata adapter.InboundContext) { - stream = &wrapStream{stream} - request, err := ReadStreamRequest(stream) - if err != nil { - logger.ErrorContext(ctx, err) - return - } - metadata.Destination = request.Destination - if request.Network == N.NetworkTCP { - logger.InfoContext(ctx, "inbound multiplex connection to ", metadata.Destination) - hErr := router.RouteConnection(ctx, &ServerConn{ExtendedConn: bufio.NewExtendedConn(stream)}, metadata) - stream.Close() - if hErr != nil { - errorHandler.NewError(ctx, hErr) - } - } else { - var packetConn N.PacketConn - if !request.PacketAddr { - logger.InfoContext(ctx, "inbound multiplex packet connection to ", metadata.Destination) - packetConn = &ServerPacketConn{ExtendedConn: bufio.NewExtendedConn(stream), destination: request.Destination} - } else { - logger.InfoContext(ctx, "inbound multiplex packet connection") - packetConn = &ServerPacketAddrConn{ExtendedConn: bufio.NewExtendedConn(stream)} - } - hErr := router.RoutePacketConnection(ctx, packetConn, metadata) - stream.Close() - if hErr != nil { - errorHandler.NewError(ctx, hErr) - } - } -} - -var _ N.HandshakeConn = (*ServerConn)(nil) - -type ServerConn struct { - N.ExtendedConn - responseWrite bool -} - -func (c *ServerConn) HandshakeFailure(err error) error { - errMessage := err.Error() - _buffer := buf.StackNewSize(1 + rw.UVariantLen(uint64(len(errMessage))) + len(errMessage)) - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) - defer buffer.Release() - common.Must( - buffer.WriteByte(statusError), - rw.WriteVString(_buffer, errMessage), - ) - return c.ExtendedConn.WriteBuffer(buffer) -} - -func (c *ServerConn) Write(b []byte) (n int, err error) { - if c.responseWrite { - return c.ExtendedConn.Write(b) - } - _buffer := buf.StackNewSize(1 + len(b)) - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) - defer buffer.Release() - common.Must( - buffer.WriteByte(statusSuccess), - common.Error(buffer.Write(b)), - ) - _, err = c.ExtendedConn.Write(buffer.Bytes()) - if err != nil { - return - } - c.responseWrite = true - return len(b), nil -} - -func (c *ServerConn) WriteBuffer(buffer *buf.Buffer) error { - if c.responseWrite { - return c.ExtendedConn.WriteBuffer(buffer) - } - buffer.ExtendHeader(1)[0] = statusSuccess - c.responseWrite = true - return c.ExtendedConn.WriteBuffer(buffer) -} - -func (c *ServerConn) FrontHeadroom() int { - if !c.responseWrite { - return 1 - } - return 0 -} - -func (c *ServerConn) NeedAdditionalReadDeadline() bool { - return true -} - -func (c *ServerConn) Upstream() any { - return c.ExtendedConn -} - -var ( - _ N.HandshakeConn = (*ServerPacketConn)(nil) - _ N.PacketConn = (*ServerPacketConn)(nil) -) - -type ServerPacketConn struct { - N.ExtendedConn - destination M.Socksaddr - responseWrite bool -} - -func (c *ServerPacketConn) HandshakeFailure(err error) error { - errMessage := err.Error() - _buffer := buf.StackNewSize(1 + rw.UVariantLen(uint64(len(errMessage))) + len(errMessage)) - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) - defer buffer.Release() - common.Must( - buffer.WriteByte(statusError), - rw.WriteVString(_buffer, errMessage), - ) - return c.ExtendedConn.WriteBuffer(buffer) -} - -func (c *ServerPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { - var length uint16 - err = binary.Read(c.ExtendedConn, binary.BigEndian, &length) - if err != nil { - return - } - _, err = buffer.ReadFullFrom(c.ExtendedConn, int(length)) - if err != nil { - return - } - destination = c.destination - return -} - -func (c *ServerPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { - pLen := buffer.Len() - common.Must(binary.Write(buf.With(buffer.ExtendHeader(2)), binary.BigEndian, uint16(pLen))) - if !c.responseWrite { - buffer.ExtendHeader(1)[0] = statusSuccess - c.responseWrite = true - } - return c.ExtendedConn.WriteBuffer(buffer) -} - -func (c *ServerPacketConn) NeedAdditionalReadDeadline() bool { - return true -} - -func (c *ServerPacketConn) Upstream() any { - return c.ExtendedConn -} - -func (c *ServerPacketConn) FrontHeadroom() int { - if !c.responseWrite { - return 3 - } - return 2 -} - -var ( - _ N.HandshakeConn = (*ServerPacketAddrConn)(nil) - _ N.PacketConn = (*ServerPacketAddrConn)(nil) -) - -type ServerPacketAddrConn struct { - N.ExtendedConn - responseWrite bool -} - -func (c *ServerPacketAddrConn) HandshakeFailure(err error) error { - errMessage := err.Error() - _buffer := buf.StackNewSize(1 + rw.UVariantLen(uint64(len(errMessage))) + len(errMessage)) - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) - defer buffer.Release() - common.Must( - buffer.WriteByte(statusError), - rw.WriteVString(_buffer, errMessage), - ) - return c.ExtendedConn.WriteBuffer(buffer) -} - -func (c *ServerPacketAddrConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { - destination, err = M.SocksaddrSerializer.ReadAddrPort(c.ExtendedConn) - if err != nil { - return - } - var length uint16 - err = binary.Read(c.ExtendedConn, binary.BigEndian, &length) - if err != nil { - return - } - _, err = buffer.ReadFullFrom(c.ExtendedConn, int(length)) - if err != nil { - return - } - return -} - -func (c *ServerPacketAddrConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { - pLen := buffer.Len() - common.Must(binary.Write(buf.With(buffer.ExtendHeader(2)), binary.BigEndian, uint16(pLen))) - common.Must(M.SocksaddrSerializer.WriteAddrPort(buf.With(buffer.ExtendHeader(M.SocksaddrSerializer.AddrPortLen(destination))), destination)) - if !c.responseWrite { - buffer.ExtendHeader(1)[0] = statusSuccess - c.responseWrite = true - } - return c.ExtendedConn.WriteBuffer(buffer) -} - -func (c *ServerPacketAddrConn) NeedAdditionalReadDeadline() bool { - return true -} - -func (c *ServerPacketAddrConn) Upstream() any { - return c.ExtendedConn -} - -func (c *ServerPacketAddrConn) FrontHeadroom() int { - if !c.responseWrite { - return 3 + M.MaxSocksaddrLength - } - return 2 + M.MaxSocksaddrLength -} diff --git a/common/mux/session.go b/common/mux/session.go deleted file mode 100644 index 04d1426e..00000000 --- a/common/mux/session.go +++ /dev/null @@ -1,91 +0,0 @@ -package mux - -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" - "github.com/sagernet/smux" -) - -type abstractSession interface { - Open() (net.Conn, error) - Accept() (net.Conn, error) - NumStreams() int - Close() error - IsClosed() bool -} - -var _ abstractSession = (*smuxSession)(nil) - -type smuxSession struct { - *smux.Session -} - -func (s *smuxSession) Open() (net.Conn, error) { - return s.OpenStream() -} - -func (s *smuxSession) Accept() (net.Conn, error) { - return s.AcceptStream() -} - -type protocolConn struct { - net.Conn - protocol Protocol - protocolWritten bool -} - -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))) - n, err = c.Conn.Write(buffer.Bytes()) - if err == nil { - n-- - } - c.protocolWritten = true - return n, err -} - -func (c *protocolConn) ReadFrom(r io.Reader) (n int64, err error) { - if !c.protocolWritten { - return bufio.ReadFrom0(c, r) - } - return bufio.Copy(c.Conn, r) -} - -func (c *protocolConn) Upstream() any { - return c.Conn -} - -type vectorisedProtocolConn struct { - protocolConn - N.VectorisedWriter -} - -func (c *vectorisedProtocolConn) WriteVectorised(buffers []*buf.Buffer) error { - if c.protocolWritten { - return c.VectorisedWriter.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...)) -} diff --git a/docs/configuration/shared/multiplex.md b/docs/configuration/shared/multiplex.md index 02e3c90a..833efaff 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 } ``` @@ -28,8 +29,9 @@ Multiplex protocol. |----------|------------------------------------| | smux | https://github.com/xtaci/smux | | yamux | https://github.com/hashicorp/yamux | +| h2mux | https://golang.org/x/net/http2 | -SMux is used by default. +h2mux is used by default. #### max_connections @@ -48,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 c336e8ec..99a0ba03 100644 --- a/docs/configuration/shared/multiplex.zh.md +++ b/docs/configuration/shared/multiplex.zh.md @@ -28,8 +28,9 @@ |-------|------------------------------------| | smux | https://github.com/xtaci/smux | | yamux | https://github.com/hashicorp/yamux | +| h2mux | https://golang.org/x/net/http2 | -默认使用 SMux。 +默认使用 h2mux。 #### max_connections @@ -47,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/go.mod b/go.mod index 1bf8825e..2d1a96f3 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,6 @@ require ( github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.2 github.com/gofrs/uuid/v5 v5.0.0 - github.com/hashicorp/yamux v0.1.1 github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb github.com/logrusorgru/aurora v2.0.3+incompatible github.com/mholt/acmez v1.1.1 @@ -25,8 +24,9 @@ require ( github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035 github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.2.4 + github.com/sagernet/sing v0.2.5-0.20230423085534-0902e6216207 github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc + github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646 github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507 github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-tun v0.1.5-0.20230422121432-209ec123ca7b @@ -63,6 +63,7 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect + github.com/hashicorp/yamux v0.1.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.15.15 // indirect diff --git a/go.sum b/go.sum index 8ee02d03..7f7ebc29 100644 --- a/go.sum +++ b/go.sum @@ -111,10 +111,12 @@ 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 h1:gC8BR5sglbJZX23RtMyFa8EETP9YEUADhfbEzU1yVbo= -github.com/sagernet/sing v0.2.4/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing v0.2.5-0.20230423085534-0902e6216207 h1:+dDVjW20IT+e8maKryaDeRY2+RFmTFdrQeIzqE2WOss= +github.com/sagernet/sing v0.2.5-0.20230423085534-0902e6216207/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-mux v0.0.0-20230517134606-1ebe6bb26646 h1:X3ADfMqeGns1Q1FlXc9kaL9FwW1UM6D6tEQo8jFstpc= +github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= 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= 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/outbound/shadowsocks.go b/outbound/shadowsocks.go index e196c03a..1e2e2e63 100644 --- a/outbound/shadowsocks.go +++ b/outbound/shadowsocks.go @@ -30,7 +30,7 @@ type Shadowsocks struct { serverAddr M.Socksaddr plugin sip003.Plugin uotClient *uot.Client - multiplexDialer N.Dialer + multiplexDialer *mux.Client } func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksOutboundOptions) (*Shadowsocks, error) { @@ -58,7 +58,7 @@ func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte } uotOptions := common.PtrValueOrDefault(options.UDPOverTCPOptions) if !uotOptions.Enabled { - outbound.multiplexDialer, err = mux.NewClientWithOptions(ctx, (*shadowsocksDialer)(outbound), common.PtrValueOrDefault(options.MultiplexOptions)) + outbound.multiplexDialer, err = mux.NewClientWithOptions((*shadowsocksDialer)(outbound), common.PtrValueOrDefault(options.MultiplexOptions)) if err != nil { return nil, err } @@ -127,8 +127,15 @@ func (h *Shadowsocks) NewPacketConnection(ctx context.Context, conn N.PacketConn return NewPacketConnection(ctx, h, conn, metadata) } +func (h *Shadowsocks) InterfaceUpdated() error { + if h.multiplexDialer != nil { + h.multiplexDialer.Reset() + } + return nil +} + func (h *Shadowsocks) Close() error { - return common.Close(h.multiplexDialer) + return common.Close(common.PtrOrNil(h.multiplexDialer)) } var _ N.Dialer = (*shadowsocksDialer)(nil) diff --git a/outbound/trojan.go b/outbound/trojan.go index 2e4bc96a..c33f9867 100644 --- a/outbound/trojan.go +++ b/outbound/trojan.go @@ -27,7 +27,7 @@ type Trojan struct { dialer N.Dialer serverAddr M.Socksaddr key [56]byte - multiplexDialer N.Dialer + multiplexDialer *mux.Client tlsConfig tls.Config transport adapter.V2RayClientTransport } @@ -58,7 +58,7 @@ func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLog return nil, E.Cause(err, "create client transport: ", options.Transport.Type) } } - outbound.multiplexDialer, err = mux.NewClientWithOptions(ctx, (*trojanDialer)(outbound), common.PtrValueOrDefault(options.Multiplex)) + outbound.multiplexDialer, err = mux.NewClientWithOptions((*trojanDialer)(outbound), common.PtrValueOrDefault(options.Multiplex)) if err != nil { return nil, err } @@ -103,8 +103,15 @@ func (h *Trojan) NewPacketConnection(ctx context.Context, conn N.PacketConn, met return NewPacketConnection(ctx, h, conn, metadata) } +func (h *Trojan) InterfaceUpdated() error { + if h.multiplexDialer != nil { + h.multiplexDialer.Reset() + } + return nil +} + func (h *Trojan) Close() error { - return common.Close(h.multiplexDialer, h.transport) + return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport) } type trojanDialer Trojan diff --git a/outbound/vmess.go b/outbound/vmess.go index cb6ba40f..288bc42d 100644 --- a/outbound/vmess.go +++ b/outbound/vmess.go @@ -27,7 +27,7 @@ type VMess struct { dialer N.Dialer client *vmess.Client serverAddr M.Socksaddr - multiplexDialer N.Dialer + multiplexDialer *mux.Client tlsConfig tls.Config transport adapter.V2RayClientTransport packetAddr bool @@ -59,7 +59,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg return nil, E.Cause(err, "create client transport: ", options.Transport.Type) } } - outbound.multiplexDialer, err = mux.NewClientWithOptions(ctx, (*vmessDialer)(outbound), common.PtrValueOrDefault(options.Multiplex)) + outbound.multiplexDialer, err = mux.NewClientWithOptions((*vmessDialer)(outbound), common.PtrValueOrDefault(options.Multiplex)) if err != nil { return nil, err } @@ -97,8 +97,15 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg return outbound, nil } +func (h *VMess) InterfaceUpdated() error { + if h.multiplexDialer != nil { + h.multiplexDialer.Reset() + } + return nil +} + func (h *VMess) Close() error { - return common.Close(h.multiplexDialer, h.transport) + return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport) } func (h *VMess) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { diff --git a/route/router.go b/route/router.go index 95e417da..c1e3ba50 100644 --- a/route/router.go +++ b/route/router.go @@ -589,7 +589,8 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad switch metadata.Destination.Fqdn { case mux.Destination.Fqdn: r.logger.InfoContext(ctx, "inbound multiplex connection") - return mux.NewConnection(ctx, r, r, r.logger, conn, metadata) + handler := adapter.NewUpstreamHandler(metadata, r.RouteConnection, r.RoutePacketConnection, r) + return mux.HandleConnection(ctx, handler, r.logger, conn, adapter.UpstreamMetadata(metadata)) case vmess.MuxDestination.Fqdn: r.logger.InfoContext(ctx, "inbound legacy multiplex connection") return vmess.HandleMuxConnection(ctx, conn, adapter.NewUpstreamHandler(metadata, r.RouteConnection, r.RoutePacketConnection, r)) diff --git a/test/go.mod b/test/go.mod index 86a55171..812d572f 100644 --- a/test/go.mod +++ b/test/go.mod @@ -9,9 +9,9 @@ replace github.com/sagernet/sing-box => ../ require ( github.com/docker/docker v20.10.18+incompatible github.com/docker/go-connections v0.4.0 - github.com/gofrs/uuid v4.4.0+incompatible - github.com/sagernet/sing v0.2.4-0.20230418025125-f196b4303e31 - github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d + github.com/gofrs/uuid/v5 v5.0.0 + 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 go.uber.org/goleak v1.2.0 @@ -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 @@ -36,7 +36,6 @@ require ( github.com/go-chi/cors v1.2.1 // indirect github.com/go-chi/render v1.0.2 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect - github.com/gofrs/uuid/v5 v5.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.2 // indirect @@ -51,7 +50,7 @@ require ( github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/mholt/acmez v1.1.0 // indirect github.com/miekg/dns v1.1.53 // indirect - github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c // indirect + github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect github.com/ooni/go-libtor v1.1.7 // indirect @@ -71,15 +70,15 @@ require ( github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect - github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322 // indirect - github.com/sagernet/sing-shadowtls v0.1.0 // indirect - github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302 // indirect - github.com/sagernet/sing-vmess v0.1.3 // 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.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 @@ -93,15 +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 ) - -//replace github.com/sagernet/sing => ../../sing diff --git a/test/go.sum b/test/go.sum index 63a47ae1..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= @@ -43,8 +43,6 @@ github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg= github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= -github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -84,8 +82,8 @@ github.com/mholt/acmez v1.1.0 h1:IQ9CGHKOHokorxnffsqDvmmE30mDenO1lptYZ1AYkHY= github.com/mholt/acmez v1.1.0/go.mod h1:zwo5+fbLLTowAX8o8ETfQzbDtwGEXnPhkmGdKIP+bgs= github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= -github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c h1:RC8WMpjonrBfyAh6VN/POIPtYD5tRAq0qMqCRjQNK+g= -github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c/go.mod h1:9OcmHNQQUTbk4XCffrLgN1NEKc2mh5u++biHVrvHsSU= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= @@ -128,18 +126,18 @@ 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.20230418025125-f196b4303e31 h1:qgq8jeY/rbnY9NwYXByO//AP0ByIxnsKUxQx1tOB3W0= -github.com/sagernet/sing v0.2.4-0.20230418025125-f196b4303e31/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322 h1:UDSeJZ2xB3dj1lySnM5LpF48dGlphGstw2BqtkJwcZI= -github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322/go.mod h1:2wjxSr1Gbecq9A0ESA9cnR399tQTcpCZEOGytekb+qI= -github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d h1:UUxtLujzp5jmtOXqXpSOGvHwHSZcBveKVDzRJ4GlnFU= -github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d/go.mod h1:Co3PJXcaZoLwHGBfT0rbSnn9C7ywc41zVYWtDeoeI/Q= -github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= -github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= -github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302 h1:aPb0T2HQRTG2t7fEwLvFLZSXmhmnBh+SMs2NufhmrsI= -github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302/go.mod h1:bvcVzlf9q9dgxt8qKluW+zOXCFoN1+SpBG3sHTq8/9Q= -github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM= -github.com/sagernet/sing-vmess v0.1.3/go.mod h1:GVXqAHwe9U21uS+Voh4YBIrADQyE4F9v0ayGSixSQAE= +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.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= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0= github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= @@ -148,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= @@ -158,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= @@ -218,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= @@ -243,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= @@ -272,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 32e32b76..aff082fd 100644 --- a/test/mux_test.go +++ b/test/mux_test.go @@ -18,18 +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 testShadowsocksMux(t *testing.T, protocol string) { +func TestShadowsockH2Mux(t *testing.T) { + testShadowsocksMux(t, option.MultiplexOptions{ + Enabled: true, + Protocol: mux.ProtocolH2Mux.String(), + Padding: true, + }) +} + +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{ @@ -68,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, }, }, }, @@ -91,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{ @@ -132,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, }, }, }, diff --git a/test/udpnat_test.go b/test/udpnat_test.go index b4db86ae..0956d812 100644 --- a/test/udpnat_test.go +++ b/test/udpnat_test.go @@ -19,7 +19,7 @@ func TestUDPNatClose(t *testing.T) { defer cancel() connCtx, connCancel := common.ContextWithCancelCause(context.Background()) defer connCancel(net.ErrClosed) - service := udpnat.New[int](ctx, 1, &testUDPNatCloseHandler{connCancel}) + service := udpnat.New[int](1, &testUDPNatCloseHandler{connCancel}) service.NewPacket(ctx, 0, buf.As([]byte("Hello")), M.Metadata{}, func(natConn N.PacketConn) N.PacketWriter { return &testPacketWriter{} }) diff --git a/transport/v2rayhttp/conn.go b/transport/v2rayhttp/conn.go index 3e1716d1..27f88134 100644 --- a/transport/v2rayhttp/conn.go +++ b/transport/v2rayhttp/conn.go @@ -199,13 +199,13 @@ func (c *HTTP2Conn) NeedAdditionalReadDeadline() bool { type ServerHTTPConn struct { HTTP2Conn - flusher http.Flusher + Flusher http.Flusher } func (c *ServerHTTPConn) Write(b []byte) (n int, err error) { n, err = c.writer.Write(b) if err == nil { - c.flusher.Flush() + c.Flusher.Flush() } return } @@ -246,6 +246,11 @@ func (w *HTTP2ConnWrapper) CloseWrapper() { w.closed = true } +func (w *HTTP2ConnWrapper) Close() error { + w.CloseWrapper() + return w.ExtendedConn.Close() +} + func (w *HTTP2ConnWrapper) Upstream() any { return w.ExtendedConn }