Index: asr/getaddrinfo_async.c =================================================================== RCS file: /cvs/src/lib/libc/asr/getaddrinfo_async.c,v retrieving revision 1.56 diff -u -p -r1.56 getaddrinfo_async.c --- asr/getaddrinfo_async.c 3 Nov 2018 09:13:24 -0000 1.56 +++ asr/getaddrinfo_async.c 21 Oct 2019 23:19:47 -0000 @@ -34,36 +34,15 @@ #include "asr_private.h" -struct match { - int family; - int socktype; - int protocol; -}; - static int getaddrinfo_async_run(struct asr_query *, struct asr_result *); static int get_port(const char *, const char *, int); +static int get_service(const char *, int, int); static int iter_family(struct asr_query *, int); static int addrinfo_add(struct asr_query *, const struct sockaddr *, const char *); static int addrinfo_from_file(struct asr_query *, int, FILE *); static int addrinfo_from_pkt(struct asr_query *, char *, size_t); static int addrconfig_setup(struct asr_query *); -static const struct match matches[] = { - { PF_INET, SOCK_DGRAM, IPPROTO_UDP }, - { PF_INET, SOCK_STREAM, IPPROTO_TCP }, - { PF_INET, SOCK_RAW, 0 }, - { PF_INET6, SOCK_DGRAM, IPPROTO_UDP }, - { PF_INET6, SOCK_STREAM, IPPROTO_TCP }, - { PF_INET6, SOCK_RAW, 0 }, - { -1, 0, 0, }, -}; - -#define MATCH_FAMILY(a, b) ((a) == matches[(b)].family || (a) == PF_UNSPEC) -#define MATCH_PROTO(a, b) ((a) == matches[(b)].protocol || (a) == 0 || matches[(b)].protocol == 0) -/* Do not match SOCK_RAW unless explicitly specified */ -#define MATCH_SOCKTYPE(a, b) ((a) == matches[(b)].socktype || ((a) == 0 && \ - matches[(b)].socktype != SOCK_RAW)) - enum { DOM_INIT, DOM_DOMAIN, @@ -199,24 +178,28 @@ getaddrinfo_async_run(struct asr_query * } } - /* Make sure there is at least a valid combination */ - for (i = 0; matches[i].family != -1; i++) - if (MATCH_FAMILY(ai->ai_family, i) && - MATCH_SOCKTYPE(ai->ai_socktype, i) && - MATCH_PROTO(ai->ai_protocol, i)) - break; - if (matches[i].family == -1) { - ar->ar_gai_errno = EAI_BADHINTS; - async_set_state(as, ASR_STATE_HALT); - break; - } - - if (ai->ai_protocol == 0 || ai->ai_protocol == IPPROTO_UDP) + switch (ai->ai_protocol) { + case 0: as->as.ai.port_udp = get_port(as->as.ai.servname, "udp", as->as.ai.hints.ai_flags & AI_NUMERICSERV); - if (ai->ai_protocol == 0 || ai->ai_protocol == IPPROTO_TCP) as->as.ai.port_tcp = get_port(as->as.ai.servname, "tcp", as->as.ai.hints.ai_flags & AI_NUMERICSERV); + break; + case IPPROTO_TCP: + as->as.ai.port_tcp = get_port(as->as.ai.servname, "tcp", + as->as.ai.hints.ai_flags & AI_NUMERICSERV); + break; + case IPPROTO_UDP: + /* handle UDP-Lite here too */ + as->as.ai.port_udp = get_port(as->as.ai.servname, "udp", + as->as.ai.hints.ai_flags & AI_NUMERICSERV); + break; + default: + as->as.ai.port_udp = get_service(as->as.ai.servname, + ai->ai_protocol, + as->as.ai.hints.ai_flags & AI_NUMERICSERV); + break; + } if (as->as.ai.port_tcp == -2 || as->as.ai.port_udp == -2 || (as->as.ai.port_tcp == -1 && as->as.ai.port_udp == -1) || (ai->ai_protocol && (as->as.ai.port_udp == -1 || @@ -491,6 +474,24 @@ get_port(const char *servname, const cha return (port); } +static int +get_service(const char *servname, int protocol, int numonly) +{ + struct protoent pe; + struct protoent_data ped; + int rv; + + memset(&ped, 0, sizeof(ped)); + rv = getprotobynumber_r(protocol, &pe, &ped); + if (rv == -1) + return (-1); + + rv = get_port(servname, pe.p_name, numonly); + endprotoent_r(&ped); + + return (rv); +} + /* * Iterate over the address families that are to be queried. Use the * list on the async context, unless a specific family was given in hints. @@ -519,65 +520,107 @@ iter_family(struct asr_query *as, int fi * entry per protocol/socktype match. */ static int -addrinfo_add(struct asr_query *as, const struct sockaddr *sa, const char *cname) +addrinfo_add_ai(struct asr_query *as, const struct sockaddr *sa, + const char *cname, int socktype, int proto, int port) { struct addrinfo *ai; - int i, port, proto; - - for (i = 0; matches[i].family != -1; i++) { - if (matches[i].family != sa->sa_family || - !MATCH_SOCKTYPE(as->as.ai.hints.ai_socktype, i) || - !MATCH_PROTO(as->as.ai.hints.ai_protocol, i)) - continue; - - proto = as->as.ai.hints.ai_protocol; - if (!proto) - proto = matches[i].protocol; - - if (proto == IPPROTO_TCP) - port = as->as.ai.port_tcp; - else if (proto == IPPROTO_UDP) - port = as->as.ai.port_udp; - else - port = 0; + int i; - /* servname specified, but not defined for this protocol */ - if (port == -1) - continue; + if (port == -1) + return (0); - ai = calloc(1, sizeof(*ai) + sa->sa_len); - if (ai == NULL) + ai = calloc(1, sizeof(*ai) + sa->sa_len); + if (ai == NULL) + return (EAI_MEMORY); + ai->ai_family = sa->sa_family; + ai->ai_socktype = socktype; + ai->ai_protocol = proto; + ai->ai_flags = as->as.ai.hints.ai_flags; + ai->ai_addrlen = sa->sa_len; + ai->ai_addr = (void *)(ai + 1); + if (cname && + as->as.ai.hints.ai_flags & (AI_CANONNAME | AI_FQDN)) { + if ((ai->ai_canonname = strdup(cname)) == NULL) { + free(ai); return (EAI_MEMORY); - ai->ai_family = sa->sa_family; - ai->ai_socktype = matches[i].socktype; - ai->ai_protocol = proto; - ai->ai_flags = as->as.ai.hints.ai_flags; - ai->ai_addrlen = sa->sa_len; - ai->ai_addr = (void *)(ai + 1); - if (cname && - as->as.ai.hints.ai_flags & (AI_CANONNAME | AI_FQDN)) { - if ((ai->ai_canonname = strdup(cname)) == NULL) { - free(ai); - return (EAI_MEMORY); - } } - memmove(ai->ai_addr, sa, sa->sa_len); - if (sa->sa_family == PF_INET) - ((struct sockaddr_in *)ai->ai_addr)->sin_port = - htons(port); - else if (sa->sa_family == PF_INET6) - ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = - htons(port); - - if (as->as.ai.aifirst == NULL) - as->as.ai.aifirst = ai; - if (as->as.ai.ailast) - as->as.ai.ailast->ai_next = ai; - as->as.ai.ailast = ai; - as->as_count += 1; } + memmove(ai->ai_addr, sa, sa->sa_len); + if (sa->sa_family == PF_INET) + ((struct sockaddr_in *)ai->ai_addr)->sin_port = + htons(port); + else if (sa->sa_family == PF_INET6) + ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = + htons(port); + + if (as->as.ai.aifirst == NULL) + as->as.ai.aifirst = ai; + if (as->as.ai.ailast) + as->as.ai.ailast->ai_next = ai; + as->as.ai.ailast = ai; + as->as_count += 1; return (0); +} + +static int +addrinfo_add_proto(struct asr_query *as, const struct sockaddr *sa, + const char *cname, int proto, int port) +{ + int rv; + + switch (as->as.ai.hints.ai_socktype) { + case 0: + rv = addrinfo_add_ai(as, sa, cname, SOCK_STREAM, proto, port); + if (rv != 0) + break; + + rv = addrinfo_add_ai(as, sa, cname, SOCK_DGRAM, proto, port); + if (rv != 0) + break; + + break; + + default: + rv = addrinfo_add_ai(as, sa, cname, + as->as.ai.hints.ai_socktype, proto, port); + break; + } + + return (rv); +} + +static int +addrinfo_add(struct asr_query *as, const struct sockaddr *sa, const char *cname) +{ + int rv; + + switch (as->as.ai.hints.ai_protocol) { + case 0: + rv = addrinfo_add_proto(as, sa, cname, + IPPROTO_TCP, as->as.ai.port_tcp); + if (rv != 0) + break; + + rv = addrinfo_add_proto(as, sa, cname, + IPPROTO_UDP, as->as.ai.port_udp); + if (rv != 0) + break; + + break; + + case IPPROTO_TCP: + rv = addrinfo_add_proto(as, sa, cname, + IPPROTO_TCP, as->as.ai.port_tcp); + break; + + default: /* includes IPPROTO_UDP */ + rv = addrinfo_add_proto(as, sa, cname, + as->as.ai.hints.ai_protocol, as->as.ai.port_udp); + break; + } + + return (rv); } static int