mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-22 08:31:30 +00:00
Update UoT protocol
This commit is contained in:
parent
ffdaae90d7
commit
78e02b52ca
4
go.mod
4
go.mod
|
@ -24,7 +24,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.20230313033500-448948d26d1a
|
github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b
|
||||||
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
|
||||||
|
@ -51,7 +51,7 @@ require (
|
||||||
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c
|
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c
|
||||||
)
|
)
|
||||||
|
|
||||||
//replace github.com/sagernet/sing-tun => ../sing-tun
|
//replace github.com/sagernet/sing => ../sing
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/ajg/form v1.5.1 // indirect
|
github.com/ajg/form v1.5.1 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -109,8 +109,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.20230313033500-448948d26d1a h1:JgPPxKLiqA95Z0oTp9FyYUfij8xsjS2rBWtpQ41zFTo=
|
github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b h1:1iKGftQ59+shDSx2RaLaxXJcMK/B+IU9WqUPwyBW+E0=
|
||||||
github.com/sagernet/sing v0.1.9-0.20230313033500-448948d26d1a/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw=
|
github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b/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=
|
||||||
|
|
|
@ -29,5 +29,6 @@ type ShadowsocksOutboundOptions struct {
|
||||||
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"`
|
UoT bool `json:"udp_over_tcp,omitempty"`
|
||||||
|
UoTVersion int `json:"udp_over_tcp_version,omitempty"`
|
||||||
MultiplexOptions *MultiplexOptions `json:"multiplex,omitempty"`
|
MultiplexOptions *MultiplexOptions `json:"multiplex,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,12 @@ type HTTPMixedInboundOptions struct {
|
||||||
type SocksOutboundOptions struct {
|
type SocksOutboundOptions struct {
|
||||||
DialerOptions
|
DialerOptions
|
||||||
ServerOptions
|
ServerOptions
|
||||||
Version string `json:"version,omitempty"`
|
Version string `json:"version,omitempty"`
|
||||||
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"`
|
UoT bool `json:"udp_over_tcp,omitempty"`
|
||||||
|
UoTVersion int `json:"udp_over_tcp_version,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPOutboundOptions struct {
|
type HTTPOutboundOptions struct {
|
||||||
|
|
|
@ -30,6 +30,7 @@ type Shadowsocks struct {
|
||||||
serverAddr M.Socksaddr
|
serverAddr M.Socksaddr
|
||||||
plugin sip003.Plugin
|
plugin sip003.Plugin
|
||||||
uot bool
|
uot bool
|
||||||
|
uotVersion int
|
||||||
multiplexDialer N.Dialer
|
multiplexDialer N.Dialer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +64,14 @@ func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
switch options.UoTVersion {
|
||||||
|
case uot.LegacyVersion:
|
||||||
|
outbound.uotVersion = uot.LegacyVersion
|
||||||
|
case 0, uot.Version:
|
||||||
|
outbound.uotVersion = uot.Version
|
||||||
|
default:
|
||||||
|
return nil, E.New("unknown udp over tcp protocol version ", options.UoTVersion)
|
||||||
|
}
|
||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,14 +86,21 @@ func (h *Shadowsocks) DialContext(ctx context.Context, network string, destinati
|
||||||
case N.NetworkUDP:
|
case N.NetworkUDP:
|
||||||
if h.uot {
|
if h.uot {
|
||||||
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
||||||
tcpConn, err := (*shadowsocksDialer)(h).DialContext(ctx, N.NetworkTCP, M.Socksaddr{
|
var uotDestination M.Socksaddr
|
||||||
Fqdn: uot.UOTMagicAddress,
|
if h.uotVersion == uot.Version {
|
||||||
Port: destination.Port,
|
uotDestination.Fqdn = uot.MagicAddress
|
||||||
})
|
} else {
|
||||||
|
uotDestination.Fqdn = uot.LegacyMagicAddress
|
||||||
|
}
|
||||||
|
tcpConn, err := (*shadowsocksDialer)(h).DialContext(ctx, N.NetworkTCP, uotDestination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return uot.NewClientConn(tcpConn), nil
|
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)
|
||||||
}
|
}
|
||||||
|
@ -107,14 +123,21 @@ func (h *Shadowsocks) ListenPacket(ctx context.Context, destination M.Socksaddr)
|
||||||
if h.multiplexDialer == nil {
|
if h.multiplexDialer == nil {
|
||||||
if h.uot {
|
if h.uot {
|
||||||
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
||||||
tcpConn, err := (*shadowsocksDialer)(h).DialContext(ctx, N.NetworkTCP, M.Socksaddr{
|
var uotDestination M.Socksaddr
|
||||||
Fqdn: uot.UOTMagicAddress,
|
if h.uotVersion == uot.Version {
|
||||||
Port: destination.Port,
|
uotDestination.Fqdn = uot.MagicAddress
|
||||||
})
|
} else {
|
||||||
|
uotDestination.Fqdn = uot.LegacyMagicAddress
|
||||||
|
}
|
||||||
|
tcpConn, err := (*shadowsocksDialer)(h).DialContext(ctx, N.NetworkTCP, uotDestination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return uot.NewClientConn(tcpConn), nil
|
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)
|
||||||
|
|
|
@ -20,13 +20,13 @@ var _ adapter.Outbound = (*Socks)(nil)
|
||||||
|
|
||||||
type Socks struct {
|
type Socks struct {
|
||||||
myOutboundAdapter
|
myOutboundAdapter
|
||||||
client *socks.Client
|
client *socks.Client
|
||||||
resolve bool
|
resolve bool
|
||||||
uot bool
|
uot bool
|
||||||
|
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) {
|
||||||
detour := dialer.New(router, options.DialerOptions)
|
|
||||||
var version socks.Version
|
var version socks.Version
|
||||||
var err error
|
var err error
|
||||||
if options.Version != "" {
|
if options.Version != "" {
|
||||||
|
@ -37,18 +37,27 @@ func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, optio
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Socks{
|
outbound := &Socks{
|
||||||
myOutboundAdapter{
|
myOutboundAdapter: myOutboundAdapter{
|
||||||
protocol: C.TypeSocks,
|
protocol: C.TypeSocks,
|
||||||
network: options.Network.Build(),
|
network: options.Network.Build(),
|
||||||
router: router,
|
router: router,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
},
|
},
|
||||||
socks.NewClient(detour, options.ServerOptions.Build(), version, options.Username, options.Password),
|
client: socks.NewClient(dialer.New(router, options.DialerOptions), options.ServerOptions.Build(), version, options.Username, options.Password),
|
||||||
version == socks.Version4,
|
resolve: version == socks.Version4,
|
||||||
options.UoT,
|
uot: options.UoT,
|
||||||
}, nil
|
}
|
||||||
|
switch options.UoTVersion {
|
||||||
|
case uot.LegacyVersion:
|
||||||
|
outbound.uotVersion = uot.LegacyVersion
|
||||||
|
case 0, uot.Version:
|
||||||
|
outbound.uotVersion = uot.Version
|
||||||
|
default:
|
||||||
|
return nil, E.New("unknown udp over tcp protocol version ", options.UoTVersion)
|
||||||
|
}
|
||||||
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Socks) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *Socks) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
@ -61,14 +70,21 @@ func (h *Socks) DialContext(ctx context.Context, network string, destination M.S
|
||||||
case N.NetworkUDP:
|
case N.NetworkUDP:
|
||||||
if h.uot {
|
if h.uot {
|
||||||
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
||||||
tcpConn, err := h.client.DialContext(ctx, N.NetworkTCP, M.Socksaddr{
|
var uotDestination M.Socksaddr
|
||||||
Fqdn: uot.UOTMagicAddress,
|
if h.uotVersion == uot.Version {
|
||||||
Port: destination.Port,
|
uotDestination.Fqdn = uot.MagicAddress
|
||||||
})
|
} else {
|
||||||
|
uotDestination.Fqdn = uot.LegacyMagicAddress
|
||||||
|
}
|
||||||
|
tcpConn, err := h.client.DialContext(ctx, N.NetworkTCP, uotDestination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return uot.NewClientConn(tcpConn), nil
|
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:
|
||||||
|
@ -90,14 +106,21 @@ func (h *Socks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
if h.uot {
|
if h.uot {
|
||||||
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
||||||
tcpConn, err := h.client.DialContext(ctx, N.NetworkTCP, M.Socksaddr{
|
var uotDestination M.Socksaddr
|
||||||
Fqdn: uot.UOTMagicAddress,
|
if h.uotVersion == uot.Version {
|
||||||
Port: destination.Port,
|
uotDestination.Fqdn = uot.MagicAddress
|
||||||
})
|
} else {
|
||||||
|
uotDestination.Fqdn = uot.LegacyMagicAddress
|
||||||
|
}
|
||||||
|
tcpConn, err := h.client.DialContext(ctx, N.NetworkTCP, uotDestination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return uot.NewClientConn(tcpConn), nil
|
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)
|
||||||
|
|
|
@ -577,10 +577,24 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
|
||||||
case vmess.MuxDestination.Fqdn:
|
case vmess.MuxDestination.Fqdn:
|
||||||
r.logger.InfoContext(ctx, "inbound legacy multiplex connection")
|
r.logger.InfoContext(ctx, "inbound legacy multiplex connection")
|
||||||
return vmess.HandleMuxConnection(ctx, conn, adapter.NewUpstreamHandler(metadata, r.RouteConnection, r.RoutePacketConnection, r))
|
return vmess.HandleMuxConnection(ctx, conn, adapter.NewUpstreamHandler(metadata, r.RouteConnection, r.RoutePacketConnection, r))
|
||||||
case uot.UOTMagicAddress:
|
case uot.MagicAddress:
|
||||||
r.logger.InfoContext(ctx, "inbound UoT connection")
|
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.RoutePacketConnection(ctx, uot.NewConn(conn, request.IsConnect, metadata.Destination), metadata)
|
||||||
|
case uot.LegacyMagicAddress:
|
||||||
|
r.logger.InfoContext(ctx, "inbound legacy UoT connection")
|
||||||
|
metadata.Domain = metadata.Destination.Fqdn
|
||||||
metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()}
|
metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()}
|
||||||
return r.RoutePacketConnection(ctx, uot.NewClientConn(conn), metadata)
|
return r.RoutePacketConnection(ctx, uot.NewConn(conn, false, metadata.Destination), metadata)
|
||||||
}
|
}
|
||||||
if metadata.InboundOptions.SniffEnabled {
|
if metadata.InboundOptions.SniffEnabled {
|
||||||
buffer := buf.NewPacket()
|
buffer := buf.NewPacket()
|
||||||
|
@ -685,7 +699,7 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||||
}
|
}
|
||||||
conn = bufio.NewCachedPacketConn(conn, buffer, destination)
|
conn = bufio.NewCachedPacketConn(conn, buffer, destination)
|
||||||
}
|
}
|
||||||
if metadata.Destination.IsFqdn() && metadata.Destination.Fqdn != uot.UOTMagicAddress && dns.DomainStrategy(metadata.InboundOptions.DomainStrategy) != dns.DomainStrategyAsIS {
|
if metadata.Destination.IsFqdn() && dns.DomainStrategy(metadata.InboundOptions.DomainStrategy) != dns.DomainStrategyAsIS {
|
||||||
addresses, err := r.Lookup(adapter.WithContext(ctx, &metadata), metadata.Destination.Fqdn, dns.DomainStrategy(metadata.InboundOptions.DomainStrategy))
|
addresses, err := r.Lookup(adapter.WithContext(ctx, &metadata), metadata.Destination.Fqdn, dns.DomainStrategy(metadata.InboundOptions.DomainStrategy))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
Loading…
Reference in a new issue