1

I want to manually build a dns query to the dns sever using socket APIs (it's part of the project and can not be changed). So I want to copy a struct like:

typedef struct {         
    uint16_t dns_id;  /* identification number */       
    uint16_t dns_flags; /* DNS flags */        
    uint16_t dns_qdc; /* number of question entries */      
    uint16_t dns_anc; /* number of answer entries */  
    uint16_t dns_nsc; /* number of authority entries */      
    uint16_t dns_arc; /* number of resource entries */
    unsigned char *host;
    unsigned short qtype;
    unsigned short qclass;     
} DNS_QUERY;


DNS_QUERY* dns_query = (DNS_QUERY *) malloc(sizeof(DNS_QUERY)); 

into a buffer like:

char* dns_buf = malloc(500);

but when I do that, nothing has been copied into the buffer. When I input different strings to the *host element, the sizeof(dns_query) stays the same. When I use

memcpy(dns_buf, dns_query, sizeof(DNS_QUERY));

it gives output like:

dns_buf:
strlen(dns_buf)= 0

Also when I print it using for loop like:

for (i = 0 ; i<strlen(dns_buf) ; i++){
        printf("%c", dns_buf[i]);   
    }

it doesn't output anything

When I use pointers instead of memcpy, like:

dns_buf = dns_query;

it gives the same output. Could anybody instruct me on what I should do?

This is the whole code:

int udp_connect(char *hostname, char *dns_name, char buf[]){

    int sockfd;
    int num_bytes;
    struct sockaddr_in servaddr;
    char str[INET_ADDRSTRLEN];
    struct hostent *hptr; /* For gethostbyname() */
    char **pptr; /* For inet_ntop() */
    char* dns_buf, recv_buf = NULL; 
    int len = 0;
    int i = 0;
    static unsigned short id = 0; /* For the query ID */

    /* Allocating memory for structs */
    DNS_QUERY* dns_query = malloc(sizeof(DNS_QUERY)); 
    /* QUESTION *dns_question = malloc(sizeof(QUESTION));*/
    recv_buf = malloc(MAXDATASIZE);

    if((hptr = gethostbyname(dns_name)) == NULL){
        perror("Error in gethostbyname()\n");
        exit(1);
    }

    if ((pptr = hptr->h_addr_list) != NULL) { /* (hptr->h_addrtype == AF_INET) && */
        printf("The address is: %s\n", inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)));
    } else {
        perror("Error in inet_ntop() \n");
    }

    memset(&servaddr, 0, sizeof (servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(DNS_PORT);
    inet_pton(AF_INET, str, &servaddr.sin_addr);

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){
        perror("Error while making a socket");
        return -1;
    }   

    /* Setting hostname into the name segment of the query */
    ChangetoDnsNameFormat(hostname);
    dns_query->host = hostname;
    printf("\ndns_query->host: %s\n", dns_query->host);


    /* memcpy(dns_buf, dns_query, sizeof(DNS_QUERY)); */    

    /* setting up the header */
    dns_query->dns_id = htons(id); /* id */
    dns_query->dns_flags = htons(0x10); /* 0000000100000000 recursion is desired*/  
    dns_query->dns_qdc = htons(0x01); /* We have one question */
    dns_query->dns_anc = htons(0x00);
    dns_query->dns_nsc = htons(0x00);
    dns_query->dns_arc = htons(0x00);

    dns_query->qtype = htons(1); /* For IPv4 */
    dns_query->qclass = htons(1); /* For internet */

    len = sizeof(DNS_QUERY) + strlen(hostname); /* Calculating the length to use it in sendto() */

    dns_buf = malloc(len);

    dns_buf = dns_query;
    /* memcpy(dns_buf, dns_query, sizeof(DNS_QUERY)); */

    for (i = 0 ; i<sizeof(DNS_QUERY) ; i++){
            printf("%02X", dns_buf[i]);   
    }

    /* to check if the same as dns_query, use the following print also */
    for (i = 0 ; i<sizeof(DNS_QUERY) ; i++){
            printf("%02X", dns_query[i]);   
        }
    print("\n");

    /* Sending the datagram to the dns server */
    printf("\n--------------------\nSending datagram: \n%s\n", dns_buf);
    if ((num_bytes = sendto(sockfd, dns_buf, len, 0, (struct sockaddr *) &servaddr, sizeof(servaddr))) == -1){
        perror("Error in sendto");
        exit(1);
    }

    /* Receiving the datagram from the dns server */
    printf("Receiving datagram...\n");
    num_bytes = recvfrom(sockfd, recv_buf, MAXDATASIZE, 0, NULL, NULL);
    printf("Received %i bytes of datagram...\n", num_bytes);

    printf("dns_buf in udp connect: %s\n", recv_buf);

    id = id + 1;

    free(dns_query);
    freeaddrinfo((struct addrinfo *) &servaddr);
    close(sockfd);

    return sockfd;
}
/******************************************************************************/
void ChangetoDnsNameFormat(char *hostname)
{
    int walker=0;
    int i;
    int counter = 0;
    char tmp[40];

    strcat(hostname, "$"); /* For having a $ at the end of the dns name format */   

    for(i=0 ; i< (int) strlen((char*)hostname) ; i++)
    {
        if(hostname[i]=='.')
        {
            tmp[walker] = (char) counter + 48;
            /*printf("%s\n", tmp);*/

            for( ; walker < i ; walker++)
            {
                tmp[walker + 1] = hostname[walker];
            }

            walker++;
            counter = -1;
        }else if(hostname[i]=='$'){

            tmp[walker] = (char) counter + 47;
            /*printf("%s\n", tmp);*/

            for( ; walker < i ; walker++)
            {
                tmp[walker + 1] = hostname[walker];
            }

            walker++;
            counter = -1;
        }
        counter++;
    }
    walker--;
    tmp[walker] = '\0'; /* Terminate the string */

    strcat(tmp, "0"); /* For having a 0 at the end of the dns name format */

    strcpy(hostname, tmp);
}
1
  • UPDATES: I fixed the for loop. The dns_buf now contains the right information but I don't know why the output of dns_buf and dns_query are not the same. Anyhow, now when I'm sending the query to the dns server, it won't return anything (sometimes it returns -1). Could anybody help on this? Commented Apr 27, 2013 at 7:16

2 Answers 2

1

The struct doesn't really contain the array of character host but rather a pointer to the first element.

This means that, although you are copying the whole structure, you just copy the pointer to the data contained in host (which then points to the same string). What you shall do is something like:

DNS_QUERY *dns_buf = malloc(sizeof(DNS_QUERY));
memcpy(dns_buf, dns_query, sizeof(DNS_QUERY));
dns_buf.host = "yourmodifiedhost";
Sign up to request clarification or add additional context in comments.

Comments

1

dns_buf is not a string (which finish with null charcter).

it's a pointer (as char *) to a memory space and the memory could contains 0 as values at the beginning so that's why when you use strlen(dns_buf) you get it = to 0 that means the fisrt element in the dns_buf is 0

to see the dns_buf content you can use:

for (i = 0 ; i<sizeof(DNS_QUERY) ; i++){
        printf("%02X", dns_buf[i]);   
    }
print("\n");

// to check if the same as dns_query, use the following print also
for (i = 0 ; i<sizeof(DNS_QUERY) ; i++){
        printf("%02X", dns_query[i]);   
    }
print("\n");

3 Comments

I did but they weren't the same! Why is that? (when I send that to the dns server it doesn't return anything so something is still wrong).
it's quite impossible to know the cause without seen the code. provide the whole code yhis will help to detect the problem
I added the code; it would be kind of you to take a look at it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.