/// <summary> /// Parses a resource record from the packet passed. /// </summary> /// <param name="message">The message containing the record being parsed.</param> /// <param name="packet">The raw DNS message packet.</param> /// <param name="offset"> /// The current offset in the packet. Returns as the offset of the first byte /// after the record. /// </param> /// <returns>The resource record or <c>null</c> if there was an error.</returns> public static DnsRR Parse(DnsMessage message, byte[] packet, ref int offset) { string qname; DnsRRType rrtype; DnsRR rr; int savePos; // Peek the qname and record type savePos = offset; if (!message.ReadName(packet, ref offset, out qname)) { return(null); } rrtype = (DnsRRType)Helper.ReadInt16(packet, ref offset); offset = savePos; switch (rrtype) { case DnsRRType.A: rr = new A_RR(); break; case DnsRRType.CNAME: rr = new CNAME_RR(); break; case DnsRRType.NS: rr = new NS_RR(); break; case DnsRRType.MX: rr = new MX_RR(); break; case DnsRRType.SOA: rr = new SOA_RR(); break; default: rr = new DnsRR(); break; } if (!rr.Read(message, packet, ref offset)) { return(null); } return(rr); }
/// <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); }