Skip to content

Commit 1b71e52

Browse files
committed
Migrate multiplex and UoT server to inbound & Add tcp-brutal support for multiplex
1 parent 6d24be2 commit 1b71e52

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+997
-176
lines changed

adapter/conn_router.go

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package adapter
2+
3+
import (
4+
"context"
5+
"net"
6+
7+
"github.com/sagernet/sing/common/logger"
8+
M "github.com/sagernet/sing/common/metadata"
9+
N "github.com/sagernet/sing/common/network"
10+
)
11+
12+
type ConnectionRouter interface {
13+
RouteConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error
14+
RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error
15+
}
16+
17+
func NewRouteHandler(
18+
metadata InboundContext,
19+
router ConnectionRouter,
20+
logger logger.ContextLogger,
21+
) UpstreamHandlerAdapter {
22+
return &routeHandlerWrapper{
23+
metadata: metadata,
24+
router: router,
25+
logger: logger,
26+
}
27+
}
28+
29+
func NewRouteContextHandler(
30+
router ConnectionRouter,
31+
logger logger.ContextLogger,
32+
) UpstreamHandlerAdapter {
33+
return &routeContextHandlerWrapper{
34+
router: router,
35+
logger: logger,
36+
}
37+
}
38+
39+
var _ UpstreamHandlerAdapter = (*routeHandlerWrapper)(nil)
40+
41+
type routeHandlerWrapper struct {
42+
metadata InboundContext
43+
router ConnectionRouter
44+
logger logger.ContextLogger
45+
}
46+
47+
func (w *routeHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
48+
myMetadata := w.metadata
49+
if metadata.Source.IsValid() {
50+
myMetadata.Source = metadata.Source
51+
}
52+
if metadata.Destination.IsValid() {
53+
myMetadata.Destination = metadata.Destination
54+
}
55+
return w.router.RouteConnection(ctx, conn, myMetadata)
56+
}
57+
58+
func (w *routeHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
59+
myMetadata := w.metadata
60+
if metadata.Source.IsValid() {
61+
myMetadata.Source = metadata.Source
62+
}
63+
if metadata.Destination.IsValid() {
64+
myMetadata.Destination = metadata.Destination
65+
}
66+
return w.router.RoutePacketConnection(ctx, conn, myMetadata)
67+
}
68+
69+
func (w *routeHandlerWrapper) NewError(ctx context.Context, err error) {
70+
w.logger.ErrorContext(ctx, err)
71+
}
72+
73+
var _ UpstreamHandlerAdapter = (*routeContextHandlerWrapper)(nil)
74+
75+
type routeContextHandlerWrapper struct {
76+
router ConnectionRouter
77+
logger logger.ContextLogger
78+
}
79+
80+
func (w *routeContextHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
81+
myMetadata := ContextFrom(ctx)
82+
if metadata.Source.IsValid() {
83+
myMetadata.Source = metadata.Source
84+
}
85+
if metadata.Destination.IsValid() {
86+
myMetadata.Destination = metadata.Destination
87+
}
88+
return w.router.RouteConnection(ctx, conn, *myMetadata)
89+
}
90+
91+
func (w *routeContextHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
92+
myMetadata := ContextFrom(ctx)
93+
if metadata.Source.IsValid() {
94+
myMetadata.Source = metadata.Source
95+
}
96+
if metadata.Destination.IsValid() {
97+
myMetadata.Destination = metadata.Destination
98+
}
99+
return w.router.RoutePacketConnection(ctx, conn, *myMetadata)
100+
}
101+
102+
func (w *routeContextHandlerWrapper) NewError(ctx context.Context, err error) {
103+
w.logger.ErrorContext(ctx, err)
104+
}

adapter/router.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ package adapter
22

33
import (
44
"context"
5-
"net"
65
"net/netip"
76

87
"github.com/sagernet/sing-box/common/geoip"
98
"github.com/sagernet/sing-dns"
109
"github.com/sagernet/sing-tun"
1110
"github.com/sagernet/sing/common/control"
12-
N "github.com/sagernet/sing/common/network"
1311
"github.com/sagernet/sing/service"
1412

1513
mdns "github.com/miekg/dns"
@@ -24,8 +22,7 @@ type Router interface {
2422

2523
FakeIPStore() FakeIPStore
2624

27-
RouteConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error
28-
RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error
25+
ConnectionRouter
2926

3027
GeoIPReader() *geoip.Reader
3128
LoadGeosite(code string) (Rule, error)

common/mux/client.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,42 @@
11
package mux
22

33
import (
4+
C "github.com/sagernet/sing-box/constant"
45
"github.com/sagernet/sing-box/option"
56
"github.com/sagernet/sing-mux"
7+
E "github.com/sagernet/sing/common/exceptions"
8+
"github.com/sagernet/sing/common/logger"
69
N "github.com/sagernet/sing/common/network"
710
)
811

9-
func NewClientWithOptions(dialer N.Dialer, options option.MultiplexOptions) (*Client, error) {
12+
type Client = mux.Client
13+
14+
func NewClientWithOptions(dialer N.Dialer, logger logger.Logger, options option.OutboundMultiplexOptions) (*Client, error) {
1015
if !options.Enabled {
1116
return nil, nil
1217
}
18+
var brutalOptions mux.BrutalOptions
19+
if options.Brutal != nil && options.Brutal.Enabled {
20+
brutalOptions = mux.BrutalOptions{
21+
Enabled: true,
22+
SendBPS: uint64(options.Brutal.UpMbps * C.MbpsToBps),
23+
ReceiveBPS: uint64(options.Brutal.DownMbps * C.MbpsToBps),
24+
}
25+
if brutalOptions.SendBPS < mux.BrutalMinSpeedBPS {
26+
return nil, E.New("brutal: invalid upload speed")
27+
}
28+
if brutalOptions.ReceiveBPS < mux.BrutalMinSpeedBPS {
29+
return nil, E.New("brutal: invalid download speed")
30+
}
31+
}
1332
return mux.NewClient(mux.Options{
1433
Dialer: dialer,
34+
Logger: logger,
1535
Protocol: options.Protocol,
1636
MaxConnections: options.MaxConnections,
1737
MinStreams: options.MinStreams,
1838
MaxStreams: options.MaxStreams,
1939
Padding: options.Padding,
40+
Brutal: brutalOptions,
2041
})
2142
}

common/mux/protocol.go

-14
This file was deleted.

common/mux/router.go

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package mux
2+
3+
import (
4+
"context"
5+
"net"
6+
7+
"github.com/sagernet/sing-box/adapter"
8+
C "github.com/sagernet/sing-box/constant"
9+
"github.com/sagernet/sing-box/log"
10+
"github.com/sagernet/sing-box/option"
11+
"github.com/sagernet/sing-mux"
12+
E "github.com/sagernet/sing/common/exceptions"
13+
"github.com/sagernet/sing/common/logger"
14+
N "github.com/sagernet/sing/common/network"
15+
)
16+
17+
type Router struct {
18+
router adapter.ConnectionRouter
19+
service *mux.Service
20+
}
21+
22+
func NewRouterWithOptions(router adapter.ConnectionRouter, logger logger.ContextLogger, options option.InboundMultiplexOptions) (adapter.ConnectionRouter, error) {
23+
if !options.Enabled {
24+
return router, nil
25+
}
26+
var brutalOptions mux.BrutalOptions
27+
if options.Brutal != nil && options.Brutal.Enabled {
28+
brutalOptions = mux.BrutalOptions{
29+
Enabled: true,
30+
SendBPS: uint64(options.Brutal.UpMbps * C.MbpsToBps),
31+
ReceiveBPS: uint64(options.Brutal.DownMbps * C.MbpsToBps),
32+
}
33+
if brutalOptions.SendBPS < mux.BrutalMinSpeedBPS {
34+
return nil, E.New("brutal: invalid upload speed")
35+
}
36+
if brutalOptions.ReceiveBPS < mux.BrutalMinSpeedBPS {
37+
return nil, E.New("brutal: invalid download speed")
38+
}
39+
}
40+
service, err := mux.NewService(mux.ServiceOptions{
41+
NewStreamContext: func(ctx context.Context, conn net.Conn) context.Context {
42+
return log.ContextWithNewID(ctx)
43+
},
44+
Logger: logger,
45+
Handler: adapter.NewRouteContextHandler(router, logger),
46+
Padding: options.Padding,
47+
Brutal: brutalOptions,
48+
})
49+
if err != nil {
50+
return nil, err
51+
}
52+
return &Router{router, service}, nil
53+
}
54+
55+
func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
56+
if metadata.Destination == mux.Destination {
57+
return r.service.NewConnection(adapter.WithContext(ctx, &metadata), conn, adapter.UpstreamMetadata(metadata))
58+
} else {
59+
return r.router.RouteConnection(ctx, conn, metadata)
60+
}
61+
}
62+
63+
func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
64+
return r.router.RoutePacketConnection(ctx, conn, metadata)
65+
}

common/mux/v2ray_legacy.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package mux
2+
3+
import (
4+
"context"
5+
"net"
6+
7+
"github.com/sagernet/sing-box/adapter"
8+
vmess "github.com/sagernet/sing-vmess"
9+
"github.com/sagernet/sing/common/logger"
10+
N "github.com/sagernet/sing/common/network"
11+
)
12+
13+
type V2RayLegacyRouter struct {
14+
router adapter.ConnectionRouter
15+
logger logger.ContextLogger
16+
}
17+
18+
func NewV2RayLegacyRouter(router adapter.ConnectionRouter, logger logger.ContextLogger) adapter.ConnectionRouter {
19+
return &V2RayLegacyRouter{router, logger}
20+
}
21+
22+
func (r *V2RayLegacyRouter) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
23+
if metadata.Destination.Fqdn == vmess.MuxDestination.Fqdn {
24+
r.logger.InfoContext(ctx, "inbound legacy multiplex connection")
25+
return vmess.HandleMuxConnection(ctx, conn, adapter.NewRouteHandler(metadata, r.router, r.logger))
26+
}
27+
return r.router.RouteConnection(ctx, conn, metadata)
28+
}
29+
30+
func (r *V2RayLegacyRouter) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
31+
return r.router.RoutePacketConnection(ctx, conn, metadata)
32+
}

common/uot/router.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package uot
2+
3+
import (
4+
"context"
5+
"net"
6+
"net/netip"
7+
8+
"github.com/sagernet/sing-box/adapter"
9+
E "github.com/sagernet/sing/common/exceptions"
10+
"github.com/sagernet/sing/common/logger"
11+
M "github.com/sagernet/sing/common/metadata"
12+
N "github.com/sagernet/sing/common/network"
13+
"github.com/sagernet/sing/common/uot"
14+
)
15+
16+
var _ adapter.ConnectionRouter = (*Router)(nil)
17+
18+
type Router struct {
19+
router adapter.ConnectionRouter
20+
logger logger.ContextLogger
21+
}
22+
23+
func NewRouter(router adapter.ConnectionRouter, logger logger.ContextLogger) *Router {
24+
return &Router{router, logger}
25+
}
26+
27+
func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
28+
switch metadata.Destination.Fqdn {
29+
case uot.MagicAddress:
30+
request, err := uot.ReadRequest(conn)
31+
if err != nil {
32+
return E.Cause(err, "read UoT request")
33+
}
34+
if request.IsConnect {
35+
r.logger.InfoContext(ctx, "inbound UoT connect connection to ", request.Destination)
36+
} else {
37+
r.logger.InfoContext(ctx, "inbound UoT connection to ", request.Destination)
38+
}
39+
metadata.Domain = metadata.Destination.Fqdn
40+
metadata.Destination = request.Destination
41+
return r.router.RoutePacketConnection(ctx, uot.NewConn(conn, *request), metadata)
42+
case uot.LegacyMagicAddress:
43+
r.logger.InfoContext(ctx, "inbound legacy UoT connection")
44+
metadata.Domain = metadata.Destination.Fqdn
45+
metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()}
46+
return r.RoutePacketConnection(ctx, uot.NewConn(conn, uot.Request{}), metadata)
47+
}
48+
return r.router.RouteConnection(ctx, conn, metadata)
49+
}
50+
51+
func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
52+
return r.router.RoutePacketConnection(ctx, conn, metadata)
53+
}

constant/speed.go

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package constant
2+
3+
const MbpsToBps = 125000

docs/configuration/inbound/hysteria2.zh.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Hysteria 用户
6262

6363
#### ignore_client_bandwidth
6464

65-
命令客户端使用 BBR 流量控制算法而不是 Hysteria CC。
65+
命令客户端使用 BBR 拥塞控制算法而不是 Hysteria CC。
6666

6767
`up_mbps``down_mbps` 冲突。
6868

docs/configuration/inbound/shadowsocks.md

+10-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
... // Listen Fields
99

1010
"method": "2022-blake3-aes-128-gcm",
11-
"password": "8JCsPssfgS8tiRwiMlhARg=="
11+
"password": "8JCsPssfgS8tiRwiMlhARg==",
12+
"multiplex": {}
1213
}
1314
```
1415

@@ -23,7 +24,8 @@
2324
"name": "sekai",
2425
"password": "PCD2Z4o12bKUoFa3cC97Hw=="
2526
}
26-
]
27+
],
28+
"multiplex": {}
2729
}
2830
```
2931

@@ -41,7 +43,8 @@
4143
"server_port": 8080,
4244
"password": "PCD2Z4o12bKUoFa3cC97Hw=="
4345
}
44-
]
46+
],
47+
"multiplex": {}
4548
}
4649
```
4750

@@ -82,3 +85,7 @@ Both if empty.
8285
| none | / |
8386
| 2022 methods | `sing-box generate rand --base64 <Key Length>` |
8487
| other methods | any string |
88+
89+
#### multiplex
90+
91+
See [Multiplex](/configuration/shared/multiplex#inbound) for details.

0 commit comments

Comments
 (0)