mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-30 04:21:28 +00:00
Add shadow-tls support
This commit is contained in:
parent
4d5c3195d2
commit
d6c2a9aab7
46
common/singbridge/destination.go
Normal file
46
common/singbridge/destination.go
Normal 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
|
||||||
|
}
|
29
common/singbridge/dialer.go
Normal file
29
common/singbridge/dialer.go
Normal 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
|
||||||
|
}
|
41
common/singbridge/dialer_tls.go
Normal file
41
common/singbridge/dialer_tls.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
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 tlsConfig *gotls.Config
|
||||||
|
conn, err := d.dialer.Dial(tls.ContextWithCustomClient(ctx, func(conn net.Conn, config *gotls.Config) net.Conn {
|
||||||
|
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, tlsConfig), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *XrayTLSDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
10
common/singbridge/error.go
Normal file
10
common/singbridge/error.go
Normal 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
|
||||||
|
}
|
70
common/singbridge/logger.go
Normal file
70
common/singbridge/logger.go
Normal 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
61
common/singbridge/pipe.go
Normal 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
|
||||||
|
}
|
1
go.mod
1
go.mod
|
@ -15,6 +15,7 @@ require (
|
||||||
github.com/refraction-networking/utls v1.2.2
|
github.com/refraction-networking/utls v1.2.2
|
||||||
github.com/sagernet/sing v0.1.6
|
github.com/sagernet/sing v0.1.6
|
||||||
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7
|
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7
|
||||||
|
github.com/sagernet/sing-shadowtls v0.0.0-20230221100347-75f55ea45b99
|
||||||
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c
|
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c
|
||||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb
|
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/stretchr/testify v1.8.1
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -147,6 +147,14 @@ 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 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 h1:Plup6oEiyLzY3HDqQ+QsUBzgBGdVmcsgf3t8h940z9U=
|
||||||
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7/go.mod h1:O5LtOs8Ivw686FqLpO0Zu+A0ROVE15VeqEK3yDRRAms=
|
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7/go.mod h1:O5LtOs8Ivw686FqLpO0Zu+A0ROVE15VeqEK3yDRRAms=
|
||||||
|
github.com/sagernet/sing-shadowtls v0.0.0-20230221081357-574313aaae1d h1:yETevmRbJ6Mf9xgavSmgxo9UCdKNyplU4ubgFXqd4XU=
|
||||||
|
github.com/sagernet/sing-shadowtls v0.0.0-20230221081357-574313aaae1d/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
|
||||||
|
github.com/sagernet/sing-shadowtls v0.0.0-20230221093358-af0356df4755 h1:5/GdWkRlHv00+4JrIy0ilWAw2p/EWtuH0CClC2/gko4=
|
||||||
|
github.com/sagernet/sing-shadowtls v0.0.0-20230221093358-af0356df4755/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
|
||||||
|
github.com/sagernet/sing-shadowtls v0.0.0-20230221100347-75f55ea45b99 h1:LhGnlaH8bV0MCNp/LW4PDPagtkJDSAX0ftN9bJ6HMxY=
|
||||||
|
github.com/sagernet/sing-shadowtls v0.0.0-20230221100347-75f55ea45b99/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
|
||||||
|
github.com/sagernet/sing-shadowtls v0.0.0-20230221110738-214729669cdc h1:T1XsW+0eNGlyy7NXY8AG2pE3d+RsdphRCH5ux0jjWf4=
|
||||||
|
github.com/sagernet/sing-shadowtls v0.0.0-20230221110738-214729669cdc/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
|
||||||
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo=
|
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/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=
|
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
|
||||||
|
|
75
infra/conf/shadowtls.go
Normal file
75
infra/conf/shadowtls.go
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ShadowTLSUser) Build() *shadowtls.User {
|
||||||
|
return &shadowtls.User{
|
||||||
|
Email: c.Email,
|
||||||
|
Password: c.Password,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShadowTLSHandshakeConfig struct {
|
||||||
|
Address *Address `json:"address"`
|
||||||
|
Port uint16 `json:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ShadowTLSHandshakeConfig) Build() *shadowtls.HandshakeConfig {
|
||||||
|
return &shadowtls.HandshakeConfig{
|
||||||
|
Address: c.Address.Build(),
|
||||||
|
Port: uint32(c.Port),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ShadowTLSServerConfig) Build() (proto.Message, error) {
|
||||||
|
var handshakeForServerName map[string]*shadowtls.HandshakeConfig
|
||||||
|
if c.HandshakeForServerName != nil {
|
||||||
|
for serverName, serverConfig := range c.HandshakeForServerName {
|
||||||
|
handshakeForServerName[serverName] = serverConfig.Build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &shadowtls.ServerConfig{
|
||||||
|
Version: uint32(c.Version),
|
||||||
|
Password: c.Password,
|
||||||
|
Users: common.Map(c.Users, ShadowTLSUser.Build),
|
||||||
|
Handshake: c.Handshake.Build(),
|
||||||
|
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) {
|
||||||
|
return &shadowtls.ClientConfig{
|
||||||
|
Address: c.Address.Build(),
|
||||||
|
Port: uint32(c.Port),
|
||||||
|
Version: uint32(c.Version),
|
||||||
|
Password: c.Password,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ var (
|
||||||
"vmess": func() interface{} { return new(VMessInboundConfig) },
|
"vmess": func() interface{} { return new(VMessInboundConfig) },
|
||||||
"trojan": func() interface{} { return new(TrojanServerConfig) },
|
"trojan": func() interface{} { return new(TrojanServerConfig) },
|
||||||
"mtproto": func() interface{} { return new(MTProtoServerConfig) },
|
"mtproto": func() interface{} { return new(MTProtoServerConfig) },
|
||||||
|
"shadow-tls": func() interface{} { return new(ShadowTLSServerConfig) },
|
||||||
}, "protocol", "settings")
|
}, "protocol", "settings")
|
||||||
|
|
||||||
outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
||||||
|
@ -41,6 +42,7 @@ var (
|
||||||
"mtproto": func() interface{} { return new(MTProtoClientConfig) },
|
"mtproto": func() interface{} { return new(MTProtoClientConfig) },
|
||||||
"dns": func() interface{} { return new(DNSOutboundConfig) },
|
"dns": func() interface{} { return new(DNSOutboundConfig) },
|
||||||
"wireguard": func() interface{} { return new(WireGuardConfig) },
|
"wireguard": func() interface{} { return new(WireGuardConfig) },
|
||||||
|
"shadow-tls": func() interface{} { return new(ShadowTLSClientConfig) },
|
||||||
}, "protocol", "settings")
|
}, "protocol", "settings")
|
||||||
|
|
||||||
ctllog = log.New(os.Stderr, "xctl> ", 0)
|
ctllog = log.New(os.Stderr, "xctl> ", 0)
|
||||||
|
|
|
@ -42,6 +42,7 @@ import (
|
||||||
_ "github.com/xtls/xray-core/proxy/loopback"
|
_ "github.com/xtls/xray-core/proxy/loopback"
|
||||||
_ "github.com/xtls/xray-core/proxy/mtproto"
|
_ "github.com/xtls/xray-core/proxy/mtproto"
|
||||||
_ "github.com/xtls/xray-core/proxy/shadowsocks"
|
_ "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/socks"
|
||||||
_ "github.com/xtls/xray-core/proxy/trojan"
|
_ "github.com/xtls/xray-core/proxy/trojan"
|
||||||
_ "github.com/xtls/xray-core/proxy/vless/inbound"
|
_ "github.com/xtls/xray-core/proxy/vless/inbound"
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"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/features/routing"
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
"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)
|
ctx = session.ContextWithDispatcher(ctx, dispatcher)
|
||||||
|
|
||||||
if network == net.Network_TCP {
|
if network == net.Network_TCP {
|
||||||
return returnError(i.service.NewConnection(ctx, connection, metadata))
|
return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
|
||||||
} else {
|
} else {
|
||||||
reader := buf.NewReader(connection)
|
reader := buf.NewReader(connection)
|
||||||
pc := &natPacketConn{connection}
|
pc := &natPacketConn{connection}
|
||||||
|
@ -81,7 +82,7 @@ func (i *Inbound) Process(ctx context.Context, network net.Network, connection s
|
||||||
mb, err := reader.ReadMultiBuffer()
|
mb, err := reader.ReadMultiBuffer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
buf.ReleaseMulti(mb)
|
buf.ReleaseMulti(mb)
|
||||||
return returnError(err)
|
return singbridge.ReturnError(err)
|
||||||
}
|
}
|
||||||
for _, buffer := range mb {
|
for _, buffer := range mb {
|
||||||
packet := B.As(buffer.Bytes()).ToOwned()
|
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))
|
newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
|
||||||
dispatcher := session.DispatcherFromContext(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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
outConn := &pipeConnWrapper{
|
return singbridge.CopyConn(ctx, nil, link, conn)
|
||||||
&buf.BufferedReader{Reader: link.Reader},
|
|
||||||
link.Writer,
|
|
||||||
conn,
|
|
||||||
}
|
|
||||||
return bufio.CopyConn(ctx, conn, outConn)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Inbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
|
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))
|
newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
|
||||||
dispatcher := session.DispatcherFromContext(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)
|
link, err := dispatcher.Dispatch(ctx, destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"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/common/uuid"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
"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)
|
ctx = session.ContextWithDispatcher(ctx, dispatcher)
|
||||||
|
|
||||||
if network == net.Network_TCP {
|
if network == net.Network_TCP {
|
||||||
return returnError(i.service.NewConnection(ctx, connection, metadata))
|
return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
|
||||||
} else {
|
} else {
|
||||||
reader := buf.NewReader(connection)
|
reader := buf.NewReader(connection)
|
||||||
pc := &natPacketConn{connection}
|
pc := &natPacketConn{connection}
|
||||||
|
@ -170,7 +171,7 @@ func (i *MultiUserInbound) Process(ctx context.Context, network net.Network, con
|
||||||
mb, err := reader.ReadMultiBuffer()
|
mb, err := reader.ReadMultiBuffer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
buf.ReleaseMulti(mb)
|
buf.ReleaseMulti(mb)
|
||||||
return returnError(err)
|
return singbridge.ReturnError(err)
|
||||||
}
|
}
|
||||||
for _, buffer := range mb {
|
for _, buffer := range mb {
|
||||||
packet := B.As(buffer.Bytes()).ToOwned()
|
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))
|
newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
|
||||||
dispatcher := session.DispatcherFromContext(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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
outConn := &pipeConnWrapper{
|
return singbridge.CopyConn(ctx, conn, link, conn)
|
||||||
&buf.BufferedReader{Reader: link.Reader},
|
|
||||||
link.Writer,
|
|
||||||
conn,
|
|
||||||
}
|
|
||||||
return bufio.CopyConn(ctx, conn, outConn)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *MultiUserInbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
|
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))
|
newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
|
||||||
dispatcher := session.DispatcherFromContext(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)
|
link, err := dispatcher.Dispatch(ctx, destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"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/common/uuid"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
"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.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) string { return it.Key }),
|
||||||
C.Map(config.Destinations, func(it *RelayDestination) M.Socksaddr {
|
C.Map(config.Destinations, func(it *RelayDestination) M.Socksaddr {
|
||||||
return toSocksaddr(net.Destination{
|
return singbridge.ToSocksaddr(net.Destination{
|
||||||
Address: it.Address.AsAddress(),
|
Address: it.Address.AsAddress(),
|
||||||
Port: net.Port(it.Port),
|
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)
|
ctx = session.ContextWithDispatcher(ctx, dispatcher)
|
||||||
|
|
||||||
if network == net.Network_TCP {
|
if network == net.Network_TCP {
|
||||||
return returnError(i.service.NewConnection(ctx, connection, metadata))
|
return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
|
||||||
} else {
|
} else {
|
||||||
reader := buf.NewReader(connection)
|
reader := buf.NewReader(connection)
|
||||||
pc := &natPacketConn{connection}
|
pc := &natPacketConn{connection}
|
||||||
|
@ -102,7 +103,7 @@ func (i *RelayInbound) Process(ctx context.Context, network net.Network, connect
|
||||||
mb, err := reader.ReadMultiBuffer()
|
mb, err := reader.ReadMultiBuffer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
buf.ReleaseMulti(mb)
|
buf.ReleaseMulti(mb)
|
||||||
return returnError(err)
|
return singbridge.ReturnError(err)
|
||||||
}
|
}
|
||||||
for _, buffer := range mb {
|
for _, buffer := range mb {
|
||||||
packet := B.As(buffer.Bytes()).ToOwned()
|
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))
|
newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
|
||||||
dispatcher := session.DispatcherFromContext(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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
outConn := &pipeConnWrapper{
|
return singbridge.CopyConn(ctx, nil, link, conn)
|
||||||
&buf.BufferedReader{Reader: link.Reader},
|
|
||||||
link.Writer,
|
|
||||||
conn,
|
|
||||||
}
|
|
||||||
return bufio.CopyConn(ctx, conn, outConn)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *RelayInbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
|
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))
|
newError("tunnelling request to udp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
|
||||||
dispatcher := session.DispatcherFromContext(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)
|
link, err := dispatcher.Dispatch(ctx, destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -2,7 +2,6 @@ package shadowsocks_2022
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -18,6 +17,7 @@ import (
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"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"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"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 {
|
if network == net.Network_TCP {
|
||||||
serverConn := o.method.DialEarlyConn(connection, toSocksaddr(destination))
|
serverConn := o.method.DialEarlyConn(connection, singbridge.ToSocksaddr(destination))
|
||||||
var handshake bool
|
var handshake bool
|
||||||
if timeoutReader, isTimeoutReader := link.Reader.(buf.TimeoutReader); isTimeoutReader {
|
if timeoutReader, isTimeoutReader := link.Reader.(buf.TimeoutReader); isTimeoutReader {
|
||||||
mb, err := timeoutReader.ReadMultiBufferTimeout(time.Millisecond * 100)
|
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)
|
return newError("client handshake").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn := &pipeConnWrapper{
|
return singbridge.CopyConn(ctx, inboundConn, link, serverConn)
|
||||||
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))
|
|
||||||
} else {
|
} else {
|
||||||
var packetConn N.PacketConn
|
var packetConn N.PacketConn
|
||||||
if pc, isPacketConn := inboundConn.(N.PacketConn); isPacketConn {
|
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 {
|
if o.uot {
|
||||||
serverConn := o.method.DialEarlyConn(connection, M.Socksaddr{Fqdn: uot.UOTMagicAddress})
|
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 {
|
} else {
|
||||||
serverConn := o.method.DialPacketConn(connection)
|
serverConn := o.method.DialPacketConn(connection)
|
||||||
return returnError(bufio.CopyPacketConn(ctx, packetConn, serverConn))
|
return singbridge.ReturnError(bufio.CopyPacketConn(ctx, packetConn, serverConn))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,82 +1,15 @@
|
||||||
package shadowsocks_2022
|
package shadowsocks_2022
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
|
|
||||||
B "github.com/sagernet/sing/common/buf"
|
B "github.com/sagernet/sing/common/buf"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"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
|
//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 {
|
type packetConnWrapper struct {
|
||||||
buf.Reader
|
buf.Reader
|
||||||
buf.Writer
|
buf.Writer
|
||||||
|
@ -100,7 +33,7 @@ func (w *packetConnWrapper) ReadPacket(buffer *B.Buffer) (M.Socksaddr, error) {
|
||||||
destination = w.Dest
|
destination = w.Dest
|
||||||
}
|
}
|
||||||
bb.Release()
|
bb.Release()
|
||||||
return toSocksaddr(destination), nil
|
return singbridge.ToSocksaddr(destination), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mb, err := w.ReadMultiBuffer()
|
mb, err := w.ReadMultiBuffer()
|
||||||
|
@ -120,14 +53,14 @@ func (w *packetConnWrapper) ReadPacket(buffer *B.Buffer) (M.Socksaddr, error) {
|
||||||
destination = w.Dest
|
destination = w.Dest
|
||||||
}
|
}
|
||||||
bb.Release()
|
bb.Release()
|
||||||
return toSocksaddr(destination), nil
|
return singbridge.ToSocksaddr(destination), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *packetConnWrapper) WritePacket(buffer *B.Buffer, destination M.Socksaddr) error {
|
func (w *packetConnWrapper) WritePacket(buffer *B.Buffer, destination M.Socksaddr) error {
|
||||||
vBuf := buf.New()
|
vBuf := buf.New()
|
||||||
vBuf.Write(buffer.Bytes())
|
vBuf.Write(buffer.Bytes())
|
||||||
endpoint := toDestination(destination, net.Network_UDP)
|
endpoint := singbridge.ToDestination(destination, net.Network_UDP)
|
||||||
vBuf.UDP = &endpoint
|
vBuf.UDP = &endpoint
|
||||||
return w.Writer.WriteMultiBuffer(buf.MultiBuffer{vBuf})
|
return w.Writer.WriteMultiBuffer(buf.MultiBuffer{vBuf})
|
||||||
}
|
}
|
||||||
|
@ -136,10 +69,3 @@ func (w *packetConnWrapper) Close() error {
|
||||||
buf.ReleaseMulti(w.cached)
|
buf.ReleaseMulti(w.cached)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func returnError(err error) error {
|
|
||||||
if E.IsClosed(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
483
proxy/shadowtls/config.pb.go
Normal file
483
proxy/shadowtls/config.pb.go
Normal 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
|
||||||
|
}
|
37
proxy/shadowtls/config.proto
Normal file
37
proxy/shadowtls/config.proto
Normal 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;
|
||||||
|
}
|
9
proxy/shadowtls/errors.generated.go
Normal file
9
proxy/shadowtls/errors.generated.go
Normal 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
136
proxy/shadowtls/inbound.go
Normal 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()
|
||||||
|
}
|
83
proxy/shadowtls/outbound.go
Normal file
83
proxy/shadowtls/outbound.go
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package shadowtls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-shadowtls"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
if clientConfig.Version == 3 {
|
||||||
|
clientConfig.Dialer = singbridge.NewTLSDialer(dialer, func(conn net.Conn, config *tls.Config) net.Conn {
|
||||||
|
client.SetTLSConfig(config)
|
||||||
|
return conn
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
clientConfig.Dialer = singbridge.NewDialer(dialer)
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
3
proxy/shadowtls/shadowtls.go
Normal file
3
proxy/shadowtls/shadowtls.go
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
package shadowtls
|
||||||
|
|
||||||
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
156
testing/scenarios/shadowtls_test.go
Normal file
156
testing/scenarios/shadowtls_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,13 +23,18 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
|
||||||
|
|
||||||
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
|
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
|
||||||
tlsConfig := config.GetTLSConfig(tls.WithDestination(dest))
|
tlsConfig := config.GetTLSConfig(tls.WithDestination(dest))
|
||||||
if fingerprint := tls.GetFingerprint(config.Fingerprint); fingerprint != nil {
|
customClient, loaded := tls.CustomClientFromContext(ctx)
|
||||||
conn = tls.UClient(conn, tlsConfig, fingerprint)
|
if loaded {
|
||||||
if err := conn.(*tls.UConn).Handshake(); err != nil {
|
conn = customClient(conn, tlsConfig)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
} 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 {
|
} else if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {
|
||||||
xtlsConfig := config.GetXTLSConfig(xtls.WithDestination(dest))
|
xtlsConfig := config.GetXTLSConfig(xtls.WithDestination(dest))
|
||||||
|
|
21
transport/internet/tls/custom.go
Normal file
21
transport/internet/tls/custom.go
Normal 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, 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)
|
||||||
|
}
|
Loading…
Reference in a new issue