1*b44da627Seric /* $OpenBSD: getnameinfo_async.c,v 1.1 2012/04/14 09:24:18 eric Exp $ */ 2*b44da627Seric /* 3*b44da627Seric * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> 4*b44da627Seric * 5*b44da627Seric * Permission to use, copy, modify, and distribute this software for any 6*b44da627Seric * purpose with or without fee is hereby granted, provided that the above 7*b44da627Seric * copyright notice and this permission notice appear in all copies. 8*b44da627Seric * 9*b44da627Seric * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10*b44da627Seric * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11*b44da627Seric * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12*b44da627Seric * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13*b44da627Seric * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14*b44da627Seric * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15*b44da627Seric * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16*b44da627Seric */ 17*b44da627Seric #include <sys/types.h> 18*b44da627Seric #include <sys/socket.h> 19*b44da627Seric #include <netinet/in.h> 20*b44da627Seric #include <arpa/inet.h> 21*b44da627Seric #include <arpa/nameser.h> 22*b44da627Seric 23*b44da627Seric #include <err.h> 24*b44da627Seric #include <errno.h> 25*b44da627Seric #include <stdlib.h> 26*b44da627Seric #include <string.h> 27*b44da627Seric #include <unistd.h> 28*b44da627Seric 29*b44da627Seric #include "asr.h" 30*b44da627Seric #include "asr_private.h" 31*b44da627Seric 32*b44da627Seric static int getnameinfo_async_run(struct async *, struct async_res *); 33*b44da627Seric static int _servname(struct async *); 34*b44da627Seric static int _numerichost(struct async *); 35*b44da627Seric 36*b44da627Seric struct async * 37*b44da627Seric getnameinfo_async(const struct sockaddr *sa, socklen_t slen, char *host, 38*b44da627Seric size_t hostlen, char *serv, size_t servlen, int flags, struct asr *asr) 39*b44da627Seric { 40*b44da627Seric struct asr_ctx *ac; 41*b44da627Seric struct async *as; 42*b44da627Seric 43*b44da627Seric ac = asr_use_resolver(asr); 44*b44da627Seric if ((as = async_new(ac, ASR_GETNAMEINFO)) == NULL) 45*b44da627Seric goto abort; /* errno set */ 46*b44da627Seric as->as_run = getnameinfo_async_run; 47*b44da627Seric 48*b44da627Seric if (sa->sa_family == AF_INET) 49*b44da627Seric memmove(&as->as.ni.sa.sa, sa, sizeof (as->as.ni.sa.sain)); 50*b44da627Seric else if (sa->sa_family == AF_INET6) 51*b44da627Seric memmove(&as->as.ni.sa.sa, sa, sizeof (as->as.ni.sa.sain6)); 52*b44da627Seric 53*b44da627Seric as->as.ni.sa.sa.sa_len = slen; 54*b44da627Seric as->as.ni.hostname = host; 55*b44da627Seric as->as.ni.hostnamelen = hostlen; 56*b44da627Seric as->as.ni.servname = serv; 57*b44da627Seric as->as.ni.servnamelen = servlen; 58*b44da627Seric as->as.ni.flags = flags; 59*b44da627Seric 60*b44da627Seric asr_ctx_unref(ac); 61*b44da627Seric return (as); 62*b44da627Seric 63*b44da627Seric abort: 64*b44da627Seric if (as) 65*b44da627Seric async_free(as); 66*b44da627Seric asr_ctx_unref(ac); 67*b44da627Seric return (NULL); 68*b44da627Seric } 69*b44da627Seric 70*b44da627Seric static int 71*b44da627Seric getnameinfo_async_run(struct async *as, struct async_res *ar) 72*b44da627Seric { 73*b44da627Seric void *addr; 74*b44da627Seric socklen_t addrlen; 75*b44da627Seric int r; 76*b44da627Seric 77*b44da627Seric next: 78*b44da627Seric switch(as->as_state) { 79*b44da627Seric 80*b44da627Seric case ASR_STATE_INIT: 81*b44da627Seric 82*b44da627Seric /* Make sure the parameters are all valid. */ 83*b44da627Seric 84*b44da627Seric if (as->as.ni.sa.sa.sa_family != AF_INET && 85*b44da627Seric as->as.ni.sa.sa.sa_family != AF_INET6) { 86*b44da627Seric ar->ar_gai_errno = EAI_FAMILY; 87*b44da627Seric async_set_state(as, ASR_STATE_HALT); 88*b44da627Seric break; 89*b44da627Seric } 90*b44da627Seric 91*b44da627Seric if ((as->as.ni.sa.sa.sa_family == AF_INET && 92*b44da627Seric (as->as.ni.sa.sa.sa_len != sizeof (as->as.ni.sa.sain))) || 93*b44da627Seric (as->as.ni.sa.sa.sa_family == AF_INET6 && 94*b44da627Seric (as->as.ni.sa.sa.sa_len != sizeof (as->as.ni.sa.sain6)))) { 95*b44da627Seric ar->ar_gai_errno = EAI_FAIL; 96*b44da627Seric async_set_state(as, ASR_STATE_HALT); 97*b44da627Seric break; 98*b44da627Seric } 99*b44da627Seric 100*b44da627Seric /* Set the service name first, if needed. */ 101*b44da627Seric if (_servname(as) == -1) { 102*b44da627Seric ar->ar_gai_errno = EAI_OVERFLOW; 103*b44da627Seric async_set_state(as, ASR_STATE_HALT); 104*b44da627Seric break; 105*b44da627Seric } 106*b44da627Seric 107*b44da627Seric if (as->as.ni.hostname == NULL || as->as.ni.hostnamelen == 0) { 108*b44da627Seric ar->ar_gai_errno = 0; 109*b44da627Seric async_set_state(as, ASR_STATE_HALT); 110*b44da627Seric break; 111*b44da627Seric } 112*b44da627Seric 113*b44da627Seric if (as->as.ni.flags & NI_NUMERICHOST) { 114*b44da627Seric if (_numerichost(as) == -1) { 115*b44da627Seric ar->ar_errno = errno; 116*b44da627Seric if (ar->ar_errno == ENOMEM) 117*b44da627Seric ar->ar_gai_errno = EAI_MEMORY; 118*b44da627Seric else if (ar->ar_errno == ENOSPC) 119*b44da627Seric ar->ar_gai_errno = EAI_OVERFLOW; 120*b44da627Seric else 121*b44da627Seric ar->ar_gai_errno = EAI_SYSTEM; 122*b44da627Seric } else 123*b44da627Seric ar->ar_gai_errno = 0; 124*b44da627Seric async_set_state(as, ASR_STATE_HALT); 125*b44da627Seric break; 126*b44da627Seric } 127*b44da627Seric 128*b44da627Seric if (as->as.ni.sa.sa.sa_family == AF_INET) { 129*b44da627Seric addrlen = sizeof(as->as.ni.sa.sain.sin_addr); 130*b44da627Seric addr = &as->as.ni.sa.sain.sin_addr; 131*b44da627Seric } else { 132*b44da627Seric addrlen = sizeof(as->as.ni.sa.sain6.sin6_addr); 133*b44da627Seric addr = &as->as.ni.sa.sain6.sin6_addr; 134*b44da627Seric } 135*b44da627Seric 136*b44da627Seric /* 137*b44da627Seric * Create a subquery to lookup the address. 138*b44da627Seric */ 139*b44da627Seric as->as.ni.subq = gethostbyaddr_async_ctx(addr, addrlen, 140*b44da627Seric as->as.ni.sa.sa.sa_family, 141*b44da627Seric as->as_ctx); 142*b44da627Seric if (as->as.ni.subq == NULL) { 143*b44da627Seric ar->ar_errno = errno; 144*b44da627Seric ar->ar_gai_errno = EAI_MEMORY; 145*b44da627Seric async_set_state(as, ASR_STATE_HALT); 146*b44da627Seric break; 147*b44da627Seric } 148*b44da627Seric 149*b44da627Seric async_set_state(as, ASR_STATE_SUBQUERY); 150*b44da627Seric break; 151*b44da627Seric 152*b44da627Seric case ASR_STATE_SUBQUERY: 153*b44da627Seric 154*b44da627Seric if ((r = async_run(as->as.ni.subq, ar)) == ASYNC_COND) 155*b44da627Seric return (ASYNC_COND); 156*b44da627Seric 157*b44da627Seric /* 158*b44da627Seric * Request done. 159*b44da627Seric */ 160*b44da627Seric as->as.ni.subq = NULL; 161*b44da627Seric 162*b44da627Seric if (ar->ar_hostent == NULL) { 163*b44da627Seric if (as->as.ni.flags & NI_NAMEREQD) { 164*b44da627Seric ar->ar_gai_errno = EAI_NONAME; 165*b44da627Seric } else if (_numerichost(as) == -1) { 166*b44da627Seric ar->ar_errno = errno; 167*b44da627Seric if (ar->ar_errno == ENOMEM) 168*b44da627Seric ar->ar_gai_errno = EAI_MEMORY; 169*b44da627Seric else if (ar->ar_errno == ENOSPC) 170*b44da627Seric ar->ar_gai_errno = EAI_OVERFLOW; 171*b44da627Seric else 172*b44da627Seric ar->ar_gai_errno = EAI_SYSTEM; 173*b44da627Seric } else 174*b44da627Seric ar->ar_gai_errno = 0; 175*b44da627Seric } else { 176*b44da627Seric if (strlcpy(as->as.ni.hostname, 177*b44da627Seric ar->ar_hostent->h_name, 178*b44da627Seric as->as.ni.hostnamelen) >= as->as.ni.hostnamelen) 179*b44da627Seric ar->ar_gai_errno = EAI_OVERFLOW; 180*b44da627Seric else 181*b44da627Seric ar->ar_gai_errno = 0; 182*b44da627Seric freehostent(ar->ar_hostent); 183*b44da627Seric } 184*b44da627Seric 185*b44da627Seric async_set_state(as, ASR_STATE_HALT); 186*b44da627Seric break; 187*b44da627Seric 188*b44da627Seric case ASR_STATE_HALT: 189*b44da627Seric return (ASYNC_DONE); 190*b44da627Seric 191*b44da627Seric default: 192*b44da627Seric ar->ar_errno = EOPNOTSUPP; 193*b44da627Seric ar->ar_h_errno = NETDB_INTERNAL; 194*b44da627Seric ar->ar_gai_errno = EAI_SYSTEM; 195*b44da627Seric async_set_state(as, ASR_STATE_HALT); 196*b44da627Seric break; 197*b44da627Seric } 198*b44da627Seric goto next; 199*b44da627Seric } 200*b44da627Seric 201*b44da627Seric 202*b44da627Seric /* 203*b44da627Seric * Set the service name on the result buffer is not NULL. 204*b44da627Seric * return (-1) if the buffer is too small. 205*b44da627Seric */ 206*b44da627Seric static int 207*b44da627Seric _servname(struct async *as) 208*b44da627Seric { 209*b44da627Seric struct servent s; 210*b44da627Seric struct servent_data sd; 211*b44da627Seric int port, r; 212*b44da627Seric char *buf = as->as.ni.servname; 213*b44da627Seric size_t buflen = as->as.ni.servnamelen; 214*b44da627Seric 215*b44da627Seric if (as->as.ni.servname == NULL || as->as.ni.servnamelen == 0) 216*b44da627Seric return (0); 217*b44da627Seric 218*b44da627Seric if (as->as.ni.sa.sa.sa_family == AF_INET) 219*b44da627Seric port = as->as.ni.sa.sain.sin_port; 220*b44da627Seric else 221*b44da627Seric port = as->as.ni.sa.sain6.sin6_port; 222*b44da627Seric 223*b44da627Seric if (!(as->as.ni.flags & NI_NUMERICSERV)) { 224*b44da627Seric memset(&sd, 0, sizeof (sd)); 225*b44da627Seric if (getservbyport_r(port, 226*b44da627Seric (as->as.ni.flags & NI_DGRAM) ? "udp" : "tcp", 227*b44da627Seric &s, &sd) != -1) { 228*b44da627Seric r = strlcpy(buf, s.s_name, buflen) >= buflen; 229*b44da627Seric endservent_r(&sd); 230*b44da627Seric return (r ? -1 : 0); 231*b44da627Seric } 232*b44da627Seric } 233*b44da627Seric 234*b44da627Seric r = snprintf(buf, buflen, "%u", ntohs(port)); 235*b44da627Seric if (r == -1 || r >= buflen) 236*b44da627Seric return (-1); 237*b44da627Seric 238*b44da627Seric return (0); 239*b44da627Seric } 240*b44da627Seric 241*b44da627Seric /* 242*b44da627Seric * Write the numeric address 243*b44da627Seric */ 244*b44da627Seric static int 245*b44da627Seric _numerichost(struct async *as) 246*b44da627Seric { 247*b44da627Seric void *addr; 248*b44da627Seric char *buf = as->as.ni.hostname; 249*b44da627Seric size_t buflen = as->as.ni.hostnamelen; 250*b44da627Seric 251*b44da627Seric if (as->as.ni.sa.sa.sa_family == AF_INET) 252*b44da627Seric addr = &as->as.ni.sa.sain.sin_addr; 253*b44da627Seric else 254*b44da627Seric addr = &as->as.ni.sa.sain6.sin6_addr; 255*b44da627Seric 256*b44da627Seric if (inet_ntop(as->as.ni.sa.sa.sa_family, addr, buf, buflen) == NULL) 257*b44da627Seric /* errno set */ 258*b44da627Seric return (-1); 259*b44da627Seric 260*b44da627Seric return (0); 261*b44da627Seric } 262