public static QueryHeader ParseQueryHeader(byte[] buffer) { //https://tools.ietf.org/html/rfc1035#section-4.1.1 var header = new QueryHeader(); //this is the first place I was bitten by endianness header.ID = endianBitConverter.ToUInt16(buffer, 0); //first 2 bytes is the ID //and this is the second BitArray byteTwo = new BitArray(new byte[] { buffer[2] }); byteTwo.Reverse(); BitArray byteThree = new BitArray(new byte[] { buffer[3] }); byteThree.Reverse(); header.QueryResponse = byteTwo[0]; //Query Response bit //chop up the next nybble as we'll use it to get the opcode itself var opcodeArray = new BitArray(4); opcodeArray[0] = byteTwo[1]; opcodeArray[1] = byteTwo[2]; opcodeArray[2] = byteTwo[3]; opcodeArray[3] = byteTwo[4]; //Look away, children! //I'm converting the BitArray to a string (1010), then to a short, then to my OpCode value //todo: use bitmasking to do this header.OPCODE = (OpCode)Convert.ToInt16(opcodeArray.ToBitString(), 2); //this takes us to position 5 of the second byte header.AuthoritativeAnswer = byteTwo[5]; header.Truncation = byteTwo[6]; header.RecursionDesired = byteTwo[7]; //next! header.RecursionAvailable = byteThree[0]; header.Z = byteThree[1]; //header.ResponseCode //bits two through 5 header.QuestionCount = endianBitConverter.ToUInt16(buffer, 4); header.AnswerCount = endianBitConverter.ToUInt16(buffer, 6); header.NameServerCount = endianBitConverter.ToUInt16(buffer, 8); header.AdditonalRecordCount = endianBitConverter.ToUInt16(buffer, 10); //wtf happened with endianness here? return header; }