mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-24 17:41:29 +00:00
Add custom tls client support for std grpc
This commit is contained in:
parent
972491c19d
commit
eb2e8a0b40
|
@ -24,11 +24,11 @@ func NewDialerFromOptions(router adapter.Router, dialer N.Dialer, serverAddress
|
||||||
|
|
||||||
func NewClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
func NewClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
||||||
if options.ECH != nil && options.ECH.Enabled {
|
if options.ECH != nil && options.ECH.Enabled {
|
||||||
return newECHClient(router, serverAddress, options)
|
return NewECHClient(router, serverAddress, options)
|
||||||
} else if options.UTLS != nil && options.UTLS.Enabled {
|
} else if options.UTLS != nil && options.UTLS.Enabled {
|
||||||
return newUTLSClient(router, serverAddress, options)
|
return NewUTLSClient(router, serverAddress, options)
|
||||||
} else {
|
} else {
|
||||||
return newStdClient(serverAddress, options)
|
return NewSTDClient(serverAddress, options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,13 @@ type (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config interface {
|
type Config interface {
|
||||||
|
ServerName() string
|
||||||
|
SetServerName(serverName string)
|
||||||
NextProtos() []string
|
NextProtos() []string
|
||||||
SetNextProtos(nextProto []string)
|
SetNextProtos(nextProto []string)
|
||||||
Config() (*STDConfig, error)
|
Config() (*STDConfig, error)
|
||||||
Client(conn net.Conn) Conn
|
Client(conn net.Conn) Conn
|
||||||
|
Clone() Config
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerConfig interface {
|
type ServerConfig interface {
|
||||||
|
|
|
@ -20,26 +20,40 @@ import (
|
||||||
mDNS "github.com/miekg/dns"
|
mDNS "github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
type echClientConfig struct {
|
type ECHClientConfig struct {
|
||||||
config *cftls.Config
|
config *cftls.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *echClientConfig) NextProtos() []string {
|
func (e *ECHClientConfig) ServerName() string {
|
||||||
|
return e.config.ServerName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ECHClientConfig) SetServerName(serverName string) {
|
||||||
|
e.config.ServerName = serverName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ECHClientConfig) NextProtos() []string {
|
||||||
return e.config.NextProtos
|
return e.config.NextProtos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *echClientConfig) SetNextProtos(nextProto []string) {
|
func (e *ECHClientConfig) SetNextProtos(nextProto []string) {
|
||||||
e.config.NextProtos = nextProto
|
e.config.NextProtos = nextProto
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *echClientConfig) Config() (*STDConfig, error) {
|
func (e *ECHClientConfig) Config() (*STDConfig, error) {
|
||||||
return nil, E.New("unsupported usage for ECH")
|
return nil, E.New("unsupported usage for ECH")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *echClientConfig) Client(conn net.Conn) Conn {
|
func (e *ECHClientConfig) Client(conn net.Conn) Conn {
|
||||||
return &echConnWrapper{cftls.Client(conn, e.config)}
|
return &echConnWrapper{cftls.Client(conn, e.config)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *ECHClientConfig) Clone() Config {
|
||||||
|
return &ECHClientConfig{
|
||||||
|
config: e.config.Clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type echConnWrapper struct {
|
type echConnWrapper struct {
|
||||||
*cftls.Conn
|
*cftls.Conn
|
||||||
}
|
}
|
||||||
|
@ -62,7 +76,7 @@ func (c *echConnWrapper) ConnectionState() tls.ConnectionState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newECHClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
func NewECHClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
||||||
var serverName string
|
var serverName string
|
||||||
if options.ServerName != "" {
|
if options.ServerName != "" {
|
||||||
serverName = options.ServerName
|
serverName = options.ServerName
|
||||||
|
@ -162,7 +176,7 @@ func newECHClient(router adapter.Router, serverAddress string, options option.Ou
|
||||||
} else {
|
} else {
|
||||||
tlsConfig.GetClientECHConfigs = fetchECHClientConfig(router)
|
tlsConfig.GetClientECHConfigs = fetchECHClientConfig(router)
|
||||||
}
|
}
|
||||||
return &echClientConfig{&tlsConfig}, nil
|
return &ECHClientConfig{&tlsConfig}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchECHClientConfig(router adapter.Router) func(ctx context.Context, serverName string) ([]cftls.ECHConfig, error) {
|
func fetchECHClientConfig(router adapter.Router) func(ctx context.Context, serverName string) ([]cftls.ECHConfig, error) {
|
||||||
|
|
|
@ -8,6 +8,6 @@ import (
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newECHClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
func NewECHClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
||||||
return nil, E.New(`ECH is not included in this build, rebuild with -tags with_ech`)
|
return nil, E.New(`ECH is not included in this build, rebuild with -tags with_ech`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) {
|
func NewServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) {
|
||||||
return newSTDServer(ctx, logger, options)
|
return NewSTDServer(ctx, logger, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ServerHandshake(ctx context.Context, conn net.Conn, config ServerConfig) (Conn, error) {
|
func ServerHandshake(ctx context.Context, conn net.Conn, config ServerConfig) (Conn, error) {
|
||||||
|
|
|
@ -11,11 +11,39 @@ import (
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
)
|
)
|
||||||
|
|
||||||
type stdClientConfig struct {
|
type STDClientConfig struct {
|
||||||
config *tls.Config
|
config *tls.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStdClient(serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
func (s *STDClientConfig) ServerName() string {
|
||||||
|
return s.config.ServerName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *STDClientConfig) SetServerName(serverName string) {
|
||||||
|
s.config.ServerName = serverName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *STDClientConfig) NextProtos() []string {
|
||||||
|
return s.config.NextProtos
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *STDClientConfig) SetNextProtos(nextProto []string) {
|
||||||
|
s.config.NextProtos = nextProto
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *STDClientConfig) Config() (*STDConfig, error) {
|
||||||
|
return s.config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *STDClientConfig) Client(conn net.Conn) Conn {
|
||||||
|
return tls.Client(conn, s.config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *STDClientConfig) Clone() Config {
|
||||||
|
return &STDClientConfig{s.config.Clone()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSTDClient(serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
||||||
var serverName string
|
var serverName string
|
||||||
if options.ServerName != "" {
|
if options.ServerName != "" {
|
||||||
serverName = options.ServerName
|
serverName = options.ServerName
|
||||||
|
@ -96,21 +124,5 @@ func newStdClient(serverAddress string, options option.OutboundTLSOptions) (Conf
|
||||||
}
|
}
|
||||||
tlsConfig.RootCAs = certPool
|
tlsConfig.RootCAs = certPool
|
||||||
}
|
}
|
||||||
return &stdClientConfig{&tlsConfig}, nil
|
return &STDClientConfig{&tlsConfig}, nil
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stdClientConfig) NextProtos() []string {
|
|
||||||
return s.config.NextProtos
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stdClientConfig) SetNextProtos(nextProto []string) {
|
|
||||||
s.config.NextProtos = nextProto
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stdClientConfig) Config() (*STDConfig, error) {
|
|
||||||
return s.config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stdClientConfig) Client(conn net.Conn) Conn {
|
|
||||||
return tls.Client(conn, s.config)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ import (
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var errInsecureUnused = E.New("tls: insecure unused")
|
||||||
|
|
||||||
type STDServerConfig struct {
|
type STDServerConfig struct {
|
||||||
config *tls.Config
|
config *tls.Config
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
|
@ -26,6 +28,14 @@ type STDServerConfig struct {
|
||||||
watcher *fsnotify.Watcher
|
watcher *fsnotify.Watcher
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) ServerName() string {
|
||||||
|
return c.config.ServerName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) SetServerName(serverName string) {
|
||||||
|
c.config.ServerName = serverName
|
||||||
|
}
|
||||||
|
|
||||||
func (c *STDServerConfig) NextProtos() []string {
|
func (c *STDServerConfig) NextProtos() []string {
|
||||||
return c.config.NextProtos
|
return c.config.NextProtos
|
||||||
}
|
}
|
||||||
|
@ -34,9 +44,119 @@ func (c *STDServerConfig) SetNextProtos(nextProto []string) {
|
||||||
c.config.NextProtos = nextProto
|
c.config.NextProtos = nextProto
|
||||||
}
|
}
|
||||||
|
|
||||||
var errInsecureUnused = E.New("tls: insecure unused")
|
func (c *STDServerConfig) Config() (*STDConfig, error) {
|
||||||
|
return c.config, nil
|
||||||
|
}
|
||||||
|
|
||||||
func newSTDServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) {
|
func (c *STDServerConfig) Client(conn net.Conn) Conn {
|
||||||
|
return tls.Client(conn, c.config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) Server(conn net.Conn) Conn {
|
||||||
|
return tls.Server(conn, c.config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) Clone() Config {
|
||||||
|
return &STDServerConfig{
|
||||||
|
config: c.config.Clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) Start() error {
|
||||||
|
if c.acmeService != nil {
|
||||||
|
return c.acmeService.Start()
|
||||||
|
} else {
|
||||||
|
if c.certificatePath == "" && c.keyPath == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := c.startWatcher()
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Warn("create fsnotify watcher: ", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) startWatcher() error {
|
||||||
|
watcher, err := fsnotify.NewWatcher()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c.certificatePath != "" {
|
||||||
|
err = watcher.Add(c.certificatePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.keyPath != "" {
|
||||||
|
err = watcher.Add(c.keyPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.watcher = watcher
|
||||||
|
go c.loopUpdate()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) loopUpdate() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case event, ok := <-c.watcher.Events:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if event.Op&fsnotify.Write != fsnotify.Write {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err := c.reloadKeyPair()
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Error(E.Cause(err, "reload TLS key pair"))
|
||||||
|
}
|
||||||
|
case err, ok := <-c.watcher.Errors:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.logger.Error(E.Cause(err, "fsnotify error"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) reloadKeyPair() error {
|
||||||
|
if c.certificatePath != "" {
|
||||||
|
certificate, err := os.ReadFile(c.certificatePath)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "reload certificate from ", c.certificatePath)
|
||||||
|
}
|
||||||
|
c.certificate = certificate
|
||||||
|
}
|
||||||
|
if c.keyPath != "" {
|
||||||
|
key, err := os.ReadFile(c.keyPath)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "reload key from ", c.keyPath)
|
||||||
|
}
|
||||||
|
c.key = key
|
||||||
|
}
|
||||||
|
keyPair, err := tls.X509KeyPair(c.certificate, c.key)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "reload key pair")
|
||||||
|
}
|
||||||
|
c.config.Certificates = []tls.Certificate{keyPair}
|
||||||
|
c.logger.Info("reloaded TLS certificate")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) Close() error {
|
||||||
|
if c.acmeService != nil {
|
||||||
|
return c.acmeService.Close()
|
||||||
|
}
|
||||||
|
if c.watcher != nil {
|
||||||
|
return c.watcher.Close()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSTDServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) {
|
||||||
if !options.Enabled {
|
if !options.Enabled {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -136,109 +256,3 @@ func newSTDServer(ctx context.Context, logger log.Logger, options option.Inbound
|
||||||
keyPath: options.KeyPath,
|
keyPath: options.KeyPath,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *STDServerConfig) Config() (*STDConfig, error) {
|
|
||||||
return c.config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *STDServerConfig) Client(conn net.Conn) Conn {
|
|
||||||
return tls.Client(conn, c.config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *STDServerConfig) Server(conn net.Conn) Conn {
|
|
||||||
return tls.Server(conn, c.config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *STDServerConfig) Start() error {
|
|
||||||
if c.acmeService != nil {
|
|
||||||
return c.acmeService.Start()
|
|
||||||
} else {
|
|
||||||
if c.certificatePath == "" && c.keyPath == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
err := c.startWatcher()
|
|
||||||
if err != nil {
|
|
||||||
c.logger.Warn("create fsnotify watcher: ", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *STDServerConfig) startWatcher() error {
|
|
||||||
watcher, err := fsnotify.NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if c.certificatePath != "" {
|
|
||||||
err = watcher.Add(c.certificatePath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if c.keyPath != "" {
|
|
||||||
err = watcher.Add(c.keyPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.watcher = watcher
|
|
||||||
go c.loopUpdate()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *STDServerConfig) loopUpdate() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case event, ok := <-c.watcher.Events:
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if event.Op&fsnotify.Write != fsnotify.Write {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
err := c.reloadKeyPair()
|
|
||||||
if err != nil {
|
|
||||||
c.logger.Error(E.Cause(err, "reload TLS key pair"))
|
|
||||||
}
|
|
||||||
case err, ok := <-c.watcher.Errors:
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.logger.Error(E.Cause(err, "fsnotify error"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *STDServerConfig) reloadKeyPair() error {
|
|
||||||
if c.certificatePath != "" {
|
|
||||||
certificate, err := os.ReadFile(c.certificatePath)
|
|
||||||
if err != nil {
|
|
||||||
return E.Cause(err, "reload certificate from ", c.certificatePath)
|
|
||||||
}
|
|
||||||
c.certificate = certificate
|
|
||||||
}
|
|
||||||
if c.keyPath != "" {
|
|
||||||
key, err := os.ReadFile(c.keyPath)
|
|
||||||
if err != nil {
|
|
||||||
return E.Cause(err, "reload key from ", c.keyPath)
|
|
||||||
}
|
|
||||||
c.key = key
|
|
||||||
}
|
|
||||||
keyPair, err := tls.X509KeyPair(c.certificate, c.key)
|
|
||||||
if err != nil {
|
|
||||||
return E.Cause(err, "reload key pair")
|
|
||||||
}
|
|
||||||
c.config.Certificates = []tls.Certificate{keyPair}
|
|
||||||
c.logger.Info("reloaded TLS certificate")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *STDServerConfig) Close() error {
|
|
||||||
if c.acmeService != nil {
|
|
||||||
return c.acmeService.Close()
|
|
||||||
}
|
|
||||||
if c.watcher != nil {
|
|
||||||
return c.watcher.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,24 +16,32 @@ import (
|
||||||
utls "github.com/refraction-networking/utls"
|
utls "github.com/refraction-networking/utls"
|
||||||
)
|
)
|
||||||
|
|
||||||
type utlsClientConfig struct {
|
type UTLSClientConfig struct {
|
||||||
config *utls.Config
|
config *utls.Config
|
||||||
id utls.ClientHelloID
|
id utls.ClientHelloID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *utlsClientConfig) NextProtos() []string {
|
func (e *UTLSClientConfig) ServerName() string {
|
||||||
|
return e.config.ServerName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UTLSClientConfig) SetServerName(serverName string) {
|
||||||
|
e.config.ServerName = serverName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UTLSClientConfig) NextProtos() []string {
|
||||||
return e.config.NextProtos
|
return e.config.NextProtos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *utlsClientConfig) SetNextProtos(nextProto []string) {
|
func (e *UTLSClientConfig) SetNextProtos(nextProto []string) {
|
||||||
e.config.NextProtos = nextProto
|
e.config.NextProtos = nextProto
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *utlsClientConfig) Config() (*STDConfig, error) {
|
func (e *UTLSClientConfig) Config() (*STDConfig, error) {
|
||||||
return nil, E.New("unsupported usage for uTLS")
|
return nil, E.New("unsupported usage for uTLS")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *utlsClientConfig) Client(conn net.Conn) Conn {
|
func (e *UTLSClientConfig) Client(conn net.Conn) Conn {
|
||||||
return &utlsConnWrapper{utls.UClient(conn, e.config.Clone(), e.id)}
|
return &utlsConnWrapper{utls.UClient(conn, e.config.Clone(), e.id)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +67,14 @@ func (c *utlsConnWrapper) ConnectionState() tls.ConnectionState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUTLSClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
func (e *UTLSClientConfig) Clone() Config {
|
||||||
|
return &UTLSClientConfig{
|
||||||
|
config: e.config.Clone(),
|
||||||
|
id: e.id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUTLSClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
||||||
var serverName string
|
var serverName string
|
||||||
if options.ServerName != "" {
|
if options.ServerName != "" {
|
||||||
serverName = options.ServerName
|
serverName = options.ServerName
|
||||||
|
@ -152,5 +167,5 @@ func newUTLSClient(router adapter.Router, serverAddress string, options option.O
|
||||||
default:
|
default:
|
||||||
return nil, E.New("unknown uTLS fingerprint: ", options.UTLS.Fingerprint)
|
return nil, E.New("unknown uTLS fingerprint: ", options.UTLS.Fingerprint)
|
||||||
}
|
}
|
||||||
return &utlsClientConfig{&tlsConfig, id}, nil
|
return &UTLSClientConfig{&tlsConfig, id}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,6 @@ import (
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newUTLSClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
func NewUTLSClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
||||||
return nil, E.New(`uTLS is not included in this build, rebuild with -tags with_utls`)
|
return nil, E.New(`uTLS is not included in this build, rebuild with -tags with_utls`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ func init() {
|
||||||
return nil, C.ErrQUICNotIncluded
|
return nil, C.ErrQUICNotIncluded
|
||||||
})
|
})
|
||||||
v2ray.RegisterQUICConstructor(
|
v2ray.RegisterQUICConstructor(
|
||||||
func(ctx context.Context, options option.V2RayQUICOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) {
|
func(ctx context.Context, options option.V2RayQUICOptions, tlsConfig tls.ServerConfig, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) {
|
||||||
return nil, C.ErrQUICNotIncluded
|
return nil, C.ErrQUICNotIncluded
|
||||||
},
|
},
|
||||||
func(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayQUICOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) {
|
func(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayQUICOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) {
|
||||||
|
|
|
@ -61,13 +61,13 @@ require (
|
||||||
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 // indirect
|
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 // indirect
|
||||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
|
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
|
||||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
||||||
github.com/sagernet/quic-go v0.0.0-20221031051350-29d8bb1c8127 // indirect
|
github.com/sagernet/quic-go v0.0.0-20221108053023-645bcc4f9b15 // indirect
|
||||||
github.com/sagernet/sing-dns v0.0.0-20221031055845-7de76401d403 // indirect
|
github.com/sagernet/sing-dns v0.0.0-20221031055845-7de76401d403 // indirect
|
||||||
github.com/sagernet/sing-tun v0.0.0-20221104121441-66c48a57776f // indirect
|
github.com/sagernet/sing-tun v0.0.0-20221104121441-66c48a57776f // indirect
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220925083655-063bc85ea685 // indirect
|
github.com/sagernet/sing-vmess v0.0.0-20221109021549-b446d5bdddf0 // indirect
|
||||||
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 // indirect
|
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 // indirect
|
||||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect
|
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect
|
||||||
github.com/sagernet/wireguard-go v0.0.0-20221107074148-ffff5ffac938 // indirect
|
github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c // indirect
|
||||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||||
go.etcd.io/bbolt v1.3.6 // indirect
|
go.etcd.io/bbolt v1.3.6 // indirect
|
||||||
|
@ -78,7 +78,7 @@ require (
|
||||||
golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077 // indirect
|
golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077 // indirect
|
||||||
golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f // indirect
|
golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f // indirect
|
||||||
golang.org/x/mod v0.6.0 // indirect
|
golang.org/x/mod v0.6.0 // indirect
|
||||||
golang.org/x/sys v0.1.1-0.20221102194838-fc697a31fa06 // indirect
|
golang.org/x/sys v0.2.0 // indirect
|
||||||
golang.org/x/text v0.4.0 // indirect
|
golang.org/x/text v0.4.0 // indirect
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
||||||
golang.org/x/tools v0.2.0 // indirect
|
golang.org/x/tools v0.2.0 // indirect
|
||||||
|
|
16
test/go.sum
16
test/go.sum
|
@ -146,8 +146,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c
|
||||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
|
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
|
||||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
|
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
|
||||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||||
github.com/sagernet/quic-go v0.0.0-20221031051350-29d8bb1c8127 h1:rraPfWlUy2cdZ61FLXRCFbL0lb7oocScbr4Ac0rIzTU=
|
github.com/sagernet/quic-go v0.0.0-20221108053023-645bcc4f9b15 h1:l8RQTjz5LlGEFOc49dXAr14ORbj8mTW7nX88Rbm+FiY=
|
||||||
github.com/sagernet/quic-go v0.0.0-20221031051350-29d8bb1c8127/go.mod h1:oWFbojDMm85/Jbm/fyWoo8Pux6dIssxGi3q1r+5642A=
|
github.com/sagernet/quic-go v0.0.0-20221108053023-645bcc4f9b15/go.mod h1:oWFbojDMm85/Jbm/fyWoo8Pux6dIssxGi3q1r+5642A=
|
||||||
github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||||
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||||
github.com/sagernet/sing v0.0.0-20221008120626-60a9910eefe4 h1:LO7xMvMGhYmjQg2vjhTzsODyzs9/WLYu5Per+/8jIeo=
|
github.com/sagernet/sing v0.0.0-20221008120626-60a9910eefe4 h1:LO7xMvMGhYmjQg2vjhTzsODyzs9/WLYu5Per+/8jIeo=
|
||||||
|
@ -158,14 +158,14 @@ github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDe
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
|
||||||
github.com/sagernet/sing-tun v0.0.0-20221104121441-66c48a57776f h1:CXF+nErOb9f7qiHingSgTa2/lJAgmEFtAQ47oVwdRGU=
|
github.com/sagernet/sing-tun v0.0.0-20221104121441-66c48a57776f h1:CXF+nErOb9f7qiHingSgTa2/lJAgmEFtAQ47oVwdRGU=
|
||||||
github.com/sagernet/sing-tun v0.0.0-20221104121441-66c48a57776f/go.mod h1:1u3pjXA9HmH7kRiBJqM3C/zPxrxnCLd3svmqtub/RFU=
|
github.com/sagernet/sing-tun v0.0.0-20221104121441-66c48a57776f/go.mod h1:1u3pjXA9HmH7kRiBJqM3C/zPxrxnCLd3svmqtub/RFU=
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220925083655-063bc85ea685 h1:AZzFNRR/ZwMTceUQ1b/mxx6oyKqmFymdMn/yleJmoVM=
|
github.com/sagernet/sing-vmess v0.0.0-20221109021549-b446d5bdddf0 h1:z3kuD3hPNdEq7/wVy5lwE21f+8ZTazBtR81qswxJoCc=
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220925083655-063bc85ea685/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM=
|
github.com/sagernet/sing-vmess v0.0.0-20221109021549-b446d5bdddf0/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM=
|
||||||
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
|
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
|
||||||
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
|
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
|
||||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
|
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
|
||||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY=
|
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY=
|
||||||
github.com/sagernet/wireguard-go v0.0.0-20221107074148-ffff5ffac938 h1:QBeUPiA35gP6XqSUXCdwfDfWjhBRV2m0+mtXNUzLpZ0=
|
github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c h1:qP3ZOHnjZalvqbjundbXiv/YrNlo3HOgrKc+S1QGs0U=
|
||||||
github.com/sagernet/wireguard-go v0.0.0-20221107074148-ffff5ffac938/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI=
|
github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
@ -278,8 +278,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.1-0.20221102194838-fc697a31fa06 h1:E1pm64FqQa4v8dHd/bAneyMkR4hk8LTJhoSlc5mc1cM=
|
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||||
golang.org/x/sys v0.1.1-0.20221102194838-fc697a31fa06/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
|
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewGRPCServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) {
|
func NewGRPCServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.ServerConfig, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) {
|
||||||
if options.ForceLite {
|
if options.ForceLite {
|
||||||
return v2raygrpclite.NewServer(ctx, options, tlsConfig, handler, errorHandler)
|
return v2raygrpclite.NewServer(ctx, options, tlsConfig, handler, errorHandler)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewGRPCServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) {
|
func NewGRPCServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.ServerConfig, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) {
|
||||||
return v2raygrpclite.NewServer(ctx, options, tlsConfig, handler, errorHandler)
|
return v2raygrpclite.NewServer(ctx, options, tlsConfig, handler, errorHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ func RegisterQUICConstructor(server ServerConstructor[option.V2RayQUICOptions],
|
||||||
quicClientConstructor = client
|
quicClientConstructor = client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewQUICServer(ctx context.Context, options option.V2RayQUICOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) {
|
func NewQUICServer(ctx context.Context, options option.V2RayQUICOptions, tlsConfig tls.ServerConfig, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) {
|
||||||
if quicServerConstructor == nil {
|
if quicServerConstructor == nil {
|
||||||
return nil, os.ErrInvalid
|
return nil, os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
ServerConstructor[O any] func(ctx context.Context, options O, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error)
|
ServerConstructor[O any] func(ctx context.Context, options O, tlsConfig tls.ServerConfig, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error)
|
||||||
ClientConstructor[O any] func(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options O, tlsConfig tls.Config) (adapter.V2RayClientTransport, error)
|
ClientConstructor[O any] func(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options O, tlsConfig tls.Config) (adapter.V2RayClientTransport, error)
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewServerTransport(ctx context.Context, options option.V2RayTransportOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) {
|
func NewServerTransport(ctx context.Context, options option.V2RayTransportOptions, tlsConfig tls.ServerConfig, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) {
|
||||||
if options.Type == "" {
|
if options.Type == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/backoff"
|
"google.golang.org/grpc/backoff"
|
||||||
"google.golang.org/grpc/connectivity"
|
"google.golang.org/grpc/connectivity"
|
||||||
"google.golang.org/grpc/credentials"
|
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,11 +34,7 @@ type Client struct {
|
||||||
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) {
|
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) {
|
||||||
var dialOptions []grpc.DialOption
|
var dialOptions []grpc.DialOption
|
||||||
if tlsConfig != nil {
|
if tlsConfig != nil {
|
||||||
stdConfig, err := tlsConfig.Config()
|
dialOptions = append(dialOptions, grpc.WithTransportCredentials(NewTLSTransportCredentials(tlsConfig)))
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
dialOptions = append(dialOptions, grpc.WithTransportCredentials(credentials.NewTLS(stdConfig)))
|
|
||||||
} else {
|
} else {
|
||||||
dialOptions = append(dialOptions, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
dialOptions = append(dialOptions, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||||
}
|
}
|
||||||
|
|
49
transport/v2raygrpc/credentials/credentials.go
Normal file
49
transport/v2raygrpc/credentials/credentials.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 gRPC authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// requestInfoKey is a struct to be used as the key to store RequestInfo in a
|
||||||
|
// context.
|
||||||
|
type requestInfoKey struct{}
|
||||||
|
|
||||||
|
// NewRequestInfoContext creates a context with ri.
|
||||||
|
func NewRequestInfoContext(ctx context.Context, ri interface{}) context.Context {
|
||||||
|
return context.WithValue(ctx, requestInfoKey{}, ri)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestInfoFromContext extracts the RequestInfo from ctx.
|
||||||
|
func RequestInfoFromContext(ctx context.Context) interface{} {
|
||||||
|
return ctx.Value(requestInfoKey{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// clientHandshakeInfoKey is a struct used as the key to store
|
||||||
|
// ClientHandshakeInfo in a context.
|
||||||
|
type clientHandshakeInfoKey struct{}
|
||||||
|
|
||||||
|
// ClientHandshakeInfoFromContext extracts the ClientHandshakeInfo from ctx.
|
||||||
|
func ClientHandshakeInfoFromContext(ctx context.Context) interface{} {
|
||||||
|
return ctx.Value(clientHandshakeInfoKey{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClientHandshakeInfoContext creates a context with chi.
|
||||||
|
func NewClientHandshakeInfoContext(ctx context.Context, chi interface{}) context.Context {
|
||||||
|
return context.WithValue(ctx, clientHandshakeInfoKey{}, chi)
|
||||||
|
}
|
75
transport/v2raygrpc/credentials/spiffe.go
Normal file
75
transport/v2raygrpc/credentials/spiffe.go
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright 2020 gRPC authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Package credentials defines APIs for parsing SPIFFE ID.
|
||||||
|
//
|
||||||
|
// All APIs in this package are experimental.
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/grpclog"
|
||||||
|
)
|
||||||
|
|
||||||
|
var logger = grpclog.Component("credentials")
|
||||||
|
|
||||||
|
// SPIFFEIDFromState parses the SPIFFE ID from State. If the SPIFFE ID format
|
||||||
|
// is invalid, return nil with warning.
|
||||||
|
func SPIFFEIDFromState(state tls.ConnectionState) *url.URL {
|
||||||
|
if len(state.PeerCertificates) == 0 || len(state.PeerCertificates[0].URIs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return SPIFFEIDFromCert(state.PeerCertificates[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// SPIFFEIDFromCert parses the SPIFFE ID from x509.Certificate. If the SPIFFE
|
||||||
|
// ID format is invalid, return nil with warning.
|
||||||
|
func SPIFFEIDFromCert(cert *x509.Certificate) *url.URL {
|
||||||
|
if cert == nil || cert.URIs == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var spiffeID *url.URL
|
||||||
|
for _, uri := range cert.URIs {
|
||||||
|
if uri == nil || uri.Scheme != "spiffe" || uri.Opaque != "" || (uri.User != nil && uri.User.Username() != "") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// From this point, we assume the uri is intended for a SPIFFE ID.
|
||||||
|
if len(uri.String()) > 2048 {
|
||||||
|
logger.Warning("invalid SPIFFE ID: total ID length larger than 2048 bytes")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(uri.Host) == 0 || len(uri.Path) == 0 {
|
||||||
|
logger.Warning("invalid SPIFFE ID: domain or workload ID is empty")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(uri.Host) > 255 {
|
||||||
|
logger.Warning("invalid SPIFFE ID: domain length larger than 255 characters")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// A valid SPIFFE certificate can only have exactly one URI SAN field.
|
||||||
|
if len(cert.URIs) > 1 {
|
||||||
|
logger.Warning("invalid SPIFFE ID: multiple URI SANs")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
spiffeID = uri
|
||||||
|
}
|
||||||
|
return spiffeID
|
||||||
|
}
|
58
transport/v2raygrpc/credentials/syscallconn.go
Normal file
58
transport/v2raygrpc/credentials/syscallconn.go
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright 2018 gRPC authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
type sysConn = syscall.Conn
|
||||||
|
|
||||||
|
// syscallConn keeps reference of rawConn to support syscall.Conn for channelz.
|
||||||
|
// SyscallConn() (the method in interface syscall.Conn) is explicitly
|
||||||
|
// implemented on this type,
|
||||||
|
//
|
||||||
|
// Interface syscall.Conn is implemented by most net.Conn implementations (e.g.
|
||||||
|
// TCPConn, UnixConn), but is not part of net.Conn interface. So wrapper conns
|
||||||
|
// that embed net.Conn don't implement syscall.Conn. (Side note: tls.Conn
|
||||||
|
// doesn't embed net.Conn, so even if syscall.Conn is part of net.Conn, it won't
|
||||||
|
// help here).
|
||||||
|
type syscallConn struct {
|
||||||
|
net.Conn
|
||||||
|
// sysConn is a type alias of syscall.Conn. It's necessary because the name
|
||||||
|
// `Conn` collides with `net.Conn`.
|
||||||
|
sysConn
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapSyscallConn tries to wrap rawConn and newConn into a net.Conn that
|
||||||
|
// implements syscall.Conn. rawConn will be used to support syscall, and newConn
|
||||||
|
// will be used for read/write.
|
||||||
|
//
|
||||||
|
// This function returns newConn if rawConn doesn't implement syscall.Conn.
|
||||||
|
func WrapSyscallConn(rawConn, newConn net.Conn) net.Conn {
|
||||||
|
sysConn, ok := rawConn.(syscall.Conn)
|
||||||
|
if !ok {
|
||||||
|
return newConn
|
||||||
|
}
|
||||||
|
return &syscallConn{
|
||||||
|
Conn: newConn,
|
||||||
|
sysConn: sysConn,
|
||||||
|
}
|
||||||
|
}
|
52
transport/v2raygrpc/credentials/util.go
Normal file
52
transport/v2raygrpc/credentials/util.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright 2020 gRPC authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
)
|
||||||
|
|
||||||
|
const alpnProtoStrH2 = "h2"
|
||||||
|
|
||||||
|
// AppendH2ToNextProtos appends h2 to next protos.
|
||||||
|
func AppendH2ToNextProtos(ps []string) []string {
|
||||||
|
for _, p := range ps {
|
||||||
|
if p == alpnProtoStrH2 {
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret := make([]string, 0, len(ps)+1)
|
||||||
|
ret = append(ret, ps...)
|
||||||
|
return append(ret, alpnProtoStrH2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloneTLSConfig returns a shallow clone of the exported
|
||||||
|
// fields of cfg, ignoring the unexported sync.Once, which
|
||||||
|
// contains a mutex and must not be copied.
|
||||||
|
//
|
||||||
|
// If cfg is nil, a new zero tls.Config is returned.
|
||||||
|
//
|
||||||
|
// TODO: inline this function if possible.
|
||||||
|
func CloneTLSConfig(cfg *tls.Config) *tls.Config {
|
||||||
|
if cfg == nil {
|
||||||
|
return &tls.Config{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg.Clone()
|
||||||
|
}
|
|
@ -13,7 +13,6 @@ import (
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
|
||||||
gM "google.golang.org/grpc/metadata"
|
gM "google.golang.org/grpc/metadata"
|
||||||
"google.golang.org/grpc/peer"
|
"google.golang.org/grpc/peer"
|
||||||
)
|
)
|
||||||
|
@ -26,15 +25,11 @@ type Server struct {
|
||||||
server *grpc.Server
|
server *grpc.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler) (*Server, error) {
|
func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.ServerConfig, handler N.TCPConnectionHandler) (*Server, error) {
|
||||||
var serverOptions []grpc.ServerOption
|
var serverOptions []grpc.ServerOption
|
||||||
if tlsConfig != nil {
|
if tlsConfig != nil {
|
||||||
stdConfig, err := tlsConfig.Config()
|
tlsConfig.SetNextProtos([]string{"h2"})
|
||||||
if err != nil {
|
serverOptions = append(serverOptions, grpc.Creds(NewTLSTransportCredentials(tlsConfig)))
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
stdConfig.NextProtos = []string{"h2"}
|
|
||||||
serverOptions = append(serverOptions, grpc.Creds(credentials.NewTLS(stdConfig)))
|
|
||||||
}
|
}
|
||||||
server := &Server{ctx, handler, grpc.NewServer(serverOptions...)}
|
server := &Server{ctx, handler, grpc.NewServer(serverOptions...)}
|
||||||
RegisterGunServiceCustomNameServer(server.server, server, options.ServiceName)
|
RegisterGunServiceCustomNameServer(server.server, server, options.ServiceName)
|
||||||
|
|
86
transport/v2raygrpc/tls_credentials.go
Normal file
86
transport/v2raygrpc/tls_credentials.go
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package v2raygrpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
|
internal_credentials "github.com/sagernet/sing-box/transport/v2raygrpc/credentials"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/credentials"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TLSTransportCredentials struct {
|
||||||
|
config tls.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTLSTransportCredentials(config tls.Config) credentials.TransportCredentials {
|
||||||
|
return &TLSTransportCredentials{config}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TLSTransportCredentials) Info() credentials.ProtocolInfo {
|
||||||
|
return credentials.ProtocolInfo{
|
||||||
|
SecurityProtocol: "tls",
|
||||||
|
SecurityVersion: "1.2",
|
||||||
|
ServerName: c.config.ServerName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TLSTransportCredentials) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
|
||||||
|
cfg := c.config.Clone()
|
||||||
|
if cfg.ServerName() == "" {
|
||||||
|
serverName, _, err := net.SplitHostPort(authority)
|
||||||
|
if err != nil {
|
||||||
|
serverName = authority
|
||||||
|
}
|
||||||
|
cfg.SetServerName(serverName)
|
||||||
|
}
|
||||||
|
conn, err := tls.ClientHandshake(ctx, rawConn, cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
tlsInfo := credentials.TLSInfo{
|
||||||
|
State: conn.ConnectionState(),
|
||||||
|
CommonAuthInfo: credentials.CommonAuthInfo{
|
||||||
|
SecurityLevel: credentials.PrivacyAndIntegrity,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
id := internal_credentials.SPIFFEIDFromState(conn.ConnectionState())
|
||||||
|
if id != nil {
|
||||||
|
tlsInfo.SPIFFEID = id
|
||||||
|
}
|
||||||
|
return internal_credentials.WrapSyscallConn(rawConn, conn), tlsInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TLSTransportCredentials) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
|
||||||
|
serverConfig, isServer := c.config.(tls.ServerConfig)
|
||||||
|
if !isServer {
|
||||||
|
return nil, nil, os.ErrInvalid
|
||||||
|
}
|
||||||
|
conn, err := tls.ServerHandshake(context.Background(), rawConn, serverConfig)
|
||||||
|
if err != nil {
|
||||||
|
rawConn.Close()
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
tlsInfo := credentials.TLSInfo{
|
||||||
|
State: conn.ConnectionState(),
|
||||||
|
CommonAuthInfo: credentials.CommonAuthInfo{
|
||||||
|
SecurityLevel: credentials.PrivacyAndIntegrity,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
id := internal_credentials.SPIFFEIDFromState(conn.ConnectionState())
|
||||||
|
if id != nil {
|
||||||
|
tlsInfo.SPIFFEID = id
|
||||||
|
}
|
||||||
|
return internal_credentials.WrapSyscallConn(rawConn, conn), tlsInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TLSTransportCredentials) Clone() credentials.TransportCredentials {
|
||||||
|
return NewTLSTransportCredentials(c.config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TLSTransportCredentials) OverrideServerName(serverNameOverride string) error {
|
||||||
|
c.config.SetServerName(serverNameOverride)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -34,7 +34,7 @@ func (s *Server) Network() []string {
|
||||||
return []string{N.NetworkTCP}
|
return []string{N.NetworkTCP}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (*Server, error) {
|
func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.ServerConfig, handler N.TCPConnectionHandler, errorHandler E.Handler) (*Server, error) {
|
||||||
server := &Server{
|
server := &Server{
|
||||||
handler: handler,
|
handler: handler,
|
||||||
errorHandler: errorHandler,
|
errorHandler: errorHandler,
|
||||||
|
|
|
@ -37,7 +37,7 @@ func (s *Server) Network() []string {
|
||||||
return []string{N.NetworkTCP}
|
return []string{N.NetworkTCP}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(ctx context.Context, options option.V2RayHTTPOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (*Server, error) {
|
func NewServer(ctx context.Context, options option.V2RayHTTPOptions, tlsConfig tls.ServerConfig, handler N.TCPConnectionHandler, errorHandler E.Handler) (*Server, error) {
|
||||||
server := &Server{
|
server := &Server{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
handler: handler,
|
handler: handler,
|
||||||
|
|
|
@ -29,7 +29,7 @@ type Server struct {
|
||||||
quicListener quic.Listener
|
quicListener quic.Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(ctx context.Context, options option.V2RayQUICOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) {
|
func NewServer(ctx context.Context, options option.V2RayQUICOptions, tlsConfig tls.ServerConfig, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) {
|
||||||
quicConfig := &quic.Config{
|
quicConfig := &quic.Config{
|
||||||
DisablePathMTUDiscovery: !C.IsLinux && !C.IsWindows,
|
DisablePathMTUDiscovery: !C.IsLinux && !C.IsWindows,
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ type Server struct {
|
||||||
earlyDataHeaderName string
|
earlyDataHeaderName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(ctx context.Context, options option.V2RayWebsocketOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (*Server, error) {
|
func NewServer(ctx context.Context, options option.V2RayWebsocketOptions, tlsConfig tls.ServerConfig, handler N.TCPConnectionHandler, errorHandler E.Handler) (*Server, error) {
|
||||||
server := &Server{
|
server := &Server{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
handler: handler,
|
handler: handler,
|
||||||
|
|
Loading…
Reference in a new issue