mirror of
https://github.com/yusing/godoxy.git
synced 2026-02-26 04:14:52 +01:00
feat(ReverseProxy): add SSL/TLS configuration options and build TLS config method
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
@@ -44,10 +43,12 @@ func NewReverseProxyRoute(base *Route) (*ReveseProxyRoute, gperr.Error) {
|
||||
trans = a.Transport()
|
||||
proxyURL = nettypes.NewURL(agent.HTTPProxyURL)
|
||||
} else {
|
||||
trans = gphttp.NewTransport()
|
||||
if httpConfig.NoTLSVerify {
|
||||
trans.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //nolint:gosec
|
||||
tlsConfig, err := httpConfig.BuildTLSConfig(base.ProxyURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
trans = gphttp.NewTransportWithTLSConfig(tlsConfig)
|
||||
if httpConfig.ResponseHeaderTimeout > 0 {
|
||||
trans.ResponseHeaderTimeout = httpConfig.ResponseHeaderTimeout
|
||||
}
|
||||
|
||||
@@ -1,11 +1,118 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
nettypes "github.com/yusing/go-proxy/internal/net/types"
|
||||
)
|
||||
|
||||
type HTTPConfig struct {
|
||||
NoTLSVerify bool `json:"no_tls_verify,omitempty"`
|
||||
ResponseHeaderTimeout time.Duration `json:"response_header_timeout,omitempty" swaggertype:"primitive,integer"`
|
||||
DisableCompression bool `json:"disable_compression,omitempty"`
|
||||
|
||||
// SSL/TLS proxy options (nginx-like)
|
||||
SSLServerName *string `json:"ssl_server_name,omitempty"` // SNI server name
|
||||
SSLTrustedCertificate string `json:"ssl_trusted_certificate,omitempty"` // Path to trusted CA certificates
|
||||
SSLCertificate string `json:"ssl_certificate,omitempty"` // Path to client certificate
|
||||
SSLCertificateKey string `json:"ssl_certificate_key,omitempty"` // Path to client certificate key
|
||||
SSLProtocols []string `json:"ssl_protocols,omitempty"` // Allowed TLS protocols
|
||||
}
|
||||
|
||||
// BuildTLSConfig creates a TLS configuration based on the HTTP config options.
|
||||
func (cfg *HTTPConfig) BuildTLSConfig(targetURL *nettypes.URL) (*tls.Config, gperr.Error) {
|
||||
tlsConfig := &tls.Config{}
|
||||
|
||||
// Handle InsecureSkipVerify (legacy NoTLSVerify option)
|
||||
if cfg.NoTLSVerify {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
}
|
||||
|
||||
// Handle ssl_server_name (SNI)
|
||||
if cfg.SSLServerName != nil {
|
||||
switch *cfg.SSLServerName {
|
||||
case "off":
|
||||
// Disable SNI by setting empty string
|
||||
tlsConfig.ServerName = ""
|
||||
case "on", "":
|
||||
// Use hostname from target URL for SNI
|
||||
tlsConfig.ServerName = targetURL.Hostname()
|
||||
default:
|
||||
tlsConfig.ServerName = *cfg.SSLServerName
|
||||
}
|
||||
} else {
|
||||
// Default behavior - use hostname for SNI
|
||||
tlsConfig.ServerName = targetURL.Hostname()
|
||||
}
|
||||
|
||||
// Handle ssl_trusted_certificate
|
||||
if cfg.SSLTrustedCertificate != "" {
|
||||
caCertData, err := os.ReadFile(cfg.SSLTrustedCertificate)
|
||||
if err != nil {
|
||||
return nil, gperr.New("failed to read trusted certificate file").
|
||||
Subject(cfg.SSLTrustedCertificate).
|
||||
With(err)
|
||||
}
|
||||
|
||||
caCertPool := x509.NewCertPool()
|
||||
if !caCertPool.AppendCertsFromPEM(caCertData) {
|
||||
return nil, gperr.New("failed to parse trusted certificates").
|
||||
Subject(cfg.SSLTrustedCertificate)
|
||||
}
|
||||
tlsConfig.RootCAs = caCertPool
|
||||
}
|
||||
|
||||
// Handle ssl_certificate and ssl_certificate_key (client certificates)
|
||||
if cfg.SSLCertificate != "" {
|
||||
if cfg.SSLCertificateKey == "" {
|
||||
return nil, gperr.New("ssl_certificate_key is required when ssl_certificate is specified")
|
||||
}
|
||||
|
||||
clientCert, err := tls.LoadX509KeyPair(cfg.SSLCertificate, cfg.SSLCertificateKey)
|
||||
if err != nil {
|
||||
return nil, gperr.New("failed to load client certificate").
|
||||
Subject(cfg.SSLCertificate).
|
||||
With(err)
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{clientCert}
|
||||
}
|
||||
|
||||
// Handle ssl_protocols (TLS versions)
|
||||
if len(cfg.SSLProtocols) > 0 {
|
||||
var minVersion, maxVersion uint16
|
||||
|
||||
for _, protocol := range cfg.SSLProtocols {
|
||||
var version uint16
|
||||
switch strings.ToLower(protocol) {
|
||||
case "tlsv1.0":
|
||||
version = tls.VersionTLS10
|
||||
case "tlsv1.1":
|
||||
version = tls.VersionTLS11
|
||||
case "tlsv1.2":
|
||||
version = tls.VersionTLS12
|
||||
case "tlsv1.3":
|
||||
version = tls.VersionTLS13
|
||||
default:
|
||||
return nil, gperr.New("unsupported TLS protocol").
|
||||
Subject(protocol)
|
||||
}
|
||||
|
||||
if minVersion == 0 || version < minVersion {
|
||||
minVersion = version
|
||||
}
|
||||
if maxVersion == 0 || version > maxVersion {
|
||||
maxVersion = version
|
||||
}
|
||||
}
|
||||
|
||||
tlsConfig.MinVersion = minVersion
|
||||
tlsConfig.MaxVersion = maxVersion
|
||||
}
|
||||
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user