Annotation of embedaddon/sudo/compat/getaddrinfo.c, revision 1.1

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

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