gethostbyname() vs getaddrinfo()

In IPv4 environment(usually) we used to call function gethostbyname() to do DNS lookups.then the information is load into a struct hostent.

#include <netdb.h>
struct hostent *gethostbyname(const char *name);

struct  hostent {
        char    *h_name;        /* official name of host */
        char    **h_aliases;    /* alias list */
        int     h_addrtype;     /* host address type */
        int     h_length;       /* length of address */
        char    **h_addr_list;  /* list of addresses from name server */
};
#define h_addr  h_addr_list[0]  /* address, for backward compatibility */

So, the easiest way to get information from gethostbyname() call is by extracting hostent structure.

example:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[ ]) {
  struct hostent *h;

/* error check the command line */
if(argc != 2) {
fprintf(stderr, "Usage: %s hostname\n", argv[0]);
exit(1);
}

/* get the host info */
if((h=gethostbyname(argv[1])) == NULL) {
herror("gethostbyname(): ");
exit(1);
}
else

printf("Hostname: %s\n", h->h_name);
printf("IP Address: %s\n", inet_ntoa(*((struct in_addr *)h->h_addr)));

return 0;
}
$ gcc getipaddr.c -o getipaddr
$ ./getipaddr www.kutukupret.com
Hostname: www.kutukupret.com
IP Address: 202.127.97.30

The hostent structure returns the official host name, the address type, the address length, a number of addresses, and every possible aliases. The function can return both IPv4 and IPv6 addresses.but never can return both types at  the same time.in my case it cannot resolving hostname with ipv6 at all.

$ ./getipaddr mx.ipv6.kutukupret.com
gethostbyname(): : No address associated with name

For solution the gethostbyname2 function was instroduced

#include <netdb.h>
struct hostent *gethostbyname2(const char *name, int af);

It allows to request IPv4 or IPv6 addresses based on the second parameter which can be AF_INET or AF_INET6. These interfaces were OK in the early days. Machines had one network interfaces, but had trouble with names associated with multiple addresse.

In these recent times, we  now have the function getaddrinfo() that does all kinds stuff for us, including DNS and service name lookups, and fills out the structs we need.

#include <netdb.h>
int getaddrinfo(const char *node, const char *service,
                const struct addrinfo *hints, struct addrinfo **res);
struct addrinfo {
    int              ai_flags;     // AI_PASSIVE, AI_CANONNAME, etc.
    int              ai_family;    // AF_INET, AF_INET6, AF_UNSPEC
    int              ai_socktype;  // SOCK_STREAM, SOCK_DGRAM
    int              ai_protocol;  // use 0 for "any"
    size_t           ai_addrlen;   // size of ai_addr in bytes
    struct sockaddr *ai_addr;      // struct sockaddr_in or _in6
    char            *ai_canonname; // full canonical hostname

struct addrinfo *ai_next;      // linked list, next node
};

It’s complicated and has many options. we’ll give this function three input parameters, and it gives us a pointer to a linked-list, res, of results.

The node parameter is the host name to connect to, or an IP address.

Next is the parameter service, which can be a port number, like “80”, or the name of a particular service like “http” or “ftp” or “telnet” or “smtp” or whatever.

Finally, the hints parameter points to a struct addrinfo that you’ve already filled out with relevant information.

Here’s a sample call if we want resolving host with ipv6 address.

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    struct addrinfo hints, *res, *p;
    int status;
    char ipstr[INET6_ADDRSTRLEN];

    if (argc != 2) {
fprintf(stderr, "Usage: %s hostname\n", argv[0]);
return 1;
}

memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
hints.ai_socktype = SOCK_STREAM;

if ((status = getaddrinfo(argv[1], NULL, &hints, &res)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 2;
}

for(p = res;p != NULL; p = p->ai_next) {

void *addr;

if (p->ai_family == AF_INET) {
return 1;

} else {

struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);

/* convert the IP to a string and print it: */
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);

printf("Hostname: %s\n", argv[1]);
printf("IP Address: %s\n", ipstr);

}
}

freeaddrinfo(res); // free the linked list

return 0;
}
$ gcc getipaddr6.c -o getipaddr6
$ ./getipaddr6 ipv6.google.com
Hostname: ipv6.google.com
IP Address: 2001:4860:c004::68

source: http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

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