internal DnsQueryResponse(DnsResponseMessage dnsResponseMessage, NameServer nameServer, LookupClientAudit audit)
 {
     if (dnsResponseMessage == null)
     {
         throw new ArgumentNullException(nameof(dnsResponseMessage));
     }
     Header      = dnsResponseMessage.Header;
     MessageSize = dnsResponseMessage.MessageSize;
     Questions   = dnsResponseMessage.Questions.ToArray();
     Answers     = dnsResponseMessage.Answers.ToArray();
     Additionals = dnsResponseMessage.Additionals.ToArray();
     Authorities = dnsResponseMessage.Authorities.ToArray();
     NameServer  = nameServer ?? throw new ArgumentNullException(nameof(nameServer));
     Audit       = audit ?? throw new ArgumentNullException(nameof(audit));
 }
Example #2
0
 internal DnsQueryResponse(DnsResponseMessage dnsResponseMessage, NameServer nameServer, DnsQuerySettings settings)
 {
     if (dnsResponseMessage == null)
     {
         throw new ArgumentNullException(nameof(dnsResponseMessage));
     }
     Header      = dnsResponseMessage.Header;
     MessageSize = dnsResponseMessage.MessageSize;
     Questions   = dnsResponseMessage.Questions.ToArray();
     Answers     = dnsResponseMessage.Answers.ToArray();
     Additionals = dnsResponseMessage.Additionals.ToArray();
     Authorities = dnsResponseMessage.Authorities.ToArray();
     NameServer  = nameServer ?? throw new ArgumentNullException(nameof(nameServer));
     Settings    = settings;
 }
Example #3
0
        public override async Task <DnsResponseMessage> QueryAsync(
            IPEndPoint server,
            DnsRequestMessage request,
            CancellationToken cancellationToken,
            Action <Action> cancelationCallback)
        {
            cancellationToken.ThrowIfCancellationRequested();

            ClientPool pool;

            ClientPool.ClientEntry entry = null;
            while (!_pools.TryGetValue(server, out pool))
            {
                _pools.TryAdd(server, new ClientPool(true, server));
            }

            cancelationCallback(() =>
            {
                if (entry == null)
                {
                    return;
                }
                entry.DisposeClient();
            });

            DnsResponseMessage response = null;

            while (response == null)
            {
                entry = await pool.GetNexClient().ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();

                response = await QueryAsyncInternal(entry.Client, entry.Client.GetStream(), request, cancellationToken)
                           .ConfigureAwait(false);

                if (response != null)
                {
                    pool.Enqueue(entry);
                }
                else
                {
                    entry.DisposeClient();
                }
            }

            return(response);
        }
Example #4
0
        public virtual DnsResponseMessage GetResponseMessage(ArraySegment <byte> responseData)
        {
            var reader  = new DnsDatagramReader(responseData);
            var factory = new DnsRecordFactory(reader);

            var id              = reader.ReadUInt16NetworkOrder();
            var flags           = reader.ReadUInt16NetworkOrder();
            var questionCount   = reader.ReadUInt16NetworkOrder();
            var answerCount     = reader.ReadUInt16NetworkOrder();
            var nameServerCount = reader.ReadUInt16NetworkOrder();
            var additionalCount = reader.ReadUInt16NetworkOrder();

            var header   = new DnsResponseHeader(id, flags, questionCount, answerCount, additionalCount, nameServerCount);
            var response = new DnsResponseMessage(header, responseData.Count);

            for (int questionIndex = 0; questionIndex < questionCount; questionIndex++)
            {
                var question = new DnsQuestion(reader.ReadQuestionQueryString(), (QueryType)reader.ReadUInt16NetworkOrder(), (QueryClass)reader.ReadUInt16NetworkOrder());
                response.AddQuestion(question);
            }

            for (int answerIndex = 0; answerIndex < answerCount; answerIndex++)
            {
                var info   = factory.ReadRecordInfo();
                var record = factory.GetRecord(info);
                response.AddAnswer(record);
            }

            for (int serverIndex = 0; serverIndex < nameServerCount; serverIndex++)
            {
                var info   = factory.ReadRecordInfo();
                var record = factory.GetRecord(info);
                response.AddAuthority(record);
            }

            for (int additionalIndex = 0; additionalIndex < additionalCount; additionalIndex++)
            {
                var info   = factory.ReadRecordInfo();
                var record = factory.GetRecord(info);
                response.AddAdditional(record);
            }

            return(response);
        }
Example #5
0
            public IDnsQueryResponse GetResponse()
            {
                var elapsed = Elapsed();

                if (elapsed <= 0)
                {
                    return(_response);
                }

                var response = new DnsResponseMessage(_response.Header, _response.MessageSize)
                {
                    Audit = (_response as DnsQueryResponse)?.Audit ?? new LookupClientAudit()
                };

                foreach (var record in _response.Questions)
                {
                    response.AddQuestion(record);
                }

                foreach (var record in _response.Answers)
                {
                    var clone = record.Clone();
                    clone.TimeToLive = clone.TimeToLive - elapsed;
                    response.AddAnswer(clone);
                }

                foreach (var record in _response.Additionals)
                {
                    var clone = record.Clone();
                    clone.TimeToLive = clone.TimeToLive - elapsed;
                    response.AddAnswer(clone);
                }

                foreach (var record in _response.Authorities)
                {
                    var clone = record.Clone();
                    clone.TimeToLive = clone.TimeToLive - elapsed;
                    response.AddAnswer(clone);
                }

                var qr = response.AsQueryResponse(_response.NameServer);

                return(qr);
            }
Example #6
0
        private void HandleOptRecords(Audit audit, NameServer serverInfo, DnsResponseMessage response)
        {
            var opt = response.Additionals.OfType <OptRecord>().FirstOrDefault();

            if (opt != null)
            {
                if (EnableAuditTrail)
                {
                    audit.AuditOptPseudo();
                }

                serverInfo.SupportedUdpPayloadSize = opt.UdpSize;

                // TODO: handle opt records and remove them later
                response.Additionals.Remove(opt);

                if (EnableAuditTrail)
                {
                    audit.AuditEdnsOpt(opt.UdpSize, opt.Version, opt.ResponseCodeEx);
                }
            }
        }
Example #7
0
        private IDnsQueryResponse ResolveQuery(DnsMessageHandler handler, DnsRequestMessage request, Audit continueAudit = null)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var audit   = continueAudit ?? new Audit();
            var servers = GetNextServers();

            foreach (var serverInfo in servers)
            {
                var tries = 0;
                do
                {
                    tries++;

                    try
                    {
                        if (EnableAuditTrail)
                        {
                            audit.StartTimer();
                        }

                        DnsResponseMessage response = handler.Query(serverInfo.Endpoint, request, Timeout);

                        if (response.Header.ResultTruncated && UseTcpFallback && !handler.GetType().Equals(typeof(DnsTcpMessageHandler)))
                        {
                            if (EnableAuditTrail)
                            {
                                audit.AuditTruncatedRetryTcp();
                            }

                            return(ResolveQuery(_tcpFallbackHandler, request, audit));
                        }

                        if (EnableAuditTrail)
                        {
                            audit.AuditResolveServers(_endpoints.Count);
                            audit.AuditResponseHeader(response.Header);
                        }

                        if (response.Header.ResponseCode != DnsResponseCode.NoError)
                        {
                            if (EnableAuditTrail)
                            {
                                audit.AuditResponseError(response.Header.ResponseCode);
                            }

                            if (ThrowDnsErrors)
                            {
                                throw new DnsResponseException(response.Header.ResponseCode);
                            }
                        }

                        HandleOptRecords(audit, serverInfo, response);

                        DnsQueryResponse queryResponse = response.AsQueryResponse(serverInfo.Clone());

                        if (EnableAuditTrail)
                        {
                            audit.AuditResponse(queryResponse);
                            audit.AuditEnd(queryResponse);
                            queryResponse.AuditTrail = audit.Build();
                        }

                        Interlocked.Increment(ref StaticLog.ResolveQueryCount);
                        Interlocked.Add(ref StaticLog.ResolveQueryTries, tries);
                        return(queryResponse);
                    }
                    catch (DnsResponseException ex)
                    {
                        audit.AuditException(ex);
                        ex.AuditTrail = audit.Build();
                        throw;
                    }
                    catch (SocketException ex) when(ex.SocketErrorCode == SocketError.AddressFamilyNotSupported)
                    {
                        // this socket error might indicate the server endpoint is actually bad and should be ignored in future queries.
                        DisableServer(serverInfo);
                        break;
                    }
                    catch (Exception ex) when(ex is TimeoutException || handler.IsTransientException(ex))
                    {
                        DisableServer(serverInfo);
                    }
                    catch (Exception ex)
                    {
                        DisableServer(serverInfo);

                        if (ex is OperationCanceledException || ex is TaskCanceledException)
                        {
                            // timeout
                            continue;
                        }

                        audit.AuditException(ex);

                        throw new DnsResponseException(DnsResponseCode.Unassigned, "Unhandled exception", ex)
                              {
                                  AuditTrail = audit.Build()
                              };
                    }
                } while (tries <= Retries && serverInfo.Enabled);
            }
            throw new DnsResponseException(DnsResponseCode.ConnectionTimeout, $"No connection could be established to any of the following name servers: {string.Join(", ", NameServers)}.")
                  {
                      AuditTrail = audit.Build()
                  };
        }
Example #8
0
        private async Task <DnsResponseMessage> QueryAsyncInternal(TcpClient client, NetworkStream stream, DnsRequestMessage request, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            // use a pooled buffer to writer the data + the length of the data later into the frist two bytes
            using (var memory = new PooledBytes(DnsDatagramWriter.BufferSize + 2))
                using (var writer = new DnsDatagramWriter(new ArraySegment <byte>(memory.Buffer, 2, memory.Buffer.Length - 2)))
                {
                    GetRequestData(request, writer);
                    int dataLength = writer.Index;
                    memory.Buffer[0] = (byte)((dataLength >> 8) & 0xff);
                    memory.Buffer[1] = (byte)(dataLength & 0xff);

                    //await client.Client.SendAsync(new ArraySegment<byte>(memory.Buffer, 0, dataLength + 2), SocketFlags.None).ConfigureAwait(false);
                    await stream.WriteAsync(memory.Buffer, 0, dataLength + 2, cancellationToken).ConfigureAwait(false);

                    await stream.FlushAsync(cancellationToken).ConfigureAwait(false);
                }

            if (!stream.CanRead)
            {
                return(null);
            }

            cancellationToken.ThrowIfCancellationRequested();

            var responses = new List <DnsResponseMessage>();

            do
            {
                int length = 0;
                try
                {
                    length = stream.ReadByte() << 8 | stream.ReadByte();
                }
                catch (Exception ex) when(ex is IOException || ex is SocketException)
                {
                    break;
                }

                if (length <= 0)
                {
                    // server signals close/disconnecting
                    break;
                }

                using (var memory = new PooledBytes(length))
                {
                    int bytesReceived = 0;
                    int readSize      = length > 4096 ? 4096 : length;

                    while (!cancellationToken.IsCancellationRequested && (bytesReceived += await stream.ReadAsync(memory.Buffer, bytesReceived, readSize).ConfigureAwait(false)) < length)
                    {
                        if (bytesReceived <= 0)
                        {
                            // disconnected
                            return(null);
                        }
                        if (bytesReceived + readSize > length)
                        {
                            readSize = length - bytesReceived;

                            if (readSize <= 0)
                            {
                                break;
                            }
                        }
                    }

                    DnsResponseMessage response = GetResponseMessage(new ArraySegment <byte>(memory.Buffer, 0, bytesReceived));
                    if (request.Header.Id != response.Header.Id)
                    {
                        throw new DnsResponseException("Header id mismatch.");
                    }

                    responses.Add(response);
                }
            } while (stream.DataAvailable && !cancellationToken.IsCancellationRequested);

            return(DnsResponseMessage.Combine(responses.ToArray()));
        }