Exemple #1
0
        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);
        }
Exemple #2
0
        /// <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);
        }
Exemple #4
0
        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);
            }
        }
Exemple #5
0
        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);
        }