diff --git a/inbound/tls_acme.go b/common/tls/acme.go similarity index 99% rename from inbound/tls_acme.go rename to common/tls/acme.go index 0e9d32cf..eb6eac39 100644 --- a/inbound/tls_acme.go +++ b/common/tls/acme.go @@ -1,6 +1,6 @@ //go:build with_acme -package inbound +package tls import ( "context" diff --git a/inbound/tls_acme_stub.go b/common/tls/acme_stub.go similarity index 96% rename from inbound/tls_acme_stub.go rename to common/tls/acme_stub.go index f787aa14..d97d0540 100644 --- a/inbound/tls_acme_stub.go +++ b/common/tls/acme_stub.go @@ -1,6 +1,6 @@ //go:build !with_acme -package inbound +package tls import ( "context" diff --git a/common/tls/client.go b/common/tls/client.go new file mode 100644 index 00000000..c5dc4cb1 --- /dev/null +++ b/common/tls/client.go @@ -0,0 +1,57 @@ +package tls + +import ( + "context" + "net" + "os" + + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/option" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +func NewDialerFromOptions(router adapter.Router, dialer N.Dialer, serverAddress string, options option.OutboundTLSOptions) (N.Dialer, error) { + config, err := NewClient(router, serverAddress, options) + if err != nil { + return nil, err + } + return NewDialer(dialer, config), nil +} + +func NewClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) { + return newStdClient(serverAddress, options) +} + +func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (net.Conn, error) { + tlsConn := config.Client(conn) + ctx, cancel := context.WithTimeout(ctx, C.TCPTimeout) + defer cancel() + err := tlsConn.HandshakeContext(ctx) + return tlsConn, err +} + +type Dialer struct { + dialer N.Dialer + config Config +} + +func NewDialer(dialer N.Dialer, config Config) N.Dialer { + return &Dialer{dialer, config} +} + +func (d *Dialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + if network != N.NetworkTCP { + return nil, os.ErrInvalid + } + conn, err := d.dialer.DialContext(ctx, network, destination) + if err != nil { + return nil, err + } + return ClientHandshake(ctx, conn, d.config) +} + +func (d *Dialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + return nil, os.ErrInvalid +} diff --git a/common/tls/common.go b/common/tls/common.go new file mode 100644 index 00000000..66cf1223 --- /dev/null +++ b/common/tls/common.go @@ -0,0 +1,12 @@ +package tls + +const ( + VersionTLS10 = 0x0301 + VersionTLS11 = 0x0302 + VersionTLS12 = 0x0303 + VersionTLS13 = 0x0304 + + // Deprecated: SSLv3 is cryptographically broken, and is no longer + // supported by this package. See golang.org/issue/32716. + VersionSSL30 = 0x0300 +) diff --git a/common/tls/config.go b/common/tls/config.go new file mode 100644 index 00000000..68c1a951 --- /dev/null +++ b/common/tls/config.go @@ -0,0 +1,46 @@ +package tls + +import ( + "context" + "crypto/tls" + "net" + + "github.com/sagernet/sing-box/adapter" + E "github.com/sagernet/sing/common/exceptions" +) + +type ( + STDConfig = tls.Config + STDConn = tls.Conn +) + +type Config interface { + Config() (*STDConfig, error) + Client(conn net.Conn) Conn +} + +type ServerConfig interface { + Config + adapter.Service + Server(conn net.Conn) Conn +} + +type Conn interface { + net.Conn + HandshakeContext(ctx context.Context) error +} + +func ParseTLSVersion(version string) (uint16, error) { + switch version { + case "1.0": + return tls.VersionTLS10, nil + case "1.1": + return tls.VersionTLS11, nil + case "1.2": + return tls.VersionTLS12, nil + case "1.3": + return tls.VersionTLS13, nil + default: + return 0, E.New("unknown tls version:", version) + } +} diff --git a/common/dialer/tls.go b/common/tls/std_client.go similarity index 59% rename from common/dialer/tls.go rename to common/tls/std_client.go index 0cd5e85b..de2076ae 100644 --- a/common/dialer/tls.go +++ b/common/tls/std_client.go @@ -1,34 +1,26 @@ -package dialer +package tls import ( - "context" "crypto/tls" "crypto/x509" "net" "net/netip" "os" - C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" - M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" ) -type TLSDialer struct { - dialer N.Dialer +type stdClientConfig struct { config *tls.Config } -func TLSConfig(serverAddress string, options option.OutboundTLSOptions) (*tls.Config, error) { - if !options.Enabled { - return nil, nil - } +func newStdClient(serverAddress string, options option.OutboundTLSOptions) (Config, error) { var serverName string if options.ServerName != "" { serverName = options.ServerName } else if serverAddress != "" { - if _, err := netip.ParseAddr(serverName); err == nil { + if _, err := netip.ParseAddr(serverName); err != nil { serverName = serverAddress } } @@ -62,14 +54,14 @@ func TLSConfig(serverAddress string, options option.OutboundTLSOptions) (*tls.Co tlsConfig.NextProtos = options.ALPN } if options.MinVersion != "" { - minVersion, err := option.ParseTLSVersion(options.MinVersion) + minVersion, err := ParseTLSVersion(options.MinVersion) if err != nil { return nil, E.Cause(err, "parse min_version") } tlsConfig.MinVersion = minVersion } if options.MaxVersion != "" { - maxVersion, err := option.ParseTLSVersion(options.MaxVersion) + maxVersion, err := ParseTLSVersion(options.MaxVersion) if err != nil { return nil, E.Cause(err, "parse max_version") } @@ -104,42 +96,13 @@ func TLSConfig(serverAddress string, options option.OutboundTLSOptions) (*tls.Co } tlsConfig.RootCAs = certPool } - return &tlsConfig, nil + return &stdClientConfig{&tlsConfig}, nil } -func NewTLS(dialer N.Dialer, serverAddress string, options option.OutboundTLSOptions) (N.Dialer, error) { - if !options.Enabled { - return dialer, nil - } - tlsConfig, err := TLSConfig(serverAddress, options) - if err != nil { - return nil, err - } - return &TLSDialer{ - dialer: dialer, - config: tlsConfig, - }, nil +func (s *stdClientConfig) Config() (*STDConfig, error) { + return s.config, nil } -func (d *TLSDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - if network != N.NetworkTCP { - return nil, os.ErrInvalid - } - conn, err := d.dialer.DialContext(ctx, network, destination) - if err != nil { - return nil, err - } - return TLSClient(ctx, conn, d.config) -} - -func (d *TLSDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - return nil, os.ErrInvalid -} - -func TLSClient(ctx context.Context, conn net.Conn, tlsConfig *tls.Config) (*tls.Conn, error) { - tlsConn := tls.Client(conn, tlsConfig) - ctx, cancel := context.WithTimeout(ctx, C.TCPTimeout) - defer cancel() - err := tlsConn.HandshakeContext(ctx) - return tlsConn, err +func (s *stdClientConfig) Client(conn net.Conn) Conn { + return tls.Client(conn, s.config) } diff --git a/inbound/tls.go b/common/tls/std_server.go similarity index 85% rename from inbound/tls.go rename to common/tls/std_server.go index 465b545a..9ffbc7eb 100644 --- a/inbound/tls.go +++ b/common/tls/std_server.go @@ -1,8 +1,9 @@ -package inbound +package tls import ( "context" "crypto/tls" + "net" "os" "github.com/sagernet/sing-box/adapter" @@ -14,9 +15,7 @@ import ( "github.com/fsnotify/fsnotify" ) -var _ adapter.Service = (*TLSConfig)(nil) - -type TLSConfig struct { +type STDServerConfig struct { config *tls.Config logger log.Logger acmeService adapter.Service @@ -27,105 +26,7 @@ type TLSConfig struct { watcher *fsnotify.Watcher } -func (c *TLSConfig) Config() *tls.Config { - return c.config -} - -func (c *TLSConfig) 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 *TLSConfig) 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 *TLSConfig) 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 *TLSConfig) 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 *TLSConfig) Close() error { - if c.acmeService != nil { - return c.acmeService.Close() - } - if c.watcher != nil { - return c.watcher.Close() - } - return nil -} - -func NewTLSConfig(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (*TLSConfig, error) { +func NewServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) { if !options.Enabled { return nil, nil } @@ -147,14 +48,14 @@ func NewTLSConfig(ctx context.Context, logger log.Logger, options option.Inbound tlsConfig.NextProtos = append(tlsConfig.NextProtos, options.ALPN...) } if options.MinVersion != "" { - minVersion, err := option.ParseTLSVersion(options.MinVersion) + minVersion, err := ParseTLSVersion(options.MinVersion) if err != nil { return nil, E.Cause(err, "parse min_version") } tlsConfig.MinVersion = minVersion } if options.MaxVersion != "" { - maxVersion, err := option.ParseTLSVersion(options.MaxVersion) + maxVersion, err := ParseTLSVersion(options.MaxVersion) if err != nil { return nil, E.Cause(err, "parse max_version") } @@ -205,7 +106,7 @@ func NewTLSConfig(ctx context.Context, logger log.Logger, options option.Inbound } tlsConfig.Certificates = []tls.Certificate{keyPair} } - return &TLSConfig{ + return &STDServerConfig{ config: tlsConfig, logger: logger, acmeService: acmeService, @@ -215,3 +116,109 @@ func NewTLSConfig(ctx context.Context, logger log.Logger, options option.Inbound keyPath: options.KeyPath, }, 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 +} diff --git a/inbound/http.go b/inbound/http.go index 4a54fccd..fdc5bd2b 100644 --- a/inbound/http.go +++ b/inbound/http.go @@ -3,11 +3,11 @@ package inbound import ( std_bufio "bufio" "context" - "crypto/tls" "net" "os" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -26,7 +26,7 @@ var ( type HTTP struct { myInboundAdapter authenticator auth.Authenticator - tlsConfig *TLSConfig + tlsConfig tls.ServerConfig } func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPMixedInboundOptions) (*HTTP, error) { @@ -44,7 +44,7 @@ func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogge authenticator: auth.NewAuthenticator(options.Users), } if options.TLS != nil { - tlsConfig, err := NewTLSConfig(ctx, logger, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } @@ -67,13 +67,13 @@ func (h *HTTP) Start() error { func (h *HTTP) Close() error { return common.Close( &h.myInboundAdapter, - common.PtrOrNil(h.tlsConfig), + h.tlsConfig, ) } func (h *HTTP) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { if h.tlsConfig != nil { - conn = tls.Server(conn, h.tlsConfig.Config()) + conn = h.tlsConfig.Server(conn) } return http.HandleConnection(ctx, conn, std_bufio.NewReader(conn), h.authenticator, h.upstreamUserHandler(metadata), adapter.UpstreamMetadata(metadata)) } diff --git a/inbound/hysteria.go b/inbound/hysteria.go index 3f0ff74c..959cc905 100644 --- a/inbound/hysteria.go +++ b/inbound/hysteria.go @@ -10,6 +10,7 @@ import ( "github.com/sagernet/quic-go" "github.com/sagernet/quic-go/congestion" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -26,7 +27,7 @@ var _ adapter.Inbound = (*Hysteria)(nil) type Hysteria struct { myInboundAdapter quicConfig *quic.Config - tlsConfig *TLSConfig + tlsConfig tls.ServerConfig authKey []byte xplusKey []byte sendBPS uint64 @@ -116,7 +117,7 @@ func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextL if len(options.TLS.ALPN) == 0 { options.TLS.ALPN = []string{hysteria.DefaultALPN} } - tlsConfig, err := NewTLSConfig(ctx, logger, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } @@ -137,7 +138,11 @@ func (h *Hysteria) Start() error { if err != nil { return err } - listener, err := quic.Listen(packetConn, h.tlsConfig.Config(), h.quicConfig) + rawConfig, err := h.tlsConfig.Config() + if err != nil { + return err + } + listener, err := quic.Listen(packetConn, rawConfig, h.quicConfig) if err != nil { return err } @@ -301,6 +306,6 @@ func (h *Hysteria) Close() error { return common.Close( &h.myInboundAdapter, h.listener, - common.PtrOrNil(h.tlsConfig), + h.tlsConfig, ) } diff --git a/inbound/naive.go b/inbound/naive.go index 5e343572..14d31a44 100644 --- a/inbound/naive.go +++ b/inbound/naive.go @@ -2,7 +2,6 @@ package inbound import ( "context" - "crypto/tls" "encoding/base64" "encoding/binary" "io" @@ -14,6 +13,7 @@ import ( "time" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -32,7 +32,7 @@ var _ adapter.Inbound = (*Naive)(nil) type Naive struct { myInboundAdapter authenticator auth.Authenticator - tlsConfig *TLSConfig + tlsConfig tls.ServerConfig httpServer *http.Server h3Server any } @@ -59,7 +59,7 @@ func NewNaive(ctx context.Context, router adapter.Router, logger log.ContextLogg return nil, E.New("missing users") } if options.TLS != nil { - tlsConfig, err := NewTLSConfig(ctx, logger, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } @@ -69,13 +69,16 @@ func NewNaive(ctx context.Context, router adapter.Router, logger log.ContextLogg } func (n *Naive) Start() error { - var tlsConfig *tls.Config + var tlsConfig *tls.STDConfig if n.tlsConfig != nil { err := n.tlsConfig.Start() if err != nil { return E.Cause(err, "create TLS config") } - tlsConfig = n.tlsConfig.Config() + tlsConfig, err = n.tlsConfig.Config() + if err != nil { + return err + } } if common.Contains(n.network, N.NetworkTCP) { @@ -117,7 +120,7 @@ func (n *Naive) Close() error { &n.myInboundAdapter, common.PtrOrNil(n.httpServer), n.h3Server, - common.PtrOrNil(n.tlsConfig), + n.tlsConfig, ) } diff --git a/inbound/naive_quic.go b/inbound/naive_quic.go index acb3e003..f518796f 100644 --- a/inbound/naive_quic.go +++ b/inbound/naive_quic.go @@ -8,9 +8,13 @@ import ( ) func (n *Naive) configureHTTP3Listener() error { + tlsConfig, err := n.tlsConfig.Config() + if err != nil { + return err + } h3Server := &http3.Server{ Port: int(n.listenOptions.ListenPort), - TLSConfig: n.tlsConfig.Config(), + TLSConfig: tlsConfig, Handler: n, } diff --git a/inbound/trojan.go b/inbound/trojan.go index 2160bc89..49f1a58a 100644 --- a/inbound/trojan.go +++ b/inbound/trojan.go @@ -2,11 +2,11 @@ package inbound import ( "context" - "crypto/tls" "net" "os" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -29,7 +29,7 @@ type Trojan struct { myInboundAdapter service *trojan.Service[int] users []option.TrojanUser - tlsConfig *TLSConfig + tlsConfig tls.ServerConfig fallbackAddr M.Socksaddr fallbackAddrTLSNextProto map[string]M.Socksaddr transport adapter.V2RayServerTransport @@ -49,7 +49,7 @@ func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLog users: options.Users, } if options.TLS != nil { - tlsConfig, err := NewTLSConfig(ctx, logger, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } @@ -89,11 +89,7 @@ func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLog return nil, err } if options.Transport != nil { - var tlsConfig *tls.Config - if inbound.tlsConfig != nil { - tlsConfig = inbound.tlsConfig.Config() - } - inbound.transport, err = v2ray.NewServerTransport(ctx, common.PtrValueOrDefault(options.Transport), tlsConfig, adapter.NewUpstreamHandler(adapter.InboundContext{}, inbound.newTransportConnection, nil, nil), inbound) + inbound.transport, err = v2ray.NewServerTransport(ctx, common.PtrValueOrDefault(options.Transport), inbound.tlsConfig, adapter.NewUpstreamHandler(adapter.InboundContext{}, inbound.newTransportConnection, nil, nil), inbound) if err != nil { return nil, E.Cause(err, "create server transport: ", options.Transport.Type) } @@ -143,7 +139,7 @@ func (h *Trojan) Start() error { func (h *Trojan) Close() error { return common.Close( &h.myInboundAdapter, - common.PtrOrNil(h.tlsConfig), + h.tlsConfig, h.transport, ) } @@ -155,7 +151,7 @@ func (h *Trojan) newTransportConnection(ctx context.Context, conn net.Conn, meta func (h *Trojan) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { if h.tlsConfig != nil && h.transport == nil { - conn = tls.Server(conn, h.tlsConfig.Config()) + conn = h.tlsConfig.Server(conn) } return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata)) } @@ -182,7 +178,7 @@ func (h *Trojan) newConnection(ctx context.Context, conn net.Conn, metadata adap func (h *Trojan) fallbackConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { var fallbackAddr M.Socksaddr if len(h.fallbackAddrTLSNextProto) > 0 { - if tlsConn, loaded := common.Cast[*tls.Conn](conn); loaded { + if tlsConn, loaded := common.Cast[*tls.STDConn](conn); loaded { connectionState := tlsConn.ConnectionState() if connectionState.NegotiatedProtocol != "" { if fallbackAddr, loaded = h.fallbackAddrTLSNextProto[connectionState.NegotiatedProtocol]; !loaded { diff --git a/inbound/vmess.go b/inbound/vmess.go index 255d21d6..5f310ff6 100644 --- a/inbound/vmess.go +++ b/inbound/vmess.go @@ -2,11 +2,11 @@ package inbound import ( "context" - "crypto/tls" "net" "os" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -31,7 +31,7 @@ type VMess struct { ctx context.Context service *vmess.Service[int] users []option.VMessUser - tlsConfig *TLSConfig + tlsConfig tls.ServerConfig transport adapter.V2RayServerTransport } @@ -62,17 +62,13 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg return nil, err } if options.TLS != nil { - inbound.tlsConfig, err = NewTLSConfig(ctx, logger, common.PtrValueOrDefault(options.TLS)) + inbound.tlsConfig, err = tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } } if options.Transport != nil { - var tlsConfig *tls.Config - if inbound.tlsConfig != nil { - tlsConfig = inbound.tlsConfig.Config() - } - inbound.transport, err = v2ray.NewServerTransport(ctx, common.PtrValueOrDefault(options.Transport), tlsConfig, adapter.NewUpstreamHandler(adapter.InboundContext{}, inbound.newTransportConnection, nil, nil), inbound) + inbound.transport, err = v2ray.NewServerTransport(ctx, common.PtrValueOrDefault(options.Transport), inbound.tlsConfig, adapter.NewUpstreamHandler(adapter.InboundContext{}, inbound.newTransportConnection, nil, nil), inbound) if err != nil { return nil, E.Cause(err, "create server transport: ", options.Transport.Type) } @@ -84,7 +80,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg func (h *VMess) Start() error { err := common.Start( h.service, - common.PtrOrNil(h.tlsConfig), + h.tlsConfig, ) if err != nil { return err @@ -123,7 +119,7 @@ func (h *VMess) Close() error { return common.Close( h.service, &h.myInboundAdapter, - common.PtrOrNil(h.tlsConfig), + h.tlsConfig, h.transport, ) } @@ -135,7 +131,7 @@ func (h *VMess) newTransportConnection(ctx context.Context, conn net.Conn, metad func (h *VMess) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { if h.tlsConfig != nil && h.transport == nil { - conn = tls.Server(conn, h.tlsConfig.Config()) + conn = h.tlsConfig.Server(conn) } return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata)) } diff --git a/option/tls.go b/option/tls.go index 4ee64f59..d5b9d46e 100644 --- a/option/tls.go +++ b/option/tls.go @@ -1,11 +1,5 @@ package option -import ( - "crypto/tls" - - E "github.com/sagernet/sing/common/exceptions" -) - type InboundTLSOptions struct { Enabled bool `json:"enabled,omitempty"` ServerName string `json:"server_name,omitempty"` @@ -32,18 +26,3 @@ type OutboundTLSOptions struct { Certificate string `json:"certificate,omitempty"` CertificatePath string `json:"certificate_path,omitempty"` } - -func ParseTLSVersion(version string) (uint16, error) { - switch version { - case "1.0": - return tls.VersionTLS10, nil - case "1.1": - return tls.VersionTLS11, nil - case "1.2": - return tls.VersionTLS12, nil - case "1.3": - return tls.VersionTLS13, nil - default: - return 0, E.New("unknown tls version:", version) - } -} diff --git a/outbound/http.go b/outbound/http.go index 9d7bc094..f812c2e4 100644 --- a/outbound/http.go +++ b/outbound/http.go @@ -7,6 +7,7 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/dialer" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -24,7 +25,7 @@ type HTTP struct { } func NewHTTP(router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPOutboundOptions) (*HTTP, error) { - detour, err := dialer.NewTLS(dialer.New(router, options.DialerOptions), options.Server, common.PtrValueOrDefault(options.TLS)) + detour, err := tls.NewDialerFromOptions(router, dialer.New(router, options.DialerOptions), options.Server, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } diff --git a/outbound/hysteria.go b/outbound/hysteria.go index 43e342de..176d417d 100644 --- a/outbound/hysteria.go +++ b/outbound/hysteria.go @@ -4,7 +4,6 @@ package outbound import ( "context" - "crypto/tls" "net" "sync" @@ -12,6 +11,7 @@ import ( "github.com/sagernet/quic-go/congestion" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/dialer" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -30,7 +30,7 @@ type Hysteria struct { ctx context.Context dialer N.Dialer serverAddr M.Socksaddr - tlsConfig *tls.Config + tlsConfig *tls.STDConfig quicConfig *quic.Config authKey []byte xplusKey []byte @@ -47,7 +47,11 @@ func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextL if options.TLS == nil || !options.TLS.Enabled { return nil, C.ErrTLSRequired } - tlsConfig, err := dialer.TLSConfig(options.Server, common.PtrValueOrDefault(options.TLS)) + abstractTLSConfig, err := tls.NewClient(router, options.Server, common.PtrValueOrDefault(options.TLS)) + if err != nil { + return nil, err + } + tlsConfig, err := abstractTLSConfig.Config() if err != nil { return nil, err } diff --git a/outbound/shadowtls.go b/outbound/shadowtls.go index fa255d57..7d7a4da3 100644 --- a/outbound/shadowtls.go +++ b/outbound/shadowtls.go @@ -2,12 +2,12 @@ package outbound import ( "context" - "crypto/tls" "net" "os" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/dialer" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -22,7 +22,7 @@ type ShadowTLS struct { myOutboundAdapter dialer N.Dialer serverAddr M.Socksaddr - tlsConfig *tls.Config + tlsConfig tls.Config } func NewShadowTLS(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowTLSOutboundOptions) (*ShadowTLS, error) { @@ -43,7 +43,7 @@ func NewShadowTLS(ctx context.Context, router adapter.Router, logger log.Context options.TLS.MinVersion = "1.2" options.TLS.MaxVersion = "1.2" var err error - outbound.tlsConfig, err = dialer.TLSConfig(options.Server, common.PtrValueOrDefault(options.TLS)) + outbound.tlsConfig, err = tls.NewClient(router, options.Server, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } @@ -60,15 +60,7 @@ func (s *ShadowTLS) DialContext(ctx context.Context, network string, destination if err != nil { return nil, err } - tlsConn, err := dialer.TLSClient(ctx, conn, s.tlsConfig) - if err != nil { - return nil, err - } - err = tlsConn.HandshakeContext(ctx) - if err != nil { - return nil, err - } - return conn, nil + return tls.ClientHandshake(ctx, conn, s.tlsConfig) } func (s *ShadowTLS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { diff --git a/outbound/trojan.go b/outbound/trojan.go index 90dcbb9f..20e64802 100644 --- a/outbound/trojan.go +++ b/outbound/trojan.go @@ -2,12 +2,12 @@ package outbound import ( "context" - "crypto/tls" "net" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/dialer" "github.com/sagernet/sing-box/common/mux" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -28,7 +28,7 @@ type Trojan struct { serverAddr M.Socksaddr key [56]byte multiplexDialer N.Dialer - tlsConfig *tls.Config + tlsConfig tls.Config transport adapter.V2RayClientTransport } @@ -47,7 +47,7 @@ func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLog } var err error if options.TLS != nil { - outbound.tlsConfig, err = dialer.TLSConfig(options.Server, common.PtrValueOrDefault(options.TLS)) + outbound.tlsConfig, err = tls.NewClient(router, options.Server, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } @@ -116,7 +116,7 @@ func (h *trojanDialer) DialContext(ctx context.Context, network string, destinat } else { conn, err = h.dialer.DialContext(ctx, N.NetworkTCP, h.serverAddr) if err == nil && h.tlsConfig != nil { - conn, err = dialer.TLSClient(ctx, conn, h.tlsConfig) + conn, err = tls.ClientHandshake(ctx, conn, h.tlsConfig) } } if err != nil { diff --git a/outbound/vmess.go b/outbound/vmess.go index b4abc906..f2f23c5a 100644 --- a/outbound/vmess.go +++ b/outbound/vmess.go @@ -2,12 +2,12 @@ package outbound import ( "context" - "crypto/tls" "net" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/dialer" "github.com/sagernet/sing-box/common/mux" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -28,7 +28,7 @@ type VMess struct { client *vmess.Client serverAddr M.Socksaddr multiplexDialer N.Dialer - tlsConfig *tls.Config + tlsConfig tls.Config transport adapter.V2RayClientTransport packetAddr bool } @@ -47,7 +47,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg } var err error if options.TLS != nil { - outbound.tlsConfig, err = dialer.TLSConfig(options.Server, common.PtrValueOrDefault(options.TLS)) + outbound.tlsConfig, err = tls.NewClient(router, options.Server, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } @@ -142,7 +142,7 @@ func (h *vmessDialer) DialContext(ctx context.Context, network string, destinati } else { conn, err = h.dialer.DialContext(ctx, N.NetworkTCP, h.serverAddr) if err == nil && h.tlsConfig != nil { - conn, err = dialer.TLSClient(ctx, conn, h.tlsConfig) + conn, err = tls.ClientHandshake(ctx, conn, h.tlsConfig) } } if err != nil { @@ -169,7 +169,7 @@ func (h *vmessDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) } else { conn, err = h.dialer.DialContext(ctx, N.NetworkTCP, h.serverAddr) if err == nil && h.tlsConfig != nil { - conn, err = dialer.TLSClient(ctx, conn, h.tlsConfig) + conn, err = tls.ClientHandshake(ctx, conn, h.tlsConfig) } } if err != nil { diff --git a/transport/v2ray/grpc.go b/transport/v2ray/grpc.go index a6f031f8..961c2bbb 100644 --- a/transport/v2ray/grpc.go +++ b/transport/v2ray/grpc.go @@ -4,9 +4,9 @@ package v2ray import ( "context" - "crypto/tls" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/transport/v2raygrpc" "github.com/sagernet/sing-box/transport/v2raygrpclite" @@ -15,16 +15,16 @@ import ( 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.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) { if options.ForceLite { - return v2raygrpclite.NewServer(ctx, options, tlsConfig, handler, errorHandler), nil + return v2raygrpclite.NewServer(ctx, options, tlsConfig, handler, errorHandler) } - return v2raygrpc.NewServer(ctx, options, tlsConfig, handler), nil + return v2raygrpc.NewServer(ctx, options, tlsConfig, handler) } -func NewGRPCClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig *tls.Config) (adapter.V2RayClientTransport, error) { +func NewGRPCClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) { if options.ForceLite { return v2raygrpclite.NewClient(ctx, dialer, serverAddr, options, tlsConfig), nil } - return v2raygrpc.NewClient(ctx, dialer, serverAddr, options, tlsConfig), nil + return v2raygrpc.NewClient(ctx, dialer, serverAddr, options, tlsConfig) } diff --git a/transport/v2ray/quic.go b/transport/v2ray/quic.go index 535864e7..6cbbb952 100644 --- a/transport/v2ray/quic.go +++ b/transport/v2ray/quic.go @@ -4,9 +4,9 @@ package v2ray import ( "context" - "crypto/tls" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/transport/v2rayquic" E "github.com/sagernet/sing/common/exceptions" @@ -14,10 +14,10 @@ import ( N "github.com/sagernet/sing/common/network" ) -func NewQUICServer(ctx context.Context, options option.V2RayQUICOptions, tlsConfig *tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) { - return v2rayquic.NewServer(ctx, options, tlsConfig, handler, errorHandler), nil +func NewQUICServer(ctx context.Context, options option.V2RayQUICOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) { + return v2rayquic.NewServer(ctx, options, tlsConfig, handler, errorHandler) } -func NewQUICClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayQUICOptions, tlsConfig *tls.Config) (adapter.V2RayClientTransport, error) { - return v2rayquic.NewClient(ctx, dialer, serverAddr, options, tlsConfig), nil +func NewQUICClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayQUICOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) { + return v2rayquic.NewClient(ctx, dialer, serverAddr, options, tlsConfig) } diff --git a/transport/v2ray/transport.go b/transport/v2ray/transport.go index fc4f02e0..9f26073e 100644 --- a/transport/v2ray/transport.go +++ b/transport/v2ray/transport.go @@ -2,9 +2,9 @@ package v2ray import ( "context" - "crypto/tls" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/transport/v2rayhttp" @@ -14,15 +14,15 @@ import ( N "github.com/sagernet/sing/common/network" ) -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.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (adapter.V2RayServerTransport, error) { if options.Type == "" { return nil, nil } switch options.Type { case C.V2RayTransportTypeHTTP: - return v2rayhttp.NewServer(ctx, options.HTTPOptions, tlsConfig, handler, errorHandler), nil + return v2rayhttp.NewServer(ctx, options.HTTPOptions, tlsConfig, handler, errorHandler) case C.V2RayTransportTypeWebsocket: - return v2raywebsocket.NewServer(ctx, options.WebsocketOptions, tlsConfig, handler, errorHandler), nil + return v2raywebsocket.NewServer(ctx, options.WebsocketOptions, tlsConfig, handler, errorHandler) case C.V2RayTransportTypeQUIC: if tlsConfig == nil { return nil, C.ErrTLSRequired @@ -35,7 +35,7 @@ func NewServerTransport(ctx context.Context, options option.V2RayTransportOption } } -func NewClientTransport(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayTransportOptions, tlsConfig *tls.Config) (adapter.V2RayClientTransport, error) { +func NewClientTransport(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayTransportOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) { if options.Type == "" { return nil, nil } diff --git a/transport/v2raygrpc/client.go b/transport/v2raygrpc/client.go index f10c607b..d53ef0a6 100644 --- a/transport/v2raygrpc/client.go +++ b/transport/v2raygrpc/client.go @@ -2,12 +2,12 @@ package v2raygrpc import ( "context" - "crypto/tls" "net" "sync" "time" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing/common" M "github.com/sagernet/sing/common/metadata" @@ -32,10 +32,14 @@ type Client struct { connAccess sync.Mutex } -func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig *tls.Config) adapter.V2RayClientTransport { +func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) { var dialOptions []grpc.DialOption if tlsConfig != nil { - dialOptions = append(dialOptions, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))) + stdConfig, err := tlsConfig.Config() + if err != nil { + return nil, err + } + dialOptions = append(dialOptions, grpc.WithTransportCredentials(credentials.NewTLS(stdConfig))) } else { dialOptions = append(dialOptions, grpc.WithTransportCredentials(insecure.NewCredentials())) } @@ -58,7 +62,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt serverAddr: serverAddr.String(), serviceName: options.ServiceName, dialOptions: dialOptions, - } + }, nil } func (c *Client) Close() error { diff --git a/transport/v2raygrpc/server.go b/transport/v2raygrpc/server.go index 41ad0a70..875cf197 100644 --- a/transport/v2raygrpc/server.go +++ b/transport/v2raygrpc/server.go @@ -2,11 +2,11 @@ package v2raygrpc import ( "context" - "crypto/tls" "net" "os" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/option" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" @@ -23,15 +23,19 @@ type Server struct { server *grpc.Server } -func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig *tls.Config, handler N.TCPConnectionHandler) *Server { +func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler) (*Server, error) { var serverOptions []grpc.ServerOption if tlsConfig != nil { - tlsConfig.NextProtos = []string{"h2"} - serverOptions = append(serverOptions, grpc.Creds(credentials.NewTLS(tlsConfig))) + stdConfig, err := tlsConfig.Config() + if err != nil { + return nil, err + } + stdConfig.NextProtos = []string{"h2"} + serverOptions = append(serverOptions, grpc.Creds(credentials.NewTLS(stdConfig))) } server := &Server{ctx, handler, grpc.NewServer(serverOptions...)} RegisterGunServiceCustomNameServer(server.server, server, options.ServiceName) - return server + return server, nil } func (s *Server) Tun(server GunService_TunServer) error { diff --git a/transport/v2raygrpclite/client.go b/transport/v2raygrpclite/client.go index 1fc36bbc..7205e9c6 100644 --- a/transport/v2raygrpclite/client.go +++ b/transport/v2raygrpclite/client.go @@ -2,7 +2,6 @@ package v2raygrpclite import ( "context" - "crypto/tls" "fmt" "io" "net" @@ -10,6 +9,7 @@ import ( "net/url" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/option" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" @@ -32,18 +32,21 @@ type Client struct { url *url.URL } -func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig *tls.Config) adapter.V2RayClientTransport { +func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig tls.Config) adapter.V2RayClientTransport { return &Client{ ctx: ctx, dialer: dialer, serverAddr: serverAddr, options: options, transport: &http.Transport{ - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) + DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + conn, err := dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) + if err != nil { + return nil, err + } + return tls.ClientHandshake(ctx, conn, tlsConfig) }, ForceAttemptHTTP2: true, - TLSClientConfig: tlsConfig, }, url: &url.URL{ Scheme: "https", diff --git a/transport/v2raygrpclite/server.go b/transport/v2raygrpclite/server.go index 0af41593..8319baca 100644 --- a/transport/v2raygrpclite/server.go +++ b/transport/v2raygrpclite/server.go @@ -2,7 +2,6 @@ package v2raygrpclite import ( "context" - "crypto/tls" "fmt" "net" "net/http" @@ -11,6 +10,7 @@ import ( "strings" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" @@ -32,22 +32,26 @@ func (s *Server) Network() []string { return []string{N.NetworkTCP} } -func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig *tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) *Server { +func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (*Server, error) { server := &Server{ handler: handler, errorHandler: errorHandler, path: fmt.Sprintf("/%s/Tun", url.QueryEscape(options.ServiceName)), } - if tlsConfig != nil { - if !common.Contains(tlsConfig.NextProtos, "h2") { - tlsConfig.NextProtos = append(tlsConfig.NextProtos, "h2") - } - } server.httpServer = &http.Server{ - Handler: server, - TLSConfig: tlsConfig, + Handler: server, } - return server + if tlsConfig != nil { + stdConfig, err := tlsConfig.Config() + if err != nil { + return nil, err + } + if !common.Contains(stdConfig.NextProtos, "h2") { + stdConfig.NextProtos = append(stdConfig.NextProtos, "h2") + } + server.httpServer.TLSConfig = stdConfig + } + return server, nil } func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { diff --git a/transport/v2rayhttp/client.go b/transport/v2rayhttp/client.go index 7e06e18e..45ee62ab 100644 --- a/transport/v2rayhttp/client.go +++ b/transport/v2rayhttp/client.go @@ -3,7 +3,6 @@ package v2rayhttp import ( "bufio" "context" - "crypto/tls" "io" "math/rand" "net" @@ -12,6 +11,7 @@ import ( "strings" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" @@ -32,7 +32,7 @@ type Client struct { headers http.Header } -func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayHTTPOptions, tlsConfig *tls.Config) adapter.V2RayClientTransport { +func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayHTTPOptions, tlsConfig tls.Config) adapter.V2RayClientTransport { client := &Client{ ctx: ctx, dialer: dialer, @@ -40,16 +40,26 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt host: options.Host, method: options.Method, headers: make(http.Header), - client: &http.Client{ - Transport: &http.Transport{ - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) - }, - ForceAttemptHTTP2: true, - TLSClientConfig: tlsConfig, + client: &http.Client{}, + http2: tlsConfig != nil, + } + if client.http2 { + client.client.Transport = &http.Transport{ + DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + conn, err := dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) + if err != nil { + return nil, err + } + return tls.ClientHandshake(ctx, conn, tlsConfig) }, - }, - http2: tlsConfig != nil, + ForceAttemptHTTP2: true, + } + } else { + client.client.Transport = &http.Transport{ + DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) + }, + } } if client.method == "" { client.method = "PUT" diff --git a/transport/v2rayhttp/server.go b/transport/v2rayhttp/server.go index f82f92b6..8d838349 100644 --- a/transport/v2rayhttp/server.go +++ b/transport/v2rayhttp/server.go @@ -2,13 +2,13 @@ package v2rayhttp import ( "context" - "crypto/tls" "net" "net/http" "os" "strings" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing/common" @@ -35,7 +35,7 @@ func (s *Server) Network() []string { return []string{N.NetworkTCP} } -func NewServer(ctx context.Context, options option.V2RayHTTPOptions, tlsConfig *tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) *Server { +func NewServer(ctx context.Context, options option.V2RayHTTPOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (*Server, error) { server := &Server{ ctx: ctx, handler: handler, @@ -58,9 +58,15 @@ func NewServer(ctx context.Context, options option.V2RayHTTPOptions, tlsConfig * Handler: server, ReadHeaderTimeout: C.TCPTimeout, MaxHeaderBytes: http.DefaultMaxHeaderBytes, - TLSConfig: tlsConfig, } - return server + if tlsConfig != nil { + stdConfig, err := tlsConfig.Config() + if err != nil { + return nil, err + } + server.httpServer.TLSConfig = stdConfig + } + return server, nil } func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { diff --git a/transport/v2rayquic/client.go b/transport/v2rayquic/client.go index 06acaf14..7dfb6ee0 100644 --- a/transport/v2rayquic/client.go +++ b/transport/v2rayquic/client.go @@ -2,12 +2,12 @@ package v2rayquic import ( "context" - "crypto/tls" "net" "sync" "github.com/sagernet/quic-go" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/transport/hysteria" @@ -23,26 +23,30 @@ type Client struct { ctx context.Context dialer N.Dialer serverAddr M.Socksaddr - tlsConfig *tls.Config + tlsConfig *tls.STDConfig quicConfig *quic.Config conn quic.Connection connAccess sync.Mutex } -func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayQUICOptions, tlsConfig *tls.Config) adapter.V2RayClientTransport { +func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayQUICOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) { quicConfig := &quic.Config{ DisablePathMTUDiscovery: !C.IsLinux && !C.IsWindows, } - if len(tlsConfig.NextProtos) == 0 { - tlsConfig.NextProtos = []string{"h2", "http/1.1"} + stdConfig, err := tlsConfig.Config() + if err != nil { + return nil, err + } + if len(stdConfig.NextProtos) == 0 { + stdConfig.NextProtos = []string{"h2", "http/1.1"} } return &Client{ ctx: ctx, dialer: dialer, serverAddr: serverAddr, - tlsConfig: tlsConfig, + tlsConfig: stdConfig, quicConfig: quicConfig, - } + }, nil } func (c *Client) offer() (quic.Connection, error) { diff --git a/transport/v2rayquic/server.go b/transport/v2rayquic/server.go index f376ccdc..95ee9691 100644 --- a/transport/v2rayquic/server.go +++ b/transport/v2rayquic/server.go @@ -2,12 +2,12 @@ package v2rayquic import ( "context" - "crypto/tls" "net" "os" "github.com/sagernet/quic-go" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/transport/hysteria" @@ -21,7 +21,7 @@ var _ adapter.V2RayServerTransport = (*Server)(nil) type Server struct { ctx context.Context - tlsConfig *tls.Config + tlsConfig *tls.STDConfig quicConfig *quic.Config handler N.TCPConnectionHandler errorHandler E.Handler @@ -29,21 +29,25 @@ type Server struct { quicListener quic.Listener } -func NewServer(ctx context.Context, options option.V2RayQUICOptions, tlsConfig *tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) *Server { +func NewServer(ctx context.Context, options option.V2RayQUICOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (*Server, error) { quicConfig := &quic.Config{ DisablePathMTUDiscovery: !C.IsLinux && !C.IsWindows, } - if len(tlsConfig.NextProtos) == 0 { - tlsConfig.NextProtos = []string{"h2", "http/1.1"} + stdConfig, err := tlsConfig.Config() + if err != nil { + return nil, err + } + if len(stdConfig.NextProtos) == 0 { + stdConfig.NextProtos = []string{"h2", "http/1.1"} } server := &Server{ ctx: ctx, - tlsConfig: tlsConfig, + tlsConfig: stdConfig, quicConfig: quicConfig, handler: handler, errorHandler: errorHandler, } - return server + return server, nil } func (s *Server) Network() []string { diff --git a/transport/v2raywebsocket/client.go b/transport/v2raywebsocket/client.go index d3b7a7a6..bece8f90 100644 --- a/transport/v2raywebsocket/client.go +++ b/transport/v2raywebsocket/client.go @@ -2,7 +2,6 @@ package v2raywebsocket import ( "context" - "crypto/tls" "net" "net/http" "net/url" @@ -10,6 +9,7 @@ import ( "time" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" @@ -28,16 +28,25 @@ type Client struct { earlyDataHeaderName string } -func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayWebsocketOptions, tlsConfig *tls.Config) adapter.V2RayClientTransport { +func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayWebsocketOptions, tlsConfig tls.Config) adapter.V2RayClientTransport { wsDialer := &websocket.Dialer{ - NetDialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) - }, - TLSClientConfig: tlsConfig, ReadBufferSize: 4 * 1024, WriteBufferSize: 4 * 1024, HandshakeTimeout: time.Second * 8, } + if tlsConfig != nil { + wsDialer.NetDialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) { + conn, err := dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) + if err != nil { + return nil, err + } + return tls.ClientHandshake(ctx, conn, tlsConfig) + } + } else { + wsDialer.NetDialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { + return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) + } + } var uri url.URL if tlsConfig == nil { uri.Scheme = "ws" diff --git a/transport/v2raywebsocket/server.go b/transport/v2raywebsocket/server.go index 673836d6..36c26dbe 100644 --- a/transport/v2raywebsocket/server.go +++ b/transport/v2raywebsocket/server.go @@ -2,7 +2,6 @@ package v2raywebsocket import ( "context" - "crypto/tls" "encoding/base64" "net" "net/http" @@ -10,6 +9,7 @@ import ( "strings" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing/common" @@ -35,7 +35,7 @@ type Server struct { earlyDataHeaderName string } -func NewServer(ctx context.Context, options option.V2RayWebsocketOptions, tlsConfig *tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) *Server { +func NewServer(ctx context.Context, options option.V2RayWebsocketOptions, tlsConfig tls.Config, handler N.TCPConnectionHandler, errorHandler E.Handler) (*Server, error) { server := &Server{ ctx: ctx, handler: handler, @@ -51,9 +51,15 @@ func NewServer(ctx context.Context, options option.V2RayWebsocketOptions, tlsCon Handler: server, ReadHeaderTimeout: C.TCPTimeout, MaxHeaderBytes: http.DefaultMaxHeaderBytes, - TLSConfig: tlsConfig, } - return server + if tlsConfig != nil { + stdConfig, err := tlsConfig.Config() + if err != nil { + return nil, err + } + server.httpServer.TLSConfig = stdConfig + } + return server, nil } var upgrader = websocket.Upgrader{