Beispiel #1
0
        private void EndUdpReceive(IAsyncResult ar)
        {
            try
            {
                lock (_udpListener)
                {
                    _hasActiveUdpListener = false;
                }
                StartUdpListen();

                IPEndPoint endpoint;

                byte[] buffer = _udpListener.EndReceive(ar, out endpoint);

                DnsMessageBase query;
                byte[]         originalMac;
                try
                {
                    query       = DnsMessageBase.CreateByFlag(buffer, TsigKeySelector, null);
                    originalMac = (query.TSigOptions == null) ? null : query.TSigOptions.Mac;
                }
                catch (Exception e)
                {
                    throw new Exception("Error parsing dns query", e);
                }

                DnsMessageBase response;
                try
                {
                    response = ProcessMessage(query, endpoint.Address, ProtocolType.Udp);
                }
                catch (Exception ex)
                {
                    OnExceptionThrown(ex);
                    response = null;
                }

                if (response == null)
                {
                    response         = query;
                    query.IsQuery    = false;
                    query.ReturnCode = ReturnCode.ServerFailure;
                }

                int length = response.Encode(false, originalMac, out buffer);

                #region Truncating
                DnsMessage message = response as DnsMessage;

                if (message != null)
                {
                    int maxLength = 512;
                    if (query.IsEDnsEnabled && message.IsEDnsEnabled)
                    {
                        maxLength = Math.Max(512, (int)message.EDnsOptions.UdpPayloadSize);
                    }

                    while (length > maxLength)
                    {
                        // First step: remove data from additional records except the opt record
                        if ((message.IsEDnsEnabled && (message.AdditionalRecords.Count > 1)) || (!message.IsEDnsEnabled && (message.AdditionalRecords.Count > 0)))
                        {
                            for (int i = message.AdditionalRecords.Count - 1; i >= 0; i--)
                            {
                                if (message.AdditionalRecords[i].RecordType != RecordType.Opt)
                                {
                                    message.AdditionalRecords.RemoveAt(i);
                                }
                            }

                            length = message.Encode(false, originalMac, out buffer);
                            continue;
                        }

                        int savedLength = 0;
                        if (message.AuthorityRecords.Count > 0)
                        {
                            for (int i = message.AuthorityRecords.Count - 1; i >= 0; i--)
                            {
                                savedLength += message.AuthorityRecords[i].MaximumLength;
                                message.AuthorityRecords.RemoveAt(i);

                                if ((length - savedLength) < maxLength)
                                {
                                    break;
                                }
                            }

                            message.IsTruncated = true;

                            length = message.Encode(false, originalMac, out buffer);
                            continue;
                        }

                        if (message.AnswerRecords.Count > 0)
                        {
                            for (int i = message.AnswerRecords.Count - 1; i >= 0; i--)
                            {
                                savedLength += message.AnswerRecords[i].MaximumLength;
                                message.AnswerRecords.RemoveAt(i);

                                if ((length - savedLength) < maxLength)
                                {
                                    break;
                                }
                            }

                            message.IsTruncated = true;

                            length = message.Encode(false, originalMac, out buffer);
                            continue;
                        }

                        if (message.Questions.Count > 0)
                        {
                            for (int i = message.Questions.Count - 1; i >= 0; i--)
                            {
                                savedLength += message.Questions[i].MaximumLength;
                                message.Questions.RemoveAt(i);

                                if ((length - savedLength) < maxLength)
                                {
                                    break;
                                }
                            }

                            message.IsTruncated = true;

                            length = message.Encode(false, originalMac, out buffer);
                        }
                    }
                }
                #endregion

                _udpListener.BeginSend(buffer, 0, length, endpoint, EndUdpSend, null);
            }
            catch (Exception e)
            {
                HandleUdpException(e);
            }
        }
Beispiel #2
0
        private void UdpReceiveCompleted <TMessage>(IAsyncResult ar)
            where TMessage : DnsMessageBase, new()
        {
            DnsClientAsyncState <TMessage> state = (DnsClientAsyncState <TMessage>)ar.AsyncState;

            if (state.Timer != null)
            {
                state.Timer.Dispose();
            }

            if (state.TimedOut)
            {
                state.EndpointInfoIndex++;
                UdpBeginSend(state);
            }
            else
            {
                try
                {
                    int    length       = state.UdpClient.EndReceiveFrom(ar, ref state.UdpEndpoint);
                    byte[] responseData = new byte[length];
                    Buffer.BlockCopy(state.Buffer, 0, responseData, 0, length);

                    TMessage response = DnsMessageBase.Parse <TMessage>(responseData, state.TSigKeySelector, state.TSigOriginalMac);

                    if (AreMultipleResponsesAllowedInParallelMode)
                    {
                        if (ValidateResponse(state.Query, response))
                        {
                            if (response.IsTcpResendingRequested)
                            {
                                TcpBeginConnect <TMessage>(state.CreateTcpCloneWithoutCallback(), ((IPEndPoint)state.UdpEndpoint).Address);
                            }
                            else
                            {
                                state.Responses.Add(response);
                            }
                        }

                        state.Buffer = new byte[65535];

                        if (state.EndpointInfos[state.EndpointInfoIndex].IsMulticast)
                        {
                            state.UdpEndpoint = new IPEndPoint(state.UdpClient.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, _port);
                        }

                        IAsyncResult asyncResult = state.UdpClient.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.UdpEndpoint, UdpReceiveCompleted <TMessage>, state);
                        state.Timer = new Timer(UdpTimedOut <TMessage>, asyncResult, state.TimeRemaining, Timeout.Infinite);
                    }
                    else
                    {
                        state.UdpClient.Close();
                        state.UdpClient   = null;
                        state.UdpEndpoint = null;

                        if (!ValidateResponse(state.Query, response) || (response.ReturnCode == ReturnCode.ServerFailure))
                        {
                            state.EndpointInfoIndex++;
                            UdpBeginSend(state);
                        }
                        else
                        {
                            if (response.IsTcpResendingRequested)
                            {
                                TcpBeginConnect <TMessage>(state, ((IPEndPoint)state.UdpEndpoint).Address);
                            }
                            else
                            {
                                state.Responses.Add(response);
                                state.SetCompleted();
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Trace.TraceError("Error on dns query: " + e);

                    try
                    {
                        state.UdpClient.Close();
                        state.Timer.Dispose();
                    }
                    catch { }

                    state.EndpointInfoIndex++;
                    UdpBeginSend(state);
                }
            }
        }
Beispiel #3
0
        private void TcpReceiveCompleted <TMessage>(IAsyncResult ar)
            where TMessage : DnsMessageBase, new()
        {
            DnsClientAsyncState <TMessage> state = (DnsClientAsyncState <TMessage>)ar.AsyncState;

            if (state.Timer != null)
            {
                state.Timer.Dispose();
            }

            if (state.TimedOut)
            {
                state.EndpointInfoIndex++;
                TcpBeginConnect(state);
            }
            else
            {
                try
                {
                    state.TcpBytesToReceive -= state.TcpStream.EndRead(ar);

                    if (state.TcpBytesToReceive > 0)
                    {
                        IAsyncResult asyncResult = state.TcpStream.BeginRead(state.Buffer, state.Buffer.Length - state.TcpBytesToReceive, state.TcpBytesToReceive, TcpReceiveCompleted <TMessage>, state);
                        state.Timer = new Timer(TcpTimedOut <TMessage>, asyncResult, state.TimeRemaining, Timeout.Infinite);
                    }
                    else
                    {
                        byte[] buffer = state.Buffer;
                        state.Buffer = null;

                        TMessage response = DnsMessageBase.Parse <TMessage>(buffer, state.TSigKeySelector, state.TSigOriginalMac);

                        if (!ValidateResponse(state.Query, response) || (response.ReturnCode == ReturnCode.ServerFailure))
                        {
                            state.EndpointInfoIndex++;
                            state.PartialMessage = null;
                            state.TcpStream.Close();
                            state.TcpClient.Close();
                            state.TcpStream = null;
                            state.TcpClient = null;
                            TcpBeginConnect(state);
                        }
                        else
                        {
                            bool isSubsequentResponseMessage = (state.PartialMessage != null);

                            if (isSubsequentResponseMessage)
                            {
                                state.PartialMessage.AnswerRecords.AddRange(response.AnswerRecords);
                            }
                            else
                            {
                                state.PartialMessage = response;
                            }

                            if (response.IsTcpNextMessageWaiting(isSubsequentResponseMessage))
                            {
                                state.TcpBytesToReceive = 2;
                                state.Buffer            = new byte[2];

                                IAsyncResult asyncResult = state.TcpStream.BeginRead(state.Buffer, 0, 2, TcpReceiveLengthCompleted <TMessage>, state);
                                state.Timer = new Timer(TcpTimedOut <TMessage>, asyncResult, state.TimeRemaining, Timeout.Infinite);
                            }
                            else
                            {
                                state.TcpStream.Close();
                                state.TcpClient.Close();
                                state.TcpStream = null;
                                state.TcpClient = null;

                                state.Responses.Add(state.PartialMessage);
                                state.SetCompleted();
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Trace.TraceError("Error on dns query: " + e);

                    try
                    {
                        state.TcpClient.Close();
                        state.Timer.Dispose();
                    }
                    catch { }

                    state.EndpointInfoIndex++;
                    TcpBeginConnect(state);
                }
            }
        }
Beispiel #4
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);

            var endpointInfos = GetEndpointInfos <TMessage>();

            for (int i = 0; i < endpointInfos.Count; i++)
            {
                TcpClient     tcpClient = null;
                NetworkStream tcpStream = null;

                try
                {
                    var endpointInfo = endpointInfos[i];

                    IPAddress responderAddress;
                    byte[]    resultData = sendByTcp ? QueryByTcp(endpointInfo.ServerAddress, messageData, messageLength, ref tcpClient, ref tcpStream, out responderAddress) : 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, messageData, messageLength, ref tcpClient, ref tcpStream, out responderAddress);
                            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, null, 0, ref tcpClient, ref tcpStream, out responderAddress);
                            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 (tcpStream != null)
                        {
                            tcpStream.Dispose();
                        }
                        if (tcpClient != null)
                        {
                            tcpClient.Close();
                        }
                    }
                    catch { }
                }
            }

            return(null);
        }
Beispiel #5
0
 internal void Encode(byte[] messageData, int offset, ref int currentPosition, Dictionary <string, ushort> domainNames)
 {
     DnsMessageBase.EncodeDomainName(messageData, offset, ref currentPosition, Name, true, domainNames);
     DnsMessageBase.EncodeUShort(messageData, ref currentPosition, (ushort)RecordType);
     DnsMessageBase.EncodeUShort(messageData, ref currentPosition, (ushort)RecordClass);
 }