Migrate multiplex and UoT server to inbound &

Add tcp-brutal support for multiplex
This commit is contained in:
世界 2023-11-03 01:47:25 +08:00
parent 58c0759cdf
commit 5b9d1e2ae2
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
63 changed files with 708 additions and 160 deletions

104
adapter/conn_router.go Normal file
View File

@ -0,0 +1,104 @@
package adapter
import (
"context"
"net"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)
type ConnectionRouter interface {
RouteConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error
RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error
}
func NewRouteHandler(
metadata InboundContext,
router ConnectionRouter,
logger logger.ContextLogger,
) UpstreamHandlerAdapter {
return &routeHandlerWrapper{
metadata: metadata,
router: router,
logger: logger,
}
}
func NewRouteContextHandler(
router ConnectionRouter,
logger logger.ContextLogger,
) UpstreamHandlerAdapter {
return &routeContextHandlerWrapper{
router: router,
logger: logger,
}
}
var _ UpstreamHandlerAdapter = (*routeHandlerWrapper)(nil)
type routeHandlerWrapper struct {
metadata InboundContext
router ConnectionRouter
logger logger.ContextLogger
}
func (w *routeHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
myMetadata := w.metadata
if metadata.Source.IsValid() {
myMetadata.Source = metadata.Source
}
if metadata.Destination.IsValid() {
myMetadata.Destination = metadata.Destination
}
return w.router.RouteConnection(ctx, conn, myMetadata)
}
func (w *routeHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
myMetadata := w.metadata
if metadata.Source.IsValid() {
myMetadata.Source = metadata.Source
}
if metadata.Destination.IsValid() {
myMetadata.Destination = metadata.Destination
}
return w.router.RoutePacketConnection(ctx, conn, myMetadata)
}
func (w *routeHandlerWrapper) NewError(ctx context.Context, err error) {
w.logger.ErrorContext(ctx, err)
}
var _ UpstreamHandlerAdapter = (*routeContextHandlerWrapper)(nil)
type routeContextHandlerWrapper struct {
router ConnectionRouter
logger logger.ContextLogger
}
func (w *routeContextHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
myMetadata := ContextFrom(ctx)
if metadata.Source.IsValid() {
myMetadata.Source = metadata.Source
}
if metadata.Destination.IsValid() {
myMetadata.Destination = metadata.Destination
}
return w.router.RouteConnection(ctx, conn, *myMetadata)
}
func (w *routeContextHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
myMetadata := ContextFrom(ctx)
if metadata.Source.IsValid() {
myMetadata.Source = metadata.Source
}
if metadata.Destination.IsValid() {
myMetadata.Destination = metadata.Destination
}
return w.router.RoutePacketConnection(ctx, conn, *myMetadata)
}
func (w *routeContextHandlerWrapper) NewError(ctx context.Context, err error) {
w.logger.ErrorContext(ctx, err)
}

View File

@ -2,14 +2,12 @@ package adapter
import ( import (
"context" "context"
"net"
"net/netip" "net/netip"
"github.com/sagernet/sing-box/common/geoip" "github.com/sagernet/sing-box/common/geoip"
"github.com/sagernet/sing-dns" "github.com/sagernet/sing-dns"
"github.com/sagernet/sing-tun" "github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common/control" "github.com/sagernet/sing/common/control"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service" "github.com/sagernet/sing/service"
mdns "github.com/miekg/dns" mdns "github.com/miekg/dns"
@ -24,8 +22,7 @@ type Router interface {
FakeIPStore() FakeIPStore FakeIPStore() FakeIPStore
RouteConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error ConnectionRouter
RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error
GeoIPReader() *geoip.Reader GeoIPReader() *geoip.Reader
LoadGeosite(code string) (Rule, error) LoadGeosite(code string) (Rule, error)

View File

@ -1,21 +1,42 @@
package mux package mux
import ( import (
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-mux" "github.com/sagernet/sing-mux"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
) )
func NewClientWithOptions(dialer N.Dialer, options option.MultiplexOptions) (*Client, error) { type Client = mux.Client
func NewClientWithOptions(dialer N.Dialer, logger logger.Logger, options option.OutboundMultiplexOptions) (*Client, error) {
if !options.Enabled { if !options.Enabled {
return nil, nil return nil, nil
} }
var brutalOptions mux.BrutalOptions
if options.Brutal != nil && options.Brutal.Enabled {
brutalOptions = mux.BrutalOptions{
Enabled: true,
SendBPS: uint64(options.Brutal.UpMbps * C.MbpsToBps),
ReceiveBPS: uint64(options.Brutal.DownMbps * C.MbpsToBps),
}
if brutalOptions.SendBPS < mux.BrutalMinSpeedBPS {
return nil, E.New("brutal: invalid upload speed")
}
if brutalOptions.ReceiveBPS < mux.BrutalMinSpeedBPS {
return nil, E.New("brutal: invalid download speed")
}
}
return mux.NewClient(mux.Options{ return mux.NewClient(mux.Options{
Dialer: dialer, Dialer: dialer,
Logger: logger,
Protocol: options.Protocol, Protocol: options.Protocol,
MaxConnections: options.MaxConnections, MaxConnections: options.MaxConnections,
MinStreams: options.MinStreams, MinStreams: options.MinStreams,
MaxStreams: options.MaxStreams, MaxStreams: options.MaxStreams,
Padding: options.Padding, Padding: options.Padding,
Brutal: brutalOptions,
}) })
} }

View File

@ -1,14 +0,0 @@
package mux
import (
"github.com/sagernet/sing-mux"
)
type (
Client = mux.Client
)
var (
Destination = mux.Destination
HandleConnection = mux.HandleConnection
)

65
common/mux/router.go Normal file
View File

@ -0,0 +1,65 @@
package mux
import (
"context"
"net"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-mux"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
N "github.com/sagernet/sing/common/network"
)
type Router struct {
router adapter.ConnectionRouter
service *mux.Service
}
func NewRouterWithOptions(router adapter.ConnectionRouter, logger logger.ContextLogger, options option.InboundMultiplexOptions) (adapter.ConnectionRouter, error) {
if !options.Enabled {
return router, nil
}
var brutalOptions mux.BrutalOptions
if options.Brutal != nil && options.Brutal.Enabled {
brutalOptions = mux.BrutalOptions{
Enabled: true,
SendBPS: uint64(options.Brutal.UpMbps * C.MbpsToBps),
ReceiveBPS: uint64(options.Brutal.DownMbps * C.MbpsToBps),
}
if brutalOptions.SendBPS < mux.BrutalMinSpeedBPS {
return nil, E.New("brutal: invalid upload speed")
}
if brutalOptions.ReceiveBPS < mux.BrutalMinSpeedBPS {
return nil, E.New("brutal: invalid download speed")
}
}
service, err := mux.NewService(mux.ServiceOptions{
NewStreamContext: func(ctx context.Context, conn net.Conn) context.Context {
return log.ContextWithNewID(ctx)
},
Logger: logger,
Handler: adapter.NewRouteContextHandler(router, logger),
Padding: options.Padding,
Brutal: brutalOptions,
})
if err != nil {
return nil, err
}
return &Router{router, service}, nil
}
func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
if metadata.Destination == mux.Destination {
return r.service.NewConnection(adapter.WithContext(ctx, &metadata), conn, adapter.UpstreamMetadata(metadata))
} else {
return r.router.RouteConnection(ctx, conn, metadata)
}
}
func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
return r.router.RoutePacketConnection(ctx, conn, metadata)
}

View File

@ -0,0 +1,32 @@
package mux
import (
"context"
"net"
"github.com/sagernet/sing-box/adapter"
vmess "github.com/sagernet/sing-vmess"
"github.com/sagernet/sing/common/logger"
N "github.com/sagernet/sing/common/network"
)
type V2RayLegacyRouter struct {
router adapter.ConnectionRouter
logger logger.ContextLogger
}
func NewV2RayLegacyRouter(router adapter.ConnectionRouter, logger logger.ContextLogger) adapter.ConnectionRouter {
return &V2RayLegacyRouter{router, logger}
}
func (r *V2RayLegacyRouter) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
if metadata.Destination.Fqdn == vmess.MuxDestination.Fqdn {
r.logger.InfoContext(ctx, "inbound legacy multiplex connection")
return vmess.HandleMuxConnection(ctx, conn, adapter.NewRouteHandler(metadata, r.router, r.logger))
}
return r.router.RouteConnection(ctx, conn, metadata)
}
func (r *V2RayLegacyRouter) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
return r.router.RoutePacketConnection(ctx, conn, metadata)
}

53
common/uot/router.go Normal file
View File

@ -0,0 +1,53 @@
package uot
import (
"context"
"net"
"net/netip"
"github.com/sagernet/sing-box/adapter"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/uot"
)
var _ adapter.ConnectionRouter = (*Router)(nil)
type Router struct {
router adapter.ConnectionRouter
logger logger.ContextLogger
}
func NewRouter(router adapter.ConnectionRouter, logger logger.ContextLogger) *Router {
return &Router{router, logger}
}
func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
switch metadata.Destination.Fqdn {
case uot.MagicAddress:
request, err := uot.ReadRequest(conn)
if err != nil {
return E.Cause(err, "read UoT request")
}
if request.IsConnect {
r.logger.InfoContext(ctx, "inbound UoT connect connection to ", request.Destination)
} else {
r.logger.InfoContext(ctx, "inbound UoT connection to ", request.Destination)
}
metadata.Domain = metadata.Destination.Fqdn
metadata.Destination = request.Destination
return r.router.RoutePacketConnection(ctx, uot.NewConn(conn, *request), metadata)
case uot.LegacyMagicAddress:
r.logger.InfoContext(ctx, "inbound legacy UoT connection")
metadata.Domain = metadata.Destination.Fqdn
metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()}
return r.RoutePacketConnection(ctx, uot.NewConn(conn, uot.Request{}), metadata)
}
return r.router.RouteConnection(ctx, conn, metadata)
}
func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
return r.router.RoutePacketConnection(ctx, conn, metadata)
}

3
constant/speed.go Normal file
View File

@ -0,0 +1,3 @@
package constant
const MbpsToBps = 125000

View File

@ -62,7 +62,7 @@ Hysteria 用户
#### ignore_client_bandwidth #### ignore_client_bandwidth
命令客户端使用 BBR 流量控制算法而不是 Hysteria CC。 命令客户端使用 BBR 拥塞控制算法而不是 Hysteria CC。
`up_mbps``down_mbps` 冲突。 `up_mbps``down_mbps` 冲突。

View File

@ -8,7 +8,8 @@
... // Listen Fields ... // Listen Fields
"method": "2022-blake3-aes-128-gcm", "method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg==" "password": "8JCsPssfgS8tiRwiMlhARg==",
"multiplex": {}
} }
``` ```
@ -23,7 +24,8 @@
"name": "sekai", "name": "sekai",
"password": "PCD2Z4o12bKUoFa3cC97Hw==" "password": "PCD2Z4o12bKUoFa3cC97Hw=="
} }
] ],
"multiplex": {}
} }
``` ```
@ -41,7 +43,8 @@
"server_port": 8080, "server_port": 8080,
"password": "PCD2Z4o12bKUoFa3cC97Hw==" "password": "PCD2Z4o12bKUoFa3cC97Hw=="
} }
] ],
"multiplex": {}
} }
``` ```
@ -82,3 +85,7 @@ Both if empty.
| none | / | | none | / |
| 2022 methods | `sing-box generate rand --base64 <Key Length>` | | 2022 methods | `sing-box generate rand --base64 <Key Length>` |
| other methods | any string | | other methods | any string |
#### multiplex
See [Multiplex](/configuration/shared/multiplex#inbound) for details.

View File

@ -8,7 +8,8 @@
... // 监听字段 ... // 监听字段
"method": "2022-blake3-aes-128-gcm", "method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg==" "password": "8JCsPssfgS8tiRwiMlhARg==",
"multiplex": {}
} }
``` ```
@ -23,7 +24,8 @@
"name": "sekai", "name": "sekai",
"password": "PCD2Z4o12bKUoFa3cC97Hw==" "password": "PCD2Z4o12bKUoFa3cC97Hw=="
} }
] ],
"multiplex": {}
} }
``` ```
@ -41,7 +43,8 @@
"server_port": 8080, "server_port": 8080,
"password": "PCD2Z4o12bKUoFa3cC97Hw==" "password": "PCD2Z4o12bKUoFa3cC97Hw=="
} }
] ],
"multiplex": {}
} }
``` ```
@ -82,3 +85,7 @@ See [Listen Fields](/configuration/shared/listen) for details.
| none | / | | none | / |
| 2022 methods | `sing-box generate rand --base64 <密钥长度>` | | 2022 methods | `sing-box generate rand --base64 <密钥长度>` |
| other methods | 任意字符串 | | other methods | 任意字符串 |
#### multiplex
参阅 [多路复用](/zh/configuration/shared/multiplex#inbound)。

View File

@ -24,6 +24,7 @@
"server_port": 8081 "server_port": 8081
} }
}, },
"multiplex": {},
"transport": {} "transport": {}
} }
``` ```
@ -58,6 +59,10 @@ Fallback server configuration for specified ALPN.
If not empty, TLS fallback requests with ALPN not in this table will be rejected. If not empty, TLS fallback requests with ALPN not in this table will be rejected.
#### multiplex
See [Multiplex](/configuration/shared/multiplex#inbound) for details.
#### transport #### transport
V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport). V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport).

View File

@ -24,6 +24,7 @@
"server_port": 8081 "server_port": 8081
} }
}, },
"multiplex": {},
"transport": {} "transport": {}
} }
``` ```
@ -60,6 +61,10 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
如果不为空ALPN 不在此列表中的 TLS 回退请求将被拒绝。 如果不为空ALPN 不在此列表中的 TLS 回退请求将被拒绝。
#### multiplex
参阅 [多路复用](/zh/configuration/shared/multiplex#inbound)。
#### transport #### transport
V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。 V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。

View File

@ -48,7 +48,7 @@ TUIC 用户密码
#### congestion_control #### congestion_control
QUIC 流量控制算法 QUIC 拥塞控制算法
可选值: `cubic`, `new_reno`, `bbr` 可选值: `cubic`, `new_reno`, `bbr`

View File

@ -15,6 +15,7 @@
} }
], ],
"tls": {}, "tls": {},
"multiplex": {},
"transport": {} "transport": {}
} }
``` ```
@ -49,6 +50,10 @@ Available values:
TLS configuration, see [TLS](/configuration/shared/tls/#inbound). TLS configuration, see [TLS](/configuration/shared/tls/#inbound).
#### multiplex
See [Multiplex](/configuration/shared/multiplex#inbound) for details.
#### transport #### transport
V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport). V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport).

View File

@ -15,6 +15,7 @@
} }
], ],
"tls": {}, "tls": {},
"multiplex": {},
"transport": {} "transport": {}
} }
``` ```
@ -49,6 +50,10 @@ VLESS 子协议。
TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。 TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
#### multiplex
参阅 [多路复用](/zh/configuration/shared/multiplex#inbound)。
#### transport #### transport
V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。 V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。

View File

@ -15,6 +15,7 @@
} }
], ],
"tls": {}, "tls": {},
"multiplex": {},
"transport": {} "transport": {}
} }
``` ```
@ -44,6 +45,10 @@ VMess users.
TLS configuration, see [TLS](/configuration/shared/tls/#inbound). TLS configuration, see [TLS](/configuration/shared/tls/#inbound).
#### multiplex
See [Multiplex](/configuration/shared/multiplex#inbound) for details.
#### transport #### transport
V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport). V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport).

View File

@ -15,6 +15,7 @@
} }
], ],
"tls": {}, "tls": {},
"multiplex": {},
"transport": {} "transport": {}
} }
``` ```
@ -44,6 +45,10 @@ VMess 用户。
TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。 TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
#### multiplex
参阅 [多路复用](/zh/configuration/shared/multiplex#inbound)。
#### transport #### transport
V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。 V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。

View File

@ -44,7 +44,7 @@
最大带宽。 最大带宽。
如果为空,将使用 BBR 流量控制算法而不是 Hysteria CC。 如果为空,将使用 BBR 拥塞控制算法而不是 Hysteria CC。
#### obfs.type #### obfs.type

View File

@ -95,7 +95,7 @@ Conflict with `multiplex`.
#### multiplex #### multiplex
Multiplex configuration, see [Multiplex](/configuration/shared/multiplex). See [Multiplex](/configuration/shared/multiplex#outbound) for details.
### Dial Fields ### Dial Fields

View File

@ -95,7 +95,7 @@ UDP over TCP 配置。
#### multiplex #### multiplex
多路复用配置, 参阅 [多路复用](/zh/configuration/shared/multiplex)。 参阅 [多路复用](/zh/configuration/shared/multiplex#outbound)。
### 拨号字段 ### 拨号字段

View File

@ -51,7 +51,7 @@ TLS configuration, see [TLS](/configuration/shared/tls/#outbound).
#### multiplex #### multiplex
Multiplex configuration, see [Multiplex](/configuration/shared/multiplex). See [Multiplex](/configuration/shared/multiplex#outbound) for details.
#### transport #### transport

View File

@ -51,7 +51,7 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#outbound)。
#### multiplex #### multiplex
多路复用配置, 参阅 [多路复用](/zh/configuration/shared/multiplex)。 参阅 [多路复用](/zh/configuration/shared/multiplex#outbound)。
#### transport #### transport

View File

@ -51,7 +51,7 @@ TUIC 用户密码
#### congestion_control #### congestion_control
QUIC 流量控制算法 QUIC 拥塞控制算法
可选值: `cubic`, `new_reno`, `bbr` 可选值: `cubic`, `new_reno`, `bbr`

View File

@ -12,6 +12,7 @@
"network": "tcp", "network": "tcp",
"tls": {}, "tls": {},
"packet_encoding": "", "packet_encoding": "",
"multiplex": {},
"transport": {}, "transport": {},
... // Dial Fields ... // Dial Fields
@ -68,6 +69,10 @@ UDP packet encoding, xudp is used by default.
| packetaddr | Supported by v2ray 5+ | | packetaddr | Supported by v2ray 5+ |
| xudp | Supported by xray | | xudp | Supported by xray |
#### multiplex
See [Multiplex](/configuration/shared/multiplex#outbound) for details.
#### transport #### transport
V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport). V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport).

View File

@ -12,6 +12,7 @@
"network": "tcp", "network": "tcp",
"tls": {}, "tls": {},
"packet_encoding": "", "packet_encoding": "",
"multiplex": {},
"transport": {}, "transport": {},
... // 拨号字段 ... // 拨号字段
@ -68,6 +69,10 @@ UDP 包编码,默认使用 xudp。
| packetaddr | 由 v2ray 5+ 支持 | | packetaddr | 由 v2ray 5+ 支持 |
| xudp | 由 xray 支持 | | xudp | 由 xray 支持 |
#### multiplex
参阅 [多路复用](/zh/configuration/shared/multiplex#outbound)。
#### transport #### transport
V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。 V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。

View File

@ -15,8 +15,8 @@
"network": "tcp", "network": "tcp",
"tls": {}, "tls": {},
"packet_encoding": "", "packet_encoding": "",
"multiplex": {},
"transport": {}, "transport": {},
"multiplex": {},
... // Dial Fields ... // Dial Fields
} }
@ -96,7 +96,7 @@ UDP packet encoding.
#### multiplex #### multiplex
Multiplex configuration, see [Multiplex](/configuration/shared/multiplex). See [Multiplex](/configuration/shared/multiplex#outbound) for details.
#### transport #### transport

View File

@ -96,7 +96,7 @@ UDP 包编码。
#### multiplex #### multiplex
多路复用配置, 参阅 [多路复用](/zh/configuration/shared/multiplex)。 参阅 [多路复用](/zh/configuration/shared/multiplex#outbound)。
#### transport #### transport

View File

@ -1,8 +1,14 @@
### Server Requirements ### Inbound
`sing-box` :) ```json
{
"enabled": true,
"padding": false,
"brutal": {}
}
```
### Structure ### Outbound
```json ```json
{ {
@ -11,11 +17,27 @@
"max_connections": 4, "max_connections": 4,
"min_streams": 4, "min_streams": 4,
"max_streams": 0, "max_streams": 0,
"padding": false "padding": false,
"brutal": {}
} }
``` ```
### Fields
### Inbound Fields
#### enabled
Enable multiplex support.
#### padding
If enabled, non-padded connections will be rejected.
#### brutal
See [TCP Brutal](/configuration/shared/tcp-brutal) for details.
### Outbound Fields
#### enabled #### enabled
@ -59,3 +81,6 @@ Conflict with `max_connections` and `min_streams`.
Enable padding. Enable padding.
#### brutal
See [TCP Brutal](/configuration/shared/tcp-brutal) for details.

View File

@ -1,8 +1,14 @@
### 服务器要求 ### 入站
`sing-box` :) ```json
{
"enabled": true,
"padding": false,
"brutal": {}
}
```
### 结构 ### 出站
```json ```json
{ {
@ -10,11 +16,27 @@
"protocol": "smux", "protocol": "smux",
"max_connections": 4, "max_connections": 4,
"min_streams": 4, "min_streams": 4,
"max_streams": 0 "max_streams": 0,
"padding": false,
"brutal": {}
} }
``` ```
### 字段 ### 入站字段
#### enabled
启用多路复用支持。
#### padding
如果启用,将拒绝非填充连接。
#### brutal
参阅 [TCP Brutal](/zh/configuration/shared/tcp-brutal)。
### 出站字段
#### enabled #### enabled
@ -58,3 +80,6 @@
启用填充。 启用填充。
#### brutal
参阅 [TCP Brutal](/zh/configuration/shared/tcp-brutal)。

View File

@ -0,0 +1,28 @@
### Server Requirements
* Linux
* `brutal` congestion control algorithm kernel module installed
See [tcp-brutal](https://github.com/apernet/tcp-brutal) for details.
### Structure
```json
{
"enabled": true,
"up_mbps": 100,
"down_mbps": 100
}
```
### Fields
#### enabled
Enable TCP Brutal congestion control algorithm。
#### up_mbps, down_mbps
==Required==
Upload and download bandwidth, in Mbps.

View File

@ -0,0 +1,28 @@
### 服务器要求
* Linux
* `brutal` 拥塞控制算法内核模块已安装
参阅 [tcp-brutal](https://github.com/apernet/tcp-brutal)。
### 结构
```json
{
"enabled": true,
"up_mbps": 100,
"down_mbps": 100
}
```
### 字段
#### enabled
启用 TCP Brutal 拥塞控制算法。
#### up_mbps, down_mbps
==必填==
上传和下载带宽,以 Mbps 为单位。

2
go.mod
View File

@ -28,7 +28,7 @@ require (
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2 github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2
github.com/sagernet/sing-dns v0.1.10 github.com/sagernet/sing-dns v0.1.10
github.com/sagernet/sing-mux v0.1.3 github.com/sagernet/sing-mux v0.1.4-0.20231105044304-ae2745a33479
github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6
github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks v0.2.5
github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/sagernet/sing-shadowsocks2 v0.1.4

4
go.sum
View File

@ -118,8 +118,8 @@ github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2 h1:PW18IgRodvppd0
github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg=
github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI= github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI=
github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c=
github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= github.com/sagernet/sing-mux v0.1.4-0.20231105044304-ae2745a33479 h1:h6ANTA5wbP5BSqbjOT7s1OKLZgdsLqiXO564KQqY2i4=
github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= github.com/sagernet/sing-mux v0.1.4-0.20231105044304-ae2745a33479/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0=
github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 h1:w+TUbIZKZFSdf/AUa/y33kY9xaLeNGz/tBNcNhqpqfg= github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 h1:w+TUbIZKZFSdf/AUa/y33kY9xaLeNGz/tBNcNhqpqfg=
github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6/go.mod h1:1M7xP4802K9Kz6BQ7LlA7UeCapWvWlH1Htmk2bAqkWc= github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6/go.mod h1:1M7xP4802K9Kz6BQ7LlA7UeCapWvWlH1Htmk2bAqkWc=
github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY=

View File

@ -22,7 +22,7 @@ type myInboundAdapter struct {
protocol string protocol string
network []string network []string
ctx context.Context ctx context.Context
router adapter.Router router adapter.ConnectionRouter
logger log.ContextLogger logger log.ContextLogger
tag string tag string
listenOptions option.ListenOptions listenOptions option.ListenOptions

View File

@ -8,6 +8,7 @@ import (
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/common/tls"
"github.com/sagernet/sing-box/common/uot"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
@ -35,7 +36,7 @@ func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogge
protocol: C.TypeHTTP, protocol: C.TypeHTTP,
network: []string{N.NetworkTCP}, network: []string{N.NetworkTCP},
ctx: ctx, ctx: ctx,
router: router, router: uot.NewRouter(router, logger),
logger: logger, logger: logger,
tag: tag, tag: tag,
listenOptions: options.ListenOptions, listenOptions: options.ListenOptions,

View File

@ -7,6 +7,7 @@ import (
"os" "os"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/uot"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
@ -37,7 +38,7 @@ func NewMixed(ctx context.Context, router adapter.Router, logger log.ContextLogg
protocol: C.TypeMixed, protocol: C.TypeMixed,
network: []string{N.NetworkTCP}, network: []string{N.NetworkTCP},
ctx: ctx, ctx: ctx,
router: router, router: uot.NewRouter(router, logger),
logger: logger, logger: logger,
tag: tag, tag: tag,
listenOptions: options.ListenOptions, listenOptions: options.ListenOptions,

View File

@ -13,6 +13,7 @@ import (
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/common/tls"
"github.com/sagernet/sing-box/common/uot"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/include" "github.com/sagernet/sing-box/include"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
@ -43,7 +44,7 @@ func NewNaive(ctx context.Context, router adapter.Router, logger log.ContextLogg
protocol: C.TypeNaive, protocol: C.TypeNaive,
network: options.Network.Build(), network: options.Network.Build(),
ctx: ctx, ctx: ctx,
router: router, router: uot.NewRouter(router, logger),
logger: logger, logger: logger,
tag: tag, tag: tag,
listenOptions: options.ListenOptions, listenOptions: options.ListenOptions,

View File

@ -6,6 +6,8 @@ import (
"os" "os"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/mux"
"github.com/sagernet/sing-box/common/uot"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
@ -48,21 +50,27 @@ func newShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
protocol: C.TypeShadowsocks, protocol: C.TypeShadowsocks,
network: options.Network.Build(), network: options.Network.Build(),
ctx: ctx, ctx: ctx,
router: router, router: uot.NewRouter(router, logger),
logger: logger, logger: logger,
tag: tag, tag: tag,
listenOptions: options.ListenOptions, listenOptions: options.ListenOptions,
}, },
} }
inbound.connHandler = inbound inbound.connHandler = inbound
inbound.packetHandler = inbound inbound.packetHandler = inbound
var err error
inbound.router, err = mux.NewRouterWithOptions(inbound.router, logger, common.PtrValueOrDefault(options.Multiplex))
if err != nil {
return nil, err
}
var udpTimeout int64 var udpTimeout int64
if options.UDPTimeout != 0 { if options.UDPTimeout != 0 {
udpTimeout = options.UDPTimeout udpTimeout = options.UDPTimeout
} else { } else {
udpTimeout = int64(C.UDPTimeout.Seconds()) udpTimeout = int64(C.UDPTimeout.Seconds())
} }
var err error
switch { switch {
case options.Method == shadowsocks.MethodNone: case options.Method == shadowsocks.MethodNone:
inbound.service = shadowsocks.NewNoneService(options.UDPTimeout, inbound.upstreamContextHandler()) inbound.service = shadowsocks.NewNoneService(options.UDPTimeout, inbound.upstreamContextHandler())

View File

@ -6,6 +6,8 @@ import (
"os" "os"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/mux"
"github.com/sagernet/sing-box/common/uot"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
@ -38,7 +40,7 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.
protocol: C.TypeShadowsocks, protocol: C.TypeShadowsocks,
network: options.Network.Build(), network: options.Network.Build(),
ctx: ctx, ctx: ctx,
router: router, router: uot.NewRouter(router, logger),
logger: logger, logger: logger,
tag: tag, tag: tag,
listenOptions: options.ListenOptions, listenOptions: options.ListenOptions,
@ -46,16 +48,18 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.
} }
inbound.connHandler = inbound inbound.connHandler = inbound
inbound.packetHandler = inbound inbound.packetHandler = inbound
var err error
inbound.router, err = mux.NewRouterWithOptions(inbound.router, logger, common.PtrValueOrDefault(options.Multiplex))
if err != nil {
return nil, err
}
var udpTimeout int64 var udpTimeout int64
if options.UDPTimeout != 0 { if options.UDPTimeout != 0 {
udpTimeout = options.UDPTimeout udpTimeout = options.UDPTimeout
} else { } else {
udpTimeout = int64(C.UDPTimeout.Seconds()) udpTimeout = int64(C.UDPTimeout.Seconds())
} }
var ( var service shadowsocks.MultiService[int]
service shadowsocks.MultiService[int]
err error
)
if common.Contains(shadowaead_2022.List, options.Method) { if common.Contains(shadowaead_2022.List, options.Method) {
service, err = shadowaead_2022.NewMultiServiceWithPassword[int]( service, err = shadowaead_2022.NewMultiServiceWithPassword[int](
options.Method, options.Method,

View File

@ -6,6 +6,8 @@ import (
"os" "os"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/mux"
"github.com/sagernet/sing-box/common/uot"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
@ -34,7 +36,7 @@ func newShadowsocksRelay(ctx context.Context, router adapter.Router, logger log.
protocol: C.TypeShadowsocks, protocol: C.TypeShadowsocks,
network: options.Network.Build(), network: options.Network.Build(),
ctx: ctx, ctx: ctx,
router: router, router: uot.NewRouter(router, logger),
logger: logger, logger: logger,
tag: tag, tag: tag,
listenOptions: options.ListenOptions, listenOptions: options.ListenOptions,
@ -43,6 +45,11 @@ func newShadowsocksRelay(ctx context.Context, router adapter.Router, logger log.
} }
inbound.connHandler = inbound inbound.connHandler = inbound
inbound.packetHandler = inbound inbound.packetHandler = inbound
var err error
inbound.router, err = mux.NewRouterWithOptions(inbound.router, logger, common.PtrValueOrDefault(options.Multiplex))
if err != nil {
return nil, err
}
var udpTimeout int64 var udpTimeout int64
if options.UDPTimeout != 0 { if options.UDPTimeout != 0 {
udpTimeout = options.UDPTimeout udpTimeout = options.UDPTimeout

View File

@ -6,6 +6,7 @@ import (
"os" "os"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/uot"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
@ -30,7 +31,7 @@ func NewSocks(ctx context.Context, router adapter.Router, logger log.ContextLogg
protocol: C.TypeSOCKS, protocol: C.TypeSOCKS,
network: []string{N.NetworkTCP}, network: []string{N.NetworkTCP},
ctx: ctx, ctx: ctx,
router: router, router: uot.NewRouter(router, logger),
logger: logger, logger: logger,
tag: tag, tag: tag,
listenOptions: options.ListenOptions, listenOptions: options.ListenOptions,

View File

@ -6,7 +6,9 @@ import (
"os" "os"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/mux"
"github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/common/tls"
"github.com/sagernet/sing-box/common/uot"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
@ -42,7 +44,7 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg
protocol: C.TypeVLESS, protocol: C.TypeVLESS,
network: []string{N.NetworkTCP}, network: []string{N.NetworkTCP},
ctx: ctx, ctx: ctx,
router: router, router: uot.NewRouter(router, logger),
logger: logger, logger: logger,
tag: tag, tag: tag,
listenOptions: options.ListenOptions, listenOptions: options.ListenOptions,
@ -50,6 +52,11 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg
ctx: ctx, ctx: ctx,
users: options.Users, users: options.Users,
} }
var err error
inbound.router, err = mux.NewRouterWithOptions(inbound.router, logger, common.PtrValueOrDefault(options.Multiplex))
if err != nil {
return nil, err
}
service := vless.NewService[int](logger, adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound)) service := vless.NewService[int](logger, adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound))
service.UpdateUsers(common.MapIndexed(inbound.users, func(index int, _ option.VLESSUser) int { service.UpdateUsers(common.MapIndexed(inbound.users, func(index int, _ option.VLESSUser) int {
return index return index
@ -59,7 +66,6 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg
return it.Flow return it.Flow
})) }))
inbound.service = service inbound.service = service
var err error
if options.TLS != nil { if options.TLS != nil {
inbound.tlsConfig, err = tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) inbound.tlsConfig, err = tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS))
if err != nil { if err != nil {

View File

@ -6,7 +6,9 @@ import (
"os" "os"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/mux"
"github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/common/tls"
"github.com/sagernet/sing-box/common/uot"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
@ -42,7 +44,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
protocol: C.TypeVMess, protocol: C.TypeVMess,
network: []string{N.NetworkTCP}, network: []string{N.NetworkTCP},
ctx: ctx, ctx: ctx,
router: router, router: uot.NewRouter(router, logger),
logger: logger, logger: logger,
tag: tag, tag: tag,
listenOptions: options.ListenOptions, listenOptions: options.ListenOptions,
@ -50,6 +52,11 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
ctx: ctx, ctx: ctx,
users: options.Users, users: options.Users,
} }
var err error
inbound.router, err = mux.NewRouterWithOptions(inbound.router, logger, common.PtrValueOrDefault(options.Multiplex))
if err != nil {
return nil, err
}
var serviceOptions []vmess.ServiceOption var serviceOptions []vmess.ServiceOption
if timeFunc := ntp.TimeFuncFromContext(ctx); timeFunc != nil { if timeFunc := ntp.TimeFuncFromContext(ctx); timeFunc != nil {
serviceOptions = append(serviceOptions, vmess.ServiceWithTimeFunc(timeFunc)) serviceOptions = append(serviceOptions, vmess.ServiceWithTimeFunc(timeFunc))
@ -59,7 +66,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
} }
service := vmess.NewService[int](adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound), serviceOptions...) service := vmess.NewService[int](adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound), serviceOptions...)
inbound.service = service inbound.service = service
err := service.UpdateUsers(common.MapIndexed(options.Users, func(index int, it option.VMessUser) int { err = service.UpdateUsers(common.MapIndexed(options.Users, func(index int, it option.VMessUser) int {
return index return index
}), common.Map(options.Users, func(it option.VMessUser) string { }), common.Map(options.Users, func(it option.VMessUser) string {
return it.UUID return it.UUID

View File

@ -75,6 +75,7 @@ nav:
- Multiplex: configuration/shared/multiplex.md - Multiplex: configuration/shared/multiplex.md
- V2Ray Transport: configuration/shared/v2ray-transport.md - V2Ray Transport: configuration/shared/v2ray-transport.md
- UDP over TCP: configuration/shared/udp-over-tcp.md - UDP over TCP: configuration/shared/udp-over-tcp.md
- TCP Brutal: configuration/shared/tcp-brutal.md
- Inbound: - Inbound:
- configuration/inbound/index.md - configuration/inbound/index.md
- Direct: configuration/inbound/direct.md - Direct: configuration/inbound/direct.md

23
option/multiplex.go Normal file
View File

@ -0,0 +1,23 @@
package option
type InboundMultiplexOptions struct {
Enabled bool `json:"enabled,omitempty"`
Padding bool `json:"padding,omitempty"`
Brutal *BrutalOptions `json:"brutal,omitempty"`
}
type OutboundMultiplexOptions struct {
Enabled bool `json:"enabled,omitempty"`
Protocol string `json:"protocol,omitempty"`
MaxConnections int `json:"max_connections,omitempty"`
MinStreams int `json:"min_streams,omitempty"`
MaxStreams int `json:"max_streams,omitempty"`
Padding bool `json:"padding,omitempty"`
Brutal *BrutalOptions `json:"brutal,omitempty"`
}
type BrutalOptions struct {
Enabled bool `json:"enabled,omitempty"`
UpMbps int `json:"up_mbps,omitempty"`
DownMbps int `json:"down_mbps,omitempty"`
}

View File

@ -154,12 +154,3 @@ type ServerOptions struct {
func (o ServerOptions) Build() M.Socksaddr { func (o ServerOptions) Build() M.Socksaddr {
return M.ParseSocksaddrHostPort(o.Server, o.ServerPort) return M.ParseSocksaddrHostPort(o.Server, o.ServerPort)
} }
type MultiplexOptions struct {
Enabled bool `json:"enabled,omitempty"`
Protocol string `json:"protocol,omitempty"`
MaxConnections int `json:"max_connections,omitempty"`
MinStreams int `json:"min_streams,omitempty"`
MaxStreams int `json:"max_streams,omitempty"`
Padding bool `json:"padding,omitempty"`
}

View File

@ -7,6 +7,7 @@ type ShadowsocksInboundOptions struct {
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
Users []ShadowsocksUser `json:"users,omitempty"` Users []ShadowsocksUser `json:"users,omitempty"`
Destinations []ShadowsocksDestination `json:"destinations,omitempty"` Destinations []ShadowsocksDestination `json:"destinations,omitempty"`
Multiplex *InboundMultiplexOptions `json:"multiplex,omitempty"`
} }
type ShadowsocksUser struct { type ShadowsocksUser struct {
@ -28,6 +29,6 @@ type ShadowsocksOutboundOptions struct {
Plugin string `json:"plugin,omitempty"` Plugin string `json:"plugin,omitempty"`
PluginOptions string `json:"plugin_opts,omitempty"` PluginOptions string `json:"plugin_opts,omitempty"`
Network NetworkList `json:"network,omitempty"` Network NetworkList `json:"network,omitempty"`
UDPOverTCPOptions *UDPOverTCPOptions `json:"udp_over_tcp,omitempty"` UDPOverTCP *UDPOverTCPOptions `json:"udp_over_tcp,omitempty"`
MultiplexOptions *MultiplexOptions `json:"multiplex,omitempty"` Multiplex *OutboundMultiplexOptions `json:"multiplex,omitempty"`
} }

View File

@ -21,7 +21,7 @@ type SocksOutboundOptions struct {
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
Network NetworkList `json:"network,omitempty"` Network NetworkList `json:"network,omitempty"`
UDPOverTCPOptions *UDPOverTCPOptions `json:"udp_over_tcp,omitempty"` UDPOverTCP *UDPOverTCPOptions `json:"udp_over_tcp,omitempty"`
} }
type HTTPOutboundOptions struct { type HTTPOutboundOptions struct {

View File

@ -6,6 +6,7 @@ type TrojanInboundOptions struct {
TLS *InboundTLSOptions `json:"tls,omitempty"` TLS *InboundTLSOptions `json:"tls,omitempty"`
Fallback *ServerOptions `json:"fallback,omitempty"` Fallback *ServerOptions `json:"fallback,omitempty"`
FallbackForALPN map[string]*ServerOptions `json:"fallback_for_alpn,omitempty"` FallbackForALPN map[string]*ServerOptions `json:"fallback_for_alpn,omitempty"`
Multiplex *InboundMultiplexOptions `json:"multiplex,omitempty"`
Transport *V2RayTransportOptions `json:"transport,omitempty"` Transport *V2RayTransportOptions `json:"transport,omitempty"`
} }
@ -20,6 +21,6 @@ type TrojanOutboundOptions struct {
Password string `json:"password"` Password string `json:"password"`
Network NetworkList `json:"network,omitempty"` Network NetworkList `json:"network,omitempty"`
TLS *OutboundTLSOptions `json:"tls,omitempty"` TLS *OutboundTLSOptions `json:"tls,omitempty"`
Multiplex *MultiplexOptions `json:"multiplex,omitempty"` Multiplex *OutboundMultiplexOptions `json:"multiplex,omitempty"`
Transport *V2RayTransportOptions `json:"transport,omitempty"` Transport *V2RayTransportOptions `json:"transport,omitempty"`
} }

View File

@ -4,6 +4,7 @@ type VLESSInboundOptions struct {
ListenOptions ListenOptions
Users []VLESSUser `json:"users,omitempty"` Users []VLESSUser `json:"users,omitempty"`
TLS *InboundTLSOptions `json:"tls,omitempty"` TLS *InboundTLSOptions `json:"tls,omitempty"`
Multiplex *InboundMultiplexOptions `json:"multiplex,omitempty"`
Transport *V2RayTransportOptions `json:"transport,omitempty"` Transport *V2RayTransportOptions `json:"transport,omitempty"`
} }
@ -20,7 +21,7 @@ type VLESSOutboundOptions struct {
Flow string `json:"flow,omitempty"` Flow string `json:"flow,omitempty"`
Network NetworkList `json:"network,omitempty"` Network NetworkList `json:"network,omitempty"`
TLS *OutboundTLSOptions `json:"tls,omitempty"` TLS *OutboundTLSOptions `json:"tls,omitempty"`
Multiplex *MultiplexOptions `json:"multiplex,omitempty"` Multiplex *OutboundMultiplexOptions `json:"multiplex,omitempty"`
Transport *V2RayTransportOptions `json:"transport,omitempty"` Transport *V2RayTransportOptions `json:"transport,omitempty"`
PacketEncoding *string `json:"packet_encoding,omitempty"` PacketEncoding *string `json:"packet_encoding,omitempty"`
} }

View File

@ -4,6 +4,7 @@ type VMessInboundOptions struct {
ListenOptions ListenOptions
Users []VMessUser `json:"users,omitempty"` Users []VMessUser `json:"users,omitempty"`
TLS *InboundTLSOptions `json:"tls,omitempty"` TLS *InboundTLSOptions `json:"tls,omitempty"`
Multiplex *InboundMultiplexOptions `json:"multiplex,omitempty"`
Transport *V2RayTransportOptions `json:"transport,omitempty"` Transport *V2RayTransportOptions `json:"transport,omitempty"`
} }
@ -24,6 +25,6 @@ type VMessOutboundOptions struct {
Network NetworkList `json:"network,omitempty"` Network NetworkList `json:"network,omitempty"`
TLS *OutboundTLSOptions `json:"tls,omitempty"` TLS *OutboundTLSOptions `json:"tls,omitempty"`
PacketEncoding string `json:"packet_encoding,omitempty"` PacketEncoding string `json:"packet_encoding,omitempty"`
Multiplex *MultiplexOptions `json:"multiplex,omitempty"` Multiplex *OutboundMultiplexOptions `json:"multiplex,omitempty"`
Transport *V2RayTransportOptions `json:"transport,omitempty"` Transport *V2RayTransportOptions `json:"transport,omitempty"`
} }

View File

@ -62,9 +62,9 @@ func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
return nil, err return nil, err
} }
} }
uotOptions := common.PtrValueOrDefault(options.UDPOverTCPOptions) uotOptions := common.PtrValueOrDefault(options.UDPOverTCP)
if !uotOptions.Enabled { if !uotOptions.Enabled {
outbound.multiplexDialer, err = mux.NewClientWithOptions((*shadowsocksDialer)(outbound), common.PtrValueOrDefault(options.MultiplexOptions)) outbound.multiplexDialer, err = mux.NewClientWithOptions((*shadowsocksDialer)(outbound), logger, common.PtrValueOrDefault(options.Multiplex))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -54,7 +54,7 @@ func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, optio
client: socks.NewClient(outboundDialer, options.ServerOptions.Build(), version, options.Username, options.Password), client: socks.NewClient(outboundDialer, options.ServerOptions.Build(), version, options.Username, options.Password),
resolve: version == socks.Version4, resolve: version == socks.Version4,
} }
uotOptions := common.PtrValueOrDefault(options.UDPOverTCPOptions) uotOptions := common.PtrValueOrDefault(options.UDPOverTCP)
if uotOptions.Enabled { if uotOptions.Enabled {
outbound.uotClient = &uot.Client{ outbound.uotClient = &uot.Client{
Dialer: outbound.client, Dialer: outbound.client,

View File

@ -62,7 +62,7 @@ func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLog
return nil, E.Cause(err, "create client transport: ", options.Transport.Type) return nil, E.Cause(err, "create client transport: ", options.Transport.Type)
} }
} }
outbound.multiplexDialer, err = mux.NewClientWithOptions((*trojanDialer)(outbound), common.PtrValueOrDefault(options.Multiplex)) outbound.multiplexDialer, err = mux.NewClientWithOptions((*trojanDialer)(outbound), logger, common.PtrValueOrDefault(options.Multiplex))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -81,7 +81,7 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg
if err != nil { if err != nil {
return nil, err return nil, err
} }
outbound.multiplexDialer, err = mux.NewClientWithOptions((*vlessDialer)(outbound), common.PtrValueOrDefault(options.Multiplex)) outbound.multiplexDialer, err = mux.NewClientWithOptions((*vlessDialer)(outbound), logger, common.PtrValueOrDefault(options.Multiplex))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -64,7 +64,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
return nil, E.Cause(err, "create client transport: ", options.Transport.Type) return nil, E.Cause(err, "create client transport: ", options.Transport.Type)
} }
} }
outbound.multiplexDialer, err = mux.NewClientWithOptions((*vmessDialer)(outbound), common.PtrValueOrDefault(options.Multiplex)) outbound.multiplexDialer, err = mux.NewClientWithOptions((*vmessDialer)(outbound), logger, common.PtrValueOrDefault(options.Multiplex))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -16,7 +16,6 @@ import (
"github.com/sagernet/sing-box/common/dialer" "github.com/sagernet/sing-box/common/dialer"
"github.com/sagernet/sing-box/common/geoip" "github.com/sagernet/sing-box/common/geoip"
"github.com/sagernet/sing-box/common/geosite" "github.com/sagernet/sing-box/common/geosite"
"github.com/sagernet/sing-box/common/mux"
"github.com/sagernet/sing-box/common/process" "github.com/sagernet/sing-box/common/process"
"github.com/sagernet/sing-box/common/sniff" "github.com/sagernet/sing-box/common/sniff"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
@ -27,6 +26,7 @@ import (
"github.com/sagernet/sing-box/outbound" "github.com/sagernet/sing-box/outbound"
"github.com/sagernet/sing-box/transport/fakeip" "github.com/sagernet/sing-box/transport/fakeip"
"github.com/sagernet/sing-dns" "github.com/sagernet/sing-dns"
mux "github.com/sagernet/sing-mux"
"github.com/sagernet/sing-tun" "github.com/sagernet/sing-tun"
"github.com/sagernet/sing-vmess" "github.com/sagernet/sing-vmess"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
@ -606,30 +606,13 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
metadata.Network = N.NetworkTCP metadata.Network = N.NetworkTCP
switch metadata.Destination.Fqdn { switch metadata.Destination.Fqdn {
case mux.Destination.Fqdn: case mux.Destination.Fqdn:
r.logger.InfoContext(ctx, "inbound multiplex connection") return E.New("global multiplex is deprecated since sing-box v1.7.0, enable multiplex in inbound options instead.")
handler := adapter.NewUpstreamHandler(metadata, r.RouteConnection, r.RoutePacketConnection, r)
return mux.HandleConnection(ctx, handler, r.logger, conn, adapter.UpstreamMetadata(metadata))
case vmess.MuxDestination.Fqdn: case vmess.MuxDestination.Fqdn:
r.logger.InfoContext(ctx, "inbound legacy multiplex connection") return E.New("global multiplex (v2ray legacy) not supported since sing-box v1.7.0.")
return vmess.HandleMuxConnection(ctx, conn, adapter.NewUpstreamHandler(metadata, r.RouteConnection, r.RoutePacketConnection, r))
case uot.MagicAddress: case uot.MagicAddress:
request, err := uot.ReadRequest(conn) return E.New("global UoT not supported since sing-box v1.7.0.")
if err != nil {
return E.Cause(err, "read UoT request")
}
if request.IsConnect {
r.logger.InfoContext(ctx, "inbound UoT connect connection to ", request.Destination)
} else {
r.logger.InfoContext(ctx, "inbound UoT connection to ", request.Destination)
}
metadata.Domain = metadata.Destination.Fqdn
metadata.Destination = request.Destination
return r.RoutePacketConnection(ctx, uot.NewConn(conn, *request), metadata)
case uot.LegacyMagicAddress: case uot.LegacyMagicAddress:
r.logger.InfoContext(ctx, "inbound legacy UoT connection") return E.New("global UoT (legacy) not supported since sing-box v1.7.0.")
metadata.Domain = metadata.Destination.Fqdn
metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()}
return r.RoutePacketConnection(ctx, uot.NewConn(conn, uot.Request{}), metadata)
} }
if r.fakeIPStore != nil && r.fakeIPStore.Contains(metadata.Destination.Addr) { if r.fakeIPStore != nil && r.fakeIPStore.Contains(metadata.Destination.Addr) {

86
test/brutal_test.go Normal file
View File

@ -0,0 +1,86 @@
package main
import (
"net/netip"
"testing"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
)
func TestMuxBrutal(t *testing.T) {
method := shadowaead_2022.List[0]
password := mkBase64(t, 16)
startInstance(t, option.Options{
Inbounds: []option.Inbound{
{
Type: C.TypeMixed,
Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
ListenPort: clientPort,
},
},
},
{
Type: C.TypeShadowsocks,
ShadowsocksOptions: option.ShadowsocksInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
ListenPort: serverPort,
},
Method: method,
Password: password,
Multiplex: &option.InboundMultiplexOptions{
Enabled: true,
Brutal: &option.BrutalOptions{
Enabled: true,
UpMbps: 100,
DownMbps: 100,
},
},
},
},
},
Outbounds: []option.Outbound{
{
Type: C.TypeDirect,
},
{
Type: C.TypeShadowsocks,
Tag: "ss-out",
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
ServerOptions: option.ServerOptions{
Server: "127.0.0.1",
ServerPort: serverPort,
},
Method: method,
Password: password,
Multiplex: &option.OutboundMultiplexOptions{
Enabled: true,
Protocol: "smux",
Padding: true,
Brutal: &option.BrutalOptions{
Enabled: true,
UpMbps: 100,
DownMbps: 100,
},
},
},
},
},
Route: &option.RouteOptions{
Rules: []option.Rule{
{
DefaultOptions: option.DefaultRule{
Inbound: []string{"mixed-in"},
Outbound: "ss-out",
},
},
},
},
})
testSuit(t, clientPort, testPort)
}

View File

@ -75,9 +75,9 @@ require (
github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab // indirect github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab // indirect
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // 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-mux v0.1.3 // indirect github.com/sagernet/sing-mux v0.1.4-0.20231105044304-ae2745a33479 // indirect
github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect
github.com/sagernet/sing-tun v0.1.17-0.20231030120513-2e85725657c1 // indirect github.com/sagernet/sing-tun v0.1.17-0.20231104000158-fb98efb75ca7 // indirect
github.com/sagernet/sing-vmess v0.1.8 // indirect github.com/sagernet/sing-vmess v0.1.8 // 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-20230816093905-5a5c285d44a6 // indirect github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect

View File

@ -135,8 +135,8 @@ github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2 h1:PW18IgRodvppd0
github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg=
github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI= github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI=
github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c=
github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= github.com/sagernet/sing-mux v0.1.4-0.20231105044304-ae2745a33479 h1:h6ANTA5wbP5BSqbjOT7s1OKLZgdsLqiXO564KQqY2i4=
github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= github.com/sagernet/sing-mux v0.1.4-0.20231105044304-ae2745a33479/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0=
github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 h1:w+TUbIZKZFSdf/AUa/y33kY9xaLeNGz/tBNcNhqpqfg= github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 h1:w+TUbIZKZFSdf/AUa/y33kY9xaLeNGz/tBNcNhqpqfg=
github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6/go.mod h1:1M7xP4802K9Kz6BQ7LlA7UeCapWvWlH1Htmk2bAqkWc= github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6/go.mod h1:1M7xP4802K9Kz6BQ7LlA7UeCapWvWlH1Htmk2bAqkWc=
github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY=
@ -145,8 +145,8 @@ github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+M
github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc=
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
github.com/sagernet/sing-tun v0.1.17-0.20231030120513-2e85725657c1 h1:QxC+myHDZ0BnkIEqXE0lWUzfYEVlhhQdSCo7mOMm7x4= github.com/sagernet/sing-tun v0.1.17-0.20231104000158-fb98efb75ca7 h1:nrjFCUNEsDZSZlxmE+tq8OuInjXI08vNfcSJ66gTbCs=
github.com/sagernet/sing-tun v0.1.17-0.20231030120513-2e85725657c1/go.mod h1:4ACZp3C6TDSy1rsMrfwtSyLrKPtm9Wm2eKHwhYIojbU= github.com/sagernet/sing-tun v0.1.17-0.20231104000158-fb98efb75ca7/go.mod h1:4ACZp3C6TDSy1rsMrfwtSyLrKPtm9Wm2eKHwhYIojbU=
github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc=
github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA=
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=

View File

@ -18,7 +18,7 @@ var muxProtocols = []string{
} }
func TestVMessSMux(t *testing.T) { func TestVMessSMux(t *testing.T) {
testVMessMux(t, option.MultiplexOptions{ testVMessMux(t, option.OutboundMultiplexOptions{
Enabled: true, Enabled: true,
Protocol: "smux", Protocol: "smux",
}) })
@ -27,7 +27,7 @@ func TestVMessSMux(t *testing.T) {
func TestShadowsocksMux(t *testing.T) { func TestShadowsocksMux(t *testing.T) {
for _, protocol := range muxProtocols { for _, protocol := range muxProtocols {
t.Run(protocol, func(t *testing.T) { t.Run(protocol, func(t *testing.T) {
testShadowsocksMux(t, option.MultiplexOptions{ testShadowsocksMux(t, option.OutboundMultiplexOptions{
Enabled: true, Enabled: true,
Protocol: protocol, Protocol: protocol,
}) })
@ -36,7 +36,7 @@ func TestShadowsocksMux(t *testing.T) {
} }
func TestShadowsockH2Mux(t *testing.T) { func TestShadowsockH2Mux(t *testing.T) {
testShadowsocksMux(t, option.MultiplexOptions{ testShadowsocksMux(t, option.OutboundMultiplexOptions{
Enabled: true, Enabled: true,
Protocol: "h2mux", Protocol: "h2mux",
Padding: true, Padding: true,
@ -44,14 +44,14 @@ func TestShadowsockH2Mux(t *testing.T) {
} }
func TestShadowsockSMuxPadding(t *testing.T) { func TestShadowsockSMuxPadding(t *testing.T) {
testShadowsocksMux(t, option.MultiplexOptions{ testShadowsocksMux(t, option.OutboundMultiplexOptions{
Enabled: true, Enabled: true,
Protocol: "smux", Protocol: "smux",
Padding: true, Padding: true,
}) })
} }
func testShadowsocksMux(t *testing.T, options option.MultiplexOptions) { func testShadowsocksMux(t *testing.T, options option.OutboundMultiplexOptions) {
method := shadowaead_2022.List[0] method := shadowaead_2022.List[0]
password := mkBase64(t, 16) password := mkBase64(t, 16)
startInstance(t, option.Options{ startInstance(t, option.Options{
@ -92,7 +92,7 @@ func testShadowsocksMux(t *testing.T, options option.MultiplexOptions) {
}, },
Method: method, Method: method,
Password: password, Password: password,
MultiplexOptions: &options, Multiplex: &options,
}, },
}, },
}, },
@ -110,7 +110,7 @@ func testShadowsocksMux(t *testing.T, options option.MultiplexOptions) {
testSuit(t, clientPort, testPort) testSuit(t, clientPort, testPort)
} }
func testVMessMux(t *testing.T, options option.MultiplexOptions) { func testVMessMux(t *testing.T, options option.OutboundMultiplexOptions) {
user, _ := uuid.NewV4() user, _ := uuid.NewV4()
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
@ -136,6 +136,9 @@ func testVMessMux(t *testing.T, options option.MultiplexOptions) {
UUID: user.String(), UUID: user.String(),
}, },
}, },
Multiplex: &option.InboundMultiplexOptions{
Enabled: true,
},
}, },
}, },
}, },

View File

@ -232,7 +232,7 @@ func TestShadowsocksUoT(t *testing.T) {
}, },
Method: method, Method: method,
Password: password, Password: password,
UDPOverTCPOptions: &option.UDPOverTCPOptions{ UDPOverTCP: &option.UDPOverTCPOptions{
Enabled: true, Enabled: true,
}, },
}, },