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