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

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

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