File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / compat / getaddrinfo.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:12:54 2014 UTC (10 years, 1 month ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_10p3_0, v1_8_10p3, HEAD
sudo v 1.8.10p3

    1: /*
    2:  * Replacement for a missing getaddrinfo.
    3:  *
    4:  * This is an implementation of getaddrinfo for systems that don't have one so
    5:  * that networking code can use a consistant interface without #ifdef.  It is
    6:  * a fairly minimal implementation, with the following limitations:
    7:  *
    8:  *   - IPv4 support only.  IPv6 is not supported.
    9:  *   - AI_ADDRCONFIG is ignored.
   10:  *   - Not thread-safe due to gethostbyname and getservbyname.
   11:  *   - SOCK_DGRAM and SOCK_STREAM only.
   12:  *   - Multiple possible socket types only generate one addrinfo struct.
   13:  *   - Protocol hints aren't used correctly.
   14:  *
   15:  * The last four issues could probably be easily remedied, but haven't been
   16:  * needed to date.  Adding IPv6 support isn't worth it; systems with IPv6
   17:  * support should already support getaddrinfo natively.
   18:  *
   19:  * The canonical version of this file is maintained in the rra-c-util package,
   20:  * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
   21:  *
   22:  * Written by Russ Allbery <rra@stanford.edu>
   23:  *
   24:  * The authors hereby relinquish any claim to any copyright that they may have
   25:  * in this work, whether granted under contract or by operation of law or
   26:  * international treaty, and hereby commit to the public, at large, that they
   27:  * shall not, at any time in the future, seek to enforce any copyright in this
   28:  * work against any person or entity, or prevent any person or entity from
   29:  * copying, publishing, distributing or creating derivative works of this
   30:  * work.
   31:  */
   32: 
   33: #include <config.h>
   34: 
   35: #ifndef HAVE_GETADDRINFO
   36: 
   37: #include <sys/types.h>
   38: #include <sys/socket.h>
   39: 
   40: #include <stdio.h>
   41: #ifdef STDC_HEADERS
   42: # include <stdlib.h>
   43: # include <stddef.h>
   44: #else
   45: # ifdef HAVE_STDLIB_H
   46: #  include <stdlib.h>
   47: # endif
   48: #endif /* STDC_HEADERS */
   49: #ifdef HAVE_STRING_H
   50: # include <string.h>
   51: #endif /* HAVE_STRING_H */
   52: #ifdef HAVE_STRINGS_H
   53: # include <strings.h>
   54: #endif /* HAVE_STRINGS_H */
   55: #include <limits.h>
   56: #include <netdb.h>
   57: #include <errno.h>
   58: 
   59: #include <arpa/inet.h>
   60: #include <netinet/in.h>
   61: 
   62: #include "compat/getaddrinfo.h"
   63: #include "missing.h"
   64: 
   65: /* We need access to h_errno to map errors from gethostbyname. */
   66: #ifndef HAVE_DECL_H_ERRNO
   67: extern int h_errno;
   68: #endif
   69: 
   70: /*
   71:  * The netdb constants, which aren't always defined (particularly if h_errno
   72:  * isn't declared).  We also make sure that a few of the less-used ones are
   73:  * defined so that we can deal with them in case statements.
   74:  */
   75: #ifndef HOST_NOT_FOUND
   76: # define HOST_NOT_FOUND 1
   77: # define TRY_AGAIN      2
   78: # define NO_RECOVERY    3
   79: # define NO_DATA        4
   80: #endif
   81: #ifndef NETDB_INTERNAL
   82: # define NETDB_INTERNAL -1
   83: #endif
   84: 
   85: /*
   86:  * If we're running the test suite, rename the functions to avoid conflicts
   87:  * with the system version.  Note that we don't rename the structures and
   88:  * constants, but that should be okay (except possibly for gai_strerror).
   89:  */
   90: #ifdef TESTING
   91: # define gai_strerror test_gai_strerror
   92: # define freeaddrinfo test_freeaddrinfo
   93: # define getaddrinfo  test_getaddrinfo
   94: const char *test_gai_strerror(int);
   95: void test_freeaddrinfo(struct addrinfo *);
   96: int test_getaddrinfo(const char *, const char *, const struct addrinfo *,
   97:                      struct addrinfo **);
   98: #endif
   99: 
  100: /*
  101:  * If the native platform doesn't support AI_NUMERICSERV or AI_NUMERICHOST,
  102:  * pick some other values for them.
  103:  */
  104: #ifdef TESTING
  105: # if AI_NUMERICSERV == 0
  106: #  undef AI_NUMERICSERV
  107: #  define AI_NUMERICSERV 0x0080
  108: # endif
  109: # if AI_NUMERICHOST == 0
  110: #  undef AI_NUMERICHOST
  111: #  define AI_NUMERICHOST 0x0100
  112: # endif
  113: #endif
  114: 
  115: /*
  116:  * Value representing all of the hint flags set.  Linux uses flags up to
  117:  * 0x0400, so be sure not to break when testing on that platform.
  118:  */
  119: #ifdef TESTING
  120: # ifdef HAVE_GETADDRINFO
  121: #  define AI_INTERNAL_ALL 0x04ff
  122: # else
  123: #  define AI_INTERNAL_ALL 0x01ff
  124: # endif
  125: #else
  126: # define AI_INTERNAL_ALL 0x007f
  127: #endif
  128: 
  129: /* Table of strings corresponding to the EAI_* error codes. */
  130: static const char * const gai_errors[] = {
  131:     "Host name lookup failure",         /*  1 EAI_AGAIN */
  132:     "Invalid flag value",               /*  2 EAI_BADFLAGS */
  133:     "Unknown server error",             /*  3 EAI_FAIL */
  134:     "Unsupported address family",       /*  4 EAI_FAMILY */
  135:     "Memory allocation failure",        /*  5 EAI_MEMORY */
  136:     "Host unknown or not given",        /*  6 EAI_NONAME */
  137:     "Service not supported for socket", /*  7 EAI_SERVICE */
  138:     "Unsupported socket type",          /*  8 EAI_SOCKTYPE */
  139:     "System error",                     /*  9 EAI_SYSTEM */
  140:     "Supplied buffer too small",        /* 10 EAI_OVERFLOW */
  141: };
  142: 
  143: /* Macro to set the len attribute of sockaddr_in. */
  144: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
  145: # define sin_set_length(s) ((s)->sin_len = sizeof(struct sockaddr_in))
  146: #else
  147: # define sin_set_length(s) /* empty */
  148: #endif
  149: 
  150: /*
  151:  * Used for iterating through arrays.  ARRAY_SIZE returns the number of
  152:  * elements in the array (useful for a < upper bound in a for loop).
  153:  */
  154: #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
  155: 
  156: 
  157: /*
  158:  * Return a constant string for a given EAI_* error code or a string
  159:  * indicating an unknown error.
  160:  */
  161: const char *
  162: gai_strerror(int ecode)
  163: {
  164:     if (ecode < 1 || (size_t) ecode > ARRAY_SIZE(gai_errors))
  165:         return "Unknown error";
  166:     else
  167:         return gai_errors[ecode - 1];
  168: }
  169: 
  170: 
  171: /*
  172:  * Free a linked list of addrinfo structs.
  173:  */
  174: void
  175: freeaddrinfo(struct addrinfo *ai)
  176: {
  177:     struct addrinfo *next;
  178: 
  179:     while (ai != NULL) {
  180:         next = ai->ai_next;
  181:         if (ai->ai_addr != NULL)
  182:             free(ai->ai_addr);
  183:         if (ai->ai_canonname != NULL)
  184:             free(ai->ai_canonname);
  185:         free(ai);
  186:         ai = next;
  187:     }
  188: }
  189: 
  190: 
  191: /*
  192:  * Allocate a new addrinfo struct, setting some defaults given that this
  193:  * implementation is IPv4 only.  Also allocates an attached sockaddr_in and
  194:  * zeroes it, per the requirement for getaddrinfo.  Takes the socktype,
  195:  * canonical name (which is copied if not NULL), address, and port.  Returns
  196:  * NULL on a memory allocation failure.
  197:  */
  198: static struct addrinfo *
  199: gai_addrinfo_new(int socktype, const char *canonical, struct in_addr addr,
  200:                  unsigned short port)
  201: {
  202:     struct addrinfo *ai;
  203: 
  204:     ai = malloc(sizeof(*ai));
  205:     if (ai == NULL)
  206:         return NULL;
  207:     ai->ai_addr = malloc(sizeof(struct sockaddr_in));
  208:     if (ai->ai_addr == NULL) {
  209:         free(ai);
  210:         return NULL;
  211:     }
  212:     ai->ai_next = NULL;
  213:     if (canonical == NULL)
  214:         ai->ai_canonname = NULL;
  215:     else {
  216:         ai->ai_canonname = strdup(canonical);
  217:         if (ai->ai_canonname == NULL) {
  218:             freeaddrinfo(ai);
  219:             return NULL;
  220:         }
  221:     }
  222:     memset(ai->ai_addr, 0, sizeof(struct sockaddr_in));
  223:     ai->ai_flags = 0;
  224:     ai->ai_family = AF_INET;
  225:     ai->ai_socktype = socktype;
  226:     ai->ai_protocol = (socktype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP;
  227:     ai->ai_addrlen = sizeof(struct sockaddr_in);
  228:     ((struct sockaddr_in *) ai->ai_addr)->sin_family = AF_INET;
  229:     ((struct sockaddr_in *) ai->ai_addr)->sin_addr = addr;
  230:     ((struct sockaddr_in *) ai->ai_addr)->sin_port = htons(port);
  231:     sin_set_length((struct sockaddr_in *) ai->ai_addr);
  232:     return ai;
  233: }
  234: 
  235: 
  236: /*
  237:  * Look up a service.  Takes the service name (which may be numeric), the hint
  238:  * flags, a pointer to the socket type (used to determine whether TCP or UDP
  239:  * services are of interest and, if 0, is filled in with the result of
  240:  * getservbyname if the service was not numeric), and a pointer to the
  241:  * addrinfo struct to fill in.  Returns 0 on success or an EAI_* error on
  242:  * failure.
  243:  */
  244: static int
  245: gai_service(const char *servname, int flags, int *type, unsigned short *port)
  246: {
  247:     struct servent *servent;
  248:     const char *protocol;
  249:     const char *errstr;
  250:     unsigned short value;
  251: 
  252:     value = strtonum(servname, 0, USHRT_MAX, &errstr);
  253:     if (errstr == NULL) {
  254:         *port = value;
  255:     } else if (errno == ERANGE) {
  256: 	return EAI_SERVICE;
  257:     } else {
  258:         if (flags & AI_NUMERICSERV)
  259:             return EAI_NONAME;
  260:         if (*type != 0)
  261:             protocol = (*type == SOCK_DGRAM) ? "udp" : "tcp";
  262:         else
  263:             protocol = NULL;
  264: 
  265:         /*
  266:          * We really technically should be generating an addrinfo struct for
  267:          * each possible protocol unless type is set, but this works well
  268:          * enough for what I need this for.
  269:          */
  270:         servent = getservbyname(servname, protocol);
  271:         if (servent == NULL)
  272:             return EAI_NONAME;
  273:         if (strcmp(servent->s_proto, "udp") == 0)
  274:             *type = SOCK_DGRAM;
  275:         else if (strcmp(servent->s_proto, "tcp") == 0)
  276:             *type = SOCK_STREAM;
  277:         else
  278:             return EAI_SERVICE;
  279:         *port = htons(servent->s_port);
  280:     }
  281:     return 0;
  282: }
  283: 
  284: 
  285: /*
  286:  * Look up a host and fill in a linked list of addrinfo structs with the
  287:  * results, one per IP address of the returned host.  Takes the name or IP
  288:  * address of the host as a string, the lookup flags, the type of socket (to
  289:  * fill into the addrinfo structs), the port (likewise), and a pointer to
  290:  * where the head of the linked list should be put.  Returns 0 on success or
  291:  * the appropriate EAI_* error.
  292:  */
  293: static int
  294: gai_lookup(const char *nodename, int flags, int socktype, unsigned short port,
  295:            struct addrinfo **res)
  296: {
  297:     struct addrinfo *ai, *first, *prev;
  298:     struct in_addr addr;
  299:     struct hostent *host;
  300:     const char *canonical;
  301:     int i;
  302: 
  303:     if (inet_pton(AF_INET, nodename, &addr)) {
  304:         canonical = (flags & AI_CANONNAME) ? nodename : NULL;
  305:         ai = gai_addrinfo_new(socktype, canonical, addr, port);
  306:         if (ai == NULL)
  307:             return EAI_MEMORY;
  308:         *res = ai;
  309:         return 0;
  310:     } else {
  311:         if (flags & AI_NUMERICHOST)
  312:             return EAI_NONAME;
  313:         host = gethostbyname(nodename);
  314:         if (host == NULL)
  315:             switch (h_errno) {
  316:             case HOST_NOT_FOUND:
  317:                 return EAI_NONAME;
  318:             case TRY_AGAIN:
  319:             case NO_DATA:
  320:                 return EAI_AGAIN;
  321:             case NO_RECOVERY:
  322:                 return EAI_FAIL;
  323:             case NETDB_INTERNAL:
  324:             default:
  325:                 return EAI_SYSTEM;
  326:             }
  327:         if (host->h_addr_list[0] == NULL)
  328:             return EAI_FAIL;
  329:         canonical = (flags & AI_CANONNAME)
  330:             ? ((host->h_name != NULL) ? host->h_name : nodename)
  331:             : NULL;
  332:         first = NULL;
  333:         prev = NULL;
  334:         for (i = 0; host->h_addr_list[i] != NULL; i++) {
  335:             if (host->h_length != sizeof(addr)) {
  336:                 freeaddrinfo(first);
  337:                 return EAI_FAIL;
  338:             }
  339:             memcpy(&addr, host->h_addr_list[i], sizeof(addr));
  340:             ai = gai_addrinfo_new(socktype, canonical, addr, port);
  341:             if (ai == NULL) {
  342:                 freeaddrinfo(first);
  343:                 return EAI_MEMORY;
  344:             }
  345:             if (first == NULL) {
  346:                 first = ai;
  347:                 prev = ai;
  348:             } else {
  349:                 prev->ai_next = ai;
  350:                 prev = ai;
  351:             }
  352:         }
  353:         *res = first;
  354:         return 0;
  355:     }
  356: }
  357: 
  358: 
  359: /*
  360:  * The actual getaddrinfo implementation.
  361:  */
  362: int
  363: getaddrinfo(const char *nodename, const char *servname,
  364:             const struct addrinfo *hints, struct addrinfo **res)
  365: {
  366:     struct addrinfo *ai;
  367:     struct in_addr addr;
  368:     int flags, socktype, status;
  369:     unsigned short port;
  370: 
  371:     /* Take the hints into account and check them for validity. */
  372:     if (hints != NULL) {
  373:         flags = hints->ai_flags;
  374:         socktype = hints->ai_socktype;
  375:         if ((flags & AI_INTERNAL_ALL) != flags)
  376:             return EAI_BADFLAGS;
  377:         if (hints->ai_family != AF_UNSPEC && hints->ai_family != AF_INET)
  378:             return EAI_FAMILY;
  379:         if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
  380:             return EAI_SOCKTYPE;
  381: 
  382:         /* EAI_SOCKTYPE isn't quite right, but there isn't anything better. */
  383:         if (hints->ai_protocol != 0) {
  384:             int protocol = hints->ai_protocol;
  385:             if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
  386:                 return EAI_SOCKTYPE;
  387:         }
  388:     } else {
  389:         flags = 0;
  390:         socktype = 0;
  391:     }
  392: 
  393:     /*
  394:      * See what we're doing.  If nodename is null, either AI_PASSIVE is set or
  395:      * we're getting information for connecting to a service on the loopback
  396:      * address.  Otherwise, we're getting information for connecting to a
  397:      * remote system.
  398:      */
  399:     if (servname == NULL)
  400:         port = 0;
  401:     else {
  402:         status = gai_service(servname, flags, &socktype, &port);
  403:         if (status != 0)
  404:             return status;
  405:     }
  406:     if (nodename != NULL)
  407:         return gai_lookup(nodename, flags, socktype, port, res);
  408:     else {
  409:         if (servname == NULL)
  410:             return EAI_NONAME;
  411:         if ((flags & AI_PASSIVE) == AI_PASSIVE)
  412:             addr.s_addr = INADDR_ANY;
  413:         else
  414:             addr.s_addr = htonl(0x7f000001UL);
  415:         ai = gai_addrinfo_new(socktype, NULL, addr, port);
  416:         if (ai == NULL)
  417:             return EAI_MEMORY;
  418:         *res = ai;
  419:         return 0;
  420:     }
  421: }
  422: #endif /* HAVE_GETADDRINFO */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>