Example #1
0
        protected TMessage SendMessage <TMessage>(TMessage message)
            where TMessage : DnsMessageBase, new()
        {
            int messageLength;

            byte[] messageData;
            DnsServer.SelectTsigKey tsigKeySelector;
            byte[] tsigOriginalMac;

            PrepareMessage(message, out messageLength, out messageData, out tsigKeySelector, out tsigOriginalMac);

            bool sendByTcp = ((messageLength > MaximumQueryMessageSize) || message.IsTcpUsingRequested || !IsUdpEnabled);

            var endpointInfos = GetEndpointInfos();

            for (int i = 0; i < endpointInfos.Count; i++)
            {
                var              endpointInfo = endpointInfos[i];
                TcpClient        tcpClient    = null;
                System.IO.Stream tcpStream    = null;

                string reusableMapKey = string.Concat(endpointInfo.ServerAddress, endpointInfo.ServerPort);
                if (sendByTcp && this.IsReuseTcpEnabled)
                {
                    if (!this.reusableTcp.ContainsKey(reusableMapKey))
                    {
                        this.reusableTcp[reusableMapKey] = new ReusableTcpConnection();
                    }

                    ReusableTcpConnection reuse = this.reusableTcp[reusableMapKey];
                    tcpClient = reuse.Client;
                    tcpStream = reuse.Stream;
                    this.reusableTcp[reusableMapKey].LastUsed = DateTime.UtcNow;
                }

                try
                {
                    IPAddress responderAddress;
                    int       responderPort = 0;
                    byte[]    resultData    = sendByTcp ? QueryByTcp(endpointInfo.ServerAddress, endpointInfo.ServerPort, messageData, messageLength, ref tcpClient, ref tcpStream, out responderAddress, out responderPort) : QueryByUdp(endpointInfo, messageData, messageLength, out responderAddress);

                    if (resultData != null)
                    {
                        TMessage result;

                        try
                        {
                            result = DnsMessageBase.Parse <TMessage>(resultData, tsigKeySelector, tsigOriginalMac);
                        }
                        catch (Exception e)
                        {
                            Trace.TraceError("Error on dns query: " + e);
                            continue;
                        }

                        if (!ValidateResponse(message, result))
                        {
                            continue;
                        }

                        if ((result.ReturnCode == ReturnCode.ServerFailure) && (i != endpointInfos.Count - 1))
                        {
                            continue;
                        }

                        if (result.IsTcpResendingRequested)
                        {
                            resultData = QueryByTcp(responderAddress, responderPort, messageData, messageLength, ref tcpClient, ref tcpStream, out responderAddress, out responderPort);
                            if (resultData != null)
                            {
                                TMessage tcpResult;

                                try
                                {
                                    tcpResult = DnsMessageBase.Parse <TMessage>(resultData, tsigKeySelector, tsigOriginalMac);
                                }
                                catch (Exception e)
                                {
                                    Trace.TraceError("Error on dns query: " + e);
                                    continue;
                                }

                                if (tcpResult.ReturnCode == ReturnCode.ServerFailure)
                                {
                                    if (i != endpointInfos.Count - 1)
                                    {
                                        continue;
                                    }
                                }
                                else
                                {
                                    result = tcpResult;
                                }
                            }
                        }

                        bool isTcpNextMessageWaiting = result.IsTcpNextMessageWaiting(false);
                        bool isSucessfullFinished    = true;

                        while (isTcpNextMessageWaiting)
                        {
                            resultData = QueryByTcp(responderAddress, responderPort, null, 0, ref tcpClient, ref tcpStream, out responderAddress, out responderPort);
                            if (resultData != null)
                            {
                                TMessage tcpResult;

                                try
                                {
                                    tcpResult = DnsMessageBase.Parse <TMessage>(resultData, tsigKeySelector, tsigOriginalMac);
                                }
                                catch (Exception e)
                                {
                                    Trace.TraceError("Error on dns query: " + e);
                                    isSucessfullFinished = false;
                                    break;
                                }

                                if (tcpResult.ReturnCode == ReturnCode.ServerFailure)
                                {
                                    isSucessfullFinished = false;
                                    break;
                                }
                                else
                                {
                                    result.AnswerRecords.AddRange(tcpResult.AnswerRecords);
                                    isTcpNextMessageWaiting = tcpResult.IsTcpNextMessageWaiting(true);
                                }
                            }
                            else
                            {
                                isSucessfullFinished = false;
                                break;
                            }
                        }

                        if (isSucessfullFinished)
                        {
                            return(result);
                        }
                    }
                }
                finally
                {
                    try
                    {
                        if (sendByTcp && this.IsReuseTcpEnabled)
                        {
                            if (this.reusableTcp[reusableMapKey].Client == null || !ReferenceEquals(this.reusableTcp[reusableMapKey].Client, tcpClient))
                            {
                                this.reusableTcp[reusableMapKey].Client = tcpClient;
                                this.reusableTcp[reusableMapKey].Stream = tcpStream;
                            }
                        }
                        else
                        {
                            tcpStream?.Dispose();
                            tcpClient?.Close();
                        }
                    }
                    catch
                    {
                        // ignored
                    }
                }
            }

            return(null);
        }
Example #2
0
        protected virtual async Task <QueryResponse> QueryByTcpAsync(IPAddress nameServer, int port, byte[] messageData, int messageLength, TcpClient tcpClient, System.IO.Stream tcpStream, CancellationToken token)
        {
            if (!IsTcpEnabled)
            {
                return(null);
            }

            string reusableMapKey = string.Concat(nameServer, port);

            if (tcpClient == null && this.IsReuseTcpEnabled)
            {
                if (!this.reusableTcp.ContainsKey(reusableMapKey))
                {
                    this.reusableTcp[reusableMapKey] = new ReusableTcpConnection();
                }

                ReusableTcpConnection reuse = this.reusableTcp[reusableMapKey];
                tcpClient = reuse.Client;
                tcpStream = reuse.Stream;
                this.reusableTcp[reusableMapKey].LastUsed = DateTime.UtcNow;
            }

            int responderPort = port == 0 ? _port : port;

            try
            {
                if (tcpClient == null || (this.IsReuseTcpEnabled && !tcpClient.IsConnected()))
                {
                    tcpClient = new TcpClient(nameServer.AddressFamily)
                    {
                        ReceiveTimeout = QueryTimeout,
                        SendTimeout    = QueryTimeout
                    };

                    if (!await tcpClient.TryConnectAsync(nameServer, responderPort, QueryTimeout, token))
                    {
                        if (this.IsReuseTcpEnabled)
                        {
                            try
                            {
                                tcpClient.Close();
                            }
                            catch (Exception)
                            {
                            }
                        }

                        return(null);
                    }

                    tcpStream = tcpClient.GetStream();
                }

                int    tmp          = 0;
                byte[] lengthBuffer = new byte[2];

                if (messageLength > 0)
                {
                    DnsMessageBase.EncodeUShort(lengthBuffer, ref tmp, (ushort)messageLength);

                    await tcpStream.WriteAsync(lengthBuffer, 0, 2, token);

                    await tcpStream.WriteAsync(messageData, 0, messageLength, token);
                }

                if (!await TryReadAsync(tcpClient, tcpStream, lengthBuffer, 2, token))
                {
                    return(null);
                }

                tmp = 0;
                int length = DnsMessageBase.ParseUShort(lengthBuffer, ref tmp);

                byte[] resultData = new byte[length];

                return(await TryReadAsync(tcpClient, tcpStream, resultData, length, token) ? new QueryResponse(resultData, nameServer, tcpClient, tcpStream, responderPort) : null);
            }
            catch (Exception e)
            {
                Trace.TraceError("Error on dns query: " + e);
                return(null);
            }
        }
Example #3
0
        protected async override Task <QueryResponse> QueryByTcpAsync(IPAddress nameServer, int port, byte[] messageData, int messageLength, TcpClient tcpClient, System.IO.Stream tlsStream, CancellationToken token)
        {
            if (!IsTcpEnabled)
            {
                return(null);
            }
            int responderPort = port == 0 ? _port : port;

            TlsUpstreamServer tlsServer = _tlsservers.Where(t => t.IPAddress == nameServer && t.Port == responderPort).FirstOrDefault();

            if (tlsServer == null)
            {
                Trace.TraceError("Error on dns query: invalid TLS upstream server");
                return(null);
            }

            string reusableMapKey = string.Concat(nameServer, port);

            if (tcpClient == null && this.IsReuseTcpEnabled)
            {
                if (!this.reusableTcp.ContainsKey(reusableMapKey))
                {
                    this.reusableTcp[reusableMapKey] = new ReusableTcpConnection();
                }

                ReusableTcpConnection reuse = this.reusableTcp[reusableMapKey];
                tcpClient = reuse.Client;
                tlsStream = reuse.Stream;
                this.reusableTcp[reusableMapKey].LastUsed = DateTime.UtcNow;
            }

            try
            {
                if (tcpClient == null || (this.IsReuseTcpEnabled && !tcpClient.IsConnected()))
                {
                    tcpClient = new TcpClient(nameServer.AddressFamily)
                    {
                        ReceiveTimeout = QueryTimeout,
                        SendTimeout    = QueryTimeout
                    };

                    if (!await tcpClient.TryConnectAsync(nameServer, responderPort, QueryTimeout, token))
                    {
                        return(null);
                    }

                    SslStream sslStream = new SslStream(tcpClient.GetStream(), true, new RemoteCertificateValidationCallback(tlsServer.ValidateRemoteCertificate));
                    tlsStream = sslStream;
                    try
                    {
                        sslStream.AuthenticateAsClient(tlsServer.AuthName ?? string.Empty, new X509CertificateCollection(), tlsServer.SslProtocols, false);
                    }
                    catch (Exception)
                    {
                    }

                    if (!sslStream.IsAuthenticated)
                    {
                        Trace.TraceError("Error on dns query: invalid TLS upstream server certificate");
                        if (this.IsReuseTcpEnabled)
                        {
                            try
                            {
                                tlsStream.Dispose();
                                tcpClient.Close();
                            }
                            catch (Exception)
                            {
                            }
                        }

                        return(null);
                    }
                }

                int    tmp          = 0;
                byte[] lengthBuffer = new byte[2];

                if (messageLength > 0)
                {
                    DnsMessageBase.EncodeUShort(lengthBuffer, ref tmp, (ushort)messageLength);

                    await tlsStream.WriteAsync(lengthBuffer, 0, 2, token);

                    await tlsStream.WriteAsync(messageData, 0, messageLength, token);
                }

                if (!await TryReadAsync(tcpClient, tlsStream, lengthBuffer, 2, token))
                {
                    return(null);
                }

                tmp = 0;
                int length = DnsMessageBase.ParseUShort(lengthBuffer, ref tmp);

                byte[] resultData = new byte[length];

                return(await TryReadAsync(tcpClient, tlsStream, resultData, length, token) ? new QueryResponse(resultData, nameServer, tcpClient, tlsStream, responderPort) : null);
            }
            catch (Exception e)
            {
                Trace.TraceError("Error on dns query: " + e);
                return(null);
            }
        }