1
0

tls_client.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. package runtime
  2. import (
  3. "crypto/sha256"
  4. "crypto/subtle"
  5. "crypto/tls"
  6. "encoding/base64"
  7. "encoding/hex"
  8. "net/http"
  9. "strings"
  10. "sync"
  11. "time"
  12. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  13. "github.com/mhsanaei/3x-ui/v3/internal/util/common"
  14. "github.com/mhsanaei/3x-ui/v3/internal/util/netproxy"
  15. "github.com/mhsanaei/3x-ui/v3/internal/util/netsafe"
  16. )
  17. // MasterClientCertProvider supplies the master client certificate this panel
  18. // presents to nodes in mtls mode. It is injected by the web layer so the
  19. // runtime package need not import service.
  20. type MasterClientCertProvider func() (tls.Certificate, error)
  21. var (
  22. masterClientCertMu sync.RWMutex
  23. masterClientCert MasterClientCertProvider
  24. )
  25. // SetMasterClientCertProvider installs the provider used to obtain the master
  26. // client certificate for mtls nodes. Passing nil disables it.
  27. func SetMasterClientCertProvider(p MasterClientCertProvider) {
  28. masterClientCertMu.Lock()
  29. defer masterClientCertMu.Unlock()
  30. masterClientCert = p
  31. }
  32. func getMasterClientCert() (tls.Certificate, error) {
  33. masterClientCertMu.RLock()
  34. p := masterClientCert
  35. masterClientCertMu.RUnlock()
  36. if p == nil {
  37. return tls.Certificate{}, common.NewError("mtls: master client certificate provider not configured")
  38. }
  39. return p()
  40. }
  41. // defaultNodeHTTPClient reaches nodes trusting the system CA store ("verify"
  42. // mode or plain http); shared so connections pool across nodes.
  43. var defaultNodeHTTPClient = &http.Client{
  44. Transport: &http.Transport{
  45. MaxIdleConns: 64,
  46. MaxIdleConnsPerHost: 4,
  47. IdleConnTimeout: 60 * time.Second,
  48. DialContext: netsafe.SSRFGuardedDialContext,
  49. },
  50. }
  51. func HTTPClientForNode(n *model.Node, proxyURL string) (*http.Client, error) {
  52. mode := n.TlsVerifyMode
  53. if mode == "" {
  54. mode = "verify"
  55. }
  56. if proxyURL != "" {
  57. client, err := netproxy.NewHTTPClient(proxyURL, remoteHTTPTimeout)
  58. if err != nil {
  59. return nil, err
  60. }
  61. if mode == "verify" || n.Scheme == "http" {
  62. return client, nil
  63. }
  64. transport, ok := client.Transport.(*http.Transport)
  65. if !ok {
  66. return client, nil
  67. }
  68. tlsCfg, err := tlsConfigForNode(n)
  69. if err != nil {
  70. return nil, err
  71. }
  72. transport.TLSClientConfig = tlsCfg
  73. return client, nil
  74. }
  75. if mode == "verify" || n.Scheme == "http" {
  76. return defaultNodeHTTPClient, nil
  77. }
  78. tlsCfg, err := tlsConfigForNode(n)
  79. if err != nil {
  80. return nil, err
  81. }
  82. return &http.Client{
  83. Transport: &http.Transport{
  84. MaxIdleConns: 64,
  85. MaxIdleConnsPerHost: 4,
  86. IdleConnTimeout: 60 * time.Second,
  87. DialContext: netsafe.SSRFGuardedDialContext,
  88. TLSClientConfig: tlsCfg,
  89. },
  90. }, nil
  91. }
  92. func tlsConfigForNode(n *model.Node) (*tls.Config, error) {
  93. if n.TlsVerifyMode == "mtls" {
  94. // Present the master client cert; verify the node's server cert against
  95. // the system roots (no InsecureSkipVerify). mtls authenticates the
  96. // caller — it does not change how the node's server identity is checked.
  97. cert, err := getMasterClientCert()
  98. if err != nil {
  99. return nil, err
  100. }
  101. return &tls.Config{
  102. Certificates: []tls.Certificate{cert},
  103. MinVersion: tls.VersionTLS12,
  104. }, nil
  105. }
  106. tlsCfg := &tls.Config{InsecureSkipVerify: true} // lgtm[go/disabled-certificate-check]
  107. if n.TlsVerifyMode == "pin" {
  108. want, err := DecodeCertPin(n.PinnedCertSha256)
  109. if err != nil {
  110. return nil, err
  111. }
  112. tlsCfg.VerifyConnection = func(cs tls.ConnectionState) error {
  113. if len(cs.PeerCertificates) == 0 {
  114. return common.NewError("node presented no certificate")
  115. }
  116. sum := sha256.Sum256(cs.PeerCertificates[0].Raw)
  117. if subtle.ConstantTimeCompare(sum[:], want) != 1 {
  118. return common.NewError("node certificate does not match pinned SHA-256")
  119. }
  120. return nil
  121. }
  122. }
  123. return tlsCfg, nil
  124. }
  125. // DecodeCertPin decodes a SHA-256 cert pin given as base64 (Xray's
  126. // pinnedPeerCertSha256 form) or hex with optional colons into 32 raw bytes.
  127. func DecodeCertPin(s string) ([]byte, error) {
  128. s = strings.TrimSpace(s)
  129. if s == "" {
  130. return nil, common.NewError("certificate pin is empty")
  131. }
  132. if b, err := hex.DecodeString(strings.ReplaceAll(s, ":", "")); err == nil && len(b) == sha256.Size {
  133. return b, nil
  134. }
  135. for _, enc := range []*base64.Encoding{base64.StdEncoding, base64.RawStdEncoding, base64.URLEncoding, base64.RawURLEncoding} {
  136. if b, err := enc.DecodeString(s); err == nil && len(b) == sha256.Size {
  137. return b, nil
  138. }
  139. }
  140. return nil, common.NewError("certificate pin must be a SHA-256 hash (base64 or hex)")
  141. }