diff --git a/app/proxyman/outbound/uot.go b/app/proxyman/outbound/uot.go index a4af220c..4610bd79 100644 --- a/app/proxyman/outbound/uot.go +++ b/app/proxyman/outbound/uot.go @@ -11,13 +11,21 @@ import ( ) func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (stat.Connection, error) { - if !dest.Address.Family().IsDomain() || dest.Address.Domain() != uot.UOTMagicAddress { + if !dest.Address.Family().IsDomain() { + return nil, os.ErrInvalid + } + var uotVersion int + if dest.Address.Domain() == uot.MagicAddress { + uotVersion = uot.Version + } else if dest.Address.Domain() == uot.LegacyMagicAddress { + uotVersion = uot.LegacyVersion + } else { 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) + conn := uot.NewServerConn(packetConn, uotVersion) return h.getStatCouterConnection(conn), nil } diff --git a/go.mod b/go.mod index be50bf9f..dfb7ca04 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/pires/go-proxyproto v0.6.2 github.com/quic-go/quic-go v0.33.0 github.com/refraction-networking/utls v1.2.3-0.20230308205431-4f1df6c200db - github.com/sagernet/sing v0.1.8 + github.com/sagernet/sing v0.2.0 github.com/sagernet/sing-shadowsocks v0.1.1 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb diff --git a/go.sum b/go.sum index 0b7e80ff..155155a2 100644 --- a/go.sum +++ b/go.sum @@ -141,8 +141,10 @@ github.com/refraction-networking/utls v1.2.3-0.20230308205431-4f1df6c200db/go.mo github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sagernet/sing v0.1.8 h1:6DKo2FkSHn0nUcjO7bAext/ai7y7pCusK/+fScBJ5Jk= -github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b h1:1iKGftQ59+shDSx2RaLaxXJcMK/B+IU9WqUPwyBW+E0= +github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= +github.com/sagernet/sing v0.2.0 h1:iyc4TaeXG5XYXixl48zSDDTw46C9NOEAVFq6ZE0dA2k= +github.com/sagernet/sing v0.2.0/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= github.com/sagernet/sing-shadowsocks v0.1.1 h1:uFK2rlVeD/b1xhDwSMbUI2goWc6fOKxp+ZeKHZq6C9Q= github.com/sagernet/sing-shadowsocks v0.1.1/go.mod h1:f3mHTy5shnVM9l8UocMlJgC/1G/zdj5FuEuVXhDinGU= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= diff --git a/infra/conf/shadowsocks.go b/infra/conf/shadowsocks.go index 4b94c8e8..240d4aaa 100644 --- a/infra/conf/shadowsocks.go +++ b/infra/conf/shadowsocks.go @@ -155,14 +155,15 @@ func buildShadowsocks2022(v *ShadowsocksServerConfig) (proto.Message, error) { } type ShadowsocksServerTarget struct { - Address *Address `json:"address"` - Port uint16 `json:"port"` - Cipher string `json:"method"` - Password string `json:"password"` - Email string `json:"email"` - Level byte `json:"level"` - IVCheck bool `json:"ivCheck"` - UoT bool `json:"uot"` + Address *Address `json:"address"` + Port uint16 `json:"port"` + Cipher string `json:"method"` + Password string `json:"password"` + Email string `json:"email"` + Level byte `json:"level"` + IVCheck bool `json:"ivCheck"` + UoT bool `json:"uot"` + UoTVersion int `json:"uotVersion"` } type ShadowsocksClientConfig struct { @@ -193,6 +194,7 @@ func (v *ShadowsocksClientConfig) Build() (proto.Message, error) { config.Method = server.Cipher config.Key = server.Password config.UdpOverTcp = server.UoT + config.UdpOverTcpVersion = uint32(server.UoTVersion) return config, nil } } diff --git a/proxy/shadowsocks_2022/config.pb.go b/proxy/shadowsocks_2022/config.pb.go index 50626f7a..fd51459e 100644 --- a/proxy/shadowsocks_2022/config.pb.go +++ b/proxy/shadowsocks_2022/config.pb.go @@ -389,11 +389,12 @@ 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"` - UdpOverTcp bool `protobuf:"varint,5,opt,name=udp_over_tcp,json=udpOverTcp,proto3" json:"udp_over_tcp,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"` + UdpOverTcpVersion uint32 `protobuf:"varint,6,opt,name=udp_over_tcp_version,json=udpOverTcpVersion,proto3" json:"udp_over_tcp_version,omitempty"` } func (x *ClientConfig) Reset() { @@ -463,6 +464,13 @@ func (x *ClientConfig) GetUdpOverTcp() bool { return false } +func (x *ClientConfig) GetUdpOverTcpVersion() uint32 { + if x != nil { + return x.UdpOverTcpVersion + } + return 0 +} + var File_proxy_shadowsocks_2022_config_proto protoreflect.FileDescriptor var file_proxy_shadowsocks_2022_config_proto_rawDesc = []byte{ @@ -520,7 +528,7 @@ var file_proxy_shadowsocks_2022_config_proto_rawDesc = []byte{ 0x10, 0x0a, 0x03, 0x6b, 0x65, 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, 0xa5, 0x01, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0xd6, 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, @@ -531,15 +539,18 @@ var file_proxy_shadowsocks_2022_config_proto_rawDesc = []byte{ 0x64, 0x12, 0x10, 0x0a, 0x03, 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, + 0x65, 0x72, 0x54, 0x63, 0x70, 0x12, 0x2f, 0x0a, 0x14, 0x75, 0x64, 0x70, 0x5f, 0x6f, 0x76, 0x65, + 0x72, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x11, 0x75, 0x64, 0x70, 0x4f, 0x76, 0x65, 0x72, 0x54, 0x63, 0x70, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 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 ( diff --git a/proxy/shadowsocks_2022/config.proto b/proxy/shadowsocks_2022/config.proto index 2c4690e4..60540991 100644 --- a/proxy/shadowsocks_2022/config.proto +++ b/proxy/shadowsocks_2022/config.proto @@ -51,4 +51,5 @@ message ClientConfig { string method = 3; string key = 4; bool udp_over_tcp = 5; + uint32 udp_over_tcp_version = 6; } diff --git a/proxy/shadowsocks_2022/outbound.go b/proxy/shadowsocks_2022/outbound.go index cc23f737..5b1583cb 100644 --- a/proxy/shadowsocks_2022/outbound.go +++ b/proxy/shadowsocks_2022/outbound.go @@ -11,7 +11,6 @@ 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" @@ -29,10 +28,10 @@ func init() { } type Outbound struct { - ctx context.Context - server net.Destination - method shadowsocks.Method - uot bool + ctx context.Context + server net.Destination + method shadowsocks.Method + uotClient *uot.Client } func NewClient(ctx context.Context, config *ClientConfig) (*Outbound, error) { @@ -43,7 +42,6 @@ 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 == "" { @@ -57,6 +55,9 @@ func NewClient(ctx context.Context, config *ClientConfig) (*Outbound, error) { } else { return nil, newError("unknown method ", config.Method) } + if config.UdpOverTcp { + o.uotClient = &uot.Client{Version: uint8(config.UdpOverTcpVersion)} + } return o, nil } @@ -77,7 +78,7 @@ 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 - if o.uot { + if o.uotClient != nil { serverDestination.Network = net.Network_TCP } else { serverDestination.Network = network @@ -149,9 +150,12 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int } } - if o.uot { - serverConn := o.method.DialEarlyConn(connection, M.Socksaddr{Fqdn: uot.UOTMagicAddress}) - return returnError(bufio.CopyPacketConn(ctx, packetConn, uot.NewClientConn(serverConn))) + if o.uotClient != nil { + uConn, err := o.uotClient.DialEarlyConn(o.method.DialEarlyConn(connection, uot.RequestDestination(o.uotClient.Version)), false, toSocksaddr(destination)) + if err != nil { + return err + } + return returnError(bufio.CopyPacketConn(ctx, packetConn, uConn)) } else { serverConn := o.method.DialPacketConn(connection) return returnError(bufio.CopyPacketConn(ctx, packetConn, serverConn))