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)); }
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; }
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); }
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); }
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); }
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); } } }
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() }; }
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())); }