Unix Network Programming, Volume 1: The Sockets Networking API (3rd Edition)

11.3 gethostbyname Function

Host 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.

It is unlikely that gethostbyname implementations will actually disappear until the whole Internet is using IPv6, which will be far in the future. However, withdrawing the function from the POSIX specification is a way to assert that it should not be used in new code. We encourage the use of getaddrinfo (Section 11.6) in new programs.

#include <netdb.h>

struct hostent *gethostbyname (const char * hostname );

Returns: non-null pointer if OK, NULL on error with h_errno set

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.

Some versions of gethostbyname allow the hostname argument to be a dotted-decimal string. That is, a call of the form

hptr = gethostbyname ("192.168.42.2");

will work. This code was added because the Rlogin client accepts only a hostname, calling gethostbyname , and will not accept a dotted-decimal string [Vixie 1996]. The POSIX specification permits , but does not require, this behavior, so a portable application cannot depend on it.

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>:

  • HOST_NOT_FOUND

  • TRY_AGAIN

  • NO_RECOVERY

  • NO_DATA (identical to NO_ADDRESS )

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.

Example

Figure 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

Категории