4

I'm trying to decode DNS packets in c#, and, although it doesn't really matter, I'm using SharpPcap.

Everything works well but it seems that the QR and the RCODE fields are returning wrong values. I'm comparing my results with the results from Wireshark.

QR is always 1 (Response) even if the message is a request. Another weird thing that happens is that return code is 0 when the message is a query and 1 when the message is a response.

One of the sites I used to find out the DNS header was this one. Is there something I'm missing here? The code I'm using to decode the packet is: (data is a byte array which contains the payload data)

//TransactionID 16 bits (This is correct)
//Not sure why second byte has to be first but that's how wireshark displays it
transactionID = new byte[] { data[1], data[0] }; 

//Flags 16 bits
isResponse = Utilities.getBit(data[2], 0); //always returns 1

//What I'm doing here is converting the boolean returned by getBit into a
//1 or 0 which is used to create a string which will then be converted
//into a UInt16 (If there's an easier way to do this please let me know)
OpCode = Convert.ToUInt16(Convert.ToUInt16(Utilities.getBit(data[2], 1)).ToString() +
         Convert.ToUInt16(Utilities.getBit(data[2], 2)).ToString() +
         Convert.ToUInt16(Utilities.getBit(data[2], 3)).ToString() +
         Convert.ToUInt16(Utilities.getBit(data[2], 4)).ToString(), 2);

//These seem correct (Untested though since wireshark doesn't display them)
authAnswer = Utilities.getBit(data[2], 5);
truncation = Utilities.getBit(data[2], 6);
recursionDesired = Utilities.getBit(data[2], 7);

recursionAvail = Utilities.getBit(data[3], 0);
//skip 3 bits here (reserved and set to 0)...

//ReturnCode returns 0 for queries and 1 for responses, this is pretty weird
returnCode = Convert.ToUInt16(Convert.ToUInt16(Utilities.getBit(data[3], 4)).ToString() +
             Convert.ToUInt16(Utilities.getBit(data[3], 5)).ToString() +
             Convert.ToUInt16(Utilities.getBit(data[3], 6)).ToString() +
             Convert.ToUInt16(Utilities.getBit(data[3], 7)).ToString(), 2);

//Questions count, Answers count, ARR count, Additional ARR: 1 byte each
//These are correct
questionsCount = Convert.ToUInt16(data[4] * 256 + data[5]);
answersCount = Convert.ToUInt16(data[6] * 256 + data[7]);
authorityRRs = Convert.ToUInt16(data[8] * 256 + data[9]);
additionalRRs = Convert.ToUInt16(data[10] * 256 + data[11]);

The getBit method is here:

public static bool getBit(byte b, int index) {
    //Logical AND with number to find if bit is 0 or 1
    //Shift by index to represent value in binary (2^index)
    bool bit = (b & (1 << index)) != 0;

    return (bit);
}
svick
  • 236,525
  • 50
  • 385
  • 514
Orestis P.
  • 805
  • 7
  • 27
  • "Not sure why second byte has to be first" Has to do with the "endian" of the platform -- See this : http://en.wikipedia.org/wiki/UTF-16 – Hogan Mar 17 '13 at 00:36
  • Have you tried reading the flags as a 16 bit unsigned and then looking at the bits in that variable (use ToUInt16). I think this is the same endian issue -- the 16 bit unsigned will put it in the right order automatically. – Hogan Mar 17 '13 at 02:01
  • Thank you for your replies, I decided to follow your suggestions and it worked. However, the getBit() method was also one to be causing the problem (The index starts from the end of the number). Thanks again – Orestis P. Mar 25 '13 at 14:30

1 Answers1

2

Have you tried using Pcap.Net? It has full support for DNS so you don't have to decode anything manually.

brickner
  • 6,595
  • 3
  • 41
  • 54