Search code examples
csocketsiphostname

Why is inet_ntoa always returning me 0.0.0.0 as the ip address?


I don't understand because the following code is always returning me 0.0.0.0 for the ip address of google.com for instance. I need to use inet_ntoa and no other functions. Anyone could help me figuring out the pb?

#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //for exit(0);
#include<sys/socket.h>
#include<errno.h> //For errno - the error number
#include<netdb.h> //hostent
#include<arpa/inet.h>

int hostname_to_ip(char *  , char *);

int main(int argc , char *argv[])
{
    if(argc <2)
    {
        printf("Please provide a hostname to resolve");
        exit(1);
    }

    char *hostname = argv[1];
    char ip[100];

    hostname_to_ip(hostname , ip);
    printf("%s resolved to %s" , hostname , ip);

    printf("\n");

}
/*
    Get ip from domain name
 */

int hostname_to_ip(char *hostname , char *ip)
{
    int sockfd;  
    struct addrinfo hints, *servinfo, *p;
    struct sockaddr_in *h;
    int rv;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
    hints.ai_socktype = SOCK_STREAM;

    if ( (rv = getaddrinfo( hostname , "http" , &hints , &servinfo)) != 0)    
    {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    // loop through all the results and connect to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) 
    {
        h = (struct sockaddr_in *) p->ai_addr;
        strcpy(ip , inet_ntoa( h->sin_addr ) );
    }

    freeaddrinfo(servinfo); // all done with this structure
    return 0;
}

Its actually a code taken from http://www.binarytides.com/hostname-to-ip-address-c-sockets-linux/ but my code is pretty much doing the same thing, especially it uses the same function which is what I am looking for.

I compile with : $ gcc hostname_to_ip.c && ./a.out www.google.com


Solution

  • The getaddrinfo() function returns a linked list of addresses, among which clients are expected to choose. You can influence which addresses are included in the list by means of the "hints" object passed to that function. In using inet_ntoa() to process the addresses obtained, you are assuming IPv4. It would make sense, then, to tell getaddrinfo() that you're only interested in IPv4 addresses:

    hints.ai_family = AF_INET;
    

    I can reproduce your results with your original code, but making that one modification gets me a reasonable-appearing IPv4 address instead.

    Although you do walk the address list provided by getaddrinfo(), when you cast to struct sockaddr_in * without checking the address family, you assume that each address in it is in family AF_INET. That's unsafe. Moreover, you overwrite each converted address string with the next, so if getaddrinfo() does a good job of prioritizing the addresses you're most likely to want, then you turn that into breakage.

    If you do not specify that you want only IPv4 addresses, then at least you ought to check each returned address's family before deciding whether to use it. Moreover, you only have provision to return one, so you might as well break out of the loop once you find one you can use.