Example #1
0
        public void Write(IPEndPoint ep, DnsTransportProtocol protocol, DnsDatagram request, DnsDatagram response)
        {
            DnsQuestionRecord q = null;

            if (request.Header.QDCOUNT > 0)
            {
                q = request.Question[0];
            }

            string question;

            if (q == null)
            {
                question = "MISSING QUESTION!";
            }
            else
            {
                question = "QNAME: " + q.Name + "; QTYPE: " + q.Type.ToString() + "; QCLASS: " + q.Class;
            }

            string responseInfo;

            if (response == null)
            {
                responseInfo = " NO RESPONSE FROM SERVER!";
            }
            else
            {
                string answer;

                if (response.Header.ANCOUNT == 0)
                {
                    answer = "[]";
                }
                else
                {
                    answer = "[";

                    for (int i = 0; i < response.Answer.Length; i++)
                    {
                        if (i != 0)
                        {
                            answer += ", ";
                        }

                        answer += response.Answer[i].RDATA.ToString();
                    }

                    answer += "]";
                }

                responseInfo = " RCODE: " + response.Header.RCODE.ToString() + "; ANSWER: " + answer;
            }

            Write(ep, protocol, question + ";" + responseInfo);
        }
Example #2
0
        private void GetAnswers(dynamic jsonAddresses, DnsQuestionRecord question, uint appRecordTtl, string healthCheck, Uri healthCheckUrl, List <DnsResourceRecord> answers)
        {
            if (jsonAddresses == null)
            {
                return;
            }

            switch (question.Type)
            {
            case DnsResourceRecordType.A:
                foreach (dynamic jsonAddress in jsonAddresses)
                {
                    IPAddress address = IPAddress.Parse(jsonAddress.Value);

                    if (address.AddressFamily == AddressFamily.InterNetwork)
                    {
                        HealthCheckResponse response = _healthService.QueryStatus(address, healthCheck, healthCheckUrl, true);
                        switch (response.Status)
                        {
                        case HealthStatus.Unknown:
                            answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, question.Class, 30, new DnsARecord(address)));
                            break;

                        case HealthStatus.Healthy:
                            answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, question.Class, appRecordTtl, new DnsARecord(address)));
                            break;
                        }
                    }
                }
                break;

            case DnsResourceRecordType.AAAA:
                foreach (dynamic jsonAddress in jsonAddresses)
                {
                    IPAddress address = IPAddress.Parse(jsonAddress.Value);

                    if (address.AddressFamily == AddressFamily.InterNetworkV6)
                    {
                        HealthCheckResponse response = _healthService.QueryStatus(address, healthCheck, healthCheckUrl, true);
                        switch (response.Status)
                        {
                        case HealthStatus.Unknown:
                            answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, question.Class, 30, new DnsAAAARecord(address)));
                            break;

                        case HealthStatus.Healthy:
                            answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, question.Class, appRecordTtl, new DnsAAAARecord(address)));
                            break;
                        }
                    }
                }
                break;
            }
        }
Example #3
0
        public static async Task <StubZone> CreateAsync(DnsServer dnsServer, string name, string primaryNameServerAddresses = null)
        {
            StubZone stubZone = new StubZone(dnsServer, name);

            DnsQuestionRecord soaQuestion = new DnsQuestionRecord(name, DnsResourceRecordType.SOA, DnsClass.IN);
            DnsDatagram       soaResponse;

            if (primaryNameServerAddresses == null)
            {
                soaResponse = await stubZone._dnsServer.DirectQueryAsync(soaQuestion);
            }
            else
            {
                DnsClient dnsClient = new DnsClient(primaryNameServerAddresses);

                foreach (NameServerAddress nameServerAddress in dnsClient.Servers)
                {
                    if (nameServerAddress.IsIPEndPointStale)
                    {
                        await nameServerAddress.ResolveIPAddressAsync(stubZone._dnsServer, stubZone._dnsServer.PreferIPv6);
                    }
                }

                dnsClient.Proxy      = stubZone._dnsServer.Proxy;
                dnsClient.PreferIPv6 = stubZone._dnsServer.PreferIPv6;

                DnsDatagram soaRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, false, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { soaQuestion }, null, null, null, DnsDatagram.EDNS_DEFAULT_UDP_PAYLOAD_SIZE);

                soaResponse = await dnsClient.ResolveAsync(soaRequest);
            }

            if ((soaResponse.Answer.Count == 0) || (soaResponse.Answer[0].Type != DnsResourceRecordType.SOA))
            {
                throw new DnsServerException("DNS Server failed to find SOA record for: " + name);
            }

            DnsSOARecordData receivedSoa = soaResponse.Answer[0].RDATA as DnsSOARecordData;

            DnsSOARecordData soa = new DnsSOARecordData(receivedSoa.PrimaryNameServer, receivedSoa.ResponsiblePerson, 0u, receivedSoa.Refresh, receivedSoa.Retry, receivedSoa.Expire, receivedSoa.Minimum);

            DnsResourceRecord[] soaRR = new DnsResourceRecord[] { new DnsResourceRecord(stubZone._name, DnsResourceRecordType.SOA, DnsClass.IN, soa.Refresh, soa) };

            if (!string.IsNullOrEmpty(primaryNameServerAddresses))
            {
                soaRR[0].SetPrimaryNameServers(primaryNameServerAddresses);
            }

            stubZone._entries[DnsResourceRecordType.SOA] = soaRR;

            stubZone._isExpired    = true; //new stub zone is considered expired till it refreshes
            stubZone._refreshTimer = new Timer(stubZone.RefreshTimerCallback, null, Timeout.Infinite, Timeout.Infinite);

            return(stubZone);
        }
Example #4
0
        private DnsDatagram DnsApplicationQueryClosestDelegation(DnsDatagram request)
        {
            if ((_dnsApplicationManager.DnsAuthoritativeRequestHandlers.Count < 1) || (request.Question.Count != 1))
            {
                return(null);
            }

            IPEndPoint        localEP       = new IPEndPoint(IPAddress.Any, 0);
            DnsQuestionRecord question      = request.Question[0];
            string            currentDomain = question.Name;

            while (true)
            {
                DnsDatagram nsRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord(currentDomain, DnsResourceRecordType.NS, DnsClass.IN) });

                foreach (IDnsAuthoritativeRequestHandler requestHandler in _dnsApplicationManager.DnsAuthoritativeRequestHandlers)
                {
                    try
                    {
                        DnsDatagram nsResponse = requestHandler.ProcessRequestAsync(nsRequest, localEP, DnsTransportProtocol.Tcp, false).Sync();
                        if (nsResponse is not null)
                        {
                            if ((nsResponse.Answer.Count > 0) && (nsResponse.Answer[0].Type == DnsResourceRecordType.NS))
                            {
                                return(new DnsDatagram(request.Identifier, true, nsResponse.OPCODE, nsResponse.AuthoritativeAnswer, nsResponse.Truncation, nsResponse.RecursionDesired, nsResponse.RecursionAvailable, nsResponse.AuthenticData, nsResponse.CheckingDisabled, nsResponse.RCODE, request.Question, null, nsResponse.Answer, nsResponse.Additional));
                            }
                            else if ((nsResponse.Authority.Count > 0) && (nsResponse.FindFirstAuthorityType() == DnsResourceRecordType.NS))
                            {
                                return(new DnsDatagram(request.Identifier, true, nsResponse.OPCODE, nsResponse.AuthoritativeAnswer, nsResponse.Truncation, nsResponse.RecursionDesired, nsResponse.RecursionAvailable, nsResponse.AuthenticData, nsResponse.CheckingDisabled, nsResponse.RCODE, request.Question, null, nsResponse.Authority, nsResponse.Additional));
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        if (_log is not null)
                        {
                            _log.Write(ex);
                        }
                    }
                }

                //get parent domain
                int i = currentDomain.IndexOf('.');
                if (i < 0)
                {
                    break;
                }

                currentDomain = currentDomain.Substring(i + 1);
            }

            return(null);
        }
        public DnsDatagram Query(DnsDatagram request)
        {
            DnsQuestionRecord question = request.Question[0];

            List <Uri> blockLists = IsZoneBlocked(question.Name);

            if (blockLists == null)
            {
                return(null); //zone not blocked
            }
            //zone is blocked
            if (_dnsServer.UseNxDomainForBlocking && (question.Type != DnsResourceRecordType.TXT))
            {
                return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NxDomain, request.Question));
            }

            DnsResourceRecord[] answers   = null;
            DnsResourceRecord[] authority = null;

            switch (question.Type)
            {
            case DnsResourceRecordType.A:
                answers = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.A, question.Class, 60, _aRecord) };
                break;

            case DnsResourceRecordType.AAAA:
                answers = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, question.Class, 60, _aaaaRecord) };
                break;

            case DnsResourceRecordType.NS:
                answers = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.NS, question.Class, 60, _nsRecord) };
                break;

            case DnsResourceRecordType.TXT:
                answers = new DnsResourceRecord[blockLists.Count];

                for (int i = 0; i < answers.Length; i++)
                {
                    answers[i] = new DnsResourceRecord(question.Name, DnsResourceRecordType.TXT, question.Class, 60, new DnsTXTRecord("blockList=" + blockLists[i].AbsoluteUri + "; domain=" + question.Name));
                }

                break;

            default:
                authority = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.SOA, question.Class, 60, _soaRecord) };
                break;
            }

            return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, answers, authority));
        }
Example #6
0
            public bool Matches(DnsQuestionRecord question)
            {
                if ((_name is not null) && !_name.Equals(question.Name, StringComparison.OrdinalIgnoreCase))
                {
                    return(false);
                }

                if ((_type != DnsResourceRecordType.Unknown) && (_type != question.Type))
                {
                    return(false);
                }

                return(true);
            }
Example #7
0
        private void GetAnswers(dynamic jsonAddresses, DnsQuestionRecord question, uint appRecordTtl, string healthCheck, List <DnsResourceRecord> answers)
        {
            if (jsonAddresses == null)
            {
                return;
            }

            switch (question.Type)
            {
            case DnsResourceRecordType.A:
                foreach (dynamic jsonAddress in jsonAddresses)
                {
                    IPAddress address = IPAddress.Parse(jsonAddress.Value);

                    if (address.AddressFamily == AddressFamily.InterNetwork)
                    {
                        HealthCheckStatus status = _healthMonitor.QueryStatus(address, healthCheck, true);
                        if (status is null)
                        {
                            answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, question.Class, 30, new DnsARecord(address)));
                        }
                        else if (status.IsHealthy)
                        {
                            answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, question.Class, appRecordTtl, new DnsARecord(address)));
                        }
                    }
                }
                break;

            case DnsResourceRecordType.AAAA:
                foreach (dynamic jsonAddress in jsonAddresses)
                {
                    IPAddress address = IPAddress.Parse(jsonAddress.Value);

                    if (address.AddressFamily == AddressFamily.InterNetworkV6)
                    {
                        HealthCheckStatus status = _healthMonitor.QueryStatus(address, healthCheck, true);
                        if (status is null)
                        {
                            answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, question.Class, 30, new DnsAAAARecord(address)));
                        }
                        else if (status.IsHealthy)
                        {
                            answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, question.Class, appRecordTtl, new DnsAAAARecord(address)));
                        }
                    }
                }
                break;
            }
        }
Example #8
0
        public Task <DnsRequestControllerAction> GetRequestActionAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol)
        {
            if (!_enableBlocking)
            {
                return(Task.FromResult(DnsRequestControllerAction.Allow));
            }

            if (_dropMalformedRequests && (request.ParsingException is not null))
            {
                return(Task.FromResult(DnsRequestControllerAction.DropSilently));
            }

            IPAddress remoteIp = remoteEP.Address;

            foreach (NetworkAddress allowedNetwork in _allowedNetworks)
            {
                if (allowedNetwork.Contains(remoteIp))
                {
                    return(Task.FromResult(DnsRequestControllerAction.Allow));
                }
            }

            foreach (NetworkAddress blockedNetwork in _blockedNetworks)
            {
                if (blockedNetwork.Contains(remoteIp))
                {
                    return(Task.FromResult(DnsRequestControllerAction.DropSilently));
                }
            }

            if (request.Question.Count != 1)
            {
                return(Task.FromResult(DnsRequestControllerAction.DropSilently));
            }

            DnsQuestionRecord requestQuestion = request.Question[0];

            foreach (BlockedQuestion blockedQuestion in _blockedQuestions)
            {
                if (blockedQuestion.Matches(requestQuestion))
                {
                    return(Task.FromResult(DnsRequestControllerAction.DropSilently));
                }
            }

            return(Task.FromResult(DnsRequestControllerAction.Allow));
        }
Example #9
0
        private void LoadZoneFiles()
        {
            string[] zoneFiles = Directory.GetFiles(ConfigFolder, "*.zone");

            if (zoneFiles.Length == 0)
            {
                {
                    CreateZone("localhost");
                    _dnsServer.AuthoritativeZoneRoot.SetRecords("localhost", DnsResourceRecordType.A, 3600, new DnsResourceRecordData[] { new DnsARecord(IPAddress.Loopback) });
                    _dnsServer.AuthoritativeZoneRoot.SetRecords("localhost", DnsResourceRecordType.AAAA, 3600, new DnsResourceRecordData[] { new DnsAAAARecord(IPAddress.IPv6Loopback) });

                    SaveZoneFile("localhost");
                }

                {
                    string prtDomain = new DnsQuestionRecord(IPAddress.Loopback, DnsClass.IN).Name;

                    CreateZone(prtDomain);
                    _dnsServer.AuthoritativeZoneRoot.SetRecords(prtDomain, DnsResourceRecordType.PTR, 3600, new DnsResourceRecordData[] { new DnsPTRRecord("localhost") });

                    SaveZoneFile(prtDomain);
                }

                {
                    string prtDomain = new DnsQuestionRecord(IPAddress.IPv6Loopback, DnsClass.IN).Name;

                    CreateZone(prtDomain);
                    _dnsServer.AuthoritativeZoneRoot.SetRecords(prtDomain, DnsResourceRecordType.PTR, 3600, new DnsResourceRecordData[] { new DnsPTRRecord("localhost") });

                    SaveZoneFile(prtDomain);
                }
            }
            else
            {
                foreach (string zoneFile in zoneFiles)
                {
                    try
                    {
                        LoadZoneFile(zoneFile);
                    }
                    catch (Exception ex)
                    {
                        _log.Write("Failed to loaded zone file: " + zoneFile + "\r\n" + ex.ToString());
                    }
                }
            }
        }
        public static async Task <SecondaryZone> CreateAsync(DnsServer dnsServer, string name, string primaryNameServerAddresses = null, DnsTransportProtocol zoneTransferProtocol = DnsTransportProtocol.Tcp, string tsigKeyName = null)
        {
            switch (zoneTransferProtocol)
            {
            case DnsTransportProtocol.Tcp:
            case DnsTransportProtocol.Tls:
                break;

            default:
                throw new NotSupportedException("Zone transfer protocol is not supported: XFR-over-" + zoneTransferProtocol.ToString().ToUpper());
            }

            SecondaryZone secondaryZone = new SecondaryZone(dnsServer, name);

            DnsQuestionRecord soaQuestion = new DnsQuestionRecord(name, DnsResourceRecordType.SOA, DnsClass.IN);
            DnsDatagram       soaResponse;

            if (primaryNameServerAddresses == null)
            {
                soaResponse = await secondaryZone._dnsServer.DirectQueryAsync(soaQuestion);
            }
            else
            {
                DnsClient dnsClient = new DnsClient(primaryNameServerAddresses);

                foreach (NameServerAddress nameServerAddress in dnsClient.Servers)
                {
                    if (nameServerAddress.IsIPEndPointStale)
                    {
                        await nameServerAddress.ResolveIPAddressAsync(secondaryZone._dnsServer, secondaryZone._dnsServer.PreferIPv6);
                    }
                }

                dnsClient.Proxy      = secondaryZone._dnsServer.Proxy;
                dnsClient.PreferIPv6 = secondaryZone._dnsServer.PreferIPv6;

                DnsDatagram soaRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, false, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { soaQuestion }, null, null, null, DnsDatagram.EDNS_DEFAULT_UDP_PAYLOAD_SIZE);

                if (string.IsNullOrEmpty(tsigKeyName))
                {
                    soaResponse = await dnsClient.ResolveAsync(soaRequest);
                }
                else if ((dnsServer.TsigKeys is not null) && dnsServer.TsigKeys.TryGetValue(tsigKeyName, out TsigKey key))
                {
                    soaResponse = await dnsClient.ResolveAsync(soaRequest, key, REFRESH_TSIG_FUDGE);
                }
Example #11
0
        public static async Task <StubZone> CreateAsync(DnsServer dnsServer, string name, string primaryNameServerAddresses = null)
        {
            StubZone stubZone = new StubZone(name);

            stubZone._dnsServer = dnsServer;

            DnsQuestionRecord soaQuestion = new DnsQuestionRecord(name, DnsResourceRecordType.SOA, DnsClass.IN);
            DnsDatagram       soaResponse = null;

            if (primaryNameServerAddresses == null)
            {
                soaResponse = await stubZone._dnsServer.DirectQueryAsync(soaQuestion);
            }
            else
            {
                DnsClient dnsClient = new DnsClient(primaryNameServerAddresses);

                dnsClient.Proxy      = stubZone._dnsServer.Proxy;
                dnsClient.PreferIPv6 = stubZone._dnsServer.PreferIPv6;

                soaResponse = await dnsClient.ResolveAsync(soaQuestion);
            }

            if ((soaResponse == null) || (soaResponse.Answer.Count == 0) || (soaResponse.Answer[0].Type != DnsResourceRecordType.SOA))
            {
                throw new DnsServerException("DNS Server failed to find SOA record for: " + name);
            }

            DnsSOARecord receivedSoa = soaResponse.Answer[0].RDATA as DnsSOARecord;

            DnsSOARecord soa = new DnsSOARecord(receivedSoa.PrimaryNameServer, receivedSoa.ResponsiblePerson, receivedSoa.Serial - 1, receivedSoa.Refresh, receivedSoa.Retry, receivedSoa.Expire, receivedSoa.Minimum);

            DnsResourceRecord[] soaRR = new DnsResourceRecord[] { new DnsResourceRecord(stubZone._name, DnsResourceRecordType.SOA, DnsClass.IN, soa.Refresh, soa) };

            if (!string.IsNullOrEmpty(primaryNameServerAddresses))
            {
                soaRR[0].SetGlueRecords(primaryNameServerAddresses);
            }

            stubZone._entries[DnsResourceRecordType.SOA] = soaRR;

            stubZone._isExpired    = true; //new stub zone is considered expired till it refreshes
            stubZone._refreshTimer = new Timer(stubZone.RefreshTimerCallback, null, Timeout.Infinite, Timeout.Infinite);

            return(stubZone);
        }
Example #12
0
        public SecondaryZone(DnsServer dnsServer, string name, string primaryNameServerAddresses = null)
            : base(name)
        {
            _dnsServer = dnsServer;

            DnsQuestionRecord soaQuestion = new DnsQuestionRecord(name, DnsResourceRecordType.SOA, DnsClass.IN);
            DnsDatagram       soaResponse = null;

            if (primaryNameServerAddresses == null)
            {
                soaResponse = _dnsServer.DirectQuery(soaQuestion);
            }
            else
            {
                DnsClient dnsClient = new DnsClient(primaryNameServerAddresses);

                dnsClient.Proxy      = _dnsServer.Proxy;
                dnsClient.PreferIPv6 = _dnsServer.PreferIPv6;
                dnsClient.Retries    = _dnsServer.Retries;
                dnsClient.Timeout    = _dnsServer.Timeout;

                soaResponse = dnsClient.Resolve(soaQuestion);
            }

            if ((soaResponse == null) || (soaResponse.Answer.Count == 0) || (soaResponse.Answer[0].Type != DnsResourceRecordType.SOA))
            {
                throw new DnsServerException("DNS Server failed to find SOA record for: " + name);
            }

            DnsSOARecord receivedSoa = soaResponse.Answer[0].RDATA as DnsSOARecord;

            DnsSOARecord soa = new DnsSOARecord(receivedSoa.PrimaryNameServer, receivedSoa.ResponsiblePerson, receivedSoa.Serial - 1, receivedSoa.Refresh, receivedSoa.Retry, receivedSoa.Expire, receivedSoa.Minimum);

            DnsResourceRecord[] soaRR = new DnsResourceRecord[] { new DnsResourceRecord(_name, DnsResourceRecordType.SOA, DnsClass.IN, soa.Refresh, soa) };

            if (!string.IsNullOrEmpty(primaryNameServerAddresses))
            {
                soaRR[0].SetGlueRecords(primaryNameServerAddresses);
            }

            _entries[DnsResourceRecordType.SOA] = soaRR;

            _isExpired    = true; //new secondary zone is considered expired till it refreshes
            _refreshTimer = new Timer(RefreshTimerCallback, null, Timeout.Infinite, Timeout.Infinite);
        }
Example #13
0
        private void GetStatusAnswers(string domain, bool primary, DnsQuestionRecord question, uint appRecordTtl, string healthCheck, List <DnsResourceRecord> answers)
        {
            {
                HealthCheckStatus status = _healthMonitor.QueryStatus(domain, DnsResourceRecordType.A, healthCheck, false);

                string text = "app=failover; cnameType=" + (primary ? "primary" : "secondary") + "; domain=" + domain + "; qType: A; healthCheck=" + healthCheck;

                if (status is null)
                {
                    text += "; healthStatus=Unknown;";
                }
                else if (status.IsHealthy)
                {
                    text += "; healthStatus=Healthy;";
                }
                else
                {
                    text += "; healthStatus=Failed; failureReason=" + status.FailureReason + ";";
                }

                answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.TXT, question.Class, appRecordTtl, new DnsTXTRecord(text)));
            }

            {
                HealthCheckStatus status = _healthMonitor.QueryStatus(domain, DnsResourceRecordType.AAAA, healthCheck, false);

                string text = "app=failover; cnameType=" + (primary ? "primary" : "secondary") + "; domain=" + domain + "; qType: AAAA; healthCheck=" + healthCheck;

                if (status is null)
                {
                    text += "; healthStatus=Unknown;";
                }
                else if (status.IsHealthy)
                {
                    text += "; healthStatus=Healthy;";
                }
                else
                {
                    text += "; healthStatus=Failed; failureReason=" + status.FailureReason + ";";
                }

                answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.TXT, question.Class, appRecordTtl, new DnsTXTRecord(text)));
            }
        }
Example #14
0
        /// <summary>
        /// Creates a new object initialized with all the log entry parameters.
        /// </summary>
        /// <param name="rowNumber">The row number of the entry in the selected data set.</param>
        /// <param name="timestamp">The time stamp of the log entry.</param>
        /// <param name="clientIpAddress">The client IP address of the request.</param>
        /// <param name="protocol">The DNS transport protocol of the request.</param>
        /// <param name="responseType">The type of response sent by the DNS server.</param>
        /// <param name="rcode">The response code sent by the DNS server.</param>
        /// <param name="question">The question section in the request.</param>
        /// <param name="answer">The answer in text format sent by the DNS server.</param>
        public DnsLogEntry(long rowNumber, DateTime timestamp, IPAddress clientIpAddress, DnsTransportProtocol protocol, DnsServerResponseType responseType, DnsResponseCode rcode, DnsQuestionRecord question, string answer)
        {
            _rowNumber       = rowNumber;
            _timestamp       = timestamp;
            _clientIpAddress = clientIpAddress;
            _protocol        = protocol;
            _responseType    = responseType;
            _rcode           = rcode;
            _question        = question;
            _answer          = answer;

            switch (_timestamp.Kind)
            {
            case DateTimeKind.Local:
                _timestamp = _timestamp.ToUniversalTime();
                break;

            case DateTimeKind.Unspecified:
                _timestamp = DateTime.SpecifyKind(_timestamp, DateTimeKind.Utc);
                break;
            }
        }
Example #15
0
        private void GetStatusAnswers(dynamic jsonAddresses, FailoverType type, DnsQuestionRecord question, uint appRecordTtl, string healthCheck, Uri healthCheckUrl, List <DnsResourceRecord> answers)
        {
            if (jsonAddresses == null)
            {
                return;
            }

            foreach (dynamic jsonAddress in jsonAddresses)
            {
                IPAddress           address  = IPAddress.Parse(jsonAddress.Value);
                HealthCheckResponse response = _healthService.QueryStatus(address, healthCheck, healthCheckUrl, false);

                string text = "app=failover; addressType=" + type.ToString() + "; address=" + address.ToString() + "; healthCheck=" + healthCheck + (healthCheckUrl is null ? "" : "; healthCheckUrl=" + healthCheckUrl.AbsoluteUri) + "; healthStatus=" + response.Status.ToString() + ";";

                if (response.Status == HealthStatus.Failed)
                {
                    text += " failureReason=" + response.FailureReason + ";";
                }

                answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.TXT, question.Class, appRecordTtl, new DnsTXTRecord(text)));
            }
        }
Example #16
0
        public static async Task <SecondaryZone> CreateAsync(DnsServer dnsServer, string name, string primaryNameServerAddresses = null, DnsTransportProtocol zoneTransferProtocol = DnsTransportProtocol.Tcp, string tsigKeyName = null)
        {
            switch (zoneTransferProtocol)
            {
            case DnsTransportProtocol.Tcp:
            case DnsTransportProtocol.Tls:
                break;

            default:
                throw new NotSupportedException("Zone transfer protocol is not supported: XFR-over-" + zoneTransferProtocol.ToString().ToUpper());
            }

            SecondaryZone secondaryZone = new SecondaryZone(dnsServer, name);

            DnsQuestionRecord soaQuestion = new DnsQuestionRecord(name, DnsResourceRecordType.SOA, DnsClass.IN);
            DnsDatagram       soaResponse;

            if (primaryNameServerAddresses == null)
            {
                soaResponse = await secondaryZone._dnsServer.DirectQueryAsync(soaQuestion).WithTimeout(2000);
            }
            else
            {
                DnsClient dnsClient = new DnsClient(primaryNameServerAddresses);

                dnsClient.Proxy      = secondaryZone._dnsServer.Proxy;
                dnsClient.PreferIPv6 = secondaryZone._dnsServer.PreferIPv6;

                if (string.IsNullOrEmpty(tsigKeyName))
                {
                    soaResponse = await dnsClient.ResolveAsync(soaQuestion);
                }
                else if ((dnsServer.TsigKeys is not null) && dnsServer.TsigKeys.TryGetValue(tsigKeyName, out TsigKey key))
                {
                    soaResponse = await dnsClient.ResolveAsync(soaQuestion, key, REFRESH_TSIG_FUDGE);
                }
Example #17
0
 public Task <DnsDatagram> DirectQueryAsync(DnsQuestionRecord question, int timeout = 2000)
 {
     return(_dnsServer.DirectQueryAsync(question, timeout));
 }
Example #18
0
 public Task <DnsDatagram> ResolveAsync(DnsQuestionRecord question)
 {
     return(_dnsServer.DirectQueryAsync(question));
 }
 public Task <DnsDatagram> ResolveAsync(DnsQuestionRecord question, CancellationToken cancellationToken = default)
 {
     return(_dnsServer.DirectQueryAsync(question));
 }
Example #20
0
        public Task <DnsDatagram> ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, string zoneName, uint appRecordTtl, string appRecordData, bool isRecursionAllowed, IDnsServer dnsServer)
        {
            DnsQuestionRecord question = request.Question[0];

            dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData);

            string healthCheck = jsonAppRecordData.healthCheck?.Value;

            IReadOnlyList <DnsResourceRecord> answers;

            if (question.Type == DnsResourceRecordType.TXT)
            {
                bool allowTxtStatus;

                if (jsonAppRecordData.allowTxtStatus == null)
                {
                    allowTxtStatus = false;
                }
                else
                {
                    allowTxtStatus = jsonAppRecordData.allowTxtStatus.Value;
                }

                if (!allowTxtStatus)
                {
                    return(Task.FromResult <DnsDatagram>(null));
                }

                List <DnsResourceRecord> txtAnswers = new List <DnsResourceRecord>();

                GetStatusAnswers(jsonAppRecordData.primary.Value, true, question, 30, healthCheck, txtAnswers);

                foreach (dynamic jsonDomain in jsonAppRecordData.secondary)
                {
                    GetStatusAnswers(jsonDomain.Value, false, question, 30, healthCheck, txtAnswers);
                }

                answers = txtAnswers;
            }
            else
            {
                answers = GetAnswers(jsonAppRecordData.primary.Value, question, zoneName, appRecordTtl, healthCheck);
                if (answers is null)
                {
                    foreach (dynamic jsonDomain in jsonAppRecordData.secondary)
                    {
                        answers = GetAnswers(jsonDomain.Value, question, zoneName, appRecordTtl, healthCheck);
                        if (answers is not null)
                        {
                            break;
                        }
                    }

                    if (answers is null)
                    {
                        return(Task.FromResult <DnsDatagram>(null));
                    }
                }
            }

            return(Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)));
        }
Example #21
0
        public Task <DnsDatagram> ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, string zoneName, uint appRecordTtl, string appRecordData)
        {
            DnsQuestionRecord question = request.Question[0];

            switch (question.Type)
            {
            case DnsResourceRecordType.A:
            case DnsResourceRecordType.AAAA:
            {
                dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData);

                string healthCheck    = jsonAppRecordData.healthCheck?.Value;
                Uri    healthCheckUrl = null;

                if (_healthService.HealthChecks.TryGetValue(healthCheck, out HealthCheck hc) && ((hc.Type == HealthCheckType.Https) || (hc.Type == HealthCheckType.Http)) && (hc.Url is null))
                {
                    //read health check url only for http/https type checks and only when app config does not have an url configured
                    if ((jsonAppRecordData.healthCheckUrl is not null) && (jsonAppRecordData.healthCheckUrl.Value is not null))
                    {
                        healthCheckUrl = new Uri(jsonAppRecordData.healthCheckUrl.Value);
                    }
                    else
                    {
                        if (hc.Type == HealthCheckType.Https)
                        {
                            healthCheckUrl = new Uri("https://" + question.Name);
                        }
                        else
                        {
                            healthCheckUrl = new Uri("http://" + question.Name);
                        }
                    }
                }

                List <DnsResourceRecord> answers = new List <DnsResourceRecord>();

                GetAnswers(jsonAppRecordData.primary, question, appRecordTtl, healthCheck, healthCheckUrl, answers);
                if (answers.Count == 0)
                {
                    GetAnswers(jsonAppRecordData.secondary, question, appRecordTtl, healthCheck, healthCheckUrl, answers);
                    if (answers.Count == 0)
                    {
                        if (jsonAppRecordData.serverDown is not null)
                        {
                            if (question.Type == DnsResourceRecordType.A)
                            {
                                foreach (dynamic jsonAddress in jsonAppRecordData.serverDown)
                                {
                                    IPAddress address = IPAddress.Parse(jsonAddress.Value);

                                    if (address.AddressFamily == AddressFamily.InterNetwork)
                                    {
                                        answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, question.Class, 30, new DnsARecord(address)));
                                    }
                                }
                            }
                            else
                            {
                                foreach (dynamic jsonAddress in jsonAppRecordData.serverDown)
                                {
                                    IPAddress address = IPAddress.Parse(jsonAddress.Value);

                                    if (address.AddressFamily == AddressFamily.InterNetworkV6)
                                    {
                                        answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, question.Class, 30, new DnsAAAARecord(address)));
                                    }
                                }
                            }
                        }

                        if (answers.Count == 0)
                        {
                            return(Task.FromResult <DnsDatagram>(null));
                        }
                    }
                }

                if (answers.Count > 1)
                {
                    answers.Shuffle();
                }

                return(Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)));
            }
Example #22
0
 public ResolverPrefetchDnsCache(AuthZoneManager authZoneManager, CacheZoneManager cacheZoneManager, DnsQuestionRecord prefetchQuery)
     : base(authZoneManager, cacheZoneManager)
 {
     _prefetchQuery = prefetchQuery;
 }
Example #23
0
        public Task <DnsDatagram> ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, string zoneName, uint appRecordTtl, string appRecordData, bool isRecursionAllowed, IDnsServer dnsServer)
        {
            DnsQuestionRecord question = request.Question[0];

            switch (question.Type)
            {
            case DnsResourceRecordType.A:
            case DnsResourceRecordType.AAAA:
            {
                dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData);

                string healthCheck = jsonAppRecordData.healthCheck?.Value;

                List <DnsResourceRecord> answers = new List <DnsResourceRecord>();

                GetAnswers(jsonAppRecordData.primary, question, appRecordTtl, healthCheck, answers);
                if (answers.Count == 0)
                {
                    GetAnswers(jsonAppRecordData.secondary, question, appRecordTtl, healthCheck, answers);
                    if (answers.Count == 0)
                    {
                        return(Task.FromResult <DnsDatagram>(null));
                    }
                }

                if (answers.Count > 1)
                {
                    answers.Shuffle();
                }

                return(Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)));
            }

            case DnsResourceRecordType.TXT:
            {
                dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData);

                bool allowTxtStatus;

                if (jsonAppRecordData.allowTxtStatus == null)
                {
                    allowTxtStatus = false;
                }
                else
                {
                    allowTxtStatus = jsonAppRecordData.allowTxtStatus.Value;
                }

                if (!allowTxtStatus)
                {
                    return(Task.FromResult <DnsDatagram>(null));
                }

                string healthCheck = jsonAppRecordData.healthCheck?.Value;

                List <DnsResourceRecord> answers = new List <DnsResourceRecord>();

                GetStatusAnswers(jsonAppRecordData.primary, true, question, 30, healthCheck, answers);
                GetStatusAnswers(jsonAppRecordData.secondary, false, question, 30, healthCheck, answers);

                return(Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)));
            }

            default:
                return(Task.FromResult <DnsDatagram>(null));
            }
        }
Example #24
0
        public void LoadAllZoneFiles()
        {
            _root.Clear();

            string zonesFolder = Path.Combine(_dnsServer.ConfigFolder, "zones");

            if (!Directory.Exists(zonesFolder))
            {
                Directory.CreateDirectory(zonesFolder);
            }

            //move zone files to new folder
            {
                string[] oldZoneFiles = Directory.GetFiles(_dnsServer.ConfigFolder, "*.zone");

                foreach (string oldZoneFile in oldZoneFiles)
                {
                    File.Move(oldZoneFile, Path.Combine(zonesFolder, Path.GetFileName(oldZoneFile)));
                }
            }

            //remove old internal zones
            {
                string[] oldZoneFiles = new string[] { "localhost.zone", "1.0.0.127.in-addr.arpa.zone", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.zone" };

                foreach (string oldZoneFile in oldZoneFiles)
                {
                    string filePath = Path.Combine(zonesFolder, oldZoneFile);

                    if (File.Exists(filePath))
                    {
                        try
                        {
                            File.Delete(filePath);
                        }
                        catch
                        { }
                    }
                }
            }

            //load system zones
            {
                {
                    CreatePrimaryZone("localhost", _dnsServer.ServerDomain, true);
                    SetRecords("localhost", DnsResourceRecordType.A, 3600, new DnsResourceRecordData[] { new DnsARecord(IPAddress.Loopback) });
                    SetRecords("localhost", DnsResourceRecordType.AAAA, 3600, new DnsResourceRecordData[] { new DnsAAAARecord(IPAddress.IPv6Loopback) });
                }

                {
                    string prtDomain = "0.in-addr.arpa";

                    CreatePrimaryZone(prtDomain, _dnsServer.ServerDomain, true);
                }

                {
                    string prtDomain = "255.in-addr.arpa";

                    CreatePrimaryZone(prtDomain, _dnsServer.ServerDomain, true);
                }

                {
                    string prtDomain = "127.in-addr.arpa";

                    CreatePrimaryZone(prtDomain, _dnsServer.ServerDomain, true);
                    SetRecords("1.0.0.127.in-addr.arpa", DnsResourceRecordType.PTR, 3600, new DnsResourceRecordData[] { new DnsPTRRecord("localhost") });
                }

                {
                    string prtDomain = new DnsQuestionRecord(IPAddress.IPv6Loopback, DnsClass.IN).Name;

                    CreatePrimaryZone(prtDomain, _dnsServer.ServerDomain, true);
                    SetRecords(prtDomain, DnsResourceRecordType.PTR, 3600, new DnsResourceRecordData[] { new DnsPTRRecord("localhost") });
                }
            }

            //load zone files
            string[] zoneFiles = Directory.GetFiles(zonesFolder, "*.zone");

            foreach (string zoneFile in zoneFiles)
            {
                try
                {
                    using (FileStream fS = new FileStream(zoneFile, FileMode.Open, FileAccess.Read))
                    {
                        LoadZoneFrom(fS);
                    }

                    LogManager log = _dnsServer.LogManager;
                    if (log != null)
                    {
                        log.Write("DNS Server successfully loaded zone file: " + zoneFile);
                    }
                }
                catch (Exception ex)
                {
                    LogManager log = _dnsServer.LogManager;
                    if (log != null)
                    {
                        log.Write("DNS Server failed to load zone file: " + zoneFile + "\r\n" + ex.ToString());
                    }
                }
            }
        }
Example #25
0
        private void BulkInsertLogs()
        {
            try
            {
                List <LogEntry> logs = new List <LogEntry>(BULK_INSERT_COUNT);

                while (true)
                {
                    while ((logs.Count < BULK_INSERT_COUNT) && _queuedLogs.TryDequeue(out LogEntry log))
                    {
                        logs.Add(log);
                    }

                    if (logs.Count < 1)
                    {
                        break;
                    }

                    using (SqliteConnection connection = new SqliteConnection(_connectionString))
                    {
                        connection.Open();

                        using (SqliteTransaction transaction = connection.BeginTransaction())
                        {
                            using (SqliteCommand command = connection.CreateCommand())
                            {
                                command.CommandText = "INSERT INTO dns_logs (timestamp, client_ip, protocol, response_type, rcode, qname, qtype, qclass, answer) VALUES (@timestamp, @client_ip, @protocol, @response_type, @rcode, @qname, @qtype, @qclass, @answer);";

                                SqliteParameter paramTimestamp    = command.Parameters.Add("@timestamp", SqliteType.Text);
                                SqliteParameter paramClientIp     = command.Parameters.Add("@client_ip", SqliteType.Text);
                                SqliteParameter paramProtocol     = command.Parameters.Add("@protocol", SqliteType.Integer);
                                SqliteParameter paramResponseType = command.Parameters.Add("@response_type", SqliteType.Integer);
                                SqliteParameter paramRcode        = command.Parameters.Add("@rcode", SqliteType.Integer);
                                SqliteParameter paramQname        = command.Parameters.Add("@qname", SqliteType.Text);
                                SqliteParameter paramQtype        = command.Parameters.Add("@qtype", SqliteType.Integer);
                                SqliteParameter paramQclass       = command.Parameters.Add("@qclass", SqliteType.Integer);
                                SqliteParameter paramAnswer       = command.Parameters.Add("@answer", SqliteType.Text);

                                foreach (LogEntry log in logs)
                                {
                                    paramTimestamp.Value = log.Timestamp.ToString("yyyy-MM-dd HH:mm:ss.FFFFFFF");
                                    paramClientIp.Value  = log.RemoteEP.Address.ToString();
                                    paramProtocol.Value  = (int)log.Protocol;

                                    if (log.Response.Tag == null)
                                    {
                                        paramResponseType.Value = (int)DnsServerResponseType.Recursive;
                                    }
                                    else
                                    {
                                        paramResponseType.Value = (int)(DnsServerResponseType)log.Response.Tag;
                                    }

                                    paramRcode.Value = (int)log.Response.RCODE;

                                    if (log.Request.Question.Count > 0)
                                    {
                                        DnsQuestionRecord query = log.Request.Question[0];

                                        paramQname.Value  = query.Name.ToLower();
                                        paramQtype.Value  = (int)query.Type;
                                        paramQclass.Value = (int)query.Class;
                                    }
                                    else
                                    {
                                        paramQname.Value  = DBNull.Value;
                                        paramQtype.Value  = DBNull.Value;
                                        paramQclass.Value = DBNull.Value;
                                    }

                                    if (log.Response.Answer.Count == 0)
                                    {
                                        paramAnswer.Value = DBNull.Value;
                                    }
                                    else if ((log.Response.Answer.Count > 2) && log.Response.IsZoneTransfer)
                                    {
                                        paramAnswer.Value = "[ZONE TRANSFER]";
                                    }
                                    else
                                    {
                                        string answer = null;

                                        for (int i = 0; i < log.Response.Answer.Count; i++)
                                        {
                                            if (answer is null)
                                            {
                                                answer = log.Response.Answer[i].RDATA.ToString();
                                            }
                                            else
                                            {
                                                answer += ", " + log.Response.Answer[i].RDATA.ToString();
                                            }
                                        }

                                        paramAnswer.Value = answer;
                                    }

                                    command.ExecuteNonQuery();
                                }

                                transaction.Commit();
                            }
                        }
                    }

                    logs.Clear();
                }
            }
            catch (Exception ex)
            {
                if (_dnsServer is not null)
                {
                    _dnsServer.WriteLog(ex);
                }
            }
        }
Example #26
0
        public Task <DnsLogPage> QueryLogsAsync(long pageNumber, int entriesPerPage, bool descendingOrder, DateTime?start, DateTime?end, IPAddress clientIpAddress, DnsTransportProtocol?protocol, DnsServerResponseType?responseType, DnsResponseCode?rcode, string qname, DnsResourceRecordType?qtype, DnsClass?qclass)
        {
            if (pageNumber < 0)
            {
                pageNumber = long.MaxValue;
            }
            else if (pageNumber == 0)
            {
                pageNumber = 1;
            }

            if (qname is not null)
            {
                qname = qname.ToLower();
            }

            string whereClause = string.Empty;

            if (start is not null)
            {
                whereClause += "timestamp >= @start AND ";
            }

            if (end is not null)
            {
                whereClause += "timestamp <= @end AND ";
            }

            if (clientIpAddress is not null)
            {
                whereClause += "client_ip = @client_ip AND ";
            }

            if (protocol is not null)
            {
                whereClause += "protocol = @protocol AND ";
            }

            if (responseType is not null)
            {
                whereClause += "response_type = @response_type AND ";
            }

            if (rcode is not null)
            {
                whereClause += "rcode = @rcode AND ";
            }

            if (qname is not null)
            {
                whereClause += "qname = @qname AND ";
            }

            if (qtype is not null)
            {
                whereClause += "qtype = @qtype AND ";
            }

            if (qclass is not null)
            {
                whereClause += "qclass = @qclass AND ";
            }

            if (!string.IsNullOrEmpty(whereClause))
            {
                whereClause = whereClause.Substring(0, whereClause.Length - 5);
            }

            using (SqliteConnection connection = new SqliteConnection(_connectionString))
            {
                connection.Open();

                //find total entries
                long totalEntries;

                using (SqliteCommand command = connection.CreateCommand())
                {
                    command.CommandText = "SELECT Count(*) FROM dns_logs" + (string.IsNullOrEmpty(whereClause) ? ";" : " WHERE " + whereClause + ";");

                    if (start is not null)
                    {
                        command.Parameters.AddWithValue("@start", start);
                    }

                    if (end is not null)
                    {
                        command.Parameters.AddWithValue("@end", end);
                    }

                    if (clientIpAddress is not null)
                    {
                        command.Parameters.AddWithValue("@client_ip", clientIpAddress.ToString());
                    }

                    if (protocol is not null)
                    {
                        command.Parameters.AddWithValue("@protocol", (byte)protocol);
                    }

                    if (responseType is not null)
                    {
                        command.Parameters.AddWithValue("@response_type", (byte)responseType);
                    }

                    if (rcode is not null)
                    {
                        command.Parameters.AddWithValue("@rcode", (byte)rcode);
                    }

                    if (qname is not null)
                    {
                        command.Parameters.AddWithValue("@qname", qname);
                    }

                    if (qtype is not null)
                    {
                        command.Parameters.AddWithValue("@qtype", (ushort)qtype);
                    }

                    if (qclass is not null)
                    {
                        command.Parameters.AddWithValue("@qclass", (ushort)qclass);
                    }

                    totalEntries = (long)command.ExecuteScalar();
                }

                long totalPages = (totalEntries / entriesPerPage) + (totalEntries % entriesPerPage > 0 ? 1 : 0);

                if (pageNumber > totalPages)
                {
                    pageNumber = totalPages;
                }

                long endRowNum;
                long startRowNum;

                if (descendingOrder)
                {
                    endRowNum   = totalEntries - ((pageNumber - 1) * entriesPerPage);
                    startRowNum = endRowNum - entriesPerPage;
                }
                else
                {
                    endRowNum   = pageNumber * entriesPerPage;
                    startRowNum = endRowNum - entriesPerPage;
                }

                List <DnsLogEntry> entries = new List <DnsLogEntry>(entriesPerPage);

                using (SqliteCommand command = connection.CreateCommand())
                {
                    command.CommandText = @"
SELECT * FROM (
    SELECT
        ROW_NUMBER() OVER ( 
            ORDER BY timestamp
        ) row_num,
        timestamp,
        client_ip,
        protocol,
        response_type,
        rcode,
        qname,
        qtype,
        qclass,
        answer
    FROM
        dns_logs
" + (string.IsNullOrEmpty(whereClause) ? "" : "WHERE " + whereClause) + @"
    ORDER BY row_num" + (descendingOrder ? " DESC" : "") + @"
) t
WHERE 
    row_num > @start_row_num AND row_num <= @end_row_num
";

                    command.Parameters.AddWithValue("@start_row_num", startRowNum);
                    command.Parameters.AddWithValue("@end_row_num", endRowNum);

                    if (start is not null)
                    {
                        command.Parameters.AddWithValue("@start", start);
                    }

                    if (end is not null)
                    {
                        command.Parameters.AddWithValue("@end", end);
                    }

                    if (clientIpAddress is not null)
                    {
                        command.Parameters.AddWithValue("@client_ip", clientIpAddress.ToString());
                    }

                    if (protocol is not null)
                    {
                        command.Parameters.AddWithValue("@protocol", (byte)protocol);
                    }

                    if (responseType is not null)
                    {
                        command.Parameters.AddWithValue("@response_type", (byte)responseType);
                    }

                    if (rcode is not null)
                    {
                        command.Parameters.AddWithValue("@rcode", (byte)rcode);
                    }

                    if (qname is not null)
                    {
                        command.Parameters.AddWithValue("@qname", qname);
                    }

                    if (qtype is not null)
                    {
                        command.Parameters.AddWithValue("@qtype", (ushort)qtype);
                    }

                    if (qclass is not null)
                    {
                        command.Parameters.AddWithValue("@qclass", (ushort)qclass);
                    }

                    using (SqliteDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            DnsQuestionRecord question;

                            if (reader.IsDBNull(6))
                            {
                                question = null;
                            }
                            else
                            {
                                question = new DnsQuestionRecord(reader.GetString(6), (DnsResourceRecordType)reader.GetInt32(7), (DnsClass)reader.GetInt32(8));
                            }

                            string answer;

                            if (reader.IsDBNull(9))
                            {
                                answer = null;
                            }
                            else
                            {
                                answer = reader.GetString(9);
                            }

                            entries.Add(new DnsLogEntry(reader.GetInt64(0), reader.GetDateTime(1), IPAddress.Parse(reader.GetString(2)), (DnsTransportProtocol)reader.GetByte(3), (DnsServerResponseType)reader.GetByte(4), (DnsResponseCode)reader.GetByte(5), question, answer));
                        }
                    }
                }

                return(Task.FromResult(new DnsLogPage(pageNumber, totalPages, totalEntries, entries)));
            }
        }
Example #27
0
        public void Write(IPEndPoint ep, DnsTransportProtocol protocol, DnsDatagram request, DnsDatagram response)
        {
            DnsQuestionRecord q = null;

            if (request.Question.Count > 0)
            {
                q = request.Question[0];
            }

            string question;

            if (q is null)
            {
                question = "MISSING QUESTION!";
            }
            else
            {
                question = "QNAME: " + q.Name + "; QTYPE: " + q.Type.ToString() + "; QCLASS: " + q.Class;
            }

            string responseInfo;

            if (response is null)
            {
                responseInfo = " NO RESPONSE FROM SERVER!";
            }
            else
            {
                string answer;

                if (response.Answer.Count == 0)
                {
                    answer = "[]";
                }
                else if ((response.Answer.Count > 2) && response.IsZoneTransfer)
                {
                    answer = "[ZONE TRANSFER]";
                }
                else
                {
                    answer = "[";

                    for (int i = 0; i < response.Answer.Count; i++)
                    {
                        if (i > 0)
                        {
                            answer += ", ";
                        }

                        answer += response.Answer[i].RDATA.ToString();
                    }

                    answer += "]";

                    if (response.Additional.Count > 0)
                    {
                        switch (q.Type)
                        {
                        case DnsResourceRecordType.NS:
                        case DnsResourceRecordType.MX:
                        case DnsResourceRecordType.SRV:
                            answer += "; ADDITIONAL: [";

                            for (int i = 0; i < response.Additional.Count; i++)
                            {
                                DnsResourceRecord additional = response.Additional[i];

                                switch (additional.Type)
                                {
                                case DnsResourceRecordType.A:
                                case DnsResourceRecordType.AAAA:
                                    if (i > 0)
                                    {
                                        answer += ", ";
                                    }

                                    answer += additional.Name + " (" + additional.RDATA.ToString() + ")";
                                    break;
                                }
                            }

                            answer += "]";
                            break;
                        }
                    }
                }

                responseInfo = " RCODE: " + response.RCODE.ToString() + "; ANSWER: " + answer;
            }

            Write(ep, protocol, question + ";" + responseInfo);
        }
Example #28
0
        public void Configure(IApplicationBuilder app, IHostEnvironment env)
        {
            int staticFilesCachePeriod;

            if (env.IsDevelopment())
            {
                staticFilesCachePeriod = 60;
                app.UseDeveloperExceptionPage();
            }
            else
            {
                staticFilesCachePeriod = 14400;
            }

            app.UseDefaultFiles();
            app.UseStaticFiles(new StaticFileOptions()
            {
                OnPrepareResponse = delegate(StaticFileResponseContext ctx)
                {
                    ctx.Context.Response.Headers.Append("Cache-Control", $"public, max-age={staticFilesCachePeriod}");
                }
            });

            app.Run(async(context) =>
            {
                HttpRequest request   = context.Request;
                HttpResponse response = context.Response;

                if (request.Path == "/api/dnsclient/")
                {
                    try
                    {
                        string server = request.Query["server"];
                        string domain = request.Query["domain"];
                        DnsResourceRecordType type = (DnsResourceRecordType)Enum.Parse(typeof(DnsResourceRecordType), request.Query["type"], true);

                        domain = domain.Trim();

                        if (domain.EndsWith("."))
                        {
                            domain = domain.Substring(0, domain.Length - 1);
                        }

                        bool preferIpv6        = Configuration.GetValue <bool>("PreferIpv6");
                        bool randomizeName     = false;
                        bool qnameMinimization = false;
                        int retries            = Configuration.GetValue <int>("Retries");
                        int timeout            = Configuration.GetValue <int>("Timeout");

                        DnsDatagram dnsResponse;

                        if (server == "recursive-resolver")
                        {
                            DnsQuestionRecord question;

                            if ((type == DnsResourceRecordType.PTR) && IPAddress.TryParse(domain, out IPAddress address))
                            {
                                question = new DnsQuestionRecord(address, DnsClass.IN);
                            }
                            else
                            {
                                question = new DnsQuestionRecord(domain, type, DnsClass.IN);
                            }

                            dnsResponse = await DnsClient.RecursiveResolveAsync(question, null, null, preferIpv6, randomizeName, qnameMinimization, retries, timeout);
                        }
                        else
                        {
                            DnsTransportProtocol protocol = (DnsTransportProtocol)Enum.Parse(typeof(DnsTransportProtocol), request.Query["protocol"], true);

                            if ((protocol == DnsTransportProtocol.Tls) && !server.Contains(":853"))
                            {
                                server += ":853";
                            }

                            NameServerAddress nameServer = new NameServerAddress(server, protocol);

                            if (nameServer.IPEndPoint == null)
                            {
                                await nameServer.ResolveIPAddressAsync(null, null, preferIpv6);
                            }
                            else if (nameServer.DomainEndPoint == null)
                            {
                                try
                                {
                                    await nameServer.ResolveDomainNameAsync(null, null, preferIpv6);
                                }
                                catch
                                { }
                            }

                            DnsClient dnsClient = new DnsClient(nameServer);

                            dnsClient.PreferIPv6    = preferIpv6;
                            dnsClient.RandomizeName = randomizeName;
                            dnsClient.Retries       = retries;
                            dnsClient.Timeout       = timeout;

                            dnsResponse = await dnsClient.ResolveAsync(domain, type);
                        }

                        string jsonResponse = JsonConvert.SerializeObject(dnsResponse, new StringEnumConverter());

                        response.Headers.Add("Content-Type", "application/json; charset=utf-8");
                        await response.WriteAsync("{\"status\":\"ok\", \"response\":" + jsonResponse + "}");
                    }
                    catch (Exception ex)
                    {
                        string jsonResponse = JsonConvert.SerializeObject(ex);

                        response.Headers.Add("Content-Type", "application/json; charset=utf-8");
                        await response.WriteAsync("{\"status\":\"error\", \"response\":" + jsonResponse + "}");
                    }
                }
            });
        }
Example #29
0
        public Task <DnsDatagram> ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, string zoneName, uint appRecordTtl, string appRecordData)
        {
            DnsQuestionRecord question = request.Question[0];

            switch (question.Type)
            {
            case DnsResourceRecordType.A:
            case DnsResourceRecordType.AAAA:
                dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData);
                dynamic jsonCountry;

                if (_maxMind.DatabaseReader.TryCountry(remoteEP.Address, out CountryResponse response))
                {
                    jsonCountry = jsonAppRecordData[response.Country.IsoCode];
                    if (jsonCountry == null)
                    {
                        jsonCountry = jsonAppRecordData["default"];
                    }
                }
                else
                {
                    jsonCountry = jsonAppRecordData["default"];
                }

                if (jsonCountry == null)
                {
                    return(Task.FromResult <DnsDatagram>(null));
                }

                List <DnsResourceRecord> answers = new List <DnsResourceRecord>();

                switch (question.Type)
                {
                case DnsResourceRecordType.A:
                    foreach (dynamic jsonAddress in jsonCountry)
                    {
                        IPAddress address = IPAddress.Parse(jsonAddress.Value);

                        if (address.AddressFamily == AddressFamily.InterNetwork)
                        {
                            answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, DnsClass.IN, appRecordTtl, new DnsARecordData(address)));
                        }
                    }
                    break;

                case DnsResourceRecordType.AAAA:
                    foreach (dynamic jsonAddress in jsonCountry)
                    {
                        IPAddress address = IPAddress.Parse(jsonAddress.Value);

                        if (address.AddressFamily == AddressFamily.InterNetworkV6)
                        {
                            answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, DnsClass.IN, appRecordTtl, new DnsAAAARecordData(address)));
                        }
                    }
                    break;
                }

                if (answers.Count == 0)
                {
                    return(Task.FromResult <DnsDatagram>(null));
                }

                if (answers.Count > 1)
                {
                    answers.Shuffle();
                }

                return(Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)));

            default:
                return(Task.FromResult <DnsDatagram>(null));
            }
        }
Example #30
0
        public DnsDatagram Query(DnsDatagram request)
        {
            DnsQuestionRecord question = request.Question[0];

            List <Uri> blockLists = IsZoneBlocked(question.Name, out string blockedDomain);

            if (blockLists is null)
            {
                return(null); //zone not blocked
            }
            //zone is blocked
            if (_dnsServer.AllowTxtBlockingReport && (question.Type == DnsResourceRecordType.TXT))
            {
                //return meta data
                DnsResourceRecord[] answer = new DnsResourceRecord[blockLists.Count];

                for (int i = 0; i < answer.Length; i++)
                {
                    answer[i] = new DnsResourceRecord(question.Name, DnsResourceRecordType.TXT, question.Class, 60, new DnsTXTRecord("source=block-list-zone; blockListUrl=" + blockLists[i].AbsoluteUri + "; domain=" + blockedDomain));
                }

                return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, answer));
            }
            else
            {
                IReadOnlyCollection <DnsARecord>    aRecords;
                IReadOnlyCollection <DnsAAAARecord> aaaaRecords;

                switch (_dnsServer.BlockingType)
                {
                case DnsServerBlockingType.AnyAddress:
                    aRecords    = _aRecords;
                    aaaaRecords = _aaaaRecords;
                    break;

                case DnsServerBlockingType.CustomAddress:
                    aRecords    = _dnsServer.CustomBlockingARecords;
                    aaaaRecords = _dnsServer.CustomBlockingAAAARecords;
                    break;

                case DnsServerBlockingType.NxDomain:
                    string parentDomain = GetParentZone(blockedDomain);
                    if (parentDomain is null)
                    {
                        parentDomain = string.Empty;
                    }

                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NxDomain, request.Question, null, new DnsResourceRecord[] { new DnsResourceRecord(parentDomain, DnsResourceRecordType.SOA, question.Class, 60, _soaRecord) }));

                default:
                    throw new InvalidOperationException();
                }

                IReadOnlyList <DnsResourceRecord> answer    = null;
                IReadOnlyList <DnsResourceRecord> authority = null;

                switch (question.Type)
                {
                case DnsResourceRecordType.A:
                {
                    List <DnsResourceRecord> rrList = new List <DnsResourceRecord>(aRecords.Count);

                    foreach (DnsARecord record in aRecords)
                    {
                        rrList.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, question.Class, 60, record));
                    }

                    answer = rrList;
                }
                break;

                case DnsResourceRecordType.AAAA:
                {
                    List <DnsResourceRecord> rrList = new List <DnsResourceRecord>(aaaaRecords.Count);

                    foreach (DnsAAAARecord record in aaaaRecords)
                    {
                        rrList.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, question.Class, 60, record));
                    }

                    answer = rrList;
                }
                break;

                case DnsResourceRecordType.NS:
                    if (question.Name.Equals(blockedDomain, StringComparison.OrdinalIgnoreCase))
                    {
                        answer = new DnsResourceRecord[] { new DnsResourceRecord(blockedDomain, DnsResourceRecordType.NS, question.Class, 60, _nsRecord) }
                    }
                    ;
                    else
                    {
                        authority = new DnsResourceRecord[] { new DnsResourceRecord(blockedDomain, DnsResourceRecordType.SOA, question.Class, 60, _soaRecord) }
                    };

                    break;

                default:
                    authority = new DnsResourceRecord[] { new DnsResourceRecord(blockedDomain, DnsResourceRecordType.SOA, question.Class, 60, _soaRecord) };
                    break;
                }

                return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, answer, authority));
            }
        }