diff --git a/AGHTechDoc.md b/AGHTechDoc.md index e5e582ec..0dcb001b 100644 --- a/AGHTechDoc.md +++ b/AGHTechDoc.md @@ -743,6 +743,7 @@ Response: "server_name":"...", "port_https":443, "port_dns_over_tls":853, + "port_dns_over_quic":784, "certificate_chain":"...", "private_key":"...", "certificate_path":"...", @@ -774,6 +775,7 @@ Request: "force_https":false, "port_https":443, "port_dns_over_tls":853, + "port_dns_over_quic":784, "certificate_chain":"...", "private_key":"...", "certificate_path":"...", // if set, certificate_chain must be empty diff --git a/dnsforward/config.go b/dnsforward/config.go index 69af11eb..5d06b9dc 100644 --- a/dnsforward/config.go +++ b/dnsforward/config.go @@ -92,6 +92,7 @@ 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:"-"` + QUICListenAddr *net.UDPAddr `yaml:"-" json:"-"` StrictSNICheck bool `yaml:"strict_sni_check" json:"-"` // Reject connection if the client uses server name (in SNI) that doesn't match the certificate CertificateChain string `yaml:"certificate_chain" json:"certificate_chain"` // PEM-encoded certificates chain @@ -153,6 +154,10 @@ func (s *Server) createProxyConfig() (proxy.Config, error) { MaxGoroutines: int(s.conf.MaxGoroutines), } + if s.conf.QUICListenAddr != nil { + proxyConfig.QUICListenAddr = []*net.UDPAddr{s.conf.QUICListenAddr} + } + if s.conf.CacheSize != 0 { proxyConfig.CacheEnabled = true proxyConfig.CacheSizeBytes = int(s.conf.CacheSize) diff --git a/dnsforward/dnsforward_http.go b/dnsforward/dnsforward_http.go index 63e82d95..79e4ded7 100644 --- a/dnsforward/dnsforward_http.go +++ b/dnsforward/dnsforward_http.go @@ -270,7 +270,7 @@ func ValidateUpstreams(upstreams []string) error { return nil } -var protocols = []string{"tls://", "https://", "tcp://", "sdns://"} +var protocols = []string{"tls://", "https://", "tcp://", "sdns://", "quic://"} func validateUpstream(u string) (bool, error) { // Check if user tries to specify upstream for domain diff --git a/home/config.go b/home/config.go index d0fc6396..348e72fa 100644 --- a/home/config.go +++ b/home/config.go @@ -92,11 +92,12 @@ 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 + 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 + PortDNSOverQUIC uint16 `yaml:"port_dns_over_quic" json:"port_dns_over_quic,omitempty"` // DNS-over-QUIC port. If 0, DoQ will be disabled // Allow DOH queries via unencrypted HTTP (e.g. for reverse proxying) AllowUnencryptedDOH bool `yaml:"allow_unencrypted_doh" json:"allow_unencrypted_doh"` @@ -124,8 +125,9 @@ var config = configuration{ FiltersUpdateIntervalHours: 24, }, TLS: tlsConfigSettings{ - PortHTTPS: 443, - PortDNSOverTLS: 853, // needs to be passed through to dnsproxy + PortHTTPS: 443, + PortDNSOverTLS: 853, // needs to be passed through to dnsproxy + PortDNSOverQUIC: 784, }, logSettings: logSettings{ LogCompress: false, diff --git a/home/control_update.go b/home/control_update.go index fb160900..b8f6bcbe 100644 --- a/home/control_update.go +++ b/home/control_update.go @@ -99,7 +99,9 @@ func getVersionResp(info update.VersionInfo) []byte { Context.tls.WriteDiskConfig(&tlsConf) if runtime.GOOS != "windows" && - ((tlsConf.Enabled && (tlsConf.PortHTTPS < 1024 || tlsConf.PortDNSOverTLS < 1024)) || + ((tlsConf.Enabled && (tlsConf.PortHTTPS < 1024 || + tlsConf.PortDNSOverTLS < 1024 || + tlsConf.PortDNSOverQUIC < 1024)) || config.BindPort < 1024 || config.DNS.Port < 1024) { // On UNIX, if we're running under a regular user, diff --git a/home/dns.go b/home/dns.go index 2d647f94..820b441a 100644 --- a/home/dns.go +++ b/home/dns.go @@ -172,12 +172,20 @@ func generateServerConfig() dnsforward.ServerConfig { Context.tls.WriteDiskConfig(&tlsConf) if tlsConf.Enabled { newconfig.TLSConfig = tlsConf.TLSConfig + if tlsConf.PortDNSOverTLS != 0 { newconfig.TLSListenAddr = &net.TCPAddr{ IP: net.ParseIP(config.DNS.BindHost), Port: tlsConf.PortDNSOverTLS, } } + + if tlsConf.PortDNSOverQUIC != 0 { + newconfig.QUICListenAddr = &net.UDPAddr{ + IP: net.ParseIP(config.DNS.BindHost), + Port: int(tlsConf.PortDNSOverQUIC), + } + } } newconfig.TLSv12Roots = Context.tlsRoots newconfig.TLSCiphers = Context.tlsCiphers @@ -225,6 +233,11 @@ func getDNSAddresses() []string { addr := fmt.Sprintf("tls://%s:%d", tlsConf.ServerName, tlsConf.PortDNSOverTLS) dnsAddresses = append(dnsAddresses, addr) } + + if tlsConf.PortDNSOverQUIC != 0 { + addr := fmt.Sprintf("quic://%s:%d", tlsConf.ServerName, tlsConf.PortDNSOverQUIC) + dnsAddresses = append(dnsAddresses, addr) + } } return dnsAddresses diff --git a/home/tls.go b/home/tls.go index 157cda2a..0b9e8f90 100644 --- a/home/tls.go +++ b/home/tls.go @@ -45,6 +45,7 @@ func tlsCreate(conf tlsConfigSettings) *TLSMod { ServerName: conf.ServerName, PortHTTPS: conf.PortHTTPS, PortDNSOverTLS: conf.PortDNSOverTLS, + PortDNSOverQUIC: conf.PortDNSOverQUIC, AllowUnencryptedDOH: conf.AllowUnencryptedDOH, }} } @@ -267,6 +268,7 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) { t.conf.ForceHTTPS = data.ForceHTTPS t.conf.PortHTTPS = data.PortHTTPS t.conf.PortDNSOverTLS = data.PortDNSOverTLS + t.conf.PortDNSOverQUIC = data.PortDNSOverQUIC t.conf.CertificateChain = data.CertificateChain t.conf.CertificatePath = data.CertificatePath t.conf.CertificateChainData = data.CertificateChainData diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 57d63c70..7777c069 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -1563,6 +1563,11 @@ components: format: int32 example: 853 description: DNS-over-TLS port. If 0, DOT will be disabled. + port_dns_over_quic: + type: integer + format: int32 + example: 784 + description: DNS-over-QUIC port. If 0, DOQ will be disabled. certificate_chain: type: string description: Base64 string with PEM-encoded certificates chain