Example #1
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();
            }
        }
Example #2
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();
            }
        }
Example #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);
            }
        }
Example #4
0
 static async Task OnClientConnected(object sender, ClientConnectedEventArgs e)
 {
     if (!IPAddress.IsLoopback(e.RemoteEndpoint.Address))
         e.RefuseConnect = true;
 }
		private async void HandleTcpListenerAsync()
		{
			TcpClient client = null;

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

					ClientConnectedEventArgs clientConnectedEventArgs = new ClientConnectedEventArgs(ProtocolType.Udp, (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
					client?.Close();
				}
				catch
				{
					// ignored
				}

				lock (_listenerLock)
				{
					_availableTcpListener++;
				}
				StartTcpListenerTask();
			}
		}
		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();
			}
		}