Thread: dns query

  1. #1
    Registered User
    Join Date
    Feb 2004
    Posts
    4

    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.


    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

  2. #2
    Registered User
    Join Date
    Feb 2004
    Posts
    46
    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)))

  3. #3
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    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

  4. #4
    Registered User
    Join Date
    Feb 2004
    Posts
    4
    Thanks for the replies guys, , 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

  5. #5
    Registered User
    Join Date
    Feb 2004
    Posts
    46
    >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;
    }

  6. #6
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    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.
    Last edited by anonytmouse; 02-23-2004 at 10:10 AM.

  7. #7
    Registered User
    Join Date
    Feb 2004
    Posts
    4
    cheers for all the help guys

    i think im starting to understand all this now

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

    thanks once again everyone

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. query problem
    By arian in forum C# Programming
    Replies: 1
    Last Post: 08-18-2008, 01:49 PM
  2. DNS issue
    By George2 in forum C# Programming
    Replies: 1
    Last Post: 08-02-2008, 10:15 AM
  3. DNS Query
    By Simpsonia in forum Networking/Device Communication
    Replies: 1
    Last Post: 04-24-2006, 12:42 AM
  4. DNS & Mail settings modifier
    By DemonSoul in forum A Brief History of Cprogramming.com
    Replies: 1
    Last Post: 05-20-2004, 12:43 PM