/// <summary> /// Shallow copies the data members from the source message passed /// to this instance. /// </summary> /// <param name="source">The source message.</param> protected void CopyFrom(DnsMessage source) { this.qid = source.qid; this.flags = source.flags; this.qname = source.qname; this.qtype = source.qtype; this.qclass = source.qclass; this.answers = source.answers; this.authorities = source.authorities; this.additional = source.additional; }
private Dictionary <string, int> namePtrs; // Set of existing name compression pointers /// <summary> /// This constructor initializes the message fields to default values. /// </summary> public DnsMessage() { this.qid = 0; this.flags = 0; this.qname = null; this.qtype = DnsQType.NULL; this.qclass = DnsQClass.IN; this.answers = null; this.authorities = null; this.additional = null; this.namePtrs = null; }
/// <summary> /// Connstructs a typical Internet class DNS request. /// </summary> /// <param name="flags">Additional flag bits (the QR and OPCODE sections will be set automatically).</param> /// <param name="qname">The query name.</param> /// <param name="qtype">The query type.</param> /// <remarks> /// <para> /// By default, this constructor initializes the OPCODE section of the message flags to /// <see cref="DnsOpcode.QUERY" />, the query ID to zero, and the query class to /// <see cref="DnsQClass.IN" />. These properties can be modified directly after /// construction if necessary. Note that the <see cref="DnsResolver" /> class /// handles the assignment of a unique query ID so it generally not necessary /// to explicitly set this property. /// </para> /// </remarks> public DnsRequest(DnsFlag flags, string qname, DnsQType qtype) : base() { if (!qname.EndsWith(".")) { throw new ArgumentException("Domain names must end with [.]", "qname"); } this.Flags = flags; this.QName = qname; this.QType = qtype; this.QClass = DnsQClass.IN; }
/// <summary> /// Converts an RCODE value encoded in message flag bits into a human readable string. /// </summary> /// <param name="flags">The message flags.</param> /// <returns>The output string.</returns> private string RCODE2String(DnsFlag flags) { switch (flags & DnsFlag.RCODE_MASK) { case DnsFlag.RCODE_OK: return("RCODE_OK"); case DnsFlag.RCODE_FORMAT: return("RCODE_FORMAT"); case DnsFlag.RCODE_SERVER: return("RCODE_SERVER"); case DnsFlag.RCODE_NAME: return("RCODE_NAME"); case DnsFlag.RCODE_NOTIMPL: return("RCODE_NOTIMPL"); case DnsFlag.RCODE_REFUSED: return("RCODE_REFUSED"); default: return(string.Format("RCODE({0})", (int)(flags & DnsFlag.RCODE_MASK))); } }
/// <summary> /// Serializes the message into a byte array formatted as a /// DNS protocol response packet as defined by RFC 1035. /// </summary> /// <param name="cb">Returns as the size of the formatted packet in bytes.</param> /// <returns>The <see cref="PacketSize" /> byte buffer with the formatted packet.</returns> public byte[] FormatPacket(out int cb) { var packet = new byte[PacketSize]; int pos; try { // Initialize the name compression pointer table. namePtrs = new Dictionary <string, int>(); // Write the message header pos = 0; Helper.WriteInt16(packet, ref pos, qid); Helper.WriteInt16(packet, ref pos, (int)flags); Helper.WriteInt16(packet, ref pos, 1); // One question Helper.WriteInt16(packet, ref pos, (int)(answers == null ? 0 : answers.Count)); Helper.WriteInt16(packet, ref pos, (int)(authorities == null ? 0 : authorities.Count)); Helper.WriteInt16(packet, ref pos, (int)(additional == null ? 0 : additional.Count)); Assertion.Test(pos == 12); // Write the question WriteName(packet, ref pos, qname); Helper.WriteInt16(packet, ref pos, (int)qtype); Helper.WriteInt16(packet, ref pos, (int)qclass); // Write the resource records if (answers != null) { for (int i = 0; i < answers.Count; i++) { ((DnsRR)answers[i]).Write(this, packet, ref pos); } } if (authorities != null) { for (int i = 0; i < authorities.Count; i++) { ((DnsRR)authorities[i]).Write(this, packet, ref pos); } } if (additional != null) { for (int i = 0; i < additional.Count; i++) { ((DnsRR)additional[i]).Write(this, packet, ref pos); } } } catch (IndexOutOfRangeException) { // $hack(jeff.lill): // // OK I know, using an exception to catch overflow // situations like this is a really bad idea but // give me a break, this is old code and I don't // want to mess with it right now. // Set the truncation bit in the response flags |= DnsFlag.TC; pos = 2; Helper.WriteInt16(packet, ref pos, (int)flags); pos = PacketSize; } finally { namePtrs = null; } cb = pos; return(packet); }
/// <summary> /// This method parses the raw DNS message packet passed and initializes /// the message properties. /// </summary> /// <param name="packet">The raw DNS packet received.</param> /// <param name="cbPacket">Number of bytes in that packet.</param> /// <returns>True on success.</returns> public bool ParsePacket(byte[] packet, int cbPacket) { uint qdCount; uint anCount; uint nsCount; uint arCount; int pos; // Read the message header pos = 0; this.qid = (ushort)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket) { return(false); } this.flags = (DnsFlag)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket) { return(false); } qdCount = (ushort)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket) { return(false); } anCount = (ushort)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket) { return(false); } nsCount = (ushort)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket) { return(false); } arCount = (ushort)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket) { return(false); } Assertion.Test(pos == 12); // Check for unsupported packets if ((this.flags & DnsFlag.TC) != 0) // truncation bit is set { return(false); } if (this.Opcode != DnsOpcode.QUERY) // only accept standard queries { return(false); } if (qdCount != 1) // only supporting one question { return(false); } // Parse the question if (!ReadName(packet, ref pos, out this.qname)) { return(false); } if (pos > cbPacket) { return(false); } this.qtype = (DnsQType)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket) { return(false); } this.qclass = (DnsQClass)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket) { return(false); } // We're only going to accept Internet queries if (this.qclass != DnsQClass.IN) { return(false); } // Parse the answer records for (int i = 0; i < anCount; i++) { var rr = DnsRR.Parse(this, packet, ref pos); if (rr == null || pos > cbPacket) { return(false); } this.Answers.Add(rr); } // Parse the authority records for (int i = 0; i < nsCount; i++) { var rr = DnsRR.Parse(this, packet, ref pos); if (rr == null || pos > cbPacket) { return(false); } this.Authorities.Add(rr); } // Parse the additional records for (int i = 0; i < arCount; i++) { var rr = DnsRR.Parse(this, packet, ref pos); if (rr == null || pos > cbPacket) { return(false); } this.Additional.Add(rr); } // $todo(jeff.lill): // // Delete this once we've figured out why the DNS server // sometimes get requests with NULL QNAME properties. if (this.QName == null) { var packetBytes = Helper.Extract(packet, cbPacket); var hexDump = Helper.HexDump(packetBytes, 16, HexDumpOption.ShowAll); var diagnostics = GetTraceDetails(IPAddress.Any); var extendedLogInfo = new StringSysLogEntryExtension(diagnostics + "\r\n\r\nPacket:\r\n\r\n" + hexDump); SysLog.LogWarning(extendedLogInfo, "DNS Packet with QNAME=NULL"); } return(true); }
/// <summary> /// Constructor. /// </summary> /// <param name="rcode">The DNS response code.</param> public DnsException(DnsFlag rcode) : base(errMsgs[(int)rcode]) { this.rcode = rcode; }