internal static DnsMessageBase CreateByFlag(byte[] data, DnsServer.SelectTsigKey tsigKeySelector, byte[] originalMac) { int flagPosition = 2; ushort flags = ParseUShort(data, ref flagPosition); DnsMessageBase res; switch ((OperationCode)((flags & 0x7800) >> 11)) { case OperationCode.Update: res = new DnsUpdateMessage(); break; default: res = new DnsMessage(); break; } res.ParseInternal(data, tsigKeySelector, originalMac); return(res); }
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); } }