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(); } }
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(); } }
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); } }
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(); } }