public async Task InvokeAsync(HttpContext context) { if (context.Request.Path != _middlewareConfig.Path) { await _next(context); return; } if (context.Request.GetTypedHeaders().Accept.All(x => x.MediaType != DnsMessageType)) { context.Response.StatusCode = (int)HttpStatusCode.UnprocessableEntity; return; } var ms = await context.Request.BodyReader.ReadAsync(context.RequestAborted); var buffer = ms.Buffer.ToArray(); var header = DnsByteExtensions.FromBytes <DnsHeader>(buffer); var answer = await _dnsClient.Query(header, context.RequestAborted); context.Response.Headers.Add("Content-Type", new StringValues(DnsMessageType)); await context.Response.BodyWriter.WriteAsync(DnsByteExtensions.ToBytes(answer), context.RequestAborted); }
/// <inheritdoc/> public async Task <DnsAnswer> Query(DnsHeader query, CancellationToken token = default) { if (_dnsFilter.IsPermitted(query)) { return(await _dnsClient.Query(query, token)); } _logger.LogInformation("DNS query blocked for {Domain}", query.Host); return(new DnsAnswer { Header = CreateNullHeader(query) }); }
/// <inheritdoc/> public async Task <DnsAnswer> Query(DnsHeader query, CancellationToken token) { string cacheKey = GetCacheKey(query); DnsAnswer answer; var cacheEntry = (DnsCacheEntry)_objectCache.Get(cacheKey); if (cacheEntry != null) { _logger.LogTrace("Returned cached DNS result for {Domain} (expires in: {ExpiryTime})", query.Host, cacheEntry.Expires); answer = DnsByteExtensions.FromBytes <DnsAnswer>(cacheEntry.Data); // Replace the ID answer.Header.Id = query.Id; // Adjust the TTLs to be correct foreach (var record in answer.Answers) { record.TimeToLive -= cacheEntry.Age; } return(answer); } answer = await _dnsClient.Query(new DnsHeader { Id = query.Id, Host = query.Host, IsQueryResponse = false, RecusionDesired = query.RecusionDesired, QueryClass = query.QueryClass, QueryType = query.QueryType, QuestionCount = query.QuestionCount }, token); _logger.LogTrace("Returned fresh DNS result for {Domain}", query.Host); if (answer.Answers.Count > 0) { cacheEntry = new DnsCacheEntry(answer); _objectCache.Add(cacheKey, cacheEntry, new CacheItemPolicy { AbsoluteExpiration = cacheEntry.Expiry }); } return(answer); }
public static async Task RunQuery(this IDnsClient client, string host, DnsQueryType queryType, DnsResponseCode expectedResponseCode = DnsResponseCode.NoError) { var query = DnsQueryFactory.CreateQuery(host, queryType); var answer = await client.Query(query); Assert.Equal(host, answer.Header.Host); Assert.Equal(query.Id, answer.Header.Id); Assert.Equal(expectedResponseCode, answer.Header.ResponseCode); if (expectedResponseCode == DnsResponseCode.NoError && !answer.Header.Truncation) { Assert.True(answer.Answers.Count > 0); } else { Assert.Empty(answer.Answers); } }
private async void Respond(UdpReceiveResult query, CancellationToken token) { var stopwatch = Stopwatch.StartNew(); DnsHeader message; try { message = DnsByteExtensions.FromBytes <DnsHeader>(query.Buffer); } catch (Exception e) { _logger.LogCritical(e, "Unable to parse incoming packet: {0}", DnsByteExtensions.ToDebugString(query.Buffer)); return; } DnsAnswer answer; try { answer = await _dnsClient.Query(message, token); } catch (Exception e) { _logger.LogCritical(e, "Unable to resolve {0}", message); return; } var answerBytes = DnsByteExtensions.ToBytes(answer).ToArray(); try { await _listener.SendAsync(answerBytes, answerBytes.Length, query.RemoteEndPoint); } catch (Exception e) { _logger.LogCritical(e, "Unable to send back response to {0}", query.RemoteEndPoint); return; } _logger.LogTrace("Responded to DNS request for {Domain} in {ResponseTime}", message.Host, stopwatch.Elapsed.TotalSeconds); }
/// <inheritdoc/> protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { // Never attempt this with a host that looks like an IP address if (IPAddress.TryParse(request.RequestUri.Host, out _)) { return(await base.SendAsync(request, cancellationToken)); } var originalHostHeader = request.Headers.Host; var originalHost = request.RequestUri.Host; // Make a DNS request for the host var answers = await _dnsClient.Query(DnsQueryFactory.CreateQuery(originalHost, _queryType), cancellationToken); // Pull out the relevant queries var ipResponses = answers.Answers.Where(x => x.Type == _queryType).ToArray(); if (!ipResponses.Any()) { throw new InvalidOperationException($"Unable to resolve {_queryType} records for host {originalHost}"); } // Pick a random IP address var addressResource = (DnsIpAddressResource)ipResponses.OrderBy(x => Guid.NewGuid()).First().Resource; // Set the request data to talk to the IP address directly request.RequestUri = ChangeHost(request.RequestUri, addressResource.IPAddress.ToString()); request.Headers.Host = originalHost; var response = await base.SendAsync(request, cancellationToken); // Restore the original request data request.RequestUri = ChangeHost(request.RequestUri, originalHost); request.Headers.Host = originalHostHeader; return(response); }