From 8a21c84cf214601dbd51182eee0f278dbd98de79 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Aug 2021 11:45:26 +0530 Subject: [PATCH] DnsServer: implemented TsigKey and tsig implementation changes. Fixed minor issue in ProcessCNAMEAsync() preventing the response from having expected authority records. --- DnsServerCore/Dns/DnsServer.cs | 72 ++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/DnsServerCore/Dns/DnsServer.cs b/DnsServerCore/Dns/DnsServer.cs index 11c87de4..c999389c 100644 --- a/DnsServerCore/Dns/DnsServer.cs +++ b/DnsServerCore/Dns/DnsServer.cs @@ -94,7 +94,7 @@ namespace DnsServerCore.Dns bool _enableDnsOverHttps; bool _isDnsOverHttpsEnabled; X509Certificate2 _certificate; - IReadOnlyDictionary _tsigKeys; + IReadOnlyDictionary _tsigKeys; readonly AuthZoneManager _authZoneManager; readonly AllowedZoneManager _allowedZoneManager; @@ -1021,7 +1021,7 @@ namespace DnsServerCore.Dns { LogManager log = _log; if (log is not null) - log.Write(remoteEP, "DNS Server received a request that failed TSIG signature verification (RCODE: " + errorResponse.RCODE + "; TSIG Error: " + errorResponse.TsigError + ")"); + log.Write(remoteEP, protocol, "DNS Server received a request that failed TSIG signature verification (RCODE: " + errorResponse.RCODE + "; TSIG Error: " + errorResponse.TsigError + ")"); errorResponse.Tag = StatsResponseType.Authoritative; return errorResponse; @@ -1099,14 +1099,14 @@ namespace DnsServerCore.Dns } case DnsOpcode.Notify: - return await ProcessNotifyQueryAsync(request, remoteEP); + return await ProcessNotifyQueryAsync(request, remoteEP, protocol); default: return new DnsDatagram(request.Identifier, true, request.OPCODE, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NotImplemented, request.Question) { Tag = StatsResponseType.Authoritative }; } } - private async Task ProcessNotifyQueryAsync(DnsDatagram request, IPEndPoint remoteEP) + private async Task ProcessNotifyQueryAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol) { AuthZoneInfo authZoneInfo = _authZoneManager.GetAuthZoneInfo(request.Question[0].Name); if ((authZoneInfo is null) || (authZoneInfo.Type != AuthZoneType.Secondary) || authZoneInfo.Disabled) @@ -1131,7 +1131,7 @@ namespace DnsServerCore.Dns LogManager log = _log; if (log is not null) - log.Write(remoteEP, "DNS Server received NOTIFY for zone: " + authZoneInfo.Name); + log.Write(remoteEP, protocol, "DNS Server received NOTIFY for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); if ((request.Answer.Count > 0) && (request.Answer[0].Type == DnsResourceRecordType.SOA)) { @@ -1232,7 +1232,7 @@ namespace DnsServerCore.Dns LogManager log = _log; if (log is not null) - log.Write(remoteEP, "DNS Server received zone transfer request for zone: " + authZoneInfo.Name); + log.Write(remoteEP, protocol, "DNS Server received zone transfer request for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); IReadOnlyList xfrRecords; @@ -1392,9 +1392,10 @@ namespace DnsServerCore.Dns List responseAnswer = new List(); responseAnswer.AddRange(response.Answer); - DnsDatagram lastResponse; + DnsDatagram lastResponse = response; bool isAuthoritativeAnswer = response.AuthoritativeAnswer; string lastDomain = (response.Answer[response.Answer.Count - 1].RDATA as DnsCNAMERecord).Domain; + DnsDatagram newResponse; int queryCount = 0; do @@ -1402,14 +1403,14 @@ namespace DnsServerCore.Dns DnsDatagram newRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord(lastDomain, request.Question[0].Type, request.Question[0].Class) }); //query authoritative zone first - lastResponse = _authZoneManager.Query(newRequest, isRecursionAllowed); - if (lastResponse is null) + newResponse = _authZoneManager.Query(newRequest, isRecursionAllowed); + if (newResponse is null) { //not found in auth zone if (newRequest.RecursionDesired && isRecursionAllowed) { //do recursion - lastResponse = await RecursiveResolveAsync(newRequest, null, false, cacheRefreshOperation); + newResponse = await RecursiveResolveAsync(newRequest, null, false, cacheRefreshOperation); isAuthoritativeAnswer = false; } else @@ -1418,38 +1419,38 @@ namespace DnsServerCore.Dns break; } } - else if ((lastResponse.Answer.Count > 0) && (lastResponse.Answer[lastResponse.Answer.Count - 1].Type == DnsResourceRecordType.ANAME)) + else if ((newResponse.Answer.Count > 0) && (newResponse.Answer[newResponse.Answer.Count - 1].Type == DnsResourceRecordType.ANAME)) { - lastResponse = await ProcessANAMEAsync(request, remoteEP, lastResponse, isRecursionAllowed, protocol); + newResponse = await ProcessANAMEAsync(request, remoteEP, newResponse, isRecursionAllowed, protocol); } - else if ((lastResponse.Answer.Count == 0) && (lastResponse.Authority.Count > 0)) + else if ((newResponse.Answer.Count == 0) && (newResponse.Authority.Count > 0)) { //found delegated/forwarded zone - switch (lastResponse.Authority[0].Type) + switch (newResponse.Authority[0].Type) { case DnsResourceRecordType.NS: if (newRequest.RecursionDesired && isRecursionAllowed) { //do forced recursive resolution using empty forwarders; name servers will be provided via ResolveDnsCache - lastResponse = await RecursiveResolveAsync(newRequest, Array.Empty(), false, false); + newResponse = await RecursiveResolveAsync(newRequest, Array.Empty(), false, false); isAuthoritativeAnswer = false; } break; case DnsResourceRecordType.FWD: - if ((lastResponse.Authority.Count == 1) && (lastResponse.Authority[0].RDATA as DnsForwarderRecord).Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase)) + if ((newResponse.Authority.Count == 1) && (newResponse.Authority[0].RDATA as DnsForwarderRecord).Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase)) { //do conditional forwarding via "this-server" - lastResponse = await RecursiveResolveAsync(newRequest, null, false, false); + newResponse = await RecursiveResolveAsync(newRequest, null, false, false); isAuthoritativeAnswer = false; } else { //do conditional forwarding - List forwarders = new List(lastResponse.Authority.Count); + List forwarders = new List(newResponse.Authority.Count); - foreach (DnsResourceRecord rr in lastResponse.Authority) + foreach (DnsResourceRecord rr in newResponse.Authority) { if (rr.Type == DnsResourceRecordType.FWD) { @@ -1463,29 +1464,30 @@ namespace DnsServerCore.Dns if (forwarders.Count < 1) forwarders = null; - lastResponse = await RecursiveResolveAsync(newRequest, forwarders, false, false); + newResponse = await RecursiveResolveAsync(newRequest, forwarders, false, false); isAuthoritativeAnswer = false; } break; case DnsResourceRecordType.APP: - lastResponse = await ProcessAPPAsync(newRequest, remoteEP, lastResponse, isRecursionAllowed, protocol); + newResponse = await ProcessAPPAsync(newRequest, remoteEP, newResponse, isRecursionAllowed, protocol); break; } } //check last response - if (lastResponse.Answer.Count == 0) + if (newResponse.Answer.Count == 0) break; //cannot proceed to resolve further - responseAnswer.AddRange(lastResponse.Answer); + responseAnswer.AddRange(newResponse.Answer); - DnsResourceRecord lastRR = lastResponse.Answer[lastResponse.Answer.Count - 1]; + DnsResourceRecord lastRR = newResponse.Answer[newResponse.Answer.Count - 1]; if (lastRR.Type != DnsResourceRecordType.CNAME) break; //cname was resolved + lastResponse = newResponse; lastDomain = (lastRR.RDATA as DnsCNAMERecord).Domain; } while (++queryCount < MAX_CNAME_HOPS); @@ -1494,25 +1496,29 @@ namespace DnsServerCore.Dns IReadOnlyList authority = null; IReadOnlyList additional = null; - if (lastResponse is null) + if (newResponse is null) { + //no recursion available rcode = DnsResponseCode.NoError; + + authority = lastResponse.Authority; + additional = lastResponse.Additional; } else { - rcode = lastResponse.RCODE; + rcode = newResponse.RCODE; if (isAuthoritativeAnswer) { - authority = response.Authority; - additional = response.Additional; + authority = newResponse.Authority; + additional = newResponse.Additional; } else { - if (lastResponse.Authority.Count > 0) + if (newResponse.Authority.Count > 0) { - if (lastResponse.Authority[0].Type == DnsResourceRecordType.SOA) - authority = lastResponse.Authority; + if (newResponse.Authority[0].Type == DnsResourceRecordType.SOA) + authority = newResponse.Authority; } else { @@ -1521,7 +1527,7 @@ namespace DnsServerCore.Dns case DnsResourceRecordType.NS: case DnsResourceRecordType.MX: case DnsResourceRecordType.SRV: - additional = lastResponse.Additional; + additional = newResponse.Additional; break; } } @@ -2982,7 +2988,7 @@ namespace DnsServerCore.Dns } } - public IReadOnlyDictionary TsigKeys + public IReadOnlyDictionary TsigKeys { get { return _tsigKeys; } set { _tsigKeys = value; }