Annotation of embedaddon/sudo/compat/getaddrinfo.c, revision 1.1.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>