Compare commits

...

9 Commits

Author SHA1 Message Date
世界
3b8f09153e Split utls library 2023-02-21 23:00:30 +08:00
世界
0188c2d67d Add uTLS support for shadowtls 2023-02-21 20:48:18 +08:00
世界
6fb673aee4 Add config check 2023-02-21 19:48:09 +08:00
世界
d6c2a9aab7 Add shadow-tls support 2023-02-21 19:19:47 +08:00
RPRX
4d5c3195d2 Refine random
Fixes https://github.com/XTLS/Xray-core/issues/1666
2023-02-18 05:55:19 +00:00
RPRX
c7358a32f5 Allow empty "spiderX" (client side) 2023-02-17 21:07:27 +08:00
RPRX
e1cd1fd33e Allow empty "shortId" (client side) 2023-02-17 12:39:18 +00:00
RPRX
82003f28b2 Upgrade github.com/xtls/reality to 085bdf2104d3
Fixes https://github.com/XTLS/Xray-core/issues/1659
2023-02-17 11:43:18 +00:00
RPRX
4d2e2b24d3 THE NEXT FUTURE becomes THE REALITY NOW
Thank @yuhan6665 for testing
2023-02-15 16:07:12 +00:00
43 changed files with 2547 additions and 240 deletions

View File

@@ -0,0 +1,46 @@
package singbridge
import (
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common/net"
)
func ToNetwork(network string) net.Network {
switch N.NetworkName(network) {
case N.NetworkTCP:
return net.Network_TCP
case N.NetworkUDP:
return net.Network_UDP
default:
return net.Network_Unknown
}
}
func ToDestination(socksaddr M.Socksaddr, network net.Network) net.Destination {
if socksaddr.IsFqdn() {
return net.Destination{
Network: network,
Address: net.DomainAddress(socksaddr.Fqdn),
Port: net.Port(socksaddr.Port),
}
} else {
return net.Destination{
Network: network,
Address: net.IPAddress(socksaddr.Addr.AsSlice()),
Port: net.Port(socksaddr.Port),
}
}
}
func ToSocksaddr(destination net.Destination) M.Socksaddr {
var addr M.Socksaddr
switch destination.Address.Family() {
case net.AddressFamilyDomain:
addr.Fqdn = destination.Address.Domain()
default:
addr.Addr = M.AddrFromIP(destination.Address.IP())
}
addr.Port = uint16(destination.Port)
return addr
}

View File

@@ -0,0 +1,29 @@
package singbridge
import (
"context"
"os"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet"
)
var _ N.Dialer = (*XrayDialer)(nil)
type XrayDialer struct {
internet.Dialer
}
func NewDialer(dialer internet.Dialer) *XrayDialer {
return &XrayDialer{dialer}
}
func (d *XrayDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
return d.Dialer.Dial(ctx, ToDestination(destination, ToNetwork(network)))
}
func (d *XrayDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
return nil, os.ErrInvalid
}

View File

@@ -0,0 +1,43 @@
package singbridge
import (
"context"
gotls "crypto/tls"
"os"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/tls"
)
type XrayTLSDialer struct {
dialer internet.Dialer
clientFunc tls.CustomClientFunc
}
func NewTLSDialer(dialer internet.Dialer, clientFunc tls.CustomClientFunc) *XrayTLSDialer {
return &XrayTLSDialer{dialer, clientFunc}
}
func (d *XrayTLSDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
var internetTLSConfig *tls.Config
var tlsConfig *gotls.Config
conn, err := d.dialer.Dial(tls.ContextWithCustomClient(ctx, func(conn net.Conn, xrayConfig *tls.Config, config *gotls.Config) net.Conn {
internetTLSConfig = xrayConfig
tlsConfig = config
return conn
}), ToDestination(destination, ToNetwork(network)))
if err != nil {
return nil, err
}
if tlsConfig == nil {
return nil, E.New("missing TLS config")
}
return d.clientFunc(conn, internetTLSConfig, tlsConfig), nil
}
func (d *XrayTLSDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
return nil, os.ErrInvalid
}

View File

@@ -0,0 +1,10 @@
package singbridge
import E "github.com/sagernet/sing/common/exceptions"
func ReturnError(err error) error {
if E.IsClosed(err) {
return nil
}
return err
}

View File

@@ -0,0 +1,70 @@
package singbridge
import (
"context"
"github.com/sagernet/sing/common/logger"
"github.com/xtls/xray-core/common/errors"
)
var _ logger.ContextLogger = (*XrayLogger)(nil)
type XrayLogger struct {
newError func(values ...any) *errors.Error
}
func NewLogger(newErrorFunc func(values ...any) *errors.Error) *XrayLogger {
return &XrayLogger{
newErrorFunc,
}
}
func (l *XrayLogger) Trace(args ...any) {
}
func (l *XrayLogger) Debug(args ...any) {
l.newError(args...).AtDebug().WriteToLog()
}
func (l *XrayLogger) Info(args ...any) {
l.newError(args...).AtInfo().WriteToLog()
}
func (l *XrayLogger) Warn(args ...any) {
l.newError(args...).AtWarning().WriteToLog()
}
func (l *XrayLogger) Error(args ...any) {
l.newError(args...).AtError().WriteToLog()
}
func (l *XrayLogger) Fatal(args ...any) {
}
func (l *XrayLogger) Panic(args ...any) {
}
func (l *XrayLogger) TraceContext(ctx context.Context, args ...any) {
}
func (l *XrayLogger) DebugContext(ctx context.Context, args ...any) {
l.newError(args...).AtDebug().WriteToLog()
}
func (l *XrayLogger) InfoContext(ctx context.Context, args ...any) {
l.newError(args...).AtInfo().WriteToLog()
}
func (l *XrayLogger) WarnContext(ctx context.Context, args ...any) {
l.newError(args...).AtWarning().WriteToLog()
}
func (l *XrayLogger) ErrorContext(ctx context.Context, args ...any) {
l.newError(args...).AtError().WriteToLog()
}
func (l *XrayLogger) FatalContext(ctx context.Context, args ...any) {
}
func (l *XrayLogger) PanicContext(ctx context.Context, args ...any) {
}

61
common/singbridge/pipe.go Normal file
View File

@@ -0,0 +1,61 @@
package singbridge
import (
"context"
"io"
"net"
"github.com/sagernet/sing/common/bufio"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/transport"
)
func CopyConn(ctx context.Context, inboundConn net.Conn, link *transport.Link, serverConn net.Conn) error {
conn := &PipeConnWrapper{
W: link.Writer,
Conn: inboundConn,
}
if ir, ok := link.Reader.(io.Reader); ok {
conn.R = ir
} else {
conn.R = &buf.BufferedReader{Reader: link.Reader}
}
return ReturnError(bufio.CopyConn(ctx, conn, serverConn))
}
type PipeConnWrapper struct {
R io.Reader
W buf.Writer
net.Conn
}
func (w *PipeConnWrapper) Close() error {
return nil
}
func (w *PipeConnWrapper) Read(b []byte) (n int, err error) {
return w.R.Read(b)
}
func (w *PipeConnWrapper) Write(p []byte) (n int, err error) {
n = len(p)
var mb buf.MultiBuffer
pLen := len(p)
for pLen > 0 {
buffer := buf.New()
if pLen > buf.Size {
_, err = buffer.Write(p[:buf.Size])
p = p[buf.Size:]
} else {
buffer.Write(p)
}
pLen -= int(buffer.Len())
mb = append(mb, buffer)
}
err = w.W.WriteMultiBuffer(mb)
if err != nil {
n = 0
buf.ReleaseMulti(mb)
}
return
}

View File

@@ -12,13 +12,19 @@ package core
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
import (
"fmt"
"runtime"
"github.com/xtls/xray-core/common/serial"
)
var (
version = "1.7.5"
Version_x byte = 1
Version_y byte = 7
Version_z byte = 5
)
var (
build = "Custom"
codename = "Xray, Penetrates Everything."
intro = "A unified platform for anti-censorship."
@@ -27,7 +33,7 @@ var (
// Version returns Xray's version as a string, in the form of "x.y.z" where x, y and z are numbers.
// ".z" part may be omitted in regular releases.
func Version() string {
return version
return fmt.Sprintf("%v.%v.%v", Version_x, Version_y, Version_z)
}
// VersionStatement returns a list of strings representing the full version info.

23
go.mod
View File

@@ -12,17 +12,20 @@ require (
github.com/pelletier/go-toml v1.9.5
github.com/pires/go-proxyproto v0.6.2
github.com/quic-go/quic-go v0.32.0
github.com/refraction-networking/utls v1.2.2-0.20230207151345-a75a4b484849
github.com/refraction-networking/utls v1.2.2
github.com/sagernet/sing v0.1.6
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7
github.com/sagernet/sing-shadowtls v0.0.0-20230221123345-78e50cd7b587
github.com/sagernet/utls v0.0.0-20230220130002-c08891932056
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb
github.com/stretchr/testify v1.8.1
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3
github.com/xtls/reality v0.0.0-20230217102704-085bdf2104d3
go.starlark.net v0.0.0-20230128213706-3f75dec8e403
golang.org/x/crypto v0.5.0
golang.org/x/net v0.5.0
golang.org/x/crypto v0.6.0
golang.org/x/net v0.7.0
golang.org/x/sync v0.1.0
golang.org/x/sys v0.5.0
google.golang.org/grpc v1.53.0
@@ -32,7 +35,7 @@ require (
)
require (
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
@@ -41,19 +44,19 @@ require (
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
github.com/klauspost/compress v1.15.15 // indirect
github.com/klauspost/cpuid/v2 v2.2.3 // indirect
github.com/onsi/ginkgo/v2 v2.8.0 // indirect
github.com/onsi/ginkgo/v2 v2.8.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qtls-go1-18 v0.2.0 // indirect
github.com/quic-go/qtls-go1-19 v0.2.0 // indirect
github.com/quic-go/qtls-go1-20 v0.1.0 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
go.uber.org/atomic v1.10.0 // indirect
golang.org/x/exp v0.0.0-20230206171751-46f607a40771 // indirect
golang.org/x/mod v0.7.0 // indirect
golang.org/x/text v0.6.0 // indirect
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.5.0 // indirect
google.golang.org/genproto v0.0.0-20230202175211-008b39050e57 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.1.7 // indirect

48
go.sum
View File

@@ -8,8 +8,8 @@ dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
@@ -112,9 +112,9 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/onsi/ginkgo/v2 v2.8.0 h1:pAM+oBNPrpXRs+E/8spkeGx9QgekbRVyr74EUvRVOUI=
github.com/onsi/ginkgo/v2 v2.8.0/go.mod h1:6JsQiECmxCa3V5st74AL/AmsV482EDdVrGaVW6z3oYU=
github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y=
github.com/onsi/ginkgo/v2 v2.8.1 h1:xFTEVwOFa1D/Ty24Ws1npBWkDYEV9BqZrsDxVrVkrrU=
github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc=
github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
@@ -138,8 +138,8 @@ github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV5
github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7tA=
github.com/quic-go/quic-go v0.32.0/go.mod h1:/fCsKANhQIeD5l76c2JFU+07gVE3KaA0FP+0zMWwfwo=
github.com/refraction-networking/utls v1.2.2-0.20230207151345-a75a4b484849 h1:vNEcNapWFwnYJTBcVkHJa8VrdL40PNDLDbSGVY+ZV7I=
github.com/refraction-networking/utls v1.2.2-0.20230207151345-a75a4b484849/go.mod h1:L1goe44KvhnTfctUffM2isnJpSjPlYShrhXDeZaoYKw=
github.com/refraction-networking/utls v1.2.2 h1:uBE6V173CwG8MQrSBpNZHAix1fxOvuLKYyjFAu3uqo0=
github.com/refraction-networking/utls v1.2.2/go.mod h1:L1goe44KvhnTfctUffM2isnJpSjPlYShrhXDeZaoYKw=
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=
@@ -147,6 +147,10 @@ github.com/sagernet/sing v0.1.6 h1:Qy63OUfKpcqKjfd5rPmUlj0RGjHZSK/PJn0duyCCsRg=
github.com/sagernet/sing v0.1.6/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w=
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7 h1:Plup6oEiyLzY3HDqQ+QsUBzgBGdVmcsgf3t8h940z9U=
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7/go.mod h1:O5LtOs8Ivw686FqLpO0Zu+A0ROVE15VeqEK3yDRRAms=
github.com/sagernet/sing-shadowtls v0.0.0-20230221123345-78e50cd7b587 h1:OjIXlHT2bblZfp+ciupM4xY9+Ccpj9FsuHRtKRBv+Pg=
github.com/sagernet/sing-shadowtls v0.0.0-20230221123345-78e50cd7b587/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 h1:gDXi/0uYe8dA48UyUI1LM2la5QYN0IvsDvR2H2+kFnA=
github.com/sagernet/utls v0.0.0-20230220130002-c08891932056/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM=
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo=
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI=
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
@@ -193,6 +197,8 @@ github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49u
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 h1:a3Y4WVjCxwoyO4E2xdNvq577tW8lkSBgyrA8E9+2NtM=
github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY=
github.com/xtls/reality v0.0.0-20230217102704-085bdf2104d3 h1:Rp9BfXZ+Li5j5L40zAdFZLcr0nXrYBPgaNpQ9lQnpWg=
github.com/xtls/reality v0.0.0-20230217102704-085bdf2104d3/go.mod h1:rkuAY1S9F8eI8gDiPDYvACE8e2uwkyg8qoOTuwWov7Y=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.starlark.net v0.0.0-20230128213706-3f75dec8e403 h1:jPeC7Exc+m8OBJUlWbBLh0O5UZPM7yU5W4adnhhbG4U=
@@ -205,18 +211,18 @@ golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg=
golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb h1:PaBZQdo+iSDyHT053FjUCgZQ/9uqVwPOcl7KSWhKn6w=
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -230,8 +236,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -267,8 +273,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
@@ -283,8 +289,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4=
golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -303,8 +309,8 @@ google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20230202175211-008b39050e57 h1:vArvWooPH749rNHpBGgVl+U9B9dATjiEhJzcWGlovNs=
google.golang.org/genproto v0.0.0-20230202175211-008b39050e57/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc h1:ijGwO+0vL2hJt5gaygqP2j6PfflOBrRot0IczKbmtio=
google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=

102
infra/conf/shadowtls.go Normal file
View File

@@ -0,0 +1,102 @@
package conf
import (
"github.com/golang/protobuf/proto"
"github.com/sagernet/sing/common"
"github.com/xtls/xray-core/proxy/shadowtls"
)
type ShadowTLSServerConfig struct {
Version uint16 `json:"version"`
Password string `json:"password,omitempty"`
Users []ShadowTLSUser `json:"users,omitempty"`
Handshake *ShadowTLSHandshakeConfig `json:"handshake"`
HandshakeForServerName map[string]*ShadowTLSHandshakeConfig `json:"handshakeForServerName,omitempty"`
StrictMode bool `json:"strictMode,omitempty"`
Detour string `json:"detour"`
}
type ShadowTLSUser struct {
Email string `json:"email,omitempty"`
Password string `json:"password,omitempty"`
}
type ShadowTLSHandshakeConfig struct {
Address *Address `json:"address"`
Port uint16 `json:"port"`
}
func (c *ShadowTLSServerConfig) Build() (proto.Message, error) {
if c.Version == 0 {
return nil, newError("shadow-tls version is not set.")
}
if c.Version == 3 && len(c.Users) == 0 {
return nil, newError("shadow-tls users is not set.")
}
if c.Handshake == nil {
return nil, newError("shadow-tls handshake config is not set.")
}
var handshakeForServerName map[string]*shadowtls.HandshakeConfig
if c.HandshakeForServerName != nil {
for serverName, serverConfig := range c.HandshakeForServerName {
if serverConfig.Address == nil {
return nil, newError("shadow-tls handshake server address is not set.")
}
if serverConfig.Port == 0 {
return nil, newError("shadow-tls handshake server port is not set.")
}
handshakeForServerName[serverName] = &shadowtls.HandshakeConfig{
Address: serverConfig.Address.Build(),
Port: uint32(serverConfig.Port),
}
}
}
if c.Handshake.Address == nil {
return nil, newError("shadow-tls handshake server address is not set.")
}
if c.Handshake.Port == 0 {
return nil, newError("shadow-tls handshake server port is not set.")
}
return &shadowtls.ServerConfig{
Version: uint32(c.Version),
Password: c.Password,
Users: common.Map(c.Users, func(it ShadowTLSUser) *shadowtls.User {
return &shadowtls.User{
Email: it.Email,
Password: it.Password,
}
}),
Handshake: &shadowtls.HandshakeConfig{
Address: c.Handshake.Address.Build(),
Port: uint32(c.Handshake.Port),
},
HandshakeForServerName: handshakeForServerName,
StrictMode: c.StrictMode,
Detour: c.Detour,
}, nil
}
type ShadowTLSClientConfig struct {
Address *Address `json:"address"`
Port uint16 `json:"port"`
Version uint16 `json:"version"`
Password string `json:"password,omitempty"`
}
func (c *ShadowTLSClientConfig) Build() (proto.Message, error) {
if c.Version == 0 {
return nil, newError("shadow-tls version is not set.")
}
if c.Address == nil {
return nil, newError("shadow-tls server address is not set.")
}
if c.Port == 0 {
return nil, newError("shadow-tls server port is not set.")
}
return &shadowtls.ClientConfig{
Address: c.Address.Build(),
Port: uint32(c.Port),
Version: uint32(c.Version),
Password: c.Password,
}, nil
}

View File

@@ -2,13 +2,17 @@ package conf
import (
"encoding/base64"
"encoding/hex"
"encoding/json"
"math"
"net/url"
"runtime"
"strconv"
"strings"
"syscall"
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform/filesystem"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
@@ -18,6 +22,7 @@ import (
"github.com/xtls/xray-core/transport/internet/http"
"github.com/xtls/xray-core/transport/internet/kcp"
"github.com/xtls/xray-core/transport/internet/quic"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/tcp"
"github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/websocket"
@@ -509,6 +514,167 @@ func (c *XTLSConfig) Build() (proto.Message, error) {
return config, nil
}
type REALITYConfig struct {
Show bool `json:"show"`
Dest json.RawMessage `json:"dest"`
Type string `json:"type"`
Xver uint64 `json:"xver"`
ServerNames []string `json:"serverNames"`
PrivateKey string `json:"privateKey"`
MinClientVer string `json:"minClientVer"`
MaxClientVer string `json:"maxClientVer"`
MaxTimeDiff uint64 `json:"maxTimeDiff"`
ShortIds []string `json:"shortIds"`
Fingerprint string `json:"fingerprint"`
ServerName string `json:"serverName"`
PublicKey string `json:"publicKey"`
ShortId string `json:"shortId"`
SpiderX string `json:"spiderX"`
}
func (c *REALITYConfig) Build() (proto.Message, error) {
config := new(reality.Config)
config.Show = c.Show
var err error
if c.Dest != nil {
var i uint16
var s string
if err = json.Unmarshal(c.Dest, &i); err == nil {
s = strconv.Itoa(int(i))
} else {
_ = json.Unmarshal(c.Dest, &s)
}
if c.Type == "" && s != "" {
switch s[0] {
case '@', '/':
c.Type = "unix"
if s[0] == '@' && len(s) > 1 && s[1] == '@' && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
copy(fullAddr, s[1:])
s = string(fullAddr)
}
default:
if _, err = strconv.Atoi(s); err == nil {
s = "127.0.0.1:" + s
}
if _, _, err = net.SplitHostPort(s); err == nil {
c.Type = "tcp"
}
}
}
if c.Type == "" {
return nil, newError(`please fill in a valid value for "dest"`)
}
if c.Xver > 2 {
return nil, newError(`invalid PROXY protocol version, "xver" only accepts 0, 1, 2`)
}
if len(c.ServerNames) == 0 {
return nil, newError(`empty "serverNames"`)
}
if c.PrivateKey == "" {
return nil, newError(`empty "privateKey"`)
}
if config.PrivateKey, err = base64.RawURLEncoding.DecodeString(c.PrivateKey); err != nil || len(config.PrivateKey) != 32 {
return nil, newError(`invalid "privateKey": `, c.PrivateKey)
}
if c.MinClientVer != "" {
config.MinClientVer = make([]byte, 3)
var u uint64
for i, s := range strings.Split(c.MinClientVer, ".") {
if i == 3 {
return nil, newError(`invalid "minClientVer": `, c.MinClientVer)
}
if u, err = strconv.ParseUint(s, 10, 8); err != nil {
return nil, newError(`"minClientVer[`, i, `]" should be lesser than 256`)
} else {
config.MinClientVer[i] = byte(u)
}
}
}
if c.MaxClientVer != "" {
config.MaxClientVer = make([]byte, 3)
var u uint64
for i, s := range strings.Split(c.MaxClientVer, ".") {
if i == 3 {
return nil, newError(`invalid "maxClientVer": `, c.MaxClientVer)
}
if u, err = strconv.ParseUint(s, 10, 8); err != nil {
return nil, newError(`"maxClientVer[`, i, `]" should be lesser than 256`)
} else {
config.MaxClientVer[i] = byte(u)
}
}
}
if len(c.ShortIds) == 0 {
return nil, newError(`empty "shortIds"`)
}
config.ShortIds = make([][]byte, len(c.ShortIds))
for i, s := range c.ShortIds {
config.ShortIds[i] = make([]byte, 8)
if _, err = hex.Decode(config.ShortIds[i], []byte(s)); err != nil {
return nil, newError(`invalid "shortIds[`, i, `]": `, s)
}
}
config.Dest = s
config.Type = c.Type
config.Xver = c.Xver
config.ServerNames = c.ServerNames
config.MaxTimeDiff = c.MaxTimeDiff
} else {
if c.Fingerprint == "" {
return nil, newError(`empty "fingerprint"`)
}
if config.Fingerprint = strings.ToLower(c.Fingerprint); tls.GetFingerprint(config.Fingerprint) == nil {
return nil, newError(`unknown "fingerprint": `, config.Fingerprint)
}
if config.Fingerprint == "hellogolang" {
return nil, newError(`invalid "fingerprint": `, config.Fingerprint)
}
if c.PublicKey == "" {
return nil, newError(`empty "publicKey"`)
}
if config.PublicKey, err = base64.RawURLEncoding.DecodeString(c.PublicKey); err != nil || len(config.PublicKey) != 32 {
return nil, newError(`invalid "publicKey": `, c.PublicKey)
}
config.ShortId = make([]byte, 8)
if _, err = hex.Decode(config.ShortId, []byte(c.ShortId)); err != nil {
return nil, newError(`invalid "shortId": `, c.ShortId)
}
if c.SpiderX == "" {
c.SpiderX = "/"
}
if c.SpiderX[0] != '/' {
return nil, newError(`invalid "spiderX": `, c.SpiderX)
}
config.SpiderY = make([]int64, 10)
u, _ := url.Parse(c.SpiderX)
q := u.Query()
parse := func(param string, index int) {
if q.Get(param) != "" {
s := strings.Split(q.Get(param), "-")
if len(s) == 1 {
config.SpiderY[index], _ = strconv.ParseInt(s[0], 10, 64)
config.SpiderY[index+1], _ = strconv.ParseInt(s[0], 10, 64)
} else {
config.SpiderY[index], _ = strconv.ParseInt(s[0], 10, 64)
config.SpiderY[index+1], _ = strconv.ParseInt(s[1], 10, 64)
}
}
q.Del(param)
}
parse("p", 0) // padding
parse("c", 2) // concurrency
parse("t", 4) // times
parse("i", 6) // interval
parse("r", 8) // return
u.RawQuery = q.Encode()
config.SpiderX = u.String()
config.ServerName = c.ServerName
}
return config, nil
}
type TransportProtocol string
// Build implements Buildable.
@@ -598,19 +764,20 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
}
type StreamConfig struct {
Network *TransportProtocol `json:"network"`
Security string `json:"security"`
TLSSettings *TLSConfig `json:"tlsSettings"`
XTLSSettings *XTLSConfig `json:"xtlsSettings"`
TCPSettings *TCPConfig `json:"tcpSettings"`
KCPSettings *KCPConfig `json:"kcpSettings"`
WSSettings *WebSocketConfig `json:"wsSettings"`
HTTPSettings *HTTPConfig `json:"httpSettings"`
DSSettings *DomainSocketConfig `json:"dsSettings"`
QUICSettings *QUICConfig `json:"quicSettings"`
SocketSettings *SocketConfig `json:"sockopt"`
GRPCConfig *GRPCConfig `json:"grpcSettings"`
GUNConfig *GRPCConfig `json:"gunSettings"`
Network *TransportProtocol `json:"network"`
Security string `json:"security"`
TLSSettings *TLSConfig `json:"tlsSettings"`
XTLSSettings *XTLSConfig `json:"xtlsSettings"`
REALITYSettings *REALITYConfig `json:"realitySettings"`
TCPSettings *TCPConfig `json:"tcpSettings"`
KCPSettings *KCPConfig `json:"kcpSettings"`
WSSettings *WebSocketConfig `json:"wsSettings"`
HTTPSettings *HTTPConfig `json:"httpSettings"`
DSSettings *DomainSocketConfig `json:"dsSettings"`
QUICSettings *QUICConfig `json:"quicSettings"`
SocketSettings *SocketConfig `json:"sockopt"`
GRPCConfig *GRPCConfig `json:"grpcSettings"`
GUNConfig *GRPCConfig `json:"gunSettings"`
}
// Build implements Buildable.
@@ -660,6 +827,21 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
config.SecuritySettings = append(config.SecuritySettings, tm)
config.SecurityType = tm.Type
}
if strings.EqualFold(c.Security, "reality") {
if config.ProtocolName != "tcp" && config.ProtocolName != "http" && config.ProtocolName != "domainsocket" {
return nil, newError("REALITY only supports TCP, H2 and DomainSocket for now.")
}
if c.REALITYSettings == nil {
return nil, newError(`REALITY: Empty "realitySettings".`)
}
ts, err := c.REALITYSettings.Build()
if err != nil {
return nil, newError("Failed to build REALITY config.").Base(err)
}
tm := serial.ToTypedMessage(ts)
config.SecuritySettings = append(config.SecuritySettings, tm)
config.SecurityType = tm.Type
}
if c.TCPSettings != nil {
ts, err := c.TCPSettings.Build()
if err != nil {

View File

@@ -26,6 +26,7 @@ var (
"vmess": func() interface{} { return new(VMessInboundConfig) },
"trojan": func() interface{} { return new(TrojanServerConfig) },
"mtproto": func() interface{} { return new(MTProtoServerConfig) },
"shadow-tls": func() interface{} { return new(ShadowTLSServerConfig) },
}, "protocol", "settings")
outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
@@ -41,6 +42,7 @@ var (
"mtproto": func() interface{} { return new(MTProtoClientConfig) },
"dns": func() interface{} { return new(DNSOutboundConfig) },
"wireguard": func() interface{} { return new(WireGuardConfig) },
"shadow-tls": func() interface{} { return new(ShadowTLSClientConfig) },
}, "protocol", "settings")
ctllog = log.New(os.Stderr, "xctl> ", 0)

View File

@@ -15,5 +15,6 @@ func init() {
// cmdConvert,
tls.CmdTLS,
cmdUUID,
cmdX25519,
)
}

View File

@@ -0,0 +1,63 @@
package all
import (
"crypto/rand"
"encoding/base64"
"fmt"
"io"
"github.com/xtls/xray-core/main/commands/base"
"golang.org/x/crypto/curve25519"
)
var cmdX25519 = &base.Command{
UsageLine: `{{.Exec}} x25519 [-i "private key (base64.RawURLEncoding)"]`,
Short: `Generate key pair for x25519 key exchange`,
Long: `
Generate key pair for x25519 key exchange.
Random: {{.Exec}} x25519
From private key: {{.Exec}} x25519 -i "private key (base64.RawURLEncoding)"
`,
}
func init() {
cmdX25519.Run = executeX25519 // break init loop
}
var input_base64 = cmdX25519.Flag.String("i", "", "")
func executeX25519(cmd *base.Command, args []string) {
var output string
var err error
var privateKey []byte
var publicKey []byte
if len(*input_base64) > 0 {
privateKey, err = base64.RawURLEncoding.DecodeString(*input_base64)
if err != nil {
output = err.Error()
goto out
}
if len(privateKey) != curve25519.ScalarSize {
output = "Invalid length of private key."
goto out
}
}
if privateKey == nil {
privateKey = make([]byte, curve25519.ScalarSize)
if _, err = io.ReadFull(rand.Reader, privateKey); err != nil {
output = err.Error()
goto out
}
}
if publicKey, err = curve25519.X25519(privateKey, curve25519.Basepoint); err != nil {
output = err.Error()
goto out
}
output = fmt.Sprintf("Private key: %v\nPublic key: %v",
base64.RawURLEncoding.EncodeToString(privateKey),
base64.RawURLEncoding.EncodeToString(publicKey))
out:
fmt.Println(output)
}

View File

@@ -42,6 +42,7 @@ import (
_ "github.com/xtls/xray-core/proxy/loopback"
_ "github.com/xtls/xray-core/proxy/mtproto"
_ "github.com/xtls/xray-core/proxy/shadowsocks"
_ "github.com/xtls/xray-core/proxy/shadowtls"
_ "github.com/xtls/xray-core/proxy/socks"
_ "github.com/xtls/xray-core/proxy/trojan"
_ "github.com/xtls/xray-core/proxy/vless/inbound"
@@ -56,6 +57,7 @@ import (
_ "github.com/xtls/xray-core/transport/internet/http"
_ "github.com/xtls/xray-core/transport/internet/kcp"
_ "github.com/xtls/xray-core/transport/internet/quic"
_ "github.com/xtls/xray-core/transport/internet/reality"
_ "github.com/xtls/xray-core/transport/internet/tcp"
_ "github.com/xtls/xray-core/transport/internet/tls"
_ "github.com/xtls/xray-core/transport/internet/udp"

View File

@@ -17,6 +17,7 @@ import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/stat"
)
@@ -73,7 +74,7 @@ func (i *Inbound) Process(ctx context.Context, network net.Network, connection s
ctx = session.ContextWithDispatcher(ctx, dispatcher)
if network == net.Network_TCP {
return returnError(i.service.NewConnection(ctx, connection, metadata))
return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
} else {
reader := buf.NewReader(connection)
pc := &natPacketConn{connection}
@@ -81,7 +82,7 @@ func (i *Inbound) Process(ctx context.Context, network net.Network, connection s
mb, err := reader.ReadMultiBuffer()
if err != nil {
buf.ReleaseMulti(mb)
return returnError(err)
return singbridge.ReturnError(err)
}
for _, buffer := range mb {
packet := B.As(buffer.Bytes()).ToOwned()
@@ -111,16 +112,11 @@ func (i *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata M.M
})
newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
dispatcher := session.DispatcherFromContext(ctx)
link, err := dispatcher.Dispatch(ctx, toDestination(metadata.Destination, net.Network_TCP))
link, err := dispatcher.Dispatch(ctx, singbridge.ToDestination(metadata.Destination, net.Network_TCP))
if err != nil {
return err
}
outConn := &pipeConnWrapper{
&buf.BufferedReader{Reader: link.Reader},
link.Writer,
conn,
}
return bufio.CopyConn(ctx, conn, outConn)
return singbridge.CopyConn(ctx, nil, link, conn)
}
func (i *Inbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
@@ -137,7 +133,7 @@ func (i *Inbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, me
})
newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
dispatcher := session.DispatcherFromContext(ctx)
destination := toDestination(metadata.Destination, net.Network_UDP)
destination := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
link, err := dispatcher.Dispatch(ctx, destination)
if err != nil {
return err

View File

@@ -21,6 +21,7 @@ import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/stat"
@@ -162,7 +163,7 @@ func (i *MultiUserInbound) Process(ctx context.Context, network net.Network, con
ctx = session.ContextWithDispatcher(ctx, dispatcher)
if network == net.Network_TCP {
return returnError(i.service.NewConnection(ctx, connection, metadata))
return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
} else {
reader := buf.NewReader(connection)
pc := &natPacketConn{connection}
@@ -170,7 +171,7 @@ func (i *MultiUserInbound) Process(ctx context.Context, network net.Network, con
mb, err := reader.ReadMultiBuffer()
if err != nil {
buf.ReleaseMulti(mb)
return returnError(err)
return singbridge.ReturnError(err)
}
for _, buffer := range mb {
packet := B.As(buffer.Bytes()).ToOwned()
@@ -202,16 +203,11 @@ func (i *MultiUserInbound) NewConnection(ctx context.Context, conn net.Conn, met
})
newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
dispatcher := session.DispatcherFromContext(ctx)
link, err := dispatcher.Dispatch(ctx, toDestination(metadata.Destination, net.Network_TCP))
link, err := dispatcher.Dispatch(ctx, singbridge.ToDestination(metadata.Destination, net.Network_TCP))
if err != nil {
return err
}
outConn := &pipeConnWrapper{
&buf.BufferedReader{Reader: link.Reader},
link.Writer,
conn,
}
return bufio.CopyConn(ctx, conn, outConn)
return singbridge.CopyConn(ctx, conn, link, conn)
}
func (i *MultiUserInbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
@@ -230,7 +226,7 @@ func (i *MultiUserInbound) NewPacketConnection(ctx context.Context, conn N.Packe
})
newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
dispatcher := session.DispatcherFromContext(ctx)
destination := toDestination(metadata.Destination, net.Network_UDP)
destination := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
link, err := dispatcher.Dispatch(ctx, destination)
if err != nil {
return err

View File

@@ -19,6 +19,7 @@ import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/stat"
@@ -66,7 +67,7 @@ func NewRelayServer(ctx context.Context, config *RelayServerConfig) (*RelayInbou
C.MapIndexed(config.Destinations, func(index int, it *RelayDestination) int { return index }),
C.Map(config.Destinations, func(it *RelayDestination) string { return it.Key }),
C.Map(config.Destinations, func(it *RelayDestination) M.Socksaddr {
return toSocksaddr(net.Destination{
return singbridge.ToSocksaddr(net.Destination{
Address: it.Address.AsAddress(),
Port: net.Port(it.Port),
})
@@ -94,7 +95,7 @@ func (i *RelayInbound) Process(ctx context.Context, network net.Network, connect
ctx = session.ContextWithDispatcher(ctx, dispatcher)
if network == net.Network_TCP {
return returnError(i.service.NewConnection(ctx, connection, metadata))
return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
} else {
reader := buf.NewReader(connection)
pc := &natPacketConn{connection}
@@ -102,7 +103,7 @@ func (i *RelayInbound) Process(ctx context.Context, network net.Network, connect
mb, err := reader.ReadMultiBuffer()
if err != nil {
buf.ReleaseMulti(mb)
return returnError(err)
return singbridge.ReturnError(err)
}
for _, buffer := range mb {
packet := B.As(buffer.Bytes()).ToOwned()
@@ -134,16 +135,11 @@ func (i *RelayInbound) NewConnection(ctx context.Context, conn net.Conn, metadat
})
newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
dispatcher := session.DispatcherFromContext(ctx)
link, err := dispatcher.Dispatch(ctx, toDestination(metadata.Destination, net.Network_TCP))
link, err := dispatcher.Dispatch(ctx, singbridge.ToDestination(metadata.Destination, net.Network_TCP))
if err != nil {
return err
}
outConn := &pipeConnWrapper{
&buf.BufferedReader{Reader: link.Reader},
link.Writer,
conn,
}
return bufio.CopyConn(ctx, conn, outConn)
return singbridge.CopyConn(ctx, nil, link, conn)
}
func (i *RelayInbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
@@ -162,7 +158,7 @@ func (i *RelayInbound) NewPacketConnection(ctx context.Context, conn N.PacketCon
})
newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
dispatcher := session.DispatcherFromContext(ctx)
destination := toDestination(metadata.Destination, net.Network_UDP)
destination := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
link, err := dispatcher.Dispatch(ctx, destination)
if err != nil {
return err

View File

@@ -2,7 +2,6 @@ package shadowsocks_2022
import (
"context"
"io"
"runtime"
"time"
@@ -18,6 +17,7 @@ import (
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
)
@@ -88,7 +88,7 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int
}
if network == net.Network_TCP {
serverConn := o.method.DialEarlyConn(connection, toSocksaddr(destination))
serverConn := o.method.DialEarlyConn(connection, singbridge.ToSocksaddr(destination))
var handshake bool
if timeoutReader, isTimeoutReader := link.Reader.(buf.TimeoutReader); isTimeoutReader {
mb, err := timeoutReader.ReadMultiBufferTimeout(time.Millisecond * 100)
@@ -123,17 +123,7 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int
return newError("client handshake").Base(err)
}
}
conn := &pipeConnWrapper{
W: link.Writer,
Conn: inboundConn,
}
if ir, ok := link.Reader.(io.Reader); ok {
conn.R = ir
} else {
conn.R = &buf.BufferedReader{Reader: link.Reader}
}
return returnError(bufio.CopyConn(ctx, conn, serverConn))
return singbridge.CopyConn(ctx, inboundConn, link, serverConn)
} else {
var packetConn N.PacketConn
if pc, isPacketConn := inboundConn.(N.PacketConn); isPacketConn {
@@ -151,10 +141,10 @@ 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)))
return singbridge.ReturnError(bufio.CopyPacketConn(ctx, packetConn, uot.NewClientConn(serverConn)))
} else {
serverConn := o.method.DialPacketConn(connection)
return returnError(bufio.CopyPacketConn(ctx, packetConn, serverConn))
return singbridge.ReturnError(bufio.CopyPacketConn(ctx, packetConn, serverConn))
}
}
}

View File

@@ -1,82 +1,15 @@
package shadowsocks_2022
import (
"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"
"github.com/xtls/xray-core/common/singbridge"
)
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
func toDestination(socksaddr M.Socksaddr, network net.Network) net.Destination {
if socksaddr.IsFqdn() {
return net.Destination{
Network: network,
Address: net.DomainAddress(socksaddr.Fqdn),
Port: net.Port(socksaddr.Port),
}
} else {
return net.Destination{
Network: network,
Address: net.IPAddress(socksaddr.Addr.AsSlice()),
Port: net.Port(socksaddr.Port),
}
}
}
func toSocksaddr(destination net.Destination) M.Socksaddr {
var addr M.Socksaddr
switch destination.Address.Family() {
case net.AddressFamilyDomain:
addr.Fqdn = destination.Address.Domain()
default:
addr.Addr = M.AddrFromIP(destination.Address.IP())
}
addr.Port = uint16(destination.Port)
return addr
}
type pipeConnWrapper struct {
R io.Reader
W buf.Writer
net.Conn
}
func (w *pipeConnWrapper) Close() error {
return nil
}
func (w *pipeConnWrapper) Read(b []byte) (n int, err error) {
return w.R.Read(b)
}
func (w *pipeConnWrapper) Write(p []byte) (n int, err error) {
n = len(p)
var mb buf.MultiBuffer
pLen := len(p)
for pLen > 0 {
buffer := buf.New()
if pLen > buf.Size {
_, err = buffer.Write(p[:buf.Size])
p = p[buf.Size:]
} else {
buffer.Write(p)
}
pLen -= int(buffer.Len())
mb = append(mb, buffer)
}
err = w.W.WriteMultiBuffer(mb)
if err != nil {
n = 0
buf.ReleaseMulti(mb)
}
return
}
type packetConnWrapper struct {
buf.Reader
buf.Writer
@@ -100,7 +33,7 @@ func (w *packetConnWrapper) ReadPacket(buffer *B.Buffer) (M.Socksaddr, error) {
destination = w.Dest
}
bb.Release()
return toSocksaddr(destination), nil
return singbridge.ToSocksaddr(destination), nil
}
}
mb, err := w.ReadMultiBuffer()
@@ -120,14 +53,14 @@ func (w *packetConnWrapper) ReadPacket(buffer *B.Buffer) (M.Socksaddr, error) {
destination = w.Dest
}
bb.Release()
return toSocksaddr(destination), nil
return singbridge.ToSocksaddr(destination), nil
}
}
func (w *packetConnWrapper) WritePacket(buffer *B.Buffer, destination M.Socksaddr) error {
vBuf := buf.New()
vBuf.Write(buffer.Bytes())
endpoint := toDestination(destination, net.Network_UDP)
endpoint := singbridge.ToDestination(destination, net.Network_UDP)
vBuf.UDP = &endpoint
return w.Writer.WriteMultiBuffer(buf.MultiBuffer{vBuf})
}
@@ -136,10 +69,3 @@ func (w *packetConnWrapper) Close() error {
buf.ReleaseMulti(w.cached)
return nil
}
func returnError(err error) error {
if E.IsClosed(err) {
return nil
}
return err
}

View File

@@ -0,0 +1,483 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.21.12
// source: proxy/shadowtls/config.proto
package shadowtls
import (
net "github.com/xtls/xray-core/common/net"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ServerConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
Users []*User `protobuf:"bytes,3,rep,name=users,proto3" json:"users,omitempty"`
Handshake *HandshakeConfig `protobuf:"bytes,4,opt,name=handshake,proto3" json:"handshake,omitempty"`
HandshakeForServerName map[string]*HandshakeConfig `protobuf:"bytes,5,rep,name=handshake_for_server_name,json=handshakeForServerName,proto3" json:"handshake_for_server_name,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
StrictMode bool `protobuf:"varint,6,opt,name=strict_mode,json=strictMode,proto3" json:"strict_mode,omitempty"`
Detour string `protobuf:"bytes,7,opt,name=detour,proto3" json:"detour,omitempty"`
}
func (x *ServerConfig) Reset() {
*x = ServerConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_shadowtls_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServerConfig) ProtoMessage() {}
func (x *ServerConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_shadowtls_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServerConfig.ProtoReflect.Descriptor instead.
func (*ServerConfig) Descriptor() ([]byte, []int) {
return file_proxy_shadowtls_config_proto_rawDescGZIP(), []int{0}
}
func (x *ServerConfig) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
func (x *ServerConfig) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
func (x *ServerConfig) GetUsers() []*User {
if x != nil {
return x.Users
}
return nil
}
func (x *ServerConfig) GetHandshake() *HandshakeConfig {
if x != nil {
return x.Handshake
}
return nil
}
func (x *ServerConfig) GetHandshakeForServerName() map[string]*HandshakeConfig {
if x != nil {
return x.HandshakeForServerName
}
return nil
}
func (x *ServerConfig) GetStrictMode() bool {
if x != nil {
return x.StrictMode
}
return false
}
func (x *ServerConfig) GetDetour() string {
if x != nil {
return x.Detour
}
return ""
}
type HandshakeConfig struct {
state protoimpl.MessageState
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"`
}
func (x *HandshakeConfig) Reset() {
*x = HandshakeConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_shadowtls_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *HandshakeConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HandshakeConfig) ProtoMessage() {}
func (x *HandshakeConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_shadowtls_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HandshakeConfig.ProtoReflect.Descriptor instead.
func (*HandshakeConfig) Descriptor() ([]byte, []int) {
return file_proxy_shadowtls_config_proto_rawDescGZIP(), []int{1}
}
func (x *HandshakeConfig) GetAddress() *net.IPOrDomain {
if x != nil {
return x.Address
}
return nil
}
func (x *HandshakeConfig) GetPort() uint32 {
if x != nil {
return x.Port
}
return 0
}
type User struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"`
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
Level int32 `protobuf:"varint,3,opt,name=level,proto3" json:"level,omitempty"`
}
func (x *User) Reset() {
*x = User{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_shadowtls_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *User) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*User) ProtoMessage() {}
func (x *User) ProtoReflect() protoreflect.Message {
mi := &file_proxy_shadowtls_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use User.ProtoReflect.Descriptor instead.
func (*User) Descriptor() ([]byte, []int) {
return file_proxy_shadowtls_config_proto_rawDescGZIP(), []int{2}
}
func (x *User) GetEmail() string {
if x != nil {
return x.Email
}
return ""
}
func (x *User) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
func (x *User) GetLevel() int32 {
if x != nil {
return x.Level
}
return 0
}
type ClientConfig struct {
state protoimpl.MessageState
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"`
Version uint32 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"`
Password string `protobuf:"bytes,4,opt,name=password,proto3" json:"password,omitempty"`
}
func (x *ClientConfig) Reset() {
*x = ClientConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proxy_shadowtls_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ClientConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientConfig) ProtoMessage() {}
func (x *ClientConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_shadowtls_config_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.
func (*ClientConfig) Descriptor() ([]byte, []int) {
return file_proxy_shadowtls_config_proto_rawDescGZIP(), []int{3}
}
func (x *ClientConfig) GetAddress() *net.IPOrDomain {
if x != nil {
return x.Address
}
return nil
}
func (x *ClientConfig) GetPort() uint32 {
if x != nil {
return x.Port
}
return 0
}
func (x *ClientConfig) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
func (x *ClientConfig) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
var File_proxy_shadowtls_config_proto protoreflect.FileDescriptor
var file_proxy_shadowtls_config_proto_rawDesc = []byte{
0x0a, 0x1c, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x74, 0x6c,
0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f,
0x77, 0x74, 0x6c, 0x73, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74,
0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe1,
0x03, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73,
0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73,
0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x03,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78,
0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x74, 0x6c, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72,
0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x43, 0x0a, 0x09, 0x68, 0x61, 0x6e, 0x64, 0x73,
0x68, 0x61, 0x6b, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x74, 0x6c,
0x73, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x52, 0x09, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x12, 0x79, 0x0a, 0x19,
0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x3e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61,
0x64, 0x6f, 0x77, 0x74, 0x6c, 0x73, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x46, 0x6f, 0x72,
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
0x16, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x72,
0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x63,
0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, 0x74,
0x72, 0x69, 0x63, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x74, 0x6f,
0x75, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x74, 0x6f, 0x75, 0x72,
0x1a, 0x70, 0x0a, 0x1b, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x46, 0x6f, 0x72,
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
0x79, 0x12, 0x3b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68,
0x61, 0x64, 0x6f, 0x77, 0x74, 0x6c, 0x73, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b,
0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
0x38, 0x01, 0x22, 0x5c, 0x0a, 0x0f, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 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, 0x72, 0x44, 0x6f, 0x6d,
0x61, 0x69, 0x6e, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04,
0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74,
0x22, 0x4e, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69,
0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a,
0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65,
0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c,
0x22, 0x8f, 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, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52,
0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x42, 0x5e, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x74, 0x6c, 0x73, 0x50, 0x01,
0x5a, 0x29, 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, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x14, 0x58, 0x72,
0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x54,
0x4c, 0x53, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proxy_shadowtls_config_proto_rawDescOnce sync.Once
file_proxy_shadowtls_config_proto_rawDescData = file_proxy_shadowtls_config_proto_rawDesc
)
func file_proxy_shadowtls_config_proto_rawDescGZIP() []byte {
file_proxy_shadowtls_config_proto_rawDescOnce.Do(func() {
file_proxy_shadowtls_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_shadowtls_config_proto_rawDescData)
})
return file_proxy_shadowtls_config_proto_rawDescData
}
var file_proxy_shadowtls_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_proxy_shadowtls_config_proto_goTypes = []interface{}{
(*ServerConfig)(nil), // 0: xray.proxy.shadowtls.ServerConfig
(*HandshakeConfig)(nil), // 1: xray.proxy.shadowtls.HandshakeConfig
(*User)(nil), // 2: xray.proxy.shadowtls.User
(*ClientConfig)(nil), // 3: xray.proxy.shadowtls.ClientConfig
nil, // 4: xray.proxy.shadowtls.ServerConfig.HandshakeForServerNameEntry
(*net.IPOrDomain)(nil), // 5: xray.common.net.IPOrDomain
}
var file_proxy_shadowtls_config_proto_depIdxs = []int32{
2, // 0: xray.proxy.shadowtls.ServerConfig.users:type_name -> xray.proxy.shadowtls.User
1, // 1: xray.proxy.shadowtls.ServerConfig.handshake:type_name -> xray.proxy.shadowtls.HandshakeConfig
4, // 2: xray.proxy.shadowtls.ServerConfig.handshake_for_server_name:type_name -> xray.proxy.shadowtls.ServerConfig.HandshakeForServerNameEntry
5, // 3: xray.proxy.shadowtls.HandshakeConfig.address:type_name -> xray.common.net.IPOrDomain
5, // 4: xray.proxy.shadowtls.ClientConfig.address:type_name -> xray.common.net.IPOrDomain
1, // 5: xray.proxy.shadowtls.ServerConfig.HandshakeForServerNameEntry.value:type_name -> xray.proxy.shadowtls.HandshakeConfig
6, // [6:6] is the sub-list for method output_type
6, // [6:6] is the sub-list for method input_type
6, // [6:6] is the sub-list for extension type_name
6, // [6:6] is the sub-list for extension extendee
0, // [0:6] is the sub-list for field type_name
}
func init() { file_proxy_shadowtls_config_proto_init() }
func file_proxy_shadowtls_config_proto_init() {
if File_proxy_shadowtls_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proxy_shadowtls_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ServerConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_shadowtls_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*HandshakeConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_shadowtls_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*User); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proxy_shadowtls_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ClientConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_shadowtls_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_shadowtls_config_proto_goTypes,
DependencyIndexes: file_proxy_shadowtls_config_proto_depIdxs,
MessageInfos: file_proxy_shadowtls_config_proto_msgTypes,
}.Build()
File_proxy_shadowtls_config_proto = out.File
file_proxy_shadowtls_config_proto_rawDesc = nil
file_proxy_shadowtls_config_proto_goTypes = nil
file_proxy_shadowtls_config_proto_depIdxs = nil
}

View File

@@ -0,0 +1,37 @@
syntax = "proto3";
package xray.proxy.shadowtls;
option csharp_namespace = "Xray.Proxy.ShadowTLS";
option go_package = "github.com/xtls/xray-core/proxy/shadowtls";
option java_package = "com.xray.proxy.shadowtls";
option java_multiple_files = true;
import "common/net/address.proto";
message ServerConfig {
uint32 version = 1;
string password = 2;
repeated User users = 3;
HandshakeConfig handshake = 4;
map<string, HandshakeConfig> handshake_for_server_name = 5;
bool strict_mode = 6;
string detour = 7;
}
message HandshakeConfig {
xray.common.net.IPOrDomain address = 1;
uint32 port = 2;
}
message User {
string email = 1;
string password = 2;
int32 level = 3;
}
message ClientConfig {
xray.common.net.IPOrDomain address = 1;
uint32 port = 2;
uint32 version = 3;
string password = 4;
}

View File

@@ -0,0 +1,9 @@
package shadowtls
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

136
proxy/shadowtls/inbound.go Normal file
View File

@@ -0,0 +1,136 @@
package shadowtls
import (
"context"
"os"
"github.com/sagernet/sing-shadowtls"
sing_common "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth"
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"
"github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/inbound"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/transport/internet/stat"
)
func init() {
common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewServer(ctx, config.(*ServerConfig))
}))
}
type Inbound struct {
service *shadowtls.Service
inboundManager inbound.Manager
detour string
}
func NewServer(ctx context.Context, config *ServerConfig) (*Inbound, error) {
v := core.MustFromContext(ctx)
inbound := &Inbound{
inboundManager: v.GetFeature(inbound.ManagerType()).(inbound.Manager),
detour: config.Detour,
}
var handshakeForServerName map[string]shadowtls.HandshakeConfig
if config.Version > 1 {
handshakeForServerName = make(map[string]shadowtls.HandshakeConfig)
for serverName, serverConfig := range config.HandshakeForServerName {
handshakeForServerName[serverName] = shadowtls.HandshakeConfig{
Server: singbridge.ToSocksaddr(net.Destination{
Address: serverConfig.Address.AsAddress(),
Port: net.Port(serverConfig.Port),
}),
Dialer: N.SystemDialer,
}
}
}
service, err := shadowtls.NewService(shadowtls.ServiceConfig{
Version: int(config.Version),
Password: config.Password,
Users: sing_common.Map(config.Users, func(it *User) shadowtls.User {
return shadowtls.User{
Name: it.Email,
Password: it.Password,
}
}),
Handshake: shadowtls.HandshakeConfig{
Server: singbridge.ToSocksaddr(net.Destination{
Address: config.Handshake.Address.AsAddress(),
Port: net.Port(config.Handshake.Port),
}),
Dialer: N.SystemDialer,
},
HandshakeForServerName: handshakeForServerName,
StrictMode: config.StrictMode,
Handler: inbound,
Logger: singbridge.NewLogger(newError),
})
if err != nil {
return nil, E.Cause(err, "create service")
}
inbound.service = service
return inbound, nil
}
func (i *Inbound) Network() []net.Network {
return []net.Network{net.Network_TCP}
}
func (i *Inbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
inbound := session.InboundFromContext(ctx)
var metadata M.Metadata
if inbound.Source.IsValid() {
metadata.Source = M.ParseSocksaddr(inbound.Source.NetAddr())
}
ctx = session.ContextWithDispatcher(ctx, dispatcher)
return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
}
func (i *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
inboundHandler, err := i.inboundManager.GetHandler(ctx, i.detour)
if err != nil {
return E.Cause(err, "detour not found")
}
inboundWrapper, loaded := inboundHandler.(proxy.GetInbound)
if !loaded {
return newError("can't get inbound proxy from handler.")
}
inboundDetour := inboundWrapper.GetInbound()
email, _ := auth.UserFromContext[string](ctx)
inbound := session.InboundFromContext(ctx)
inbound.User = &protocol.MemoryUser{
Email: email,
}
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: metadata.Source,
To: metadata.Destination,
Status: log.AccessAccepted,
Email: email,
})
newError("tunnelling request to detour").WriteToLog(session.ExportIDToError(ctx))
return inboundDetour.Process(ctx, net.Network_TCP, conn, session.DispatcherFromContext(ctx))
}
func (i *Inbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
return os.ErrInvalid
}
func (i *Inbound) NewError(ctx context.Context, err error) {
if E.IsClosed(err) {
return
}
newError(err).AtWarning().WriteToLog()
}

110
proxy/shadowtls/outbound.go Normal file
View File

@@ -0,0 +1,110 @@
package shadowtls
import (
"context"
"crypto/tls"
"github.com/sagernet/sing-shadowtls"
sing_common "github.com/sagernet/sing/common"
utls "github.com/sagernet/utls"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
internet_tls "github.com/xtls/xray-core/transport/internet/tls"
)
func init() {
common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewClient(ctx, config.(*ClientConfig))
}))
}
type Outbound struct {
ctx context.Context
clientConfig shadowtls.ClientConfig
}
func NewClient(ctx context.Context, config *ClientConfig) (*Outbound, error) {
return &Outbound{
ctx: ctx,
clientConfig: shadowtls.ClientConfig{
Version: int(config.Version),
Password: config.Password,
Server: singbridge.ToSocksaddr(net.Destination{
Address: config.Address.AsAddress(),
Port: net.Port(config.Port),
}),
Logger: singbridge.NewLogger(newError),
},
}, nil
}
func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
var inboundConn net.Conn
inbound := session.InboundFromContext(ctx)
if inbound != nil {
inboundConn = inbound.Conn
}
outbound := session.OutboundFromContext(ctx)
if outbound == nil || !outbound.Target.IsValid() {
return newError("target not specified")
}
destination := outbound.Target
if destination.Network != net.Network_TCP {
return newError("only TCP is supported")
}
newError("tunneling request to ", destination, " via ", o.clientConfig.Server).WriteToLog(session.ExportIDToError(ctx))
var client *shadowtls.Client
clientConfig := o.clientConfig
clientConfig.Dialer = singbridge.NewTLSDialer(dialer, func(conn net.Conn, xrayConfig *internet_tls.Config, config *tls.Config) net.Conn {
if fingerprint := GetFingerprint(xrayConfig.Fingerprint); fingerprint != nil {
client.SetHandshakeFunc(uTLSHandshakeFunc(config, fingerprint))
} else {
client.SetHandshakeFunc(shadowtls.DefaultTLSHandshakeFunc(clientConfig.Password, config))
}
return conn
})
var err error
client, err = shadowtls.NewClient(clientConfig)
if err != nil {
return newError("failed to create client").Base(err)
}
conn, err := client.DialContext(ctx)
if err != nil {
return newError("failed to connect to server").Base(err)
}
return singbridge.CopyConn(ctx, inboundConn, link, conn)
}
func uTLSHandshakeFunc(config *tls.Config, clientHelloID *utls.ClientHelloID) shadowtls.TLSHandshakeFunc {
return func(ctx context.Context, conn net.Conn, sessionIDGenerator shadowtls.TLSSessionIDGeneratorFunc) error {
tlsConfig := &utls.Config{
Rand: config.Rand,
Time: config.Time,
VerifyPeerCertificate: config.VerifyPeerCertificate,
RootCAs: config.RootCAs,
NextProtos: config.NextProtos,
ServerName: config.ServerName,
InsecureSkipVerify: config.InsecureSkipVerify,
CipherSuites: config.CipherSuites,
MinVersion: config.MinVersion,
MaxVersion: config.MaxVersion,
CurvePreferences: sing_common.Map(config.CurvePreferences, func(it tls.CurveID) utls.CurveID {
return utls.CurveID(it)
}),
SessionTicketsDisabled: config.SessionTicketsDisabled,
Renegotiation: utls.RenegotiationSupport(config.Renegotiation),
SessionIDGenerator: sessionIDGenerator,
}
tlsConn := utls.UClient(conn, tlsConfig, *clientHelloID)
return tlsConn.HandshakeContext(ctx)
}
}

View File

@@ -0,0 +1,3 @@
package shadowtls
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen

105
proxy/shadowtls/utls.go Normal file
View File

@@ -0,0 +1,105 @@
package shadowtls
import (
"crypto/rand"
"math/big"
utls "github.com/sagernet/utls"
)
func init() {
bigInt, _ := rand.Int(rand.Reader, big.NewInt(int64(len(ModernFingerprints))))
stopAt := int(bigInt.Int64())
i := 0
for _, v := range ModernFingerprints {
if i == stopAt {
PresetFingerprints["random"] = v
break
}
i++
}
weights := utls.DefaultWeights
weights.TLSVersMax_Set_VersionTLS13 = 1
weights.FirstKeyShare_Set_CurveP256 = 0
randomized := utls.HelloRandomized
randomized.Seed, _ = utls.NewPRNGSeed()
randomized.Weights = &weights
PresetFingerprints["randomized"] = &randomized
}
func GetFingerprint(name string) (fingerprint *utls.ClientHelloID) {
if name == "" {
return
}
if fingerprint = PresetFingerprints[name]; fingerprint != nil {
return
}
if fingerprint = ModernFingerprints[name]; fingerprint != nil {
return
}
if fingerprint = OtherFingerprints[name]; fingerprint != nil {
return
}
return
}
var PresetFingerprints = map[string]*utls.ClientHelloID{
// Recommended preset options in GUI clients
"chrome": &utls.HelloChrome_Auto,
"firefox": &utls.HelloFirefox_Auto,
"safari": &utls.HelloSafari_Auto,
"ios": &utls.HelloIOS_Auto,
"android": &utls.HelloAndroid_11_OkHttp,
"edge": &utls.HelloEdge_Auto,
"360": &utls.Hello360_Auto,
"qq": &utls.HelloQQ_Auto,
"random": nil,
"randomized": nil,
}
var ModernFingerprints = map[string]*utls.ClientHelloID{
// One of these will be chosen as `random` at startup
"hellofirefox_99": &utls.HelloFirefox_99,
"hellofirefox_102": &utls.HelloFirefox_102,
"hellofirefox_105": &utls.HelloFirefox_105,
"hellochrome_83": &utls.HelloChrome_83,
"hellochrome_87": &utls.HelloChrome_87,
"hellochrome_96": &utls.HelloChrome_96,
"hellochrome_100": &utls.HelloChrome_100,
"hellochrome_102": &utls.HelloChrome_102,
"hellochrome_106_shuffle": &utls.HelloChrome_106_Shuffle,
"helloios_13": &utls.HelloIOS_13,
"helloios_14": &utls.HelloIOS_14,
"helloedge_85": &utls.HelloEdge_85,
"helloedge_106": &utls.HelloEdge_106,
"hellosafari_16_0": &utls.HelloSafari_16_0,
"hello360_11_0": &utls.Hello360_11_0,
"helloqq_11_1": &utls.HelloQQ_11_1,
}
var OtherFingerprints = map[string]*utls.ClientHelloID{
// Golang, randomized, auto, and fingerprints that are too old
"hellogolang": &utls.HelloGolang,
"hellorandomized": &utls.HelloRandomized,
"hellorandomizedalpn": &utls.HelloRandomizedALPN,
"hellorandomizednoalpn": &utls.HelloRandomizedNoALPN,
"hellofirefox_auto": &utls.HelloFirefox_Auto,
"hellofirefox_55": &utls.HelloFirefox_55,
"hellofirefox_56": &utls.HelloFirefox_56,
"hellofirefox_63": &utls.HelloFirefox_63,
"hellofirefox_65": &utls.HelloFirefox_65,
"hellochrome_auto": &utls.HelloChrome_Auto,
"hellochrome_58": &utls.HelloChrome_58,
"hellochrome_62": &utls.HelloChrome_62,
"hellochrome_70": &utls.HelloChrome_70,
"hellochrome_72": &utls.HelloChrome_72,
"helloios_auto": &utls.HelloIOS_Auto,
"helloios_11_1": &utls.HelloIOS_11_1,
"helloios_12_1": &utls.HelloIOS_12_1,
"helloandroid_11_okhttp": &utls.HelloAndroid_11_OkHttp,
"helloedge_auto": &utls.HelloEdge_Auto,
"hellosafari_auto": &utls.HelloSafari_Auto,
"hello360_auto": &utls.Hello360_Auto,
"hello360_7_5": &utls.Hello360_7_5,
"helloqq_auto": &utls.HelloQQ_Auto,
}

View File

@@ -24,6 +24,7 @@ import (
"github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/udp"
@@ -411,6 +412,12 @@ func (s *Server) fallback(ctx context.Context, sid errors.ExportOption, err erro
alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
} else if realityConn, ok := iConn.(*reality.Conn); ok {
cs := realityConn.ConnectionState()
name = cs.ServerName
alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
}
name = strings.ToLower(name)
alpn = strings.ToLower(alpn)

View File

@@ -26,7 +26,7 @@ import (
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task"
core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/dns"
feature_inbound "github.com/xtls/xray-core/features/inbound"
"github.com/xtls/xray-core/features/policy"
@@ -34,6 +34,7 @@ import (
"github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/proxy/vless/encoding"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/xtls"
@@ -246,6 +247,12 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
} else if realityConn, ok := iConn.(*reality.Conn); ok {
cs := realityConn.ConnectionState()
name = cs.ServerName
alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
}
name = strings.ToLower(name)
alpn = strings.ToLower(alpn)
@@ -494,10 +501,14 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
}
t = reflect.TypeOf(tlsConn.Conn).Elem()
p = uintptr(unsafe.Pointer(tlsConn.Conn))
} else if realityConn, ok := iConn.(*reality.Conn); ok {
netConn = realityConn.NetConn()
t = reflect.TypeOf(realityConn.Conn).Elem()
p = uintptr(unsafe.Pointer(realityConn.Conn))
} else if _, ok := iConn.(*tls.UConn); ok {
return newError("XTLS only supports UTLS fingerprint for the outbound.").AtWarning()
} else if _, ok := iConn.(*xtls.Conn); ok {
return newError(`failed to use ` + requestAddons.Flow + `, vision "security" must be "tls"`).AtWarning()
return newError(`failed to use ` + requestAddons.Flow + `, vision "security" must be "tls" or "reality"`).AtWarning()
} else {
return newError("XTLS only supports TCP, mKCP and DomainSocket for now.").AtWarning()
}

View File

@@ -22,13 +22,14 @@ import (
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/common/xudp"
core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/proxy/vless/encoding"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/xtls"
@@ -164,8 +165,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
netConn = utlsConn.NetConn()
t = reflect.TypeOf(utlsConn.Conn).Elem()
p = uintptr(unsafe.Pointer(utlsConn.Conn))
} else if realityConn, ok := iConn.(*reality.UConn); ok {
netConn = realityConn.NetConn()
t = reflect.TypeOf(realityConn.Conn).Elem()
p = uintptr(unsafe.Pointer(realityConn.Conn))
} else if _, ok := iConn.(*xtls.Conn); ok {
return newError(`failed to use ` + requestAddons.Flow + `, vision "security" must be "tls"`).AtWarning()
return newError(`failed to use ` + requestAddons.Flow + `, vision "security" must be "tls" or "reality"`).AtWarning()
} else {
return newError("XTLS only supports TCP, mKCP and DomainSocket for now.").AtWarning()
}

View File

@@ -0,0 +1,156 @@
package scenarios
import (
"crypto/rand"
"encoding/base64"
"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"
clog "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial"
"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/proxy/shadowtls"
"github.com/xtls/xray-core/testing/servers/tcp"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/tls"
"golang.org/x/sync/errgroup"
)
func TestShadowTLSTcp(t *testing.T) {
password := make([]byte, 32)
rand.Read(password)
testShadowTLSTcp(t, shadowaead_2022.List[0], base64.StdEncoding.EncodeToString(password))
}
func testShadowTLSTcp(t *testing.T, method string, password string) {
tcpServer := tcp.Server{
MsgProcessor: xor,
}
dest, err := tcpServer.Start()
common.Must(err)
defer tcpServer.Close()
serverPort := tcp.PickPort()
serverPort = 18462
serverConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&shadowtls.ServerConfig{
Version: 3,
Users: []*shadowtls.User{{Password: password}},
Handshake: &shadowtls.HandshakeConfig{
Address: net.NewIPOrDomain(net.DomainAddress("google.com")),
Port: 443,
},
Detour: "detour",
}),
},
{
Tag: "detour",
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort + 1)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&shadowsocks_2022.ServerConfig{
Method: method,
Key: password,
Network: []net.Network{net.Network_TCP},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
clientPort := tcp.PickPort()
clientPort = 12434
clientConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
Networks: []net.Network{net.Network_TCP},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&shadowsocks_2022.ClientConfig{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(serverPort),
Method: method,
Key: password,
}),
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
ProxySettings: &internet.ProxyConfig{
Tag: "detour",
},
}),
},
{
Tag: "detour",
ProxySettings: serial.ToTypedMessage(&shadowtls.ClientConfig{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(serverPort),
Version: 3,
Password: password,
}),
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
StreamSettings: &internet.StreamConfig{
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
serial.ToTypedMessage(&tls.Config{
ServerName: "google.com",
}),
},
},
}),
},
},
}
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
common.Must(err)
defer CloseAllServers(servers)
var errGroup errgroup.Group
for i := 0; i < 10; i++ {
errGroup.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))
}
if err := errGroup.Wait(); err != nil {
t.Error(err)
}
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/xtls"
@@ -30,6 +31,8 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
return tls.Client(conn, config.GetTLSConfig(tls.WithDestination(dest))), nil
} else if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {
return xtls.Client(conn, config.GetXTLSConfig(xtls.WithDestination(dest))), nil
} else if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {
return reality.UClient(conn, config, ctx, dest)
}
return conn, nil

View File

@@ -10,9 +10,11 @@ import (
"strings"
goxtls "github.com/xtls/go"
goreality "github.com/xtls/reality"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/xtls"
@@ -20,13 +22,14 @@ import (
)
type Listener struct {
addr *net.UnixAddr
ln net.Listener
tlsConfig *gotls.Config
xtlsConfig *goxtls.Config
config *Config
addConn internet.ConnHandler
locker *fileLocker
addr *net.UnixAddr
ln net.Listener
tlsConfig *gotls.Config
xtlsConfig *goxtls.Config
realityConfig *goreality.Config
config *Config
addConn internet.ConnHandler
locker *fileLocker
}
func Listen(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) {
@@ -64,6 +67,9 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {
ln.xtlsConfig = config.GetXTLSConfig()
}
if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {
ln.realityConfig = config.GetREALITYConfig()
}
go ln.run()
@@ -91,14 +97,19 @@ func (ln *Listener) run() {
newError("failed to accepted raw connections").Base(err).AtWarning().WriteToLog()
continue
}
if ln.tlsConfig != nil {
conn = tls.Server(conn, ln.tlsConfig)
} else if ln.xtlsConfig != nil {
conn = xtls.Server(conn, ln.xtlsConfig)
}
ln.addConn(stat.Connection(conn))
go func() {
if ln.tlsConfig != nil {
conn = tls.Server(conn, ln.tlsConfig)
} else if ln.xtlsConfig != nil {
conn = xtls.Server(conn, ln.xtlsConfig)
} else if ln.realityConfig != nil {
if conn, err = reality.Server(conn, ln.realityConfig); err != nil {
newError(err).AtInfo().WriteToLog()
return
}
}
ln.addConn(stat.Connection(conn))
}()
}
}

View File

@@ -14,6 +14,7 @@ import (
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/pipe"
@@ -40,8 +41,9 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in
httpSettings := streamSettings.ProtocolSettings.(*Config)
tlsConfigs := tls.ConfigFromStreamSettings(streamSettings)
if tlsConfigs == nil {
return nil, newError("TLS must be enabled for http transport.").AtWarning()
realityConfigs := reality.ConfigFromStreamSettings(streamSettings)
if tlsConfigs == nil && realityConfigs == nil {
return nil, newError("TLS or REALITY must be enabled for http transport.").AtWarning()
}
sockopt := streamSettings.SocketSettings
@@ -74,6 +76,10 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in
return nil, err
}
if realityConfigs != nil {
return reality.UClient(pconn, realityConfigs, ctx, dest)
}
var cn tls.Interface
if fingerprint := tls.GetFingerprint(tlsConfigs.Fingerprint); fingerprint != nil {
cn = tls.UClient(pconn, tlsConfig, fingerprint).(*tls.UConn)
@@ -99,7 +105,10 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in
}
return cn, nil
},
TLSClientConfig: tlsConfigs.GetTLSConfig(tls.WithDestination(dest)),
}
if tlsConfigs != nil {
transport.TLSClientConfig = tlsConfigs.GetTLSConfig(tls.WithDestination(dest))
}
if httpSettings.IdleTimeout > 0 || httpSettings.HealthCheckTimeout > 0 {

View File

@@ -0,0 +1,45 @@
package reality
import (
"time"
"github.com/xtls/reality"
"github.com/xtls/xray-core/transport/internet"
)
func (c *Config) GetREALITYConfig() *reality.Config {
config := &reality.Config{
Show: c.Show,
Type: c.Type,
Dest: c.Dest,
Xver: byte(c.Xver),
PrivateKey: c.PrivateKey,
MinClientVer: c.MinClientVer,
MaxClientVer: c.MaxClientVer,
MaxTimeDiff: time.Duration(c.MaxTimeDiff) * time.Millisecond,
NextProtos: nil, // should be nil
SessionTicketsDisabled: true,
}
config.ServerNames = make(map[string]bool)
for _, serverName := range c.ServerNames {
config.ServerNames[serverName] = true
}
config.ShortIds = make(map[[8]byte]bool)
for _, shortId := range c.ShortIds {
config.ShortIds[*(*[8]byte)(shortId)] = true
}
return config
}
func ConfigFromStreamSettings(settings *internet.MemoryStreamConfig) *Config {
if settings == nil {
return nil
}
config, ok := settings.SecuritySettings.(*Config)
if !ok {
return nil
}
return config
}

View File

@@ -0,0 +1,300 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.21.12
// source: transport/internet/reality/config.proto
package reality
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Show bool `protobuf:"varint,1,opt,name=show,proto3" json:"show,omitempty"`
Dest string `protobuf:"bytes,2,opt,name=dest,proto3" json:"dest,omitempty"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
Xver uint64 `protobuf:"varint,4,opt,name=xver,proto3" json:"xver,omitempty"`
ServerNames []string `protobuf:"bytes,5,rep,name=server_names,json=serverNames,proto3" json:"server_names,omitempty"`
PrivateKey []byte `protobuf:"bytes,6,opt,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"`
MinClientVer []byte `protobuf:"bytes,7,opt,name=min_client_ver,json=minClientVer,proto3" json:"min_client_ver,omitempty"`
MaxClientVer []byte `protobuf:"bytes,8,opt,name=max_client_ver,json=maxClientVer,proto3" json:"max_client_ver,omitempty"`
MaxTimeDiff uint64 `protobuf:"varint,9,opt,name=max_time_diff,json=maxTimeDiff,proto3" json:"max_time_diff,omitempty"`
ShortIds [][]byte `protobuf:"bytes,10,rep,name=short_ids,json=shortIds,proto3" json:"short_ids,omitempty"`
Fingerprint string `protobuf:"bytes,21,opt,name=Fingerprint,proto3" json:"Fingerprint,omitempty"`
ServerName string `protobuf:"bytes,22,opt,name=server_name,json=serverName,proto3" json:"server_name,omitempty"`
PublicKey []byte `protobuf:"bytes,23,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
ShortId []byte `protobuf:"bytes,24,opt,name=short_id,json=shortId,proto3" json:"short_id,omitempty"`
SpiderX string `protobuf:"bytes,25,opt,name=spider_x,json=spiderX,proto3" json:"spider_x,omitempty"`
SpiderY []int64 `protobuf:"varint,26,rep,packed,name=spider_y,json=spiderY,proto3" json:"spider_y,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_transport_internet_reality_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_reality_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_transport_internet_reality_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetShow() bool {
if x != nil {
return x.Show
}
return false
}
func (x *Config) GetDest() string {
if x != nil {
return x.Dest
}
return ""
}
func (x *Config) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *Config) GetXver() uint64 {
if x != nil {
return x.Xver
}
return 0
}
func (x *Config) GetServerNames() []string {
if x != nil {
return x.ServerNames
}
return nil
}
func (x *Config) GetPrivateKey() []byte {
if x != nil {
return x.PrivateKey
}
return nil
}
func (x *Config) GetMinClientVer() []byte {
if x != nil {
return x.MinClientVer
}
return nil
}
func (x *Config) GetMaxClientVer() []byte {
if x != nil {
return x.MaxClientVer
}
return nil
}
func (x *Config) GetMaxTimeDiff() uint64 {
if x != nil {
return x.MaxTimeDiff
}
return 0
}
func (x *Config) GetShortIds() [][]byte {
if x != nil {
return x.ShortIds
}
return nil
}
func (x *Config) GetFingerprint() string {
if x != nil {
return x.Fingerprint
}
return ""
}
func (x *Config) GetServerName() string {
if x != nil {
return x.ServerName
}
return ""
}
func (x *Config) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *Config) GetShortId() []byte {
if x != nil {
return x.ShortId
}
return nil
}
func (x *Config) GetSpiderX() string {
if x != nil {
return x.SpiderX
}
return ""
}
func (x *Config) GetSpiderY() []int64 {
if x != nil {
return x.SpiderY
}
return nil
}
var File_transport_internet_reality_config_proto protoreflect.FileDescriptor
var file_transport_internet_reality_config_proto_rawDesc = []byte{
0x0a, 0x27, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1f, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x2e, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x22, 0xdc, 0x03, 0x0a, 0x06, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x18, 0x01, 0x20,
0x01, 0x28, 0x08, 0x52, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a,
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,
0x65, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52,
0x04, 0x78, 0x76, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f,
0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76,
0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70,
0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x6e,
0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x12,
0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x65,
0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x43, 0x6c, 0x69, 0x65,
0x6e, 0x74, 0x56, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x69, 0x6d,
0x65, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61,
0x78, 0x54, 0x69, 0x6d, 0x65, 0x44, 0x69, 0x66, 0x66, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x6f,
0x72, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x68,
0x6f, 0x72, 0x74, 0x49, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72,
0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x46, 0x69, 0x6e,
0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70,
0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72,
0x74, 0x5f, 0x69, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x68, 0x6f, 0x72,
0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x78, 0x18,
0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x58, 0x12, 0x19,
0x0a, 0x08, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x79, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x03,
0x52, 0x07, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x59, 0x42, 0x7f, 0x0a, 0x23, 0x63, 0x6f, 0x6d,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79,
0x50, 0x01, 0x5a, 0x34, 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, 0x74, 0x72,
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
0x2f, 0x72, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0xaa, 0x02, 0x1f, 0x58, 0x72, 0x61, 0x79, 0x2e,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x2e, 0x52, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_transport_internet_reality_config_proto_rawDescOnce sync.Once
file_transport_internet_reality_config_proto_rawDescData = file_transport_internet_reality_config_proto_rawDesc
)
func file_transport_internet_reality_config_proto_rawDescGZIP() []byte {
file_transport_internet_reality_config_proto_rawDescOnce.Do(func() {
file_transport_internet_reality_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_reality_config_proto_rawDescData)
})
return file_transport_internet_reality_config_proto_rawDescData
}
var file_transport_internet_reality_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_reality_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: xray.transport.internet.reality.Config
}
var file_transport_internet_reality_config_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_transport_internet_reality_config_proto_init() }
func file_transport_internet_reality_config_proto_init() {
if File_transport_internet_reality_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_transport_internet_reality_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_transport_internet_reality_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_reality_config_proto_goTypes,
DependencyIndexes: file_transport_internet_reality_config_proto_depIdxs,
MessageInfos: file_transport_internet_reality_config_proto_msgTypes,
}.Build()
File_transport_internet_reality_config_proto = out.File
file_transport_internet_reality_config_proto_rawDesc = nil
file_transport_internet_reality_config_proto_goTypes = nil
file_transport_internet_reality_config_proto_depIdxs = nil
}

View File

@@ -0,0 +1,27 @@
syntax = "proto3";
package xray.transport.internet.reality;
option csharp_namespace = "Xray.Transport.Internet.Reality";
option go_package = "github.com/xtls/xray-core/transport/internet/reality";
option java_package = "com.xray.transport.internet.reality";
option java_multiple_files = true;
message Config {
bool show = 1;
string dest = 2;
string type = 3;
uint64 xver = 4;
repeated string server_names = 5;
bytes private_key = 6;
bytes min_client_ver = 7;
bytes max_client_ver = 8;
uint64 max_time_diff = 9;
repeated bytes short_ids = 10;
string Fingerprint = 21;
string server_name = 22;
bytes public_key = 23;
bytes short_id = 24;
string spider_x = 25;
repeated int64 spider_y = 26;
}

View File

@@ -0,0 +1,9 @@
package reality
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

View File

@@ -0,0 +1,269 @@
package reality
import (
"bytes"
"context"
"crypto/aes"
"crypto/cipher"
"crypto/ed25519"
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
gotls "crypto/tls"
"crypto/x509"
"encoding/binary"
"fmt"
"io"
"math/big"
"net/http"
"reflect"
"regexp"
"strings"
"sync"
"time"
"unsafe"
utls "github.com/refraction-networking/utls"
"github.com/xtls/reality"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/transport/internet/tls"
"golang.org/x/crypto/hkdf"
"golang.org/x/net/http2"
)
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
type Conn struct {
*reality.Conn
}
func (c *Conn) HandshakeAddress() net.Address {
if err := c.Handshake(); err != nil {
return nil
}
state := c.ConnectionState()
if state.ServerName == "" {
return nil
}
return net.ParseAddress(state.ServerName)
}
func Server(c net.Conn, config *reality.Config) (net.Conn, error) {
realityConn, err := reality.Server(c, config)
return &Conn{Conn: realityConn}, err
}
type UConn struct {
*utls.UConn
ServerName string
AuthKey []byte
Verified bool
}
func (c *UConn) HandshakeAddress() net.Address {
if err := c.Handshake(); err != nil {
return nil
}
state := c.ConnectionState()
if state.ServerName == "" {
return nil
}
return net.ParseAddress(state.ServerName)
}
func (c *UConn) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates")
certs := *(*([]*x509.Certificate))(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + p.Offset))
if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok {
h := hmac.New(sha512.New, c.AuthKey)
h.Write(pub)
if bytes.Equal(h.Sum(nil), certs[0].Signature) {
c.Verified = true
return nil
}
}
opts := x509.VerifyOptions{
DNSName: c.ServerName,
Intermediates: x509.NewCertPool(),
}
for _, cert := range certs[1:] {
opts.Intermediates.AddCert(cert)
}
if _, err := certs[0].Verify(opts); err != nil {
return err
}
return nil
}
func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destination) (net.Conn, error) {
localAddr := c.LocalAddr().String()
uConn := &UConn{}
utlsConfig := &utls.Config{
VerifyPeerCertificate: uConn.VerifyPeerCertificate,
ServerName: config.ServerName,
InsecureSkipVerify: true,
SessionTicketsDisabled: true,
}
if utlsConfig.ServerName == "" && dest.Address.Family().IsDomain() {
utlsConfig.ServerName = dest.Address.Domain()
}
uConn.ServerName = utlsConfig.ServerName
fingerprint := tls.GetFingerprint(config.Fingerprint)
if fingerprint == nil {
return nil, newError("REALITY: failed to get fingerprint").AtError()
}
uConn.UConn = utls.UClient(c, utlsConfig, *fingerprint)
{
uConn.BuildHandshakeState()
hello := uConn.HandshakeState.Hello
hello.SessionId = make([]byte, 32)
copy(hello.Raw[39:], hello.SessionId) // the location of session ID
binary.BigEndian.PutUint64(hello.SessionId, uint64(time.Now().Unix()))
hello.SessionId[0] = core.Version_x
hello.SessionId[1] = core.Version_y
hello.SessionId[2] = core.Version_z
copy(hello.SessionId[8:], config.ShortId)
if config.Show {
fmt.Printf("REALITY localAddr: %v\thello.sessionId[:16]: %v\n", localAddr, hello.SessionId[:16])
}
uConn.AuthKey = uConn.HandshakeState.State13.EcdheParams.SharedKey(config.PublicKey)
if uConn.AuthKey == nil {
return nil, errors.New("REALITY: SharedKey == nil")
}
if _, err := hkdf.New(sha256.New, uConn.AuthKey, hello.Random[:20], []byte("REALITY")).Read(uConn.AuthKey); err != nil {
return nil, err
}
block, _ := aes.NewCipher(uConn.AuthKey)
aead, _ := cipher.NewGCM(block)
aead.Seal(hello.SessionId[:0], hello.Random[20:], hello.SessionId[:16], hello.Raw)
copy(hello.Raw[39:], hello.SessionId)
if config.Show {
fmt.Printf("REALITY localAddr: %v\thello.sessionId: %v\n", localAddr, hello.SessionId)
fmt.Printf("REALITY localAddr: %v\tuConn.AuthKey: %v\n", localAddr, uConn.AuthKey)
}
}
if err := uConn.Handshake(); err != nil {
return nil, err
}
if config.Show {
fmt.Printf("REALITY localAddr: %v\tuConn.Verified: %v\n", localAddr, uConn.Verified)
}
if !uConn.Verified {
go func() {
client := &http.Client{
Transport: &http2.Transport{
DialTLSContext: func(ctx context.Context, network, addr string, cfg *gotls.Config) (net.Conn, error) {
fmt.Printf("REALITY localAddr: %v\tDialTLSContext\n", localAddr)
return uConn, nil
},
},
}
prefix := []byte("https://" + uConn.ServerName)
maps.Lock()
if maps.maps == nil {
maps.maps = make(map[string]map[string]bool)
}
paths := maps.maps[uConn.ServerName]
if paths == nil {
paths = make(map[string]bool)
paths[config.SpiderX] = true
maps.maps[uConn.ServerName] = paths
}
firstURL := string(prefix) + getPathLocked(paths)
maps.Unlock()
get := func(first bool) {
var (
req *http.Request
resp *http.Response
err error
body []byte
)
if first {
req, _ = http.NewRequest("GET", firstURL, nil)
} else {
maps.Lock()
req, _ = http.NewRequest("GET", string(prefix)+getPathLocked(paths), nil)
maps.Unlock()
}
req.Header.Set("User-Agent", fingerprint.Client) // TODO: User-Agent map
if first && config.Show {
fmt.Printf("REALITY localAddr: %v\treq.UserAgent(): %v\n", localAddr, req.UserAgent())
}
times := 1
if !first {
times = int(randBetween(config.SpiderY[4], config.SpiderY[5]))
}
for j := 0; j < times; j++ {
if !first && j == 0 {
req.Header.Set("Referer", firstURL)
}
req.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", int(randBetween(config.SpiderY[0], config.SpiderY[1])))})
if resp, err = client.Do(req); err != nil {
break
}
req.Header.Set("Referer", req.URL.String())
if body, err = io.ReadAll(resp.Body); err != nil {
break
}
maps.Lock()
for _, m := range href.FindAllSubmatch(body, -1) {
m[1] = bytes.TrimPrefix(m[1], prefix)
if !bytes.Contains(m[1], dot) {
paths[string(m[1])] = true
}
}
req.URL.Path = getPathLocked(paths)
if config.Show {
fmt.Printf("REALITY localAddr: %v\treq.Referer(): %v\n", localAddr, req.Referer())
fmt.Printf("REALITY localAddr: %v\tlen(body): %v\n", localAddr, len(body))
fmt.Printf("REALITY localAddr: %v\tlen(paths): %v\n", localAddr, len(paths))
}
maps.Unlock()
if !first {
time.Sleep(time.Duration(randBetween(config.SpiderY[6], config.SpiderY[7])) * time.Millisecond) // interval
}
}
}
get(true)
concurrency := int(randBetween(config.SpiderY[2], config.SpiderY[3]))
for i := 0; i < concurrency; i++ {
go get(false)
}
// Do not close the connection
}()
time.Sleep(time.Duration(randBetween(config.SpiderY[8], config.SpiderY[9])) * time.Millisecond) // return
return nil, errors.New("REALITY: processed invalid connection")
}
return uConn, nil
}
var href = regexp.MustCompile(`href="([/h].*?)"`)
var dot = []byte(".")
var maps struct {
sync.Mutex
maps map[string]map[string]bool
}
func getPathLocked(paths map[string]bool) string {
stopAt := int(randBetween(0, int64(len(paths)-1)))
i := 0
for s := range paths {
if i == stopAt {
return s
}
i++
}
return "/"
}
func randBetween(left int64, right int64) int64 {
if left == right {
return left
}
bigInt, _ := rand.Int(rand.Reader, big.NewInt(right-left))
return left + bigInt.Int64()
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/xtls"
@@ -22,17 +23,26 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
tlsConfig := config.GetTLSConfig(tls.WithDestination(dest))
if fingerprint := tls.GetFingerprint(config.Fingerprint); fingerprint != nil {
conn = tls.UClient(conn, tlsConfig, fingerprint)
if err := conn.(*tls.UConn).Handshake(); err != nil {
return nil, err
}
customClient, loaded := tls.CustomClientFromContext(ctx)
if loaded {
conn = customClient(conn, config, tlsConfig)
} else {
conn = tls.Client(conn, tlsConfig)
if fingerprint := tls.GetFingerprint(config.Fingerprint); fingerprint != nil {
conn = tls.UClient(conn, tlsConfig, fingerprint)
if err := conn.(*tls.UConn).Handshake(); err != nil {
return nil, err
}
} else {
conn = tls.Client(conn, tlsConfig)
}
}
} else if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {
xtlsConfig := config.GetXTLSConfig(xtls.WithDestination(dest))
conn = xtls.Client(conn, xtlsConfig)
} else if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {
if conn, err = reality.UClient(conn, config, ctx, dest); err != nil {
return nil, err
}
}
tcpSettings := streamSettings.ProtocolSettings.(*Config)

View File

@@ -7,10 +7,12 @@ import (
"time"
goxtls "github.com/xtls/go"
goreality "github.com/xtls/reality"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/xtls"
@@ -18,13 +20,14 @@ import (
// Listener is an internet.Listener that listens for TCP connections.
type Listener struct {
listener net.Listener
tlsConfig *gotls.Config
xtlsConfig *goxtls.Config
authConfig internet.ConnectionAuthenticator
config *Config
addConn internet.ConnHandler
locker *internet.FileLocker // for unix domain socket
listener net.Listener
tlsConfig *gotls.Config
xtlsConfig *goxtls.Config
realityConfig *goreality.Config
authConfig internet.ConnectionAuthenticator
config *Config
addConn internet.ConnHandler
locker *internet.FileLocker // for unix domain socket
}
// ListenTCP creates a new Listener based on configurations.
@@ -78,6 +81,9 @@ func ListenTCP(ctx context.Context, address net.Address, port net.Port, streamSe
if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {
l.xtlsConfig = config.GetXTLSConfig()
}
if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {
l.realityConfig = config.GetREALITYConfig()
}
if tcpSettings.HeaderSettings != nil {
headerConfig, err := tcpSettings.HeaderSettings.GetInstance()
@@ -109,17 +115,22 @@ func (v *Listener) keepAccepting() {
}
continue
}
if v.tlsConfig != nil {
conn = tls.Server(conn, v.tlsConfig)
} else if v.xtlsConfig != nil {
conn = xtls.Server(conn, v.xtlsConfig)
}
if v.authConfig != nil {
conn = v.authConfig.Server(conn)
}
v.addConn(stat.Connection(conn))
go func() {
if v.tlsConfig != nil {
conn = tls.Server(conn, v.tlsConfig)
} else if v.xtlsConfig != nil {
conn = xtls.Server(conn, v.xtlsConfig)
} else if v.realityConfig != nil {
if conn, err = reality.Server(conn, v.realityConfig); err != nil {
newError(err).AtInfo().WriteToLog()
return
}
}
if v.authConfig != nil {
conn = v.authConfig.Server(conn)
}
v.addConn(stat.Connection(conn))
}()
}
}

View File

@@ -0,0 +1,21 @@
package tls
import (
"context"
"crypto/tls"
"github.com/xtls/xray-core/common/net"
)
type customClientKey struct{}
type CustomClientFunc func(conn net.Conn, xrayConfig *Config, config *tls.Config) net.Conn
func CustomClientFromContext(ctx context.Context) (CustomClientFunc, bool) {
client, loaded := ctx.Value(customClientKey{}).(CustomClientFunc)
return client, loaded
}
func ContextWithCustomClient(ctx context.Context, customClient CustomClientFunc) context.Context {
return context.WithValue(ctx, customClientKey{}, customClient)
}

View File

@@ -173,47 +173,47 @@ var PresetFingerprints = map[string]*utls.ClientHelloID{
var ModernFingerprints = map[string]*utls.ClientHelloID{
// One of these will be chosen as `random` at startup
"hellofirefox_auto": &utls.HelloFirefox_Auto,
"hellofirefox_99": &utls.HelloFirefox_99,
"hellofirefox_102": &utls.HelloFirefox_102,
"hellofirefox_105": &utls.HelloFirefox_105,
"hellochrome_auto": &utls.HelloChrome_Auto,
"hellochrome_83": &utls.HelloChrome_83,
"hellochrome_87": &utls.HelloChrome_87,
"hellochrome_96": &utls.HelloChrome_96,
"hellochrome_100": &utls.HelloChrome_100,
"hellochrome_102": &utls.HelloChrome_102,
"hellochrome_106_shuffle": &utls.HelloChrome_106_Shuffle,
"helloios_auto": &utls.HelloIOS_Auto,
"helloios_12_1": &utls.HelloIOS_12_1,
"helloios_13": &utls.HelloIOS_13,
"helloios_14": &utls.HelloIOS_14,
"helloandroid_11_okhttp": &utls.HelloAndroid_11_OkHttp,
"helloedge_auto": &utls.HelloEdge_Auto,
"helloedge_85": &utls.HelloEdge_85,
"helloedge_106": &utls.HelloEdge_106,
"hellosafari_auto": &utls.HelloSafari_Auto,
"hellosafari_16_0": &utls.HelloSafari_16_0,
"hello360_auto": &utls.Hello360_Auto,
"hello360_11_0": &utls.Hello360_11_0,
"helloqq_auto": &utls.HelloQQ_Auto,
"helloqq_11_1": &utls.HelloQQ_11_1,
}
var OtherFingerprints = map[string]*utls.ClientHelloID{
// Golang, randomized, and fingerprints that are more than 4 years old
"hellogolang": &utls.HelloGolang,
"hellorandomized": &utls.HelloRandomized,
"hellorandomizedalpn": &utls.HelloRandomizedALPN,
"hellorandomizednoalpn": &utls.HelloRandomizedNoALPN,
"hellofirefox_55": &utls.HelloFirefox_55,
"hellofirefox_56": &utls.HelloFirefox_56,
"hellofirefox_63": &utls.HelloFirefox_63,
"hellofirefox_65": &utls.HelloFirefox_65,
"hellochrome_58": &utls.HelloChrome_58,
"hellochrome_62": &utls.HelloChrome_62,
"hellochrome_70": &utls.HelloChrome_70,
"hellochrome_72": &utls.HelloChrome_72,
"helloios_11_1": &utls.HelloIOS_11_1,
"hello360_7_5": &utls.Hello360_7_5,
// Golang, randomized, auto, and fingerprints that are too old
"hellogolang": &utls.HelloGolang,
"hellorandomized": &utls.HelloRandomized,
"hellorandomizedalpn": &utls.HelloRandomizedALPN,
"hellorandomizednoalpn": &utls.HelloRandomizedNoALPN,
"hellofirefox_auto": &utls.HelloFirefox_Auto,
"hellofirefox_55": &utls.HelloFirefox_55,
"hellofirefox_56": &utls.HelloFirefox_56,
"hellofirefox_63": &utls.HelloFirefox_63,
"hellofirefox_65": &utls.HelloFirefox_65,
"hellochrome_auto": &utls.HelloChrome_Auto,
"hellochrome_58": &utls.HelloChrome_58,
"hellochrome_62": &utls.HelloChrome_62,
"hellochrome_70": &utls.HelloChrome_70,
"hellochrome_72": &utls.HelloChrome_72,
"helloios_auto": &utls.HelloIOS_Auto,
"helloios_11_1": &utls.HelloIOS_11_1,
"helloios_12_1": &utls.HelloIOS_12_1,
"helloandroid_11_okhttp": &utls.HelloAndroid_11_OkHttp,
"helloedge_auto": &utls.HelloEdge_Auto,
"hellosafari_auto": &utls.HelloSafari_Auto,
"hello360_auto": &utls.Hello360_Auto,
"hello360_7_5": &utls.Hello360_7_5,
"helloqq_auto": &utls.HelloQQ_Auto,
}