コード例 #1
0
        public override async Task <DnsDatagram> QueryAsync(DnsDatagram request, int timeout, int retries, CancellationToken cancellationToken)
        {
            _lastQueried = DateTime.UtcNow;

            async Task <HttpRequestMessage> GetHttpRequest()
            {
                //serialize request
                byte[] requestBuffer;

                using (MemoryStream mS = new MemoryStream(32))
                {
                    request.WriteTo(mS);
                    requestBuffer = mS.ToArray();
                }

                Uri queryUri;

                if (_proxy == null)
                {
                    if (_server.IsIPEndPointStale)
                    {
                        await _server.RecursiveResolveIPAddressAsync();
                    }

                    queryUri = new Uri(_server.DnsOverHttpEndPoint.Scheme + "://" + _server.IPEndPoint.ToString() + _server.DnsOverHttpEndPoint.PathAndQuery);
                }
                else
                {
                    if (_server.IPEndPoint == null)
                    {
                        queryUri = _server.DnsOverHttpEndPoint;
                    }
                    else
                    {
                        queryUri = new Uri(_server.DnsOverHttpEndPoint.Scheme + "://" + _server.IPEndPoint.ToString() + _server.DnsOverHttpEndPoint.PathAndQuery);
                    }
                }

                HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Post, queryUri);

                httpRequest.Content = new ByteArrayContent(requestBuffer);
                httpRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/dns-message");

                return(httpRequest);
            }

            //DoH wire format request
            Stopwatch stopwatch = new Stopwatch();
            int       retry     = 0;

            while (retry < retries) //retry loop
            {
                retry++;

                if (cancellationToken.IsCancellationRequested)
                {
                    return(await Task.FromCanceled <DnsDatagram>(cancellationToken)); //task cancelled
                }
                stopwatch.Start();

                Task <HttpResponseMessage> task = _httpClient.SendAsync(await GetHttpRequest(), cancellationToken);

                using (CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource())
                {
                    using (CancellationTokenRegistration ctr = cancellationToken.Register(delegate() { timeoutCancellationTokenSource.Cancel(); }))
                    {
                        if (await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token)) != task)
                        {
                            continue; //request timed out; retry
                        }
                    }

                    timeoutCancellationTokenSource.Cancel(); //to stop delay task
                }

                HttpResponseMessage httpResponse = await task;

                stopwatch.Stop();
                httpResponse.EnsureSuccessStatusCode();

                byte[] responseBuffer = await httpResponse.Content.ReadAsByteArrayAsync(cancellationToken);

                //parse response
                using (MemoryStream mS = new MemoryStream(responseBuffer, false))
                {
                    DnsDatagram response = DnsDatagram.ReadFrom(mS);

                    response.SetMetadata(_server, _protocol, stopwatch.Elapsed.TotalMilliseconds);

                    if (response.Identifier != request.Identifier)
                    {
                        throw new DnsClientResponseValidationException("Invalid response was received: query ID mismatch.");
                    }

                    if (response.Question.Count != request.Question.Count)
                    {
                        throw new DnsClientResponseValidationException("Invalid response was received: question count mismatch.");
                    }

                    for (int i = 0; i < response.Question.Count; i++)
                    {
                        if (request.Question[i].ZoneCut == null)
                        {
                            if (!response.Question[i].Name.Equals(request.Question[i].Name, StringComparison.Ordinal))
                            {
                                throw new DnsClientResponseValidationException("Invalid response was received: QNAME mismatch.");
                            }

                            if (response.Question[i].Type != request.Question[i].Type)
                            {
                                throw new DnsClientResponseValidationException("Invalid response was received: QTYPE mismatch.");
                            }
                        }
                        else
                        {
                            if (!response.Question[i].Name.Equals(request.Question[i].MinimizedName, StringComparison.Ordinal))
                            {
                                throw new DnsClientResponseValidationException("Invalid response was received: QNAME mismatch.");
                            }

                            if (response.Question[i].Type != request.Question[i].MinimizedType)
                            {
                                throw new DnsClientResponseValidationException("Invalid response was received: QTYPE mismatch.");
                            }
                        }

                        if (response.Question[i].Class != request.Question[i].Class)
                        {
                            throw new DnsClientResponseValidationException("Invalid response was received: QCLASS mismatch.");
                        }
                    }

                    return(response);
                }
            }

            throw new DnsClientException("DnsClient failed to resolve the request: request timed out.");
        }
コード例 #2
0
        public override async Task <DnsDatagram> QueryAsync(DnsDatagram request, int timeout, int retries, CancellationToken cancellationToken)
        {
            //serialize request
            byte[]       buffer       = new byte[512];
            MemoryStream bufferStream = new MemoryStream(buffer);

            try
            {
                request.WriteTo(bufferStream);
            }
            catch (NotSupportedException)
            {
                throw new DnsClientException("DnsClient cannot send request of more than 512 bytes with UDP protocol.");
            }

            int       bufferSize = (int)bufferStream.Position;
            Stopwatch stopwatch  = new Stopwatch();

            if (_proxy == null)
            {
                if (_server.IsIPEndPointStale)
                {
                    await _server.RecursiveResolveIPAddressAsync();
                }

                using (Socket socket = new Socket(_server.IPEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp))
                {
                    stopwatch.Start();

                    bufferSize = await socket.UdpQueryAsync(new ArraySegment <byte>(buffer, 0, bufferSize), buffer, _server.IPEndPoint, timeout, retries, false, cancellationToken);

                    stopwatch.Stop();
                }
            }
            else
            {
                stopwatch.Start();

                bufferSize = await _proxy.UdpQueryAsync(new ArraySegment <byte>(buffer, 0, bufferSize), buffer, _server.EndPoint, timeout, retries, false, cancellationToken);

                stopwatch.Stop();
            }

            //parse response
            bufferStream.Position = 0;
            bufferStream.SetLength(bufferSize);

            DnsDatagram response = DnsDatagram.ReadFrom(bufferStream);

            response.SetMetadata(_server, _protocol, stopwatch.Elapsed.TotalMilliseconds);

            if (response.Identifier != request.Identifier)
            {
                throw new DnsClientResponseValidationException("Invalid response was received: query ID mismatch.");
            }

            if (response.Question.Count != request.Question.Count)
            {
                throw new DnsClientResponseValidationException("Invalid response was received: question count mismatch.");
            }

            for (int i = 0; i < response.Question.Count; i++)
            {
                if (request.Question[i].ZoneCut == null)
                {
                    if (!response.Question[i].Name.Equals(request.Question[i].Name, StringComparison.Ordinal))
                    {
                        throw new DnsClientResponseValidationException("Invalid response was received: QNAME mismatch.");
                    }

                    if (response.Question[i].Type != request.Question[i].Type)
                    {
                        throw new DnsClientResponseValidationException("Invalid response was received: QTYPE mismatch.");
                    }
                }
                else
                {
                    if (!response.Question[i].Name.Equals(request.Question[i].MinimizedName, StringComparison.Ordinal))
                    {
                        throw new DnsClientResponseValidationException("Invalid response was received: QNAME mismatch.");
                    }

                    if (response.Question[i].Type != request.Question[i].MinimizedType)
                    {
                        throw new DnsClientResponseValidationException("Invalid response was received: QTYPE mismatch.");
                    }
                }

                if (response.Question[i].Class != request.Question[i].Class)
                {
                    throw new DnsClientResponseValidationException("Invalid response was received: QCLASS mismatch.");
                }
            }

            return(response);
        }