/*
         * Header Structure, the bit labeled 0 is the most significant bit.
         *
         * 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
         +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
         |                      ID                       |
         +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
         |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
         +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
         |                    QDCOUNT                    |
         +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
         |                    ANCOUNT                    |
         +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
         |                    NSCOUNT                    |
         +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
         |                    ARCOUNT                    |
         +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
         */
        public static byte[] EncodeHeader(DnsMessage message)
        {
            MemoryStream stream = new MemoryStream(12);
            BinaryWriter writer = new BinaryWriter(stream);

            WriteUInt16BE(writer, message.ID);

            int fields = (int)message.ResponseCode;

            if (message.IsRecursionAvailable)
            {
                fields |= 0x80;
            }
            if (message.IsRecursionDesired)
            {
                fields |= 0x100;
            }
            if (message.IsTruncated)
            {
                fields |= 0x200;
            }
            if (message.IsRecursionAvailable)
            {
                fields |= 0x400;
            }

            fields |= (int)message.QueryKind << 11; //Opcode

            if (message.Type == MessageType.Response)
            {
                fields |= 0x8000;
            }

            WriteUInt16BE(writer, (UInt16)fields);
            WriteUInt16BE(writer, (UInt16)message.Querys.Count);
            WriteUInt16BE(writer, (UInt16)message.Answers.Count);
            WriteUInt16BE(writer, (UInt16)message.AuthorityRecords.Count);
            WriteUInt16BE(writer, (UInt16)message.AdditionalRecords.Count);

            return(stream.ToArray());
        }
        public static DnsMessage DecodeDnsMessage(byte[] msgData)
        {
            DnsMessage message = new DnsMessage();

            message.ID           = (UInt16)(msgData[0] << 8 | msgData[1]);
            message.Type         = (MessageType)(msgData[2] >> 7);
            message.QueryKind    = (QueryKind)((msgData[2] >> 3) & 15);
            message.ResponseCode = (ResponseCode)(msgData[3] & 15);

            MemoryStream stream = new MemoryStream(msgData);

            stream.Position = 4;
            BinaryReader reader = new BinaryReader(stream);

            int queryCount  = ReadUInt16BE(reader);
            int answerCount = ReadUInt16BE(reader);
            int nsCount     = ReadUInt16BE(reader);
            int arCount     = ReadUInt16BE(reader);

            for (int i = 0; i < queryCount; i++)
            {
                message.Querys.Add(ReadDnsQuery(reader));
            }
            for (int i = 0; i < answerCount; i++)
            {
                message.Answers.Add(ReadResourceRecord(reader));
            }
            for (int i = 0; i < nsCount; i++)
            {
                message.AuthorityRecords.Add(ReadResourceRecord(reader));
            }
            for (int i = 0; i < arCount; i++)
            {
                message.AdditionalRecords.Add(ReadResourceRecord(reader));
            }

            return(message);
        }