From 8a98f32d34bbc3d13227f1cf18b5291929f96c90 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 9 Nov 2024 19:45:16 +0530 Subject: [PATCH] DnsServer: fixed issue with DoH/3 not working caused due to kestral web server changes. Fixed issue in ProcessAPPAsync() that did not check for secondary forwarder. Updated DoH cache header to avoid caching issues after server upgrade. Code refactoring changes done. --- DnsServerCore/Dns/DnsServer.cs | 56 +++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/DnsServerCore/Dns/DnsServer.cs b/DnsServerCore/Dns/DnsServer.cs index 3c2fb025..41102aa4 100644 --- a/DnsServerCore/Dns/DnsServer.cs +++ b/DnsServerCore/Dns/DnsServer.cs @@ -99,7 +99,7 @@ namespace DnsServerCore.Dns static readonly IPEndPoint IPENDPOINT_ANY_0 = new IPEndPoint(IPAddress.Any, 0); static readonly IReadOnlyCollection _aRecords = [new DnsARecordData(IPAddress.Any)]; static readonly IReadOnlyCollection _aaaaRecords = [new DnsAAAARecordData(IPAddress.IPv6Any)]; - static readonly List quicApplicationProtocols = new List() { new SslApplicationProtocol("doq") }; + static readonly List _doqApplicationProtocols = new List() { new SslApplicationProtocol("doq") }; string _serverDomain; readonly string _configFolder; @@ -172,8 +172,8 @@ namespace DnsServerCore.Dns int _dnsOverHttpsPort = 443; int _dnsOverQuicPort = 853; X509Certificate2Collection _certificateCollection; - SslServerAuthenticationOptions _sslServerAuthenticationOptions; - SslServerAuthenticationOptions _quicSslServerAuthenticationOptions; + SslServerAuthenticationOptions _dotSslServerAuthenticationOptions; + SslServerAuthenticationOptions _doqSslServerAuthenticationOptions; string _dnsOverHttpRealIpHeader = "X-Real-IP"; IReadOnlyDictionary _tsigKeys; @@ -620,7 +620,7 @@ namespace DnsServerCore.Dns return tlsStream.AuthenticateAsServerAsync(delegate (SslStream stream, SslClientHelloInfo clientHelloInfo, object state, CancellationToken cancellationToken) { serverName = clientHelloInfo.ServerName; - return ValueTask.FromResult(_sslServerAuthenticationOptions); + return ValueTask.FromResult(_dotSslServerAuthenticationOptions); }, null, cancellationToken1); }, _tcpReceiveTimeout); @@ -2207,7 +2207,7 @@ namespace DnsServerCore.Dns DnsResponseCode rcode; IReadOnlyList authority = null; - if (zoneInfo.Type == AuthZoneType.Forwarder) + if ((zoneInfo.Type == AuthZoneType.Forwarder) || (zoneInfo.Type == AuthZoneType.SecondaryForwarder)) { //process FWD record if exists if (!zoneInfo.Name.Equals(appResourceRecord.Name, StringComparison.OrdinalIgnoreCase)) @@ -4454,6 +4454,34 @@ namespace DnsServerCore.Dns //bind to https port if (_enableDnsOverHttps && (_certificateCollection is not null)) { + X509Certificate2 serverCertificate = null; + + foreach (X509Certificate2 certificate in _certificateCollection) + { + if (certificate.HasPrivateKey) + { + serverCertificate = certificate; + break; + } + } + + if (serverCertificate is null) + throw new DnsServerException("DNS Server TLS certificate file must contain a certificate with private key."); + + List applicationProtocols = new List(); + + if (_enableDnsOverHttp3) + applicationProtocols.Add(new SslApplicationProtocol("h3")); + + applicationProtocols.Add(new SslApplicationProtocol("h2")); + applicationProtocols.Add(new SslApplicationProtocol("http/1.1")); + + SslServerAuthenticationOptions sslServerAuthenticationOptions = new SslServerAuthenticationOptions + { + ApplicationProtocols = applicationProtocols, + ServerCertificateContext = SslStreamCertificateContext.Create(serverCertificate, _certificateCollection, false), + }; + foreach (IPAddress localAddress in localAddresses) { serverOptions.Listen(localAddress, _dnsOverHttpsPort, delegate (ListenOptions listenOptions) @@ -4461,7 +4489,7 @@ namespace DnsServerCore.Dns listenOptions.Protocols = _enableDnsOverHttp3 ? HttpProtocols.Http1AndHttp2AndHttp3 : HttpProtocols.Http1AndHttp2; listenOptions.UseHttps(delegate (SslStream stream, SslClientHelloInfo clientHelloInfo, object state, CancellationToken cancellationToken) { - return ValueTask.FromResult(_sslServerAuthenticationOptions); + return ValueTask.FromResult(sslServerAuthenticationOptions); }, null); }); } @@ -4487,7 +4515,7 @@ namespace DnsServerCore.Dns OnPrepareResponse = delegate (StaticFileResponseContext ctx) { ctx.Context.Response.Headers["X-Robots-Tag"] = "noindex, nofollow"; - ctx.Context.Response.Headers.CacheControl = "private, max-age=300"; + ctx.Context.Response.Headers.CacheControl = "no-cache"; }, ServeUnknownFileTypes = true }); @@ -4819,7 +4847,7 @@ namespace DnsServerCore.Dns { ListenEndPoint = quicEP, ListenBacklog = _listenBacklog, - ApplicationProtocols = quicApplicationProtocols, + ApplicationProtocols = _doqApplicationProtocols, ConnectionOptionsCallback = delegate (QuicConnection quicConnection, SslClientHelloInfo sslClientHello, CancellationToken cancellationToken) { QuicServerConnectionOptions serverConnectionOptions = new QuicServerConnectionOptions() @@ -4829,7 +4857,7 @@ namespace DnsServerCore.Dns MaxInboundUnidirectionalStreams = 0, MaxInboundBidirectionalStreams = _quicMaxInboundStreams, IdleTimeout = TimeSpan.FromMilliseconds(_quicIdleTimeout), - ServerAuthenticationOptions = _quicSslServerAuthenticationOptions + ServerAuthenticationOptions = _doqSslServerAuthenticationOptions }; return ValueTask.FromResult(serverConnectionOptions); @@ -5622,8 +5650,8 @@ namespace DnsServerCore.Dns if (value is null) { _certificateCollection = null; - _sslServerAuthenticationOptions = null; - _quicSslServerAuthenticationOptions = null; + _dotSslServerAuthenticationOptions = null; + _doqSslServerAuthenticationOptions = null; } else { @@ -5645,14 +5673,14 @@ namespace DnsServerCore.Dns SslStreamCertificateContext certificateContext = SslStreamCertificateContext.Create(serverCertificate, _certificateCollection, false); - _sslServerAuthenticationOptions = new SslServerAuthenticationOptions() + _dotSslServerAuthenticationOptions = new SslServerAuthenticationOptions() { ServerCertificateContext = certificateContext }; - _quicSslServerAuthenticationOptions = new SslServerAuthenticationOptions() + _doqSslServerAuthenticationOptions = new SslServerAuthenticationOptions() { - ApplicationProtocols = quicApplicationProtocols, + ApplicationProtocols = _doqApplicationProtocols, ServerCertificateContext = certificateContext }; }