Get ip address from hostname in C with Linux sockets

By | July 31, 2020

Socket applications often need to convert hostnames like google.com to their corresponding ip address. This is done through dns requests.

The socket api in linux provides functions like gethostbyname and getaddrinfo that can be used to perform the dns requests and get the ip address.

1. gethostbyname

The first method uses the traditional gethostbyname function to retrieve information about a hostname/domain name.

Code

#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)
{
	struct hostent *he;
	struct in_addr **addr_list;
	int i;
		
	if ( (he = gethostbyname( hostname ) ) == NULL) 
	{
		// get the host info
		herror("gethostbyname");
		return 1;
	}

	addr_list = (struct in_addr **) he->h_addr_list;
	
	for(i = 0; addr_list[i] != NULL; i++) 
	{
		//Return the first one;
		strcpy(ip , inet_ntoa(*addr_list[i]) );
		return 0;
	}
	
	return 1;
}

Compile and Run

$ gcc hostname_to_ip.c && ./a.out www.google.com
www.google.com resolved to 74.125.235.16

$ gcc hostname_to_ip.c && ./a.out www.msn.com
www.msn.com resolved to 207.46.140.34

$ gcc hostname_to_ip.c && ./a.out www.yahoo.com
www.yahoo.com resolved to 98.137.149.56

2. getaddrinfo

The second method uses the getaddrinfo function to retrieve information about a hostname/domain name. The getaddrinfo supports ipv6 better.

Code

#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;
}

Compile and Run

$ gcc hostname_to_ip.c && ./a.out www.google.com
www.google.com resolved to 74.125.235.19

$ gcc hostname_to_ip.c && ./a.out www.yahoo.com
www.yahoo.com resolved to 72.30.2.43

$ gcc hostname_to_ip.c && ./a.out www.msn.com
www.msn.com resolved to 207.46.140.34
About Silver Moon

A Tech Enthusiast, Blogger, Linux Fan and a Software Developer. Writes about Computer hardware, Linux and Open Source software and coding in Python, Php and Javascript. He can be reached at [email protected].

17 Comments

Get ip address from hostname in C with Linux sockets
  1. thisisbazz

    First of all, thanks for putting this tutorial up! I have used it as a basis for my next-gen code! Having stated that, let me show you how I have improved it.

    Your getaddrinfo example continuously overwrites the “ip” C-string, until interating through the linked list is finished. Why not simply write to it once at end of the loop, if only getting the last entry is what you REALLY want, but that’s hardly useful! What you want is to make sure you’re using an IP that works!

    “man getaddrinfo” from the terminal. On my OSX, it has nice example of iterating through the list and trying to test a socket connection for TCP. I have turned that example into usable code, integrated with your tutorial’s code:

    http://pastebin.com/cfUw5sG6

    For UDP you can do similar things by implementing a “test” msg for the server to receive and acknowledge with adaptive retransmission timeout.

    1. thisisbazz

      Actually, having learned a little more, I’ve reverted to the newer inet_ntop. Simpler to use, I’m unsure if any power is lost from using it. I think it will be alright. Just thought I would leave evidence of my trail.

    2. Clark

      I noticed the same problem. I used a similar fix. If I did the example with http://www.google.com, the original code, printed “0.0.0.0”. It appears the last entry given by default name server is broken. The first entry is correct.

      1. Yu Jing

        Thank you, It works !
        In the manual,
        “The value AF_UNSPEC indicates that getaddrinfo() should return socket addresses for any address family (either IPv4 or IPv6, for example) that can be used with node and service.”
        What is the basis of the judgments using IPv4 or IPv6?

        The server support ipv6 ? or just my pc support IPv6?

          1. Yu Jing

            Thanks for your patient , while ,what makes me confuse is …

            I mean,
            if the ai_family’s value is “AF_UNSPEC”,

            how the code judge using IPv4 or IPv6 ?

            For example , if only my pc support IPv6 , will the code trying return the IPv6 address ?

    1. Silver Moon

      check your internet connectivity by pinging the host first.
      use the following command at terminal/console

      ping hostname

      if ping replies come correctly, then try the program again and let me know the results.

Leave a Reply

Your email address will not be published. Required fields are marked *