11.3 gethostbyname FunctionHost computers are normally known by human-readable names. All the examples that we have shown so far in this book have intentionally used IP addresses instead of names , so we know exactly what goes into the socket address structures for functions such as connect and sendto , and what is returned by functions such as accept and recvfrom . But, most applications should deal with names, not addresses. This is especially true as we move to IPv6, since IPv6 addresses (hex strings) are much longer than IPv4 dotted -decimal numbers . (The example AAAA record and ip6.arpa PTR record in the previous section should make this obvious.) The most basic function that looks up a hostname is gethostbyname . If successful, it returns a pointer to a hostent structure that contains all the IPv4 addresses for the host. However, it is limited in that it can only return IPv4 addresses. See Section 11.6 for a function that handles both IPv4 and IPv6 addresses. The POSIX specification cautions that gethostbyname may be withdrawn in a future version of the spec.
The non-null pointer returned by this function points to the following hostent structure: struct hostent { char *h_name; /* official (canonical) name of host */ char **h_aliases; /* pointer to array of pointers to alias names */ int h_addrtype; /* host address type: AF_INET */ int h_length; /* length of address: 4 */ char **h_addr_list; /* ptr to array of ptrs with IPv4 addrs */ }; In terms of the DNS, gethostbyname performs a query for an A record. This function can return only IPv4 addresses. Figure 11.2 shows the arrangement of the hostent structure and the information that it points to assuming the hostname that is looked up has two alias names and three IPv4 addresses. Of these fields, the official hostname and all the aliases are null- terminated C strings. Figure 11.2. hostent structure and the information it contains.
The returned h_name is called the canonical name of the host. For example, given the CNAME records shown in the previous section, the canonical name of the host ftp.unpbook.com would be linux.unpbook.com. Also, if we call gethostbyname from the host aix with an unqualified hostname, say solaris , the FQDN (solaris.unpbook.com) is returned as the canonical name.
gethostbyname differs from the other socket functions that we have described in that it does not set errno when an error occurs. Instead, it sets the global integer h_errno to one of the following constants defined by including <netdb.h>:
The NO_DATA error means the specified name is valid, but it does not have an A record. An example of this is a hostname with only an MX record. Most modern resolvers provide the function hstrerror , which takes an h_errno value as its only argument and returns a const char * pointer to a description of the error. We show some examples of the strings returned by this function in the next example. ExampleFigure 11.3 shows a simple program that calls gethostbyname for any number of command-line arguments and prints all the returned information. Figure 11.3 Call gethostbyname and print returned information.names/hostent.c 1 #include "unp.h" 2 int 3 main(int argc, char **argv) 4 { 5 char *ptr, **pptr; 6 char str [INET_ADDRSTRLEN]; 7 struct hostent *hptr; 8 while (--argc > 0) { 9 ptr = *++argv; 10 if ( (hptr = gethostbyname (ptr) ) == NULL) { 11 err_msg ("gethostbyname error for host: %s: %s", 12 ptr, hstrerror (h_errno) ); 13 continue; 14 } 15 printf ("official hostname: %s\n", hptr->h_name); 16 for (pptr = hptr->h_aliases; *pptr ! = NULL; pptr++) 17 printf ("\talias: %s\n", *pptr); 18 switch (hptr->h_addrtype) { 19 case AF_INET: 20 pptr = hptr->h_addr_list; 21 for ( ; *pptr != NULL; pptr++) 22 printf ("\taddress: %s\n", 23 Inet_ntop (hptr->h_addrtype, *pptr, str, sizeof (str))); 24 break; 25 default: 26 err_ret ("unknown address type"); 27 break; 28 } 29 } 30 exit(0); 31 } 8 “14 gethostbyname is called for each command-line argument. 15 “17 The official hostname is output followed by a list of alias names. 18 “24 pptr points to the array of pointers to the individual addresses. For each address, we call inet_ntop and print the returned string. We first execute the program with the name of our host aix , which has just one IPv4 address. freebsd % hostent aix official hostname: aix.unpbook.com address: 192.168.42.2 Notice that the official hostname is the FQDN. Also notice that even though this host has an IPv6 address, only the IPv4 address is returned. Next is a Web server with multiple IPv4 addresses. freebsd % hostent cnn.com official hostname: cnn.com address: 64.236.16.20 address: 64.236.16.52 address: 64.236.16.84 address: 64.236.16.116 address: 64.236.24.4 address: 64.236.24.12 address: 64.236.24.20 address: 64.236.24.28 Next is a name that we showed in Section 11.2 as having a CNAME record. freebsd % hostent www official hostname: linux. unpbook. com alias: www.unpbook.com address: 206.168.112.219 As expected, the official hostname differs from our command-line argument. To see the error strings returned by the hstrerror function, we first specify a non-existent hostname, and then a name that has only an MX record. freebsd % hostent nosuchname.invalid gethostbyname error for host: nosuchname.invalid: Unknown host freebsd % hostent uunet.uu.net gethostbyname error for host: uunet.uu.net: No address associated with name |