Пример #1
0
        private async void HandleUdpListenerAsync()
        {
            try
            {
                UdpReceiveResult receiveResult;
                try
                {
                    receiveResult = await _udpListener.ReceiveAsync();
                }
                catch (ObjectDisposedException)
                {
                    return;
                }
                finally
                {
                    lock (_listenerLock)
                    {
                        _hasActiveUdpListener = false;
                    }
                }

                ClientConnectedEventArgs clientConnectedEventArgs = new ClientConnectedEventArgs(ProtocolType.Udp, receiveResult.RemoteEndPoint);
                await ClientConnected.RaiseAsync(this, clientConnectedEventArgs);

                if (clientConnectedEventArgs.RefuseConnect)
                {
                    return;
                }

                StartUdpListenerTask();

                byte[] buffer = receiveResult.Buffer;

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

                DnsMessageBase response;
                try
                {
                    response = await ProcessMessageAsync(query, ProtocolType.Udp, receiveResult.RemoteEndPoint);
                }
                catch (Exception ex)
                {
                    OnExceptionThrownAsync(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

                await _udpListener.SendAsync(buffer, length, receiveResult.RemoteEndPoint);
            }
            catch (Exception ex)
            {
                OnExceptionThrownAsync(ex);
            }
            finally
            {
                lock (_listenerLock)
                {
                    _availableUdpListener++;
                }
                StartUdpListenerTask();
            }
        }
Пример #2
0
        private async void HandleTcpListenerAsync()
        {
            TcpClient client = null;

            try
            {
                try
                {
                    client = await _tcpListener.AcceptTcpClientAsync();

                    ClientConnectedEventArgs clientConnectedEventArgs = new ClientConnectedEventArgs(ProtocolType.Tcp, (IPEndPoint)client.Client.RemoteEndPoint);
                    await ClientConnected.RaiseAsync(this, clientConnectedEventArgs);

                    if (clientConnectedEventArgs.RefuseConnect)
                    {
                        return;
                    }
                }
                finally
                {
                    lock (_listenerLock)
                    {
                        _hasActiveTcpListener = false;
                    }
                }

                StartTcpListenerTask();

                using (NetworkStream stream = client.GetStream())
                {
                    while (true)
                    {
                        byte[] buffer = await ReadIntoBufferAsync(client, stream, 2);

                        if (buffer == null)                         // client disconneted while reading or timeout
                        {
                            break;
                        }

                        int offset = 0;
                        int length = DnsMessageBase.ParseUShort(buffer, ref offset);

                        buffer = await ReadIntoBufferAsync(client, stream, length);

                        if (buffer == null)                         // client disconneted while reading or timeout
                        {
                            throw new Exception("Client disconnted or timed out while sending data");
                        }

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

                        DnsMessageBase response;
                        try
                        {
                            response = await ProcessMessageAsync(query, ProtocolType.Tcp, (IPEndPoint)client.Client.RemoteEndPoint);
                        }
                        catch (Exception ex)
                        {
                            OnExceptionThrownAsync(ex);

                            response         = DnsMessageBase.CreateByFlag(buffer, TsigKeySelector, null);
                            response.IsQuery = false;
                            response.AdditionalRecords.Clear();
                            response.AuthorityRecords.Clear();
                            response.ReturnCode = ReturnCode.ServerFailure;
                        }

                        byte[] newTsigMac;

                        length = response.Encode(true, tsigMac, false, out buffer, out newTsigMac);

                        if (length <= 65535)
                        {
                            await stream.WriteAsync(buffer, 0, length);
                        }
                        else
                        {
                            if ((response.Questions.Count == 0) || (response.Questions[0].RecordType != RecordType.Axfr))
                            {
                                OnExceptionThrownAsync(new ArgumentException("The length of the serialized response is greater than 65,535 bytes"));

                                response         = DnsMessageBase.CreateByFlag(buffer, TsigKeySelector, null);
                                response.IsQuery = false;
                                response.AdditionalRecords.Clear();
                                response.AuthorityRecords.Clear();
                                response.ReturnCode = ReturnCode.ServerFailure;

                                length = response.Encode(true, tsigMac, false, out buffer, out newTsigMac);
                                await stream.WriteAsync(buffer, 0, length);
                            }
                            else
                            {
                                bool isSubSequentResponse = false;

                                while (true)
                                {
                                    List <DnsRecordBase> nextPacketRecords = new List <DnsRecordBase>();

                                    while (length > 65535)
                                    {
                                        int lastIndex   = Math.Min(500, response.AnswerRecords.Count / 2);
                                        int removeCount = response.AnswerRecords.Count - lastIndex;

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

                                        length = response.Encode(true, tsigMac, isSubSequentResponse, out buffer, out newTsigMac);
                                    }

                                    await stream.WriteAsync(buffer, 0, length);

                                    if (nextPacketRecords.Count == 0)
                                    {
                                        break;
                                    }

                                    isSubSequentResponse = true;
                                    tsigMac = newTsigMac;
                                    response.AnswerRecords = nextPacketRecords;
                                    length = response.Encode(true, tsigMac, true, out buffer, out newTsigMac);
                                }
                            }
                        }

                        // Since support for multiple tsig signed messages is not finished, just close connection after response to first signed query
                        if (newTsigMac != null)
                        {
                            break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                OnExceptionThrownAsync(ex);
            }
            finally
            {
                try
                {
                    // ReSharper disable once ConstantConditionalAccessQualifier
#if NETSTANDARD
                    client?.Dispose();
#else
                    client?.Close();
#endif
                }
                catch
                {
                    // ignored
                }

                lock (_listenerLock)
                {
                    _availableTcpListener++;
                }
                StartTcpListenerTask();
            }
        }
Пример #3
0
        public async Task <ArraySegment <byte>?> HandleUdpMessage(IPEndPoint remoteEp, byte[] buffer)
        {
            try {
                ClientConnectedEventArgs clientConnectedEventArgs = new ClientConnectedEventArgs(ProtocolType.Udp, remoteEp);
                await ClientConnected.RaiseAsync(this, clientConnectedEventArgs);

                if (clientConnectedEventArgs.RefuseConnect)
                {
                    return(null);
                }

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

                DnsMessageBase response;
                try {
                    response = await ProcessMessageAsync(query, ProtocolType.Udp, remoteEp);
                } catch (Exception ex) {
                    OnExceptionThrownAsync(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

                return(new ArraySegment <byte>(buffer, 0, length));
            } catch (Exception ex) {
                OnExceptionThrownAsync(ex);
                return(null);
            }
        }