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); } }
private void UdpReceiveCompleted <TMessage>(IAsyncResult ar) where TMessage : DnsMessageBase, new() { DnsClientAsyncState <TMessage> state = (DnsClientAsyncState <TMessage>)ar.AsyncState; if (state.Timer != null) { state.Timer.Dispose(); } if (state.TimedOut) { state.EndpointInfoIndex++; UdpBeginSend(state); } else { try { int length = state.UdpClient.EndReceiveFrom(ar, ref state.UdpEndpoint); byte[] responseData = new byte[length]; Buffer.BlockCopy(state.Buffer, 0, responseData, 0, length); TMessage response = DnsMessageBase.Parse <TMessage>(responseData, state.TSigKeySelector, state.TSigOriginalMac); if (AreMultipleResponsesAllowedInParallelMode) { if (ValidateResponse(state.Query, response)) { if (response.IsTcpResendingRequested) { TcpBeginConnect <TMessage>(state.CreateTcpCloneWithoutCallback(), ((IPEndPoint)state.UdpEndpoint).Address); } else { state.Responses.Add(response); } } state.Buffer = new byte[65535]; if (state.EndpointInfos[state.EndpointInfoIndex].IsMulticast) { state.UdpEndpoint = new IPEndPoint(state.UdpClient.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, _port); } IAsyncResult asyncResult = state.UdpClient.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.UdpEndpoint, UdpReceiveCompleted <TMessage>, state); state.Timer = new Timer(UdpTimedOut <TMessage>, asyncResult, state.TimeRemaining, Timeout.Infinite); } else { state.UdpClient.Close(); state.UdpClient = null; state.UdpEndpoint = null; if (!ValidateResponse(state.Query, response) || (response.ReturnCode == ReturnCode.ServerFailure)) { state.EndpointInfoIndex++; UdpBeginSend(state); } else { if (response.IsTcpResendingRequested) { TcpBeginConnect <TMessage>(state, ((IPEndPoint)state.UdpEndpoint).Address); } else { state.Responses.Add(response); state.SetCompleted(); } } } } catch (Exception e) { Trace.TraceError("Error on dns query: " + e); try { state.UdpClient.Close(); state.Timer.Dispose(); } catch { } state.EndpointInfoIndex++; UdpBeginSend(state); } } }
private void TcpReceiveCompleted <TMessage>(IAsyncResult ar) where TMessage : DnsMessageBase, new() { DnsClientAsyncState <TMessage> state = (DnsClientAsyncState <TMessage>)ar.AsyncState; if (state.Timer != null) { state.Timer.Dispose(); } if (state.TimedOut) { state.EndpointInfoIndex++; TcpBeginConnect(state); } else { try { state.TcpBytesToReceive -= state.TcpStream.EndRead(ar); if (state.TcpBytesToReceive > 0) { IAsyncResult asyncResult = state.TcpStream.BeginRead(state.Buffer, state.Buffer.Length - state.TcpBytesToReceive, state.TcpBytesToReceive, TcpReceiveCompleted <TMessage>, state); state.Timer = new Timer(TcpTimedOut <TMessage>, asyncResult, state.TimeRemaining, Timeout.Infinite); } else { byte[] buffer = state.Buffer; state.Buffer = null; TMessage response = DnsMessageBase.Parse <TMessage>(buffer, state.TSigKeySelector, state.TSigOriginalMac); if (!ValidateResponse(state.Query, response) || (response.ReturnCode == ReturnCode.ServerFailure)) { state.EndpointInfoIndex++; state.PartialMessage = null; state.TcpStream.Close(); state.TcpClient.Close(); state.TcpStream = null; state.TcpClient = null; TcpBeginConnect(state); } else { bool isSubsequentResponseMessage = (state.PartialMessage != null); if (isSubsequentResponseMessage) { state.PartialMessage.AnswerRecords.AddRange(response.AnswerRecords); } else { state.PartialMessage = response; } if (response.IsTcpNextMessageWaiting(isSubsequentResponseMessage)) { state.TcpBytesToReceive = 2; state.Buffer = new byte[2]; IAsyncResult asyncResult = state.TcpStream.BeginRead(state.Buffer, 0, 2, TcpReceiveLengthCompleted <TMessage>, state); state.Timer = new Timer(TcpTimedOut <TMessage>, asyncResult, state.TimeRemaining, Timeout.Infinite); } else { state.TcpStream.Close(); state.TcpClient.Close(); state.TcpStream = null; state.TcpClient = null; state.Responses.Add(state.PartialMessage); state.SetCompleted(); } } } } catch (Exception e) { Trace.TraceError("Error on dns query: " + e); try { state.TcpClient.Close(); state.Timer.Dispose(); } catch { } state.EndpointInfoIndex++; TcpBeginConnect(state); } } }
protected TMessage SendMessage <TMessage>(TMessage message) where TMessage : DnsMessageBase, new() { int messageLength; byte[] messageData; DnsServer.SelectTsigKey tsigKeySelector; byte[] tsigOriginalMac; PrepareMessage(message, out messageLength, out messageData, out tsigKeySelector, out tsigOriginalMac); bool sendByTcp = ((messageLength > MaximumQueryMessageSize) || message.IsTcpUsingRequested); var endpointInfos = GetEndpointInfos <TMessage>(); for (int i = 0; i < endpointInfos.Count; i++) { TcpClient tcpClient = null; NetworkStream tcpStream = null; try { var endpointInfo = endpointInfos[i]; IPAddress responderAddress; byte[] resultData = sendByTcp ? QueryByTcp(endpointInfo.ServerAddress, messageData, messageLength, ref tcpClient, ref tcpStream, out responderAddress) : QueryByUdp(endpointInfo, messageData, messageLength, out responderAddress); if (resultData != null) { TMessage result; try { result = DnsMessageBase.Parse <TMessage>(resultData, tsigKeySelector, tsigOriginalMac); } catch (Exception e) { Trace.TraceError("Error on dns query: " + e); continue; } if (!ValidateResponse(message, result)) { continue; } if ((result.ReturnCode == ReturnCode.ServerFailure) && (i != endpointInfos.Count - 1)) { continue; } if (result.IsTcpResendingRequested) { resultData = QueryByTcp(responderAddress, messageData, messageLength, ref tcpClient, ref tcpStream, out responderAddress); if (resultData != null) { TMessage tcpResult; try { tcpResult = DnsMessageBase.Parse <TMessage>(resultData, tsigKeySelector, tsigOriginalMac); } catch (Exception e) { Trace.TraceError("Error on dns query: " + e); continue; } if (tcpResult.ReturnCode == ReturnCode.ServerFailure) { if (i != endpointInfos.Count - 1) { continue; } } else { result = tcpResult; } } } bool isTcpNextMessageWaiting = result.IsTcpNextMessageWaiting(false); bool isSucessfullFinished = true; while (isTcpNextMessageWaiting) { resultData = QueryByTcp(responderAddress, null, 0, ref tcpClient, ref tcpStream, out responderAddress); if (resultData != null) { TMessage tcpResult; try { tcpResult = DnsMessageBase.Parse <TMessage>(resultData, tsigKeySelector, tsigOriginalMac); } catch (Exception e) { Trace.TraceError("Error on dns query: " + e); isSucessfullFinished = false; break; } if (tcpResult.ReturnCode == ReturnCode.ServerFailure) { isSucessfullFinished = false; break; } else { result.AnswerRecords.AddRange(tcpResult.AnswerRecords); isTcpNextMessageWaiting = tcpResult.IsTcpNextMessageWaiting(true); } } else { isSucessfullFinished = false; break; } } if (isSucessfullFinished) { return(result); } } } finally { try { if (tcpStream != null) { tcpStream.Dispose(); } if (tcpClient != null) { tcpClient.Close(); } } catch { } } } return(null); }
internal void Encode(byte[] messageData, int offset, ref int currentPosition, Dictionary <string, ushort> domainNames) { DnsMessageBase.EncodeDomainName(messageData, offset, ref currentPosition, Name, true, domainNames); DnsMessageBase.EncodeUShort(messageData, ref currentPosition, (ushort)RecordType); DnsMessageBase.EncodeUShort(messageData, ref currentPosition, (ushort)RecordClass); }