mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-06-13 21:54:13 +08:00
Improve multiplex
This commit is contained in:
parent
f61c5600e0
commit
9c287094e2
@ -41,7 +41,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, protocol Protocol, maxConne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientWithOptions(ctx context.Context, dialer N.Dialer, options option.MultiplexOptions) (N.Dialer, error) {
|
func NewClientWithOptions(ctx context.Context, dialer N.Dialer, options option.MultiplexOptions) (*Client, error) {
|
||||||
if !options.Enabled {
|
if !options.Enabled {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -120,17 +120,16 @@ func (c *Client) offer() (abstractSession, error) {
|
|||||||
sessions = append(sessions, element.Value)
|
sessions = append(sessions, element.Value)
|
||||||
element = element.Next()
|
element = element.Next()
|
||||||
}
|
}
|
||||||
sLen := len(sessions)
|
session := common.MinBy(common.Filter(sessions, abstractSession.CanTakeNewRequest), abstractSession.NumStreams)
|
||||||
if sLen == 0 {
|
if session == nil {
|
||||||
return c.offerNew()
|
return c.offerNew()
|
||||||
}
|
}
|
||||||
session := common.MinBy(sessions, abstractSession.NumStreams)
|
|
||||||
numStreams := session.NumStreams()
|
numStreams := session.NumStreams()
|
||||||
if numStreams == 0 {
|
if numStreams == 0 {
|
||||||
return session, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
if c.maxConnections > 0 {
|
if c.maxConnections > 0 {
|
||||||
if sLen >= c.maxConnections || numStreams < c.minStreams {
|
if len(sessions) >= c.maxConnections || numStreams < c.minStreams {
|
||||||
return session, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -159,6 +158,15 @@ func (c *Client) offerNew() (abstractSession, error) {
|
|||||||
return session, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) Reset() {
|
||||||
|
c.access.Lock()
|
||||||
|
defer c.access.Unlock()
|
||||||
|
for _, session := range c.connections.Array() {
|
||||||
|
session.Close()
|
||||||
|
}
|
||||||
|
c.connections.Init()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) Close() error {
|
func (c *Client) Close() error {
|
||||||
c.access.Lock()
|
c.access.Lock()
|
||||||
defer c.access.Unlock()
|
defer c.access.Unlock()
|
||||||
|
235
common/mux/h2mux.go
Normal file
235
common/mux/h2mux.go
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/transport/v2rayhttp"
|
||||||
|
"github.com/sagernet/sing/common/atomic"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
"github.com/sagernet/sing/common/bufio"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
|
"golang.org/x/net/http2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const idleTimeout = 30 * time.Second
|
||||||
|
|
||||||
|
var _ abstractSession = (*H2MuxServerSession)(nil)
|
||||||
|
|
||||||
|
type H2MuxServerSession struct {
|
||||||
|
server http2.Server
|
||||||
|
active atomic.Int32
|
||||||
|
conn net.Conn
|
||||||
|
inbound chan net.Conn
|
||||||
|
done chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewH2MuxServer(conn net.Conn) *H2MuxServerSession {
|
||||||
|
session := &H2MuxServerSession{
|
||||||
|
conn: conn,
|
||||||
|
inbound: make(chan net.Conn),
|
||||||
|
done: make(chan struct{}),
|
||||||
|
server: http2.Server{
|
||||||
|
IdleTimeout: idleTimeout,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
session.server.ServeConn(conn, &http2.ServeConnOpts{
|
||||||
|
Handler: session,
|
||||||
|
})
|
||||||
|
_ = session.Close()
|
||||||
|
}()
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxServerSession) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
s.active.Add(1)
|
||||||
|
defer s.active.Add(-1)
|
||||||
|
writer.WriteHeader(http.StatusOK)
|
||||||
|
conn := newHTTP2Wrapper(&v2rayhttp.ServerHTTPConn{
|
||||||
|
HTTP2Conn: v2rayhttp.NewHTTPConn(request.Body, writer),
|
||||||
|
Flusher: writer.(http.Flusher),
|
||||||
|
})
|
||||||
|
s.inbound <- conn
|
||||||
|
select {
|
||||||
|
case <-conn.done:
|
||||||
|
case <-s.done:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxServerSession) Open() (net.Conn, error) {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxServerSession) Accept() (net.Conn, error) {
|
||||||
|
select {
|
||||||
|
case conn := <-s.inbound:
|
||||||
|
return conn, nil
|
||||||
|
case <-s.done:
|
||||||
|
return nil, os.ErrClosed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxServerSession) NumStreams() int {
|
||||||
|
return int(s.active.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxServerSession) Close() error {
|
||||||
|
select {
|
||||||
|
case <-s.done:
|
||||||
|
default:
|
||||||
|
close(s.done)
|
||||||
|
}
|
||||||
|
return s.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxServerSession) IsClosed() bool {
|
||||||
|
select {
|
||||||
|
case <-s.done:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxServerSession) CanTakeNewRequest() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type h2MuxConnWrapper struct {
|
||||||
|
N.ExtendedConn
|
||||||
|
done chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newHTTP2Wrapper(conn net.Conn) *h2MuxConnWrapper {
|
||||||
|
return &h2MuxConnWrapper{
|
||||||
|
ExtendedConn: bufio.NewExtendedConn(conn),
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *h2MuxConnWrapper) Write(p []byte) (n int, err error) {
|
||||||
|
select {
|
||||||
|
case <-w.done:
|
||||||
|
return 0, net.ErrClosed
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return w.ExtendedConn.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *h2MuxConnWrapper) WriteBuffer(buffer *buf.Buffer) error {
|
||||||
|
select {
|
||||||
|
case <-w.done:
|
||||||
|
return net.ErrClosed
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return w.ExtendedConn.WriteBuffer(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *h2MuxConnWrapper) Close() error {
|
||||||
|
select {
|
||||||
|
case <-w.done:
|
||||||
|
default:
|
||||||
|
close(w.done)
|
||||||
|
}
|
||||||
|
return w.ExtendedConn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *h2MuxConnWrapper) Upstream() any {
|
||||||
|
return w.ExtendedConn
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ abstractSession = (*H2MuxClientSession)(nil)
|
||||||
|
|
||||||
|
type H2MuxClientSession struct {
|
||||||
|
transport *http2.Transport
|
||||||
|
clientConn *http2.ClientConn
|
||||||
|
done chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewH2MuxClient(conn net.Conn) (*H2MuxClientSession, error) {
|
||||||
|
session := &H2MuxClientSession{
|
||||||
|
transport: &http2.Transport{
|
||||||
|
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||||
|
return conn, nil
|
||||||
|
},
|
||||||
|
ReadIdleTimeout: idleTimeout,
|
||||||
|
},
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
session.transport.ConnPool = session
|
||||||
|
clientConn, err := session.transport.NewClientConn(conn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
session.clientConn = clientConn
|
||||||
|
return session, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxClientSession) GetClientConn(req *http.Request, addr string) (*http2.ClientConn, error) {
|
||||||
|
return s.clientConn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxClientSession) MarkDead(conn *http2.ClientConn) {
|
||||||
|
s.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxClientSession) Open() (net.Conn, error) {
|
||||||
|
pipeInReader, pipeInWriter := io.Pipe()
|
||||||
|
request := &http.Request{
|
||||||
|
Method: http.MethodConnect,
|
||||||
|
Body: pipeInReader,
|
||||||
|
URL: &url.URL{Scheme: "https", Host: "localhost"},
|
||||||
|
}
|
||||||
|
conn := v2rayhttp.NewLateHTTPConn(pipeInWriter)
|
||||||
|
go func() {
|
||||||
|
response, err := s.transport.RoundTrip(request)
|
||||||
|
if err != nil {
|
||||||
|
conn.Setup(nil, err)
|
||||||
|
} else if response.StatusCode != 200 {
|
||||||
|
response.Body.Close()
|
||||||
|
conn.Setup(nil, E.New("unexpected status: ", response.StatusCode, " ", response.Status))
|
||||||
|
} else {
|
||||||
|
conn.Setup(response.Body, nil)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxClientSession) Accept() (net.Conn, error) {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxClientSession) NumStreams() int {
|
||||||
|
return s.clientConn.State().StreamsActive
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxClientSession) Close() error {
|
||||||
|
select {
|
||||||
|
case <-s.done:
|
||||||
|
default:
|
||||||
|
close(s.done)
|
||||||
|
}
|
||||||
|
return s.clientConn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxClientSession) IsClosed() bool {
|
||||||
|
select {
|
||||||
|
case <-s.done:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return s.clientConn.State().Closed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *H2MuxClientSession) CanTakeNewRequest() bool {
|
||||||
|
return s.clientConn.CanTakeNewRequest()
|
||||||
|
}
|
@ -25,6 +25,7 @@ var Destination = M.Socksaddr{
|
|||||||
const (
|
const (
|
||||||
ProtocolSMux Protocol = iota
|
ProtocolSMux Protocol = iota
|
||||||
ProtocolYAMux
|
ProtocolYAMux
|
||||||
|
ProtocolH2Mux
|
||||||
)
|
)
|
||||||
|
|
||||||
type Protocol byte
|
type Protocol byte
|
||||||
@ -35,8 +36,10 @@ func ParseProtocol(name string) (Protocol, error) {
|
|||||||
return ProtocolSMux, nil
|
return ProtocolSMux, nil
|
||||||
case "yamux":
|
case "yamux":
|
||||||
return ProtocolYAMux, nil
|
return ProtocolYAMux, nil
|
||||||
|
case "h2mux":
|
||||||
|
return ProtocolH2Mux, nil
|
||||||
default:
|
default:
|
||||||
return ProtocolYAMux, E.New("unknown multiplex protocol: ", name)
|
return ProtocolSMux, E.New("unknown multiplex protocol: ", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +52,13 @@ func (p Protocol) newServer(conn net.Conn) (abstractSession, error) {
|
|||||||
}
|
}
|
||||||
return &smuxSession{session}, nil
|
return &smuxSession{session}, nil
|
||||||
case ProtocolYAMux:
|
case ProtocolYAMux:
|
||||||
return yamux.Server(conn, yaMuxConfig())
|
session, err := yamux.Server(conn, yaMuxConfig())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &yamuxSession{session}, nil
|
||||||
|
case ProtocolH2Mux:
|
||||||
|
return NewH2MuxServer(conn), nil
|
||||||
default:
|
default:
|
||||||
panic("unknown protocol")
|
panic("unknown protocol")
|
||||||
}
|
}
|
||||||
@ -64,7 +73,13 @@ func (p Protocol) newClient(conn net.Conn) (abstractSession, error) {
|
|||||||
}
|
}
|
||||||
return &smuxSession{session}, nil
|
return &smuxSession{session}, nil
|
||||||
case ProtocolYAMux:
|
case ProtocolYAMux:
|
||||||
return yamux.Client(conn, yaMuxConfig())
|
session, err := yamux.Client(conn, yaMuxConfig())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &yamuxSession{session}, nil
|
||||||
|
case ProtocolH2Mux:
|
||||||
|
return NewH2MuxClient(conn)
|
||||||
default:
|
default:
|
||||||
panic("unknown protocol")
|
panic("unknown protocol")
|
||||||
}
|
}
|
||||||
@ -90,6 +105,8 @@ func (p Protocol) String() string {
|
|||||||
return "smux"
|
return "smux"
|
||||||
case ProtocolYAMux:
|
case ProtocolYAMux:
|
||||||
return "yamux"
|
return "yamux"
|
||||||
|
case ProtocolH2Mux:
|
||||||
|
return "h2mux"
|
||||||
default:
|
default:
|
||||||
return "unknown"
|
return "unknown"
|
||||||
}
|
}
|
||||||
@ -115,9 +132,6 @@ func ReadRequest(reader io.Reader) (*Request, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if protocol > byte(ProtocolYAMux) {
|
|
||||||
return nil, E.New("unsupported protocol: ", protocol)
|
|
||||||
}
|
|
||||||
return &Request{Protocol: Protocol(protocol)}, nil
|
return &Request{Protocol: Protocol(protocol)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@ import (
|
|||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
"github.com/sagernet/smux"
|
"github.com/sagernet/smux"
|
||||||
|
|
||||||
|
"github.com/hashicorp/yamux"
|
||||||
)
|
)
|
||||||
|
|
||||||
type abstractSession interface {
|
type abstractSession interface {
|
||||||
@ -17,6 +19,7 @@ type abstractSession interface {
|
|||||||
NumStreams() int
|
NumStreams() int
|
||||||
Close() error
|
Close() error
|
||||||
IsClosed() bool
|
IsClosed() bool
|
||||||
|
CanTakeNewRequest() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ abstractSession = (*smuxSession)(nil)
|
var _ abstractSession = (*smuxSession)(nil)
|
||||||
@ -33,6 +36,18 @@ func (s *smuxSession) Accept() (net.Conn, error) {
|
|||||||
return s.AcceptStream()
|
return s.AcceptStream()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *smuxSession) CanTakeNewRequest() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type yamuxSession struct {
|
||||||
|
*yamux.Session
|
||||||
|
}
|
||||||
|
|
||||||
|
func (y *yamuxSession) CanTakeNewRequest() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
type protocolConn struct {
|
type protocolConn struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
protocol Protocol
|
protocol Protocol
|
||||||
|
@ -28,6 +28,7 @@ Multiplex protocol.
|
|||||||
|----------|------------------------------------|
|
|----------|------------------------------------|
|
||||||
| smux | https://github.com/xtaci/smux |
|
| smux | https://github.com/xtaci/smux |
|
||||||
| yamux | https://github.com/hashicorp/yamux |
|
| yamux | https://github.com/hashicorp/yamux |
|
||||||
|
| h2mux | https://golang.org/x/net/http2 |
|
||||||
|
|
||||||
SMux is used by default.
|
SMux is used by default.
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|-------|------------------------------------|
|
|-------|------------------------------------|
|
||||||
| smux | https://github.com/xtaci/smux |
|
| smux | https://github.com/xtaci/smux |
|
||||||
| yamux | https://github.com/hashicorp/yamux |
|
| yamux | https://github.com/hashicorp/yamux |
|
||||||
|
| h2mux | https://golang.org/x/net/http2 |
|
||||||
|
|
||||||
默认使用 SMux。
|
默认使用 SMux。
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ type Shadowsocks struct {
|
|||||||
serverAddr M.Socksaddr
|
serverAddr M.Socksaddr
|
||||||
plugin sip003.Plugin
|
plugin sip003.Plugin
|
||||||
uotClient *uot.Client
|
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) {
|
func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksOutboundOptions) (*Shadowsocks, error) {
|
||||||
@ -127,8 +127,15 @@ func (h *Shadowsocks) NewPacketConnection(ctx context.Context, conn N.PacketConn
|
|||||||
return NewPacketConnection(ctx, h, conn, metadata)
|
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 {
|
func (h *Shadowsocks) Close() error {
|
||||||
return common.Close(h.multiplexDialer)
|
return common.Close(common.PtrOrNil(h.multiplexDialer))
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ N.Dialer = (*shadowsocksDialer)(nil)
|
var _ N.Dialer = (*shadowsocksDialer)(nil)
|
||||||
|
@ -27,7 +27,7 @@ type Trojan struct {
|
|||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
serverAddr M.Socksaddr
|
serverAddr M.Socksaddr
|
||||||
key [56]byte
|
key [56]byte
|
||||||
multiplexDialer N.Dialer
|
multiplexDialer *mux.Client
|
||||||
tlsConfig tls.Config
|
tlsConfig tls.Config
|
||||||
transport adapter.V2RayClientTransport
|
transport adapter.V2RayClientTransport
|
||||||
}
|
}
|
||||||
@ -103,8 +103,15 @@ func (h *Trojan) NewPacketConnection(ctx context.Context, conn N.PacketConn, met
|
|||||||
return NewPacketConnection(ctx, h, conn, metadata)
|
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 {
|
func (h *Trojan) Close() error {
|
||||||
return common.Close(h.multiplexDialer, h.transport)
|
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
|
||||||
}
|
}
|
||||||
|
|
||||||
type trojanDialer Trojan
|
type trojanDialer Trojan
|
||||||
|
@ -27,7 +27,7 @@ type VMess struct {
|
|||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
client *vmess.Client
|
client *vmess.Client
|
||||||
serverAddr M.Socksaddr
|
serverAddr M.Socksaddr
|
||||||
multiplexDialer N.Dialer
|
multiplexDialer *mux.Client
|
||||||
tlsConfig tls.Config
|
tlsConfig tls.Config
|
||||||
transport adapter.V2RayClientTransport
|
transport adapter.V2RayClientTransport
|
||||||
packetAddr bool
|
packetAddr bool
|
||||||
@ -97,8 +97,15 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
|
|||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *VMess) InterfaceUpdated() error {
|
||||||
|
if h.multiplexDialer != nil {
|
||||||
|
h.multiplexDialer.Reset()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (h *VMess) Close() error {
|
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) {
|
func (h *VMess) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
19
test/go.mod
19
test/go.mod
@ -9,9 +9,9 @@ replace github.com/sagernet/sing-box => ../
|
|||||||
require (
|
require (
|
||||||
github.com/docker/docker v20.10.18+incompatible
|
github.com/docker/docker v20.10.18+incompatible
|
||||||
github.com/docker/go-connections v0.4.0
|
github.com/docker/go-connections v0.4.0
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible
|
github.com/gofrs/uuid/v5 v5.0.0
|
||||||
github.com/sagernet/sing v0.2.4-0.20230418025125-f196b4303e31
|
github.com/sagernet/sing v0.2.4-0.20230419153323-5fae6fa434c1
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d
|
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507
|
||||||
github.com/spyzhov/ajson v0.7.1
|
github.com/spyzhov/ajson v0.7.1
|
||||||
github.com/stretchr/testify v1.8.2
|
github.com/stretchr/testify v1.8.2
|
||||||
go.uber.org/goleak v1.2.0
|
go.uber.org/goleak v1.2.0
|
||||||
@ -36,7 +36,6 @@ require (
|
|||||||
github.com/go-chi/cors v1.2.1 // indirect
|
github.com/go-chi/cors v1.2.1 // indirect
|
||||||
github.com/go-chi/render v1.0.2 // indirect
|
github.com/go-chi/render v1.0.2 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // 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/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang/mock v1.6.0 // indirect
|
github.com/golang/mock v1.6.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.2 // 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/logrusorgru/aurora v2.0.3+incompatible // indirect
|
||||||
github.com/mholt/acmez v1.1.0 // indirect
|
github.com/mholt/acmez v1.1.0 // indirect
|
||||||
github.com/miekg/dns v1.1.53 // 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/morikuni/aec v1.0.0 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
|
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
|
||||||
github.com/ooni/go-libtor v1.1.7 // indirect
|
github.com/ooni/go-libtor v1.1.7 // indirect
|
||||||
@ -71,10 +70,10 @@ require (
|
|||||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
||||||
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 // 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/reality v0.0.0-20230406110435-ee17307e7691 // indirect
|
||||||
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322 // indirect
|
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc // indirect
|
||||||
github.com/sagernet/sing-shadowtls v0.1.0 // indirect
|
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b // indirect
|
||||||
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302 // indirect
|
github.com/sagernet/sing-tun v0.1.4-0.20230420014302-db67add64fae // indirect
|
||||||
github.com/sagernet/sing-vmess v0.1.3 // 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/smux v0.0.0-20230312102458-337ec2a5af37 // indirect
|
||||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // 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/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect
|
||||||
@ -103,5 +102,3 @@ require (
|
|||||||
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect
|
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect
|
||||||
lukechampine.com/blake3 v1.1.7 // indirect
|
lukechampine.com/blake3 v1.1.7 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
//replace github.com/sagernet/sing => ../../sing
|
|
||||||
|
30
test/go.sum
30
test/go.sum
@ -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-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 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
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 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
|
||||||
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
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/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 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
|
||||||
github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
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-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
|
||||||
github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c/go.mod h1:9OcmHNQQUTbk4XCffrLgN1NEKc2mh5u++biHVrvHsSU=
|
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 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
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/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.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.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.20230419153323-5fae6fa434c1 h1:CdzNL25lzfVo0NMeghPqsupNsWvkzrbrUt5t8DoDPcQ=
|
||||||
github.com/sagernet/sing v0.2.4-0.20230418025125-f196b4303e31/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
github.com/sagernet/sing v0.2.4-0.20230419153323-5fae6fa434c1/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.20230415085626-111ecf799dfc h1:hmbuqKv48SAjiKPoqtJGvS5pEHVPZjTHq9CPwQY2cZ4=
|
||||||
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322/go.mod h1:2wjxSr1Gbecq9A0ESA9cnR399tQTcpCZEOGytekb+qI=
|
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc/go.mod h1:ZKuuqgsHRxDahYrzgSgy4vIAGGuKPlIf4hLcNzYzLkY=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d h1:UUxtLujzp5jmtOXqXpSOGvHwHSZcBveKVDzRJ4GlnFU=
|
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507 h1:bAHZCdWqJkb8LEW98+YsMVDXGRMUVjka8IC+St6ot88=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d/go.mod h1:Co3PJXcaZoLwHGBfT0rbSnn9C7ywc41zVYWtDeoeI/Q=
|
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507/go.mod h1:UJjvQGw0lyYaDGIDvUraL16fwaAEH1WFw1Y6sUcMPog=
|
||||||
github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ=
|
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4=
|
||||||
github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
|
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI=
|
||||||
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302 h1:aPb0T2HQRTG2t7fEwLvFLZSXmhmnBh+SMs2NufhmrsI=
|
github.com/sagernet/sing-tun v0.1.4-0.20230420014302-db67add64fae h1:yNKqOPKX9GnnEMvnm9ZVsIyMuMsU0x6uCJQMwAhGafA=
|
||||||
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302/go.mod h1:bvcVzlf9q9dgxt8qKluW+zOXCFoN1+SpBG3sHTq8/9Q=
|
github.com/sagernet/sing-tun v0.1.4-0.20230420014302-db67add64fae/go.mod h1:F7hYqaFR7RRs0aLj3gHDt+v18mpD5apJwPUfTd4e5HQ=
|
||||||
github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM=
|
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U=
|
||||||
github.com/sagernet/sing-vmess v0.1.3/go.mod h1:GVXqAHwe9U21uS+Voh4YBIrADQyE4F9v0ayGSixSQAE=
|
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 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
|
||||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0=
|
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=
|
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE=
|
||||||
|
@ -29,6 +29,10 @@ func TestShadowsocksMux(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShadowsockH2Mux(t *testing.T) {
|
||||||
|
testShadowsocksMux(t, mux.ProtocolH2Mux.String())
|
||||||
|
}
|
||||||
|
|
||||||
func testShadowsocksMux(t *testing.T, protocol string) {
|
func testShadowsocksMux(t *testing.T, protocol string) {
|
||||||
method := shadowaead_2022.List[0]
|
method := shadowaead_2022.List[0]
|
||||||
password := mkBase64(t, 16)
|
password := mkBase64(t, 16)
|
||||||
|
@ -19,7 +19,7 @@ func TestUDPNatClose(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
connCtx, connCancel := common.ContextWithCancelCause(context.Background())
|
connCtx, connCancel := common.ContextWithCancelCause(context.Background())
|
||||||
defer connCancel(net.ErrClosed)
|
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 {
|
service.NewPacket(ctx, 0, buf.As([]byte("Hello")), M.Metadata{}, func(natConn N.PacketConn) N.PacketWriter {
|
||||||
return &testPacketWriter{}
|
return &testPacketWriter{}
|
||||||
})
|
})
|
||||||
|
@ -199,13 +199,13 @@ func (c *HTTP2Conn) NeedAdditionalReadDeadline() bool {
|
|||||||
|
|
||||||
type ServerHTTPConn struct {
|
type ServerHTTPConn struct {
|
||||||
HTTP2Conn
|
HTTP2Conn
|
||||||
flusher http.Flusher
|
Flusher http.Flusher
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ServerHTTPConn) Write(b []byte) (n int, err error) {
|
func (c *ServerHTTPConn) Write(b []byte) (n int, err error) {
|
||||||
n, err = c.writer.Write(b)
|
n, err = c.writer.Write(b)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.flusher.Flush()
|
c.Flusher.Flush()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -246,6 +246,11 @@ func (w *HTTP2ConnWrapper) CloseWrapper() {
|
|||||||
w.closed = true
|
w.closed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *HTTP2ConnWrapper) Close() error {
|
||||||
|
w.CloseWrapper()
|
||||||
|
return w.ExtendedConn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
func (w *HTTP2ConnWrapper) Upstream() any {
|
func (w *HTTP2ConnWrapper) Upstream() any {
|
||||||
return w.ExtendedConn
|
return w.ExtendedConn
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user