Browse Source

Add udp over tcp support for shadowsocks-2022

pull/1096/head
世界 3 years ago
parent
commit
c3505632fd
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
  1. 4
      app/proxyman/outbound/handler.go
  2. 25
      app/proxyman/outbound/uot.go
  3. 15
      app/proxyman/outbound/uot_stub.go
  4. 4
      go.mod
  5. 8
      go.sum
  6. 2
      infra/conf/shadowsocks.go
  7. 2
      infra/conf/shadowsocks_legacy.go
  8. 38
      proxy/shadowsocks_2022/config.pb.go
  9. 1
      proxy/shadowsocks_2022/config.proto
  10. 13
      proxy/shadowsocks_2022/inbound.go
  11. 13
      proxy/shadowsocks_2022/inbound_multi.go
  12. 19
      proxy/shadowsocks_2022/outbound.go
  13. 4
      proxy/shadowsocks_2022/shadowsocks_2022.go
  14. 4
      testing/scenarios/shadowsocks_2022_test.go

4
app/proxyman/outbound/handler.go

@ -211,6 +211,10 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
}
}
if conn, err := h.getUoTConnection(ctx, dest); err != os.ErrInvalid {
return conn, err
}
conn, err := internet.Dial(ctx, dest, h.streamSettings)
return h.getStatCouterConnection(conn), err
}

25
app/proxyman/outbound/uot.go

@ -0,0 +1,25 @@
//go:build go1.18
package outbound
import (
"context"
"os"
"github.com/sagernet/sing/common/uot"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
)
func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (stat.Connection, error) {
if !dest.Address.Family().IsDomain() || dest.Address.Domain() != uot.UOTMagicAddress {
return nil, os.ErrInvalid
}
packetConn, err := internet.ListenSystemPacket(ctx, &net.UDPAddr{IP: net.AnyIP.IP(), Port: 0}, h.streamSettings.SocketSettings)
if err != nil {
return nil, newError("unable to listen socket").Base(err)
}
conn := uot.NewServerConn(packetConn)
return h.getStatCouterConnection(conn), nil
}

15
app/proxyman/outbound/uot_stub.go

@ -0,0 +1,15 @@
//go:build !go1.18
package outbound
import (
"context"
"os"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/stat"
)
func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (stat.Connection, error) {
return nil, os.ErrInvalid
}

4
go.mod

@ -16,8 +16,8 @@ require (
github.com/pelletier/go-toml v1.9.5
github.com/pires/go-proxyproto v0.6.2
github.com/refraction-networking/utls v1.1.0
github.com/sagernet/sing v0.0.0-20220530041323-c82c144a8e00
github.com/sagernet/sing-shadowsocks v0.0.0-20220531032427-182b7837c827
github.com/sagernet/sing v0.0.0-20220601033944-4e04bbd3d84d
github.com/sagernet/sing-shadowsocks v0.0.0-20220601034426-ee9be8af94e4
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb
github.com/stretchr/testify v1.7.1
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e

8
go.sum

@ -172,10 +172,10 @@ github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sagernet/sing v0.0.0-20220530041323-c82c144a8e00 h1:kQCITv1yBrSSL6RIBPWTe1+goyWLbS4DELWTeRKmoh8=
github.com/sagernet/sing v0.0.0-20220530041323-c82c144a8e00/go.mod h1:w2HnJzXKHpD6F5Z/9XlSD4qbcpHY2RSZuQnFzqgELMg=
github.com/sagernet/sing-shadowsocks v0.0.0-20220531032427-182b7837c827 h1:dy8/Ltn4TW8op9esqdXBCuOVuaUSEZW2gCVE609z2UY=
github.com/sagernet/sing-shadowsocks v0.0.0-20220531032427-182b7837c827/go.mod h1:24Hwpi7iyZ8KSUqV5GpG29xSc8jUfU//RlClJcOqph4=
github.com/sagernet/sing v0.0.0-20220601033944-4e04bbd3d84d h1:BNhKTknI2tBPUOPDV3lcgwOX6iZimL7K3TPdTdp5hiA=
github.com/sagernet/sing v0.0.0-20220601033944-4e04bbd3d84d/go.mod h1:w2HnJzXKHpD6F5Z/9XlSD4qbcpHY2RSZuQnFzqgELMg=
github.com/sagernet/sing-shadowsocks v0.0.0-20220601034426-ee9be8af94e4 h1:POJZphM4VaovhB/7GjJTG+pUTcI/Q9jaOHBqTL6jq1E=
github.com/sagernet/sing-shadowsocks v0.0.0-20220601034426-ee9be8af94e4/go.mod h1:8NNH8ACh+C0oZb4ielvRJHYA4kFmhDdSQxmwAa+N8PM=
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=

2
infra/conf/shadowsocks.go

@ -136,6 +136,7 @@ type ShadowsocksServerTarget struct {
Email string `json:"email"`
Level byte `json:"level"`
IVCheck bool `json:"ivCheck"`
UoT bool `json:"uot"`
}
type ShadowsocksClientConfig struct {
@ -165,6 +166,7 @@ func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
config.Port = uint32(server.Port)
config.Method = server.Cipher
config.Key = server.Password
config.UdpOverTcp = server.UoT
return config, nil
}
}

2
infra/conf/shadowsocks_legacy.go

@ -1,4 +1,5 @@
//go:build !go1.18
package conf
import (
@ -98,6 +99,7 @@ type ShadowsocksServerTarget struct {
Email string `json:"email"`
Level byte `json:"level"`
IVCheck bool `json:"ivCheck"`
UoT bool `json:"uot"`
}
type ShadowsocksClientConfig struct {

38
proxy/shadowsocks_2022/config.pb.go

@ -239,10 +239,11 @@ type ClientConfig struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
Method string `protobuf:"bytes,3,opt,name=method,proto3" json:"method,omitempty"`
Key string `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"`
Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
Method string `protobuf:"bytes,3,opt,name=method,proto3" json:"method,omitempty"`
Key string `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"`
UdpOverTcp bool `protobuf:"varint,5,opt,name=udp_over_tcp,json=udpOverTcp,proto3" json:"udp_over_tcp,omitempty"`
}
func (x *ClientConfig) Reset() {
@ -305,6 +306,13 @@ func (x *ClientConfig) GetKey() string {
return ""
}
func (x *ClientConfig) GetUdpOverTcp() bool {
if x != nil {
return x.UdpOverTcp
}
return false
}
var File_proxy_shadowsocks_2022_config_proto protoreflect.FileDescriptor
var file_proxy_shadowsocks_2022_config_proto_rawDesc = []byte{
@ -340,7 +348,7 @@ var file_proxy_shadowsocks_2022_config_proto_rawDesc = []byte{
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61,
0x69, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28,
0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x83, 0x01, 0x0a, 0x0c, 0x43, 0x6c, 0x69,
0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0xa5, 0x01, 0x0a, 0x0c, 0x43, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x07, 0x61, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f,
@ -348,15 +356,17 @@ var file_proxy_shadowsocks_2022_config_proto_rawDesc = []byte{
0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04,
0x70, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x10, 0x0a, 0x03,
0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x42, 0x72,
0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x32, 0x30, 0x32,
0x32, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73,
0x5f, 0x32, 0x30, 0x32, 0x32, 0xaa, 0x02, 0x1a, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f,
0x78, 0x79, 0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x32, 0x30,
0x32, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x20,
0x0a, 0x0c, 0x75, 0x64, 0x70, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x63, 0x70, 0x18, 0x05,
0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x64, 0x70, 0x4f, 0x76, 0x65, 0x72, 0x54, 0x63, 0x70,
0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x32,
0x30, 0x32, 0x32, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63,
0x6b, 0x73, 0x5f, 0x32, 0x30, 0x32, 0x32, 0xaa, 0x02, 0x1a, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x73, 0x6f, 0x63, 0x6b, 0x73,
0x32, 0x30, 0x32, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

1
proxy/shadowsocks_2022/config.proto

@ -35,4 +35,5 @@ message ClientConfig {
uint32 port = 2;
string method = 3;
string key = 4;
bool udp_over_tcp = 5;
}

13
proxy/shadowsocks_2022/inbound.go

@ -10,6 +10,7 @@ import (
C "github.com/sagernet/sing/common"
B "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common"
@ -74,20 +75,23 @@ func (i *Inbound) Process(ctx context.Context, network net.Network, connection s
ctx = session.ContextWithDispatcher(ctx, dispatcher)
if network == net.Network_TCP {
return i.service.NewConnection(ctx, connection, metadata)
return returnError(i.service.NewConnection(ctx, connection, metadata))
} else {
reader := buf.NewReader(connection)
pc := &natPacketConn{connection}
for {
mb, err := reader.ReadMultiBuffer()
if err != nil {
return err
buf.ReleaseMulti(mb)
return returnError(err)
}
for _, buffer := range mb {
err = i.service.NewPacket(ctx, pc, B.As(buffer.Bytes()), metadata)
err = i.service.NewPacket(ctx, pc, B.As(buffer.Bytes()).ToOwned(), metadata)
if err != nil {
buf.ReleaseMulti(mb)
return err
}
buffer.Release()
}
}
}
@ -147,6 +151,9 @@ func (i *Inbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, me
}
func (i *Inbound) HandleError(err error) {
if E.IsClosed(err) {
return
}
newError(err).AtWarning().WriteToLog()
}

13
proxy/shadowsocks_2022/inbound_multi.go

@ -10,6 +10,7 @@ import (
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
B "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common"
@ -93,20 +94,23 @@ func (i *MultiUserInbound) Process(ctx context.Context, network net.Network, con
ctx = session.ContextWithDispatcher(ctx, dispatcher)
if network == net.Network_TCP {
return i.service.NewConnection(ctx, connection, metadata)
return returnError(i.service.NewConnection(ctx, connection, metadata))
} else {
reader := buf.NewReader(connection)
pc := &natPacketConn{connection}
for {
mb, err := reader.ReadMultiBuffer()
if err != nil {
return err
buf.ReleaseMulti(mb)
return returnError(err)
}
for _, buffer := range mb {
err = i.service.NewPacket(ctx, pc, B.As(buffer.Bytes()), metadata)
err = i.service.NewPacket(ctx, pc, B.As(buffer.Bytes()).ToOwned(), metadata)
if err != nil {
buf.ReleaseMulti(mb)
return err
}
buffer.Release()
}
}
}
@ -170,5 +174,8 @@ func (i *MultiUserInbound) NewPacketConnection(ctx context.Context, conn N.Packe
}
func (i *MultiUserInbound) HandleError(err error) {
if E.IsClosed(err) {
return
}
newError(err).AtWarning().WriteToLog()
}

19
proxy/shadowsocks_2022/outbound.go

@ -13,7 +13,9 @@ import (
C "github.com/sagernet/sing/common"
B "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/uot"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
@ -32,6 +34,7 @@ type Outbound struct {
ctx context.Context
server net.Destination
method shadowsocks.Method
uot bool
}
func NewClient(ctx context.Context, config *ClientConfig) (*Outbound, error) {
@ -42,6 +45,7 @@ func NewClient(ctx context.Context, config *ClientConfig) (*Outbound, error) {
Port: net.Port(config.Port),
Network: net.Network_TCP,
},
uot: config.UdpOverTcp,
}
if C.Contains(shadowaead_2022.List, config.Method) {
if config.Key == "" {
@ -75,7 +79,11 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int
newError("tunneling request to ", destination, " via ", o.server.NetAddr()).WriteToLog(session.ExportIDToError(ctx))
serverDestination := o.server
serverDestination.Network = network
if o.uot {
serverDestination.Network = net.Network_TCP
} else {
serverDestination.Network = network
}
connection, err := dialer.Dial(ctx, serverDestination)
if err != nil {
return newError("failed to connect to server").Base(err)
@ -143,7 +151,12 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int
}
}
serverConn := o.method.DialPacketConn(connection)
return returnError(bufio.CopyPacketConn(ctx, packetConn, serverConn))
if o.uot {
serverConn := o.method.DialEarlyConn(connection, M.Socksaddr{Fqdn: uot.UOTMagicAddress})
return returnError(bufio.CopyPacketConn(ctx, packetConn, uot.NewClientConn(serverConn)))
} else {
serverConn := o.method.DialPacketConn(connection)
return returnError(bufio.CopyPacketConn(ctx, packetConn, serverConn))
}
}
}

4
proxy/shadowsocks_2022/shadowsocks_2022.go

@ -3,10 +3,10 @@
package shadowsocks_2022
import (
"errors"
"io"
B "github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
@ -140,7 +140,7 @@ func (w *packetConnWrapper) Close() error {
}
func returnError(err error) error {
if errors.Is(err, io.EOF) {
if E.IsClosed(err) {
return nil
}
return err

4
testing/scenarios/shadowsocks_2022_test.go

@ -3,11 +3,10 @@ package scenarios
import (
"crypto/rand"
"encoding/base64"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
"testing"
"time"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
"github.com/xtls/xray-core/app/log"
"github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common"
@ -17,6 +16,7 @@ import (
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/proxy/dokodemo"
"github.com/xtls/xray-core/proxy/freedom"
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
"github.com/xtls/xray-core/testing/servers/tcp"
"github.com/xtls/xray-core/testing/servers/udp"
"golang.org/x/sync/errgroup"

Loading…
Cancel
Save