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