mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-22 00:21:30 +00:00
Update UoT protocol
This commit is contained in:
parent
a3a5185b15
commit
43f31b40ba
|
@ -12,7 +12,7 @@
|
||||||
"plugin": "",
|
"plugin": "",
|
||||||
"plugin_opts": "",
|
"plugin_opts": "",
|
||||||
"network": "udp",
|
"network": "udp",
|
||||||
"udp_over_tcp": false,
|
"udp_over_tcp": false | {},
|
||||||
"multiplex": {},
|
"multiplex": {},
|
||||||
|
|
||||||
... // Dial Fields
|
... // Dial Fields
|
||||||
|
@ -87,7 +87,9 @@ Both is enabled by default.
|
||||||
|
|
||||||
#### udp_over_tcp
|
#### udp_over_tcp
|
||||||
|
|
||||||
Enable the UDP over TCP protocol.
|
UDP over TCP configuration.
|
||||||
|
|
||||||
|
See [UDP Over TCP](/configuration/shared/udp-over-tcp) for details.
|
||||||
|
|
||||||
Conflict with `multiplex`.
|
Conflict with `multiplex`.
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"plugin": "",
|
"plugin": "",
|
||||||
"plugin_opts": "",
|
"plugin_opts": "",
|
||||||
"network": "udp",
|
"network": "udp",
|
||||||
"udp_over_tcp": false,
|
"udp_over_tcp": false | {},
|
||||||
"multiplex": {},
|
"multiplex": {},
|
||||||
|
|
||||||
... // 拨号字段
|
... // 拨号字段
|
||||||
|
@ -87,7 +87,9 @@ Shadowsocks SIP003 插件参数。
|
||||||
|
|
||||||
#### udp_over_tcp
|
#### udp_over_tcp
|
||||||
|
|
||||||
启用 UDP over TCP 协议。
|
UDP over TCP 配置。
|
||||||
|
|
||||||
|
参阅 [UDP Over TCP](/zh/configuration/shared/udp-over-tcp)。
|
||||||
|
|
||||||
与 `multiplex` 冲突。
|
与 `multiplex` 冲突。
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"username": "sekai",
|
"username": "sekai",
|
||||||
"password": "admin",
|
"password": "admin",
|
||||||
"network": "udp",
|
"network": "udp",
|
||||||
"udp_over_tcp": false,
|
"udp_over_tcp": false | {},
|
||||||
|
|
||||||
... // Dial Fields
|
... // Dial Fields
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,9 @@ Both is enabled by default.
|
||||||
|
|
||||||
#### udp_over_tcp
|
#### udp_over_tcp
|
||||||
|
|
||||||
Enable the UDP over TCP protocol.
|
UDP over TCP protocol settings.
|
||||||
|
|
||||||
|
See [UDP Over TCP](/configuration/shared/udp-over-tcp) for details.
|
||||||
|
|
||||||
### Dial Fields
|
### Dial Fields
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"username": "sekai",
|
"username": "sekai",
|
||||||
"password": "admin",
|
"password": "admin",
|
||||||
"network": "udp",
|
"network": "udp",
|
||||||
"udp_over_tcp": false,
|
"udp_over_tcp": false | {},
|
||||||
|
|
||||||
... // 拨号字段
|
... // 拨号字段
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,9 @@ SOCKS5 密码。
|
||||||
|
|
||||||
#### udp_over_tcp
|
#### udp_over_tcp
|
||||||
|
|
||||||
启用 UDP over TCP 协议。
|
UDP over TCP 配置。
|
||||||
|
|
||||||
|
参阅 [UDP Over TCP](/zh/configuration/shared/udp-over-tcp)。
|
||||||
|
|
||||||
### 拨号字段
|
### 拨号字段
|
||||||
|
|
||||||
|
|
81
docs/configuration/shared/udp-over-tcp.md
Normal file
81
docs/configuration/shared/udp-over-tcp.md
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
# UDP over TCP
|
||||||
|
|
||||||
|
!!! warning ""
|
||||||
|
|
||||||
|
It's a proprietary protocol created by SagerNet, not part of shadowsocks.
|
||||||
|
|
||||||
|
The UDP over TCP protocol is used to transmit UDP packets in TCP.
|
||||||
|
|
||||||
|
### Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"enabled": true,
|
||||||
|
"version": 2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! info ""
|
||||||
|
|
||||||
|
The structure can be replaced with a boolean value when the version is not specified.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
#### enabled
|
||||||
|
|
||||||
|
Enable the UDP over TCP protocol.
|
||||||
|
|
||||||
|
#### version
|
||||||
|
|
||||||
|
The protocol version, `1` or `2`.
|
||||||
|
|
||||||
|
2 is used by default.
|
||||||
|
|
||||||
|
### Application support
|
||||||
|
|
||||||
|
| Project | UoT v1 | UoT v2 |
|
||||||
|
|--------------|----------------------|------------|
|
||||||
|
| sing-box | v0 (2022/08/11) | v1.2-beta9 |
|
||||||
|
| Xray-core | v1.5.7 (2022/06/05) | / |
|
||||||
|
| Clash.Meta | v1.12.0 (2022/07/02) | / |
|
||||||
|
| Shadowrocket | v2.2.12 (2022/08/13) | / |
|
||||||
|
|
||||||
|
### Protocol details
|
||||||
|
|
||||||
|
#### Protocol version 1
|
||||||
|
|
||||||
|
The client requests the magic address to the upper layer proxy protocol to indicate the request: `sp.udp-over-tcp.arpa`
|
||||||
|
|
||||||
|
#### Stream format
|
||||||
|
|
||||||
|
| ATYP | address | port | length | data |
|
||||||
|
|------|----------|-------|--------|----------|
|
||||||
|
| u8 | variable | u16be | u16be | variable |
|
||||||
|
|
||||||
|
*ATYP / address / port*: Uses the SOCKS address format.
|
||||||
|
|
||||||
|
#### Protocol version 2
|
||||||
|
|
||||||
|
Protocol version 2 uses a new magic address: `sp.v2.udp-over-tcp.arpa`
|
||||||
|
|
||||||
|
##### Request format
|
||||||
|
|
||||||
|
| isConnect | ATYP | address | port |
|
||||||
|
|-----------|------|----------|-------|
|
||||||
|
| u8 | u8 | variable | u16be |
|
||||||
|
|
||||||
|
**version**: Fixed to 2.
|
||||||
|
|
||||||
|
**isConnect**: Set to 1 to indicates that the stream uses the connect format, 0 to disable.
|
||||||
|
|
||||||
|
**ATYP / address / port**: Request destination, uses the SOCKS address format.
|
||||||
|
|
||||||
|
##### Connect stream format
|
||||||
|
|
||||||
|
| length | data |
|
||||||
|
|--------|----------|
|
||||||
|
| u16be | variable |
|
||||||
|
|
||||||
|
##### Non-connect stream format
|
||||||
|
|
||||||
|
As the same as the stream format in protocol version 1.
|
|
@ -1,5 +1,9 @@
|
||||||
# Shadowsocks
|
# Shadowsocks
|
||||||
|
|
||||||
|
!!! warning ""
|
||||||
|
|
||||||
|
For censorship bypass usage in China, we recommend using UDP over TCP and disabling UDP on the server.
|
||||||
|
|
||||||
## Single User
|
## Single User
|
||||||
|
|
||||||
#### Server
|
#### Server
|
||||||
|
@ -11,6 +15,7 @@
|
||||||
"type": "shadowsocks",
|
"type": "shadowsocks",
|
||||||
"listen": "::",
|
"listen": "::",
|
||||||
"listen_port": 8080,
|
"listen_port": 8080,
|
||||||
|
"network": "tcp",
|
||||||
"method": "2022-blake3-aes-128-gcm",
|
"method": "2022-blake3-aes-128-gcm",
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg=="
|
"password": "8JCsPssfgS8tiRwiMlhARg=="
|
||||||
}
|
}
|
||||||
|
@ -35,7 +40,8 @@
|
||||||
"server": "127.0.0.1",
|
"server": "127.0.0.1",
|
||||||
"server_port": 8080,
|
"server_port": 8080,
|
||||||
"method": "2022-blake3-aes-128-gcm",
|
"method": "2022-blake3-aes-128-gcm",
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg=="
|
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
||||||
|
"udp_over_tcp": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
"type": "shadowsocks",
|
"type": "shadowsocks",
|
||||||
"tag": "shadowsocks-in",
|
"tag": "shadowsocks-in",
|
||||||
"listen": "127.0.0.1",
|
"listen": "127.0.0.1",
|
||||||
|
"network": "tcp",
|
||||||
"method": "2022-blake3-aes-128-gcm",
|
"method": "2022-blake3-aes-128-gcm",
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg=="
|
"password": "8JCsPssfgS8tiRwiMlhARg=="
|
||||||
}
|
}
|
||||||
|
@ -46,6 +47,7 @@
|
||||||
"max_connections": 4,
|
"max_connections": 4,
|
||||||
"min_streams": 4
|
"min_streams": 4
|
||||||
}
|
}
|
||||||
|
// or "udp_over_tcp": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "shadowtls",
|
"type": "shadowtls",
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -25,7 +25,7 @@ require (
|
||||||
github.com/sagernet/gomobile v0.0.0-20221130124640-349ebaa752ca
|
github.com/sagernet/gomobile v0.0.0-20221130124640-349ebaa752ca
|
||||||
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32
|
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32
|
||||||
github.com/sagernet/reality v0.0.0-20230312150606-35ea9af0e0b8
|
github.com/sagernet/reality v0.0.0-20230312150606-35ea9af0e0b8
|
||||||
github.com/sagernet/sing v0.1.9-0.20230315163130-ed73785ecc78
|
github.com/sagernet/sing v0.1.9-0.20230317044231-85a9429eadb6
|
||||||
github.com/sagernet/sing-dns v0.1.4
|
github.com/sagernet/sing-dns v0.1.4
|
||||||
github.com/sagernet/sing-shadowsocks v0.1.2-0.20230221080503-769c01d6bba9
|
github.com/sagernet/sing-shadowsocks v0.1.2-0.20230221080503-769c01d6bba9
|
||||||
github.com/sagernet/sing-shadowtls v0.1.0
|
github.com/sagernet/sing-shadowtls v0.1.0
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -111,8 +111,8 @@ github.com/sagernet/reality v0.0.0-20230312150606-35ea9af0e0b8 h1:4M3+0/kqvJuTsi
|
||||||
github.com/sagernet/reality v0.0.0-20230312150606-35ea9af0e0b8/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
github.com/sagernet/reality v0.0.0-20230312150606-35ea9af0e0b8/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.1.9-0.20230315163130-ed73785ecc78 h1:SO7TITxjoKyQFBVR0MJhTji9msxEXcv5p60imPrEyY4=
|
github.com/sagernet/sing v0.1.9-0.20230317044231-85a9429eadb6 h1:h1wGLPBJLjujj9kYSbLiP1Tt6+IQnZ7Ok7jQd4u3xxk=
|
||||||
github.com/sagernet/sing v0.1.9-0.20230315163130-ed73785ecc78/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw=
|
github.com/sagernet/sing v0.1.9-0.20230317044231-85a9429eadb6/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw=
|
||||||
github.com/sagernet/sing-dns v0.1.4 h1:7VxgeoSCiiazDSaXXQVcvrTBxFpOePPq/4XdgnUDN+0=
|
github.com/sagernet/sing-dns v0.1.4 h1:7VxgeoSCiiazDSaXXQVcvrTBxFpOePPq/4XdgnUDN+0=
|
||||||
github.com/sagernet/sing-dns v0.1.4/go.mod h1:1+6pCa48B1AI78lD+/i/dLgpw4MwfnsSpZo0Ds8wzzk=
|
github.com/sagernet/sing-dns v0.1.4/go.mod h1:1+6pCa48B1AI78lD+/i/dLgpw4MwfnsSpZo0Ds8wzzk=
|
||||||
github.com/sagernet/sing-shadowsocks v0.1.2-0.20230221080503-769c01d6bba9 h1:qS39eA4C7x+zhEkySbASrtmb6ebdy5v0y2M6mgkmSO0=
|
github.com/sagernet/sing-shadowsocks v0.1.2-0.20230221080503-769c01d6bba9 h1:qS39eA4C7x+zhEkySbASrtmb6ebdy5v0y2M6mgkmSO0=
|
||||||
|
|
|
@ -64,6 +64,7 @@ nav:
|
||||||
- TLS: configuration/shared/tls.md
|
- TLS: configuration/shared/tls.md
|
||||||
- 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
|
||||||
- Inbound:
|
- Inbound:
|
||||||
- configuration/inbound/index.md
|
- configuration/inbound/index.md
|
||||||
- Direct: configuration/inbound/direct.md
|
- Direct: configuration/inbound/direct.md
|
||||||
|
|
|
@ -28,7 +28,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"`
|
||||||
UoT bool `json:"udp_over_tcp,omitempty"`
|
UDPOverTCPOptions *UDPOverTCPOptions `json:"udp_over_tcp,omitempty"`
|
||||||
UoTVersion int `json:"udp_over_tcp_version,omitempty"`
|
|
||||||
MultiplexOptions *MultiplexOptions `json:"multiplex,omitempty"`
|
MultiplexOptions *MultiplexOptions `json:"multiplex,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +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"`
|
||||||
UoT bool `json:"udp_over_tcp,omitempty"`
|
UDPOverTCPOptions *UDPOverTCPOptions `json:"udp_over_tcp,omitempty"`
|
||||||
UoTVersion int `json:"udp_over_tcp_version,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPOutboundOptions struct {
|
type HTTPOutboundOptions struct {
|
||||||
|
|
30
option/udp_over_tcp.go
Normal file
30
option/udp_over_tcp.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package option
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sagernet/sing-box/common/json"
|
||||||
|
"github.com/sagernet/sing/common/uot"
|
||||||
|
)
|
||||||
|
|
||||||
|
type _UDPOverTCPOptions struct {
|
||||||
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
|
Version uint8 `json:"version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UDPOverTCPOptions _UDPOverTCPOptions
|
||||||
|
|
||||||
|
func (o UDPOverTCPOptions) MarshalJSON() ([]byte, error) {
|
||||||
|
switch o.Version {
|
||||||
|
case 0, uot.Version:
|
||||||
|
return json.Marshal(o.Enabled)
|
||||||
|
default:
|
||||||
|
return json.Marshal(_UDPOverTCPOptions(o))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *UDPOverTCPOptions) UnmarshalJSON(bytes []byte) error {
|
||||||
|
err := json.Unmarshal(bytes, &o.Enabled)
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return json.Unmarshal(bytes, (*_UDPOverTCPOptions)(o))
|
||||||
|
}
|
|
@ -29,8 +29,7 @@ type Shadowsocks struct {
|
||||||
method shadowsocks.Method
|
method shadowsocks.Method
|
||||||
serverAddr M.Socksaddr
|
serverAddr M.Socksaddr
|
||||||
plugin sip003.Plugin
|
plugin sip003.Plugin
|
||||||
uot bool
|
uotClient *uot.Client
|
||||||
uotVersion int
|
|
||||||
multiplexDialer N.Dialer
|
multiplexDialer N.Dialer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +49,6 @@ func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
|
||||||
dialer: dialer.New(router, options.DialerOptions),
|
dialer: dialer.New(router, options.DialerOptions),
|
||||||
method: method,
|
method: method,
|
||||||
serverAddr: options.ServerOptions.Build(),
|
serverAddr: options.ServerOptions.Build(),
|
||||||
uot: options.UoT,
|
|
||||||
}
|
}
|
||||||
if options.Plugin != "" {
|
if options.Plugin != "" {
|
||||||
outbound.plugin, err = sip003.CreatePlugin(options.Plugin, options.PluginOptions, router, outbound.dialer, outbound.serverAddr)
|
outbound.plugin, err = sip003.CreatePlugin(options.Plugin, options.PluginOptions, router, outbound.dialer, outbound.serverAddr)
|
||||||
|
@ -58,19 +56,18 @@ func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !options.UoT {
|
uotOptions := common.PtrValueOrDefault(options.UDPOverTCPOptions)
|
||||||
|
if !uotOptions.Enabled {
|
||||||
outbound.multiplexDialer, err = mux.NewClientWithOptions(ctx, (*shadowsocksDialer)(outbound), common.PtrValueOrDefault(options.MultiplexOptions))
|
outbound.multiplexDialer, err = mux.NewClientWithOptions(ctx, (*shadowsocksDialer)(outbound), common.PtrValueOrDefault(options.MultiplexOptions))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch options.UoTVersion {
|
if uotOptions.Enabled {
|
||||||
case uot.LegacyVersion:
|
outbound.uotClient = &uot.Client{
|
||||||
outbound.uotVersion = uot.LegacyVersion
|
Dialer: (*shadowsocksDialer)(outbound),
|
||||||
case 0, uot.Version:
|
Version: uotOptions.Version,
|
||||||
outbound.uotVersion = uot.Version
|
}
|
||||||
default:
|
|
||||||
return nil, E.New("unknown udp over tcp protocol version ", options.UoTVersion)
|
|
||||||
}
|
}
|
||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
@ -84,26 +81,13 @@ func (h *Shadowsocks) DialContext(ctx context.Context, network string, destinati
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||||
case N.NetworkUDP:
|
case N.NetworkUDP:
|
||||||
if h.uot {
|
if h.uotClient != nil {
|
||||||
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound UoT connect packet connection to ", destination)
|
||||||
var uotDestination M.Socksaddr
|
return h.uotClient.DialContext(ctx, network, destination)
|
||||||
if h.uotVersion == uot.Version {
|
|
||||||
uotDestination.Fqdn = uot.MagicAddress
|
|
||||||
} else {
|
} else {
|
||||||
uotDestination.Fqdn = uot.LegacyMagicAddress
|
|
||||||
}
|
|
||||||
tcpConn, err := (*shadowsocksDialer)(h).DialContext(ctx, N.NetworkTCP, uotDestination)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if h.uotVersion == uot.Version {
|
|
||||||
return uot.NewLazyConn(tcpConn, uot.Request{IsConnect: true, Destination: destination}), nil
|
|
||||||
} else {
|
|
||||||
return uot.NewConn(tcpConn, false, destination), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return (*shadowsocksDialer)(h).DialContext(ctx, network, destination)
|
return (*shadowsocksDialer)(h).DialContext(ctx, network, destination)
|
||||||
} else {
|
} else {
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
|
@ -121,23 +105,11 @@ func (h *Shadowsocks) ListenPacket(ctx context.Context, destination M.Socksaddr)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.tag
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
if h.multiplexDialer == nil {
|
if h.multiplexDialer == nil {
|
||||||
if h.uot {
|
if h.uotClient != nil {
|
||||||
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
||||||
var uotDestination M.Socksaddr
|
return h.uotClient.ListenPacket(ctx, destination)
|
||||||
if h.uotVersion == uot.Version {
|
|
||||||
uotDestination.Fqdn = uot.MagicAddress
|
|
||||||
} else {
|
} else {
|
||||||
uotDestination.Fqdn = uot.LegacyMagicAddress
|
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
}
|
|
||||||
tcpConn, err := (*shadowsocksDialer)(h).DialContext(ctx, N.NetworkTCP, uotDestination)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if h.uotVersion == uot.Version {
|
|
||||||
return uot.NewLazyConn(tcpConn, uot.Request{Destination: destination}), nil
|
|
||||||
} else {
|
|
||||||
return uot.NewConn(tcpConn, false, destination), nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
return (*shadowsocksDialer)(h).ListenPacket(ctx, destination)
|
return (*shadowsocksDialer)(h).ListenPacket(ctx, destination)
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
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"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
@ -22,8 +23,7 @@ type Socks struct {
|
||||||
myOutboundAdapter
|
myOutboundAdapter
|
||||||
client *socks.Client
|
client *socks.Client
|
||||||
resolve bool
|
resolve bool
|
||||||
uot bool
|
uotClient *uot.Client
|
||||||
uotVersion int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, options option.SocksOutboundOptions) (*Socks, error) {
|
func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, options option.SocksOutboundOptions) (*Socks, error) {
|
||||||
|
@ -47,15 +47,13 @@ func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, optio
|
||||||
},
|
},
|
||||||
client: socks.NewClient(dialer.New(router, options.DialerOptions), options.ServerOptions.Build(), version, options.Username, options.Password),
|
client: socks.NewClient(dialer.New(router, options.DialerOptions), options.ServerOptions.Build(), version, options.Username, options.Password),
|
||||||
resolve: version == socks.Version4,
|
resolve: version == socks.Version4,
|
||||||
uot: options.UoT,
|
|
||||||
}
|
}
|
||||||
switch options.UoTVersion {
|
uotOptions := common.PtrValueOrDefault(options.UDPOverTCPOptions)
|
||||||
case uot.LegacyVersion:
|
if uotOptions.Enabled {
|
||||||
outbound.uotVersion = uot.LegacyVersion
|
outbound.uotClient = &uot.Client{
|
||||||
case 0, uot.Version:
|
Dialer: outbound.client,
|
||||||
outbound.uotVersion = uot.Version
|
Version: uotOptions.Version,
|
||||||
default:
|
}
|
||||||
return nil, E.New("unknown udp over tcp protocol version ", options.UoTVersion)
|
|
||||||
}
|
}
|
||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
@ -68,23 +66,9 @@ func (h *Socks) DialContext(ctx context.Context, network string, destination M.S
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||||
case N.NetworkUDP:
|
case N.NetworkUDP:
|
||||||
if h.uot {
|
if h.uotClient != nil {
|
||||||
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound UoT connect packet connection to ", destination)
|
||||||
var uotDestination M.Socksaddr
|
return h.uotClient.DialContext(ctx, network, destination)
|
||||||
if h.uotVersion == uot.Version {
|
|
||||||
uotDestination.Fqdn = uot.MagicAddress
|
|
||||||
} else {
|
|
||||||
uotDestination.Fqdn = uot.LegacyMagicAddress
|
|
||||||
}
|
|
||||||
tcpConn, err := h.client.DialContext(ctx, N.NetworkTCP, uotDestination)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if h.uotVersion == uot.Version {
|
|
||||||
return uot.NewLazyConn(tcpConn, uot.Request{IsConnect: true, Destination: destination}), nil
|
|
||||||
} else {
|
|
||||||
return uot.NewConn(tcpConn, false, destination), nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
default:
|
default:
|
||||||
|
@ -104,23 +88,9 @@ func (h *Socks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.
|
||||||
ctx, metadata := adapter.AppendContext(ctx)
|
ctx, metadata := adapter.AppendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.tag
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
if h.uot {
|
if h.uotClient != nil {
|
||||||
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
||||||
var uotDestination M.Socksaddr
|
return h.uotClient.ListenPacket(ctx, destination)
|
||||||
if h.uotVersion == uot.Version {
|
|
||||||
uotDestination.Fqdn = uot.MagicAddress
|
|
||||||
} else {
|
|
||||||
uotDestination.Fqdn = uot.LegacyMagicAddress
|
|
||||||
}
|
|
||||||
tcpConn, err := h.client.DialContext(ctx, N.NetworkTCP, uotDestination)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if h.uotVersion == uot.Version {
|
|
||||||
return uot.NewLazyConn(tcpConn, uot.Request{Destination: destination}), nil
|
|
||||||
} else {
|
|
||||||
return uot.NewConn(tcpConn, false, destination), nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
return h.client.ListenPacket(ctx, destination)
|
return h.client.ListenPacket(ctx, destination)
|
||||||
|
|
|
@ -589,12 +589,12 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
|
||||||
}
|
}
|
||||||
metadata.Domain = metadata.Destination.Fqdn
|
metadata.Domain = metadata.Destination.Fqdn
|
||||||
metadata.Destination = request.Destination
|
metadata.Destination = request.Destination
|
||||||
return r.RoutePacketConnection(ctx, uot.NewConn(conn, request.IsConnect, metadata.Destination), metadata)
|
return r.RoutePacketConnection(ctx, uot.NewConn(conn, *request), metadata)
|
||||||
case uot.LegacyMagicAddress:
|
case uot.LegacyMagicAddress:
|
||||||
r.logger.InfoContext(ctx, "inbound legacy UoT connection")
|
r.logger.InfoContext(ctx, "inbound legacy UoT connection")
|
||||||
metadata.Domain = metadata.Destination.Fqdn
|
metadata.Domain = metadata.Destination.Fqdn
|
||||||
metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()}
|
metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()}
|
||||||
return r.RoutePacketConnection(ctx, uot.NewConn(conn, false, metadata.Destination), metadata)
|
return r.RoutePacketConnection(ctx, uot.NewConn(conn, uot.Request{}), metadata)
|
||||||
}
|
}
|
||||||
if metadata.InboundOptions.SniffEnabled {
|
if metadata.InboundOptions.SniffEnabled {
|
||||||
buffer := buf.NewPacket()
|
buffer := buf.NewPacket()
|
||||||
|
|
Loading…
Reference in a new issue