getaddrinfo

The functions getaddrinfo() and getnameinfo() convert domain names, hostnames, and IP addresses between human-readable text representations and structured binary formats for the operating system's networking API. Both functions are contained in the POSIX standard application programming interface (API).

getaddrinfo and getnameinfo are inverse functions of each other. They are network protocol agnostic, and support both IPv4 and IPv6. It is the recommended interface for name resolution in building protocol independent applications and for transitioning legacy IPv4 code to the IPv6 Internet.

Internally, the functions perform resolutions using the Domain Name System (DNS) by calling other, lower level functions, such as gethostbyname().

On February 16 2016 a security bug was announced in the glibc implementation of getaddrinfo(), using a buffer overflow technique, that may allow execution of arbitrary code by the attacker.[1]

struct addrinfo

The C data structure used to represent addresses and hostnames within the networking API is the following:

struct addrinfo {
    int     ai_flags;
    int     ai_family;
    int     ai_socktype;
    int     ai_protocol;
    size_t  ai_addrlen;
    struct  sockaddr* ai_addr;
    char*   ai_canonname;     /* canonical name */
    struct  addrinfo* ai_next; /* this struct can form a linked list */
};

In some operating systems the type of ai_addrlen was changed from size_t to socklen_t. Most socket functions, such as accept and getpeername, require the parameter to have type socklen_t* and programmers often pass the address to the ai_addrlen element of the addrinfo structure. If the types are incompatible, e.g., on a big-endian 64-bit Solaris 9 system where size_t is 8 bytes and socklen_t is 4 bytes, then run-time errors may result.

The structure contains structures ai_family and sockaddr with its own sa_family field. These are set to the same value when the structure is created with function getaddrinfo in some implementations.

getaddrinfo()

getaddrinfo() converts human-readable text strings representing hostnames or IP addresses into a dynamically allocated linked list of struct addrinfo structures. The function prototypes for these functions are specified as follows:

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int getaddrinfo(const char* hostname,
                const char* service,
                const struct addrinfo* hints,
                struct addrinfo** res);

The function returns 0 upon success and negative if it fails.[2]

Although implementations vary among platforms, the function first attempts to obtain a port number usually by branching on service. If the string value is a number, it converts it to an integer and calls htons(). If it is a service name, such as www, the service is lookup with getservbyname(), using the protocol derived from hints->ai_socktype as the second parameter to that function. Then, if hostname is given (not NULL), a call to gethostbyname() resolves it, or otherwise the address 0.0.0.0 is used, if hints->ai_flags is set to AI_PASSIVE, and 127.0.0.1 otherwise. It calls malloc_ai in one of these conditions and passes the port retrieved at the beginning to allocate an addrinfo structure filled with the appropriate sockaddr_in. Finally, the **res parameter is dereferenced to make it point to a newly allocated addrinfo structure.[3] In some implementations, such as the Unix version for Mac OS, the hints->ai_protocol overrides the hints->ai_socktype value while in others it is the opposite, so both need to be defined with equivalent values for the code to be work across multiple platforms.

getnameinfo()

getnameinfo() converts the internal binary representation of an IP address in the form of a struct sockaddr pointer into text strings consisting of the hostname or, if the address cannot be resolved into a name, a textual IP address representation, as well as the service port name or number. The function prototype is specified as follows:

#include <sys/socket.h>
#include <netdb.h>

int getnameinfo(const struct sockaddr* sa, socklen_t salen,
                char* host, size_t hostlen,
                char* serv, size_t servlen,
                int flags);

freeaddrinfo()

This function frees the memory allocated by the getaddrinfo() function. As the result of the latter is a link list of addrinfo structures, freeaddrinfo() loops through the list and free each one it turn

#include <sys/socket.h>
#include <netdb.h>

void freeaddrinfo(struct addrinfo *ai);

Example

The following example uses getaddrinfo() to resolve the domain name www.example.com into its list of addresses and then calls getnameinfo() on each result to return the canonical name for the address. In general, this produces the original hostname, unless the particular address has multiple names, in which case the canonical name is returned. In this example, the domain name is printed three times, once for each of the three results obtained.

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>

#ifndef   NI_MAXHOST
#define   NI_MAXHOST 1025
#endif

int main(void)
{
    struct addrinfo* result;
    struct addrinfo* res;
    int error;

    /* resolve the domain name into a list of addresses */
    error = getaddrinfo("www.example.com", NULL, NULL, &result);
    if (error != 0) {   
        if (error == EAI_SYSTEM) {
            perror("getaddrinfo");
        } else {
            fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
        }   
        exit(EXIT_FAILURE);
    }   

    /* loop over all returned results and do inverse lookup */
    for (res = result; res != NULL; res = res->ai_next) {   
        char hostname[NI_MAXHOST];
        error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0); 
        if (error != 0) {
            fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error));
            continue;
        }
        if (*hostname != '\0')
            printf("hostname: %s\n", hostname);
    }   

    freeaddrinfo(result);
    return 0;
}

See also

References

  1. https://googleonlinesecurity.blogspot.ca/2016/02/cve-2015-7547-glibc-getaddrinfo-stack.html
  2. Stevens R., Fenner, Rudoff [2003] UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking API. Publisher: Addison-Wesley Professional. Pub. Date: November 14, 2003 p. 256
  3. Hajimu UMEMOTO [2000] getaddrinfo.c Accessed from: http://www.opensource.apple.com/source/passwordserver_sasl/passwordserver_sasl-14/cyrus_sasl/lib/getaddrinfo.c

External links

This article is issued from Wikipedia - version of the Wednesday, March 30, 2016. The text is available under the Creative Commons Attribution/Share Alike but additional terms may apply for the media files.