# dns query

• 02-21-2004
bulldog
dns query
Hi everyone, i'm a university student and i have been asked to write a dns query program in C.

We have to create the packet header by manipulating the bits of a 12 character array.

I have searched the internet and come up woth nothing so far to help me.

Unfortunately, i have got nothing with regards to creating the query header so far.

Im sure that if i can get some help on the first few things i can work out the rest, or at least be able to progress, but at the moment i dont really know where to start.
:confused:

So far i have created the array, and memset it to all '0's

I know then i have to change individual bits to show the identification, whether it is a query or response, etc etc.

Im just not sure how i go about changing the bits in each character of the array.

Any help would be greatly appreciated :)
• 02-21-2004
Edward
Quote:

Im just not sure how i go about changing the bits in each character of the array.
There are CHAR_BIT bits in a character, you can find CHAR_BIT in <limits.h>. From there it's just a matter of knowing which bit to look at and what operation to perform on it to do what you want. There are really only three operations you can perform on a single bit: test if it's set, set it and clear it.

Here are a few macros that perform those operations.
Code:

```#define bit(i) (1U << (i)) #define test(x, i) (((x) & bit((i))) != 0) #define set(x, i) ((x) = (x) | bit((i))) #define clear(x, i) ((x) = (x) &= ~bit((i)))```
• 02-21-2004
Thantos
Don't know if you've seen this Beej's Guide but it should help.

Code:

```#include <stdio.h> int main (void) {   unsigned char a=0;   printf("Before %u\n",(unsigned int)a);   a = 0x01 | 0xf0;   /* 0x01 = 00000001 or decimal 1,   * 0xf0 = 11110000 or decimal 240 unsigned or -16 signed   * Result should be 11110001 or 241 Unsigned*/   printf("After %u\n", (unsigned int)a);   return 0; }```
Quick definations: | is a bitwise OR operator. So say you | two numbers that have the bit patterns of 0101 and 1100 together the result will be 1101. & is a bitwise AND operator so with the previous example the result would be 0100.

Quick Hex to Binary:
0x0 = 0000
0x1 = 0001
0x2 = 0010
0x3 = 0011
0x4 = 0100
0x5 = 0101
0x6 = 0110
0x7 = 0111
0x8 = 1000
0x9 = 1001
0xA = 1010
0xB = 1011
0xC = 1100
0xD = 1101
0xE = 1110
0xF = 1111
• 02-22-2004
bulldog
Thanks for the replies guys, :D , a few further questions though.

As an example im trying to write a function that will set the QR (query or response) field of the header,

incase you dont know the structure of the dns header, i posted the image below, that shows it

Code:

```void SetQuery(unsigned char * header){     header[2] = 0x00; }```
ok, i think this code will set the 2nd character to all '0's but i only want to set the first bit,

the opcode also is in the 2nd character, but the next 4 bits, how would i set them specifically to a number passed in to the function as an argument.

thanks again for all your help guys:)
• 02-22-2004
Edward
>ok, i think this code will set the 2nd character to all '0's but i only want to set the first bit
This is where the bit macros I showed you come in handy. You can make it as simple as this.
Code:

`set(header[2], 0);`
Use & to mask off certain bits in a value, shift the value you want to replace with by the number of off bits and OR them together. Try 0xE1 as the mask for bits 2-5.
Code:

```#include <stdio.h> int main(void) {     unsigned char mask = 0xE1;     unsigned char c = 0xFF;     unsigned char d = 0xA;     printf("%#x\n", (c & mask) | (d << 1));     return 0; }```
• 02-23-2004
anonytmouse
Here is the packet struct for a dns resolver I made:
Code:

```/* DNS Header common to queries and answers  * This structure starts at byte 0 for udp packets */ typedef struct tagDnsHdr {         /* id of this request - used by application to match queries         * with replies - usually process id, but can be anything */         short id;         /* Note: We could do flags with bit fields but then we have         * to declare them twice. Once for little endian and once         * for big endian layout */         /* First byte of flags. Contains the following fields:         * QR (1 bit), OPCODE(4 bits), AA(1 bit), TC(1 bit), RD(1 bit)         * These can be set or retrieved using the bit mask constants         * eg. DNSHDR.lFlags |= BITS_RD to set.         * and to retrieve: trunc = DNSHDR.lFlags & BITS_TC         * For more information on these fields see the comments with         * the bit masks */         unsigned char lFlags;         /* Second byte of flags. Contains the following fields:         * RA (1 bit), Z(3 bits), RCODE(4 bits)         * Note: Z is marked as reserved in rfc 1035 */         unsigned char rFlags;         unsigned short qCount;  /* query count */         unsigned short anCount; /* answer count - return value only */         unsigned short nsCount; /* name server count - return value only */         unsigned short arCount; /* additional records count - return value only */ } DNSHDR; /* lFlags bit masks */ /* zero for a query, one for a response */ #define BITS_QR  128 /* usually zero for a standard query */ #define BITS_OPCODE  120 /* Authoritative Answer - this bit is valid in responses,  * and specifies that the responding name server is an  * authority for the domain name in question section. */ #define BITS_AA  4 /* Set if the answer has been truncated for being over the  * 512 byte limit (udp only) */ #define BITS_TC  2 /* Recursion desired - Should be set in the query */ #define BITS_RD  1 /* rFlags bit masks */ /* Recursion available - set by server if it was able  * to use recursion */ #define BITS_RA  128 /* Reserved - should be zero */ #define BITS_Z  112 /* The response code is returned by the server */ #define BITS_RCODE  15```
If I was doing this again I would use bitfields. Also, I would use types such as int16_t for maximum portability.

I could post my complete code but here is a much better example:
http://www.planet-source-code.com/vb...txtCodeId=5712

Search for dns.c for other examples.

NB. Buffer overruns are extremely easy to miss in a dns resolver, so if you don't want the dns server to be able to execute code on your machine be careful.

EDIT:
Bitfield example - PCs are little endian, Unix is typically big endian.
• 02-24-2004
bulldog
cheers for all the help guys :D

i think im starting to understand all this now :p

im gonna go off and have a play and hopefully all will be well,

thanks once again everyone :)