From c8c76ae12be31c3098d71588ba03a1b38e0d2704 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Fri, 13 Dec 2019 13:06:37 +0300 Subject: [PATCH] Merge: + DNS: TLS handshake: terminate handshake on bad SNI Close #1014 Squashed commit of the following: commit 759248efc0587ff2f288996c47739e602c557a76 Author: Simon Zolin Date: Thu Dec 12 19:26:46 2019 +0300 support empty ServerName commit 68afecd5eca5ae66262b12dcb414b50efe88dc02 Author: Simon Zolin Date: Wed Dec 11 14:40:22 2019 +0300 + DNS: TLS handshake: terminate handshake on bad SNI --- dnsforward/dnsforward.go | 22 +++++++++++++++++----- home/config.go | 9 ++++----- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/dnsforward/dnsforward.go b/dnsforward/dnsforward.go index 8027bc5b..01bd0469 100644 --- a/dnsforward/dnsforward.go +++ b/dnsforward/dnsforward.go @@ -147,14 +147,16 @@ type FilteringConfig struct { // TLSConfig is the TLS configuration for HTTPS, DNS-over-HTTPS, and DNS-over-TLS type TLSConfig struct { TLSListenAddr *net.TCPAddr `yaml:"-" json:"-"` + ServerName string `yaml:"server_name" json:"server_name,omitempty"` // ServerName is the hostname of your HTTPS/TLS server CertificateChain string `yaml:"certificate_chain" json:"certificate_chain"` // PEM-encoded certificates chain PrivateKey string `yaml:"private_key" json:"private_key"` // PEM-encoded private key CertificatePath string `yaml:"certificate_path" json:"certificate_path"` // certificate file name PrivateKeyPath string `yaml:"private_key_path" json:"private_key_path"` // private key file name - CertificateChainData []byte `yaml:"-" json:"-"` - PrivateKeyData []byte `yaml:"-" json:"-"` + CertificateChainData []byte `yaml:"-" json:"-"` + PrivateKeyData []byte `yaml:"-" json:"-"` + Cert tls.Certificate `yaml:"-" json:"-"` } // ServerConfig represents server configuration. @@ -294,13 +296,13 @@ func (s *Server) Prepare(config *ServerConfig) error { if s.conf.TLSListenAddr != nil && len(s.conf.CertificateChainData) != 0 && len(s.conf.PrivateKeyData) != 0 { proxyConfig.TLSListenAddr = s.conf.TLSListenAddr - keypair, err := tls.X509KeyPair(s.conf.CertificateChainData, s.conf.PrivateKeyData) + s.conf.Cert, err = tls.X509KeyPair(s.conf.CertificateChainData, s.conf.PrivateKeyData) if err != nil { return errorx.Decorate(err, "Failed to parse TLS keypair") } proxyConfig.TLSConfig = &tls.Config{ - Certificates: []tls.Certificate{keypair}, - MinVersion: tls.VersionTLS12, + GetCertificate: s.onGetCertificate, + MinVersion: tls.VersionTLS12, } } @@ -318,6 +320,16 @@ func (s *Server) Prepare(config *ServerConfig) error { return nil } +// Called by 'tls' package when Client Hello is received +// If the server name (from SNI) supplied by client is incorrect - we terminate the ongoing TLS handshake. +func (s *Server) onGetCertificate(ch *tls.ClientHelloInfo) (*tls.Certificate, error) { + if len(s.conf.ServerName) != 0 && ch.ServerName != s.conf.ServerName { + log.Info("DNS: TLS: unknown SNI in Client Hello: %s", ch.ServerName) + return nil, fmt.Errorf("Invalid SNI") + } + return &s.conf.Cert, nil +} + // Stop stops the DNS server func (s *Server) Stop() error { s.Lock() diff --git a/home/config.go b/home/config.go index 019612eb..84a0f2e4 100644 --- a/home/config.go +++ b/home/config.go @@ -111,11 +111,10 @@ type dnsConfig struct { } type tlsConfigSettings struct { - Enabled bool `yaml:"enabled" json:"enabled"` // Enabled is the encryption (DOT/DOH/HTTPS) status - ServerName string `yaml:"server_name" json:"server_name,omitempty"` // ServerName is the hostname of your HTTPS/TLS server - ForceHTTPS bool `yaml:"force_https" json:"force_https,omitempty"` // ForceHTTPS: if true, forces HTTP->HTTPS redirect - PortHTTPS int `yaml:"port_https" json:"port_https,omitempty"` // HTTPS port. If 0, HTTPS will be disabled - PortDNSOverTLS int `yaml:"port_dns_over_tls" json:"port_dns_over_tls,omitempty"` // DNS-over-TLS port. If 0, DOT will be disabled + Enabled bool `yaml:"enabled" json:"enabled"` // Enabled is the encryption (DOT/DOH/HTTPS) status + ForceHTTPS bool `yaml:"force_https" json:"force_https,omitempty"` // ForceHTTPS: if true, forces HTTP->HTTPS redirect + PortHTTPS int `yaml:"port_https" json:"port_https,omitempty"` // HTTPS port. If 0, HTTPS will be disabled + PortDNSOverTLS int `yaml:"port_dns_over_tls" json:"port_dns_over_tls,omitempty"` // DNS-over-TLS port. If 0, DOT will be disabled dnsforward.TLSConfig `yaml:",inline" json:",inline"` }