Beispiel #1
0
        private void EndTcpReadData(IAsyncResult ar)
        {
            TcpClient     client = null;
            NetworkStream stream = null;

            try
            {
                MyState state = (MyState)ar.AsyncState;
                client = state.Client;
                stream = state.Stream;

                state.Timer.Dispose();

                state.BytesToReceive -= stream.EndRead(ar);

                if (state.BytesToReceive > 0)
                {
                    if (!IsTcpClientConnected(client))
                    {
                        HandleTcpException(null, stream, client);
                        return;
                    }

                    state.Timer       = new Timer(TcpTimedOut, state, state.TimeRemaining, System.Threading.Timeout.Infinite);
                    state.AsyncResult = stream.BeginRead(state.Buffer, state.Buffer.Length - state.BytesToReceive, state.BytesToReceive, EndTcpReadData, state);
                }
                else
                {
                    DnsMessageBase query;
                    try
                    {
                        query             = DnsMessageBase.CreateByFlag(state.Buffer, TsigKeySelector, null);
                        state.NextTsigMac = (query.TSigOptions == null) ? null : query.TSigOptions.Mac;
                    }
                    catch (Exception e)
                    {
                        throw new Exception("Error parsing dns query", e);
                    }

                    try
                    {
                        state.Response = ProcessMessage(query, ((IPEndPoint)client.Client.RemoteEndPoint).Address, ProtocolType.Tcp);
                    }
                    catch (Exception ex)
                    {
                        OnExceptionThrown(ex);
                        state.Response = null;
                    }

                    ProcessAndSendTcpResponse(state, false);
                }
            }
            catch (Exception e)
            {
                HandleTcpException(e, stream, client);
            }
        }
Beispiel #2
0
        private void ProcessAndSendTcpResponse(MyState state, bool isSubSequentResponse)
        {
            if (state.Response == null)
            {
                state.Response         = DnsMessageBase.CreateByFlag(state.Buffer, TsigKeySelector, null);
                state.Response.IsQuery = false;
                state.Response.AdditionalRecords.Clear();
                state.Response.AuthorityRecords.Clear();
                state.Response.ReturnCode = ReturnCode.ServerFailure;
            }

            byte[] newTsigMac;

            int length = state.Response.Encode(true, state.NextTsigMac, isSubSequentResponse, out state.Buffer, out newTsigMac);

            if (length > 65535)
            {
                if ((state.Response.Questions.Count == 0) || (state.Response.Questions[0].RecordType != RecordType.Axfr))
                {
                    OnExceptionThrown(new ArgumentException("The length of the serialized response is greater than 65,535 bytes"));
                    state.Response            = DnsMessageBase.CreateByFlag(state.Buffer, TsigKeySelector, null);
                    state.Response.IsQuery    = false;
                    state.Response.ReturnCode = ReturnCode.ServerFailure;
                    state.Response.AdditionalRecords.Clear();
                    state.Response.AuthorityRecords.Clear();
                    length = state.Response.Encode(true, state.NextTsigMac, isSubSequentResponse, out state.Buffer, out newTsigMac);
                }
                else
                {
                    List <DnsRecordBase> nextPacketRecords = new List <DnsRecordBase>();

                    do
                    {
                        int lastIndex   = Math.Min(500, state.Response.AnswerRecords.Count / 2);
                        int removeCount = state.Response.AnswerRecords.Count - lastIndex;

                        nextPacketRecords.InsertRange(0, state.Response.AnswerRecords.GetRange(lastIndex, removeCount));
                        state.Response.AnswerRecords.RemoveRange(lastIndex, removeCount);

                        length = state.Response.Encode(true, state.NextTsigMac, isSubSequentResponse, out state.Buffer, out newTsigMac);
                    } while (length > 65535);

                    state.Response.AnswerRecords = nextPacketRecords;
                }
            }
            else
            {
                state.Response = null;
            }

            state.NextTsigMac = newTsigMac;

            state.Timer       = new Timer(TcpTimedOut, state, state.TimeRemaining, System.Threading.Timeout.Infinite);
            state.AsyncResult = state.Stream.BeginWrite(state.Buffer, 0, length, EndTcpSendData, state);
        }
Beispiel #3
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);
            }
        }