📄 getaddrinfo.c
字号:
pai->ai_family = ex->e_af; if (pai->ai_socktype == ANY && ex->e_socktype != ANY) pai->ai_socktype = ex->e_socktype; if (pai->ai_protocol == ANY && ex->e_protocol != ANY) pai->ai_protocol = ex->e_protocol; if (hostname == NULL) error = explore_null(pai, servname, &cur->ai_next); else error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next); if (error) goto free; while (cur && cur->ai_next) cur = cur->ai_next; } /* * XXX * If numreic representation of AF1 can be interpreted as FQDN * representation of AF2, we need to think again about the code below. */ if (sentinel.ai_next) goto good; if (pai->ai_flags & AI_NUMERICHOST) ERR(EAI_NONAME); if (hostname == NULL) ERR(EAI_NODATA); if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0)) ERR(EAI_FAIL); /* * hostname as alphabetical name. * we would like to prefer AF_INET6 than AF_INET, so we'll make a * outer loop by AFs. */ for (ex = explore; ex->e_af >= 0; ex++) { *pai = ai0; /* require exact match for family field */ if (pai->ai_family != ex->e_af) continue; if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) { continue; } if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) { continue; } if (pai->ai_socktype == ANY && ex->e_socktype != ANY) pai->ai_socktype = ex->e_socktype; if (pai->ai_protocol == ANY && ex->e_protocol != ANY) pai->ai_protocol = ex->e_protocol; error = explore_fqdn(pai, hostname, servname, &cur->ai_next); while (cur && cur->ai_next) cur = cur->ai_next; } /* XXX */ if (sentinel.ai_next) error = 0; if (error) goto free; if (error == 0) { if (sentinel.ai_next) { good: *res = sentinel.ai_next; return SUCCESS; } else error = EAI_FAIL; } free: bad: if (sentinel.ai_next) freeaddrinfo(sentinel.ai_next); *res = NULL; return error;}/* * FQDN hostname, DNS lookup */static intexplore_fqdn(pai, hostname, servname, res) const struct addrinfo *pai; const char *hostname; const char *servname; struct addrinfo **res;{ struct addrinfo *result; struct addrinfo *cur; int error = 0; static const ns_dtab dtab[] = { NS_FILES_CB(_files_getaddrinfo, NULL) { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ NS_NIS_CB(_yp_getaddrinfo, NULL) { 0 } }; result = NULL; /* * if the servname does not match socktype/protocol, ignore it. */ if (get_portmatch(pai, servname) != 0) return 0; switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", default_dns_files, hostname, pai)) { case NS_TRYAGAIN: error = EAI_AGAIN; goto free; case NS_UNAVAIL: error = EAI_FAIL; goto free; case NS_NOTFOUND: error = EAI_NODATA; goto free; case NS_SUCCESS: error = 0; for (cur = result; cur; cur = cur->ai_next) { GET_PORT(cur, servname); /* canonname should be filled already */ } break; } *res = result; return 0;free: if (result) freeaddrinfo(result); return error;}/* * hostname == NULL. * passive socket -> anyaddr (0.0.0.0 or ::) * non-passive socket -> localhost (127.0.0.1 or ::1) */static intexplore_null(pai, servname, res) const struct addrinfo *pai; const char *servname; struct addrinfo **res;{ int s; const struct afd *afd; struct addrinfo *cur; struct addrinfo sentinel; int error; *res = NULL; sentinel.ai_next = NULL; cur = &sentinel; /* * filter out AFs that are not supported by the kernel * XXX errno? */ s = socket(pai->ai_family, SOCK_DGRAM, 0); if (s < 0) { if (errno != EMFILE) return 0; } else close(s); /* * if the servname does not match socktype/protocol, ignore it. */ if (get_portmatch(pai, servname) != 0) return 0; afd = find_afd(pai->ai_family); if (afd == NULL) return 0; if (pai->ai_flags & AI_PASSIVE) { GET_AI(cur->ai_next, afd, afd->a_addrany); /* xxx meaningless? * GET_CANONNAME(cur->ai_next, "anyaddr"); */ GET_PORT(cur->ai_next, servname); } else { GET_AI(cur->ai_next, afd, afd->a_loopback); /* xxx meaningless? * GET_CANONNAME(cur->ai_next, "localhost"); */ GET_PORT(cur->ai_next, servname); } cur = cur->ai_next; *res = sentinel.ai_next; return 0;free: if (sentinel.ai_next) freeaddrinfo(sentinel.ai_next); return error;}/* * numeric hostname */static intexplore_numeric(pai, hostname, servname, res) const struct addrinfo *pai; const char *hostname; const char *servname; struct addrinfo **res;{ const struct afd *afd; struct addrinfo *cur; struct addrinfo sentinel; int error; char pton[PTON_MAX]; *res = NULL; sentinel.ai_next = NULL; cur = &sentinel; /* * if the servname does not match socktype/protocol, ignore it. */ if (get_portmatch(pai, servname) != 0) return 0; afd = find_afd(pai->ai_family); if (afd == NULL) return 0; switch (afd->a_af) {#if 1 /*X/Open spec*/ case AF_INET: if (inet_aton(hostname, (struct in_addr *)pton) == 1) { if (pai->ai_family == afd->a_af || pai->ai_family == PF_UNSPEC /*?*/) { GET_AI(cur->ai_next, afd, pton); GET_PORT(cur->ai_next, servname); while (cur && cur->ai_next) cur = cur->ai_next; } else ERR(EAI_FAMILY); /*xxx*/ } break;#endif default: if (inet_pton(afd->a_af, hostname, pton) == 1) { if (pai->ai_family == afd->a_af || pai->ai_family == PF_UNSPEC /*?*/) { GET_AI(cur->ai_next, afd, pton); GET_PORT(cur->ai_next, servname); while (cur && cur->ai_next) cur = cur->ai_next; } else ERR(EAI_FAMILY); /*xxx*/ } break; } *res = sentinel.ai_next; return 0;free:bad: if (sentinel.ai_next) freeaddrinfo(sentinel.ai_next); return error;}/* * numeric hostname with scope */static intexplore_numeric_scope(pai, hostname, servname, res) const struct addrinfo *pai; const char *hostname; const char *servname; struct addrinfo **res;{#if !defined(SCOPE_DELIMITER) || !defined(INET6) return explore_numeric(pai, hostname, servname, res);#else const struct afd *afd; struct addrinfo *cur; int error; char *cp, *hostname2 = NULL, *scope, *addr; struct sockaddr_in6 *sin6; /* * if the servname does not match socktype/protocol, ignore it. */ if (get_portmatch(pai, servname) != 0) return 0; afd = find_afd(pai->ai_family); if (afd == NULL) return 0; if (!afd->a_scoped) return explore_numeric(pai, hostname, servname, res); cp = strchr(hostname, SCOPE_DELIMITER); if (cp == NULL) return explore_numeric(pai, hostname, servname, res); /* * Handle special case of <scoped_address><delimiter><scope id> */ hostname2 = strdup(hostname); if (hostname2 == NULL) return EAI_MEMORY; /* terminate at the delimiter */ hostname2[cp - hostname] = '\0'; addr = hostname2; scope = cp + 1; error = explore_numeric(pai, addr, servname, res); if (error == 0) { int scopeid; for (cur = *res; cur; cur = cur->ai_next) { if (cur->ai_family != AF_INET6) continue; sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; if ((scopeid = ip6_str2scopeid(scope, sin6)) == -1) { free(hostname2); return(EAI_NODATA); /* XXX: is return OK? */ } sin6->sin6_scope_id = scopeid; } } free(hostname2); return error;#endif}static intget_canonname(pai, ai, str) const struct addrinfo *pai; struct addrinfo *ai; const char *str;{ if ((pai->ai_flags & AI_CANONNAME) != 0) { ai->ai_canonname = (char *)malloc(strlen(str) + 1); if (ai->ai_canonname == NULL) return EAI_MEMORY; strcpy(ai->ai_canonname, str); } return 0;}static struct addrinfo *get_ai(pai, afd, addr) const struct addrinfo *pai; const struct afd *afd; const char *addr;{ char *p; struct addrinfo *ai;#ifdef FAITH struct in6_addr faith_prefix; char *fp_str; int translate = 0;#endif#ifdef FAITH /* * Transfrom an IPv4 addr into a special IPv6 addr format for * IPv6->IPv4 translation gateway. (only TCP is supported now) * * +-----------------------------------+------------+ * | faith prefix part (12 bytes) | embedded | * | | IPv4 addr part (4 bytes) * +-----------------------------------+------------+ * * faith prefix part is specified as ascii IPv6 addr format * in environmental variable GAI. * For FAITH to work correctly, routing to faith prefix must be * setup toward a machine where a FAITH daemon operates. * Also, the machine must enable some mechanizm * (e.g. faith interface hack) to divert those packet with * faith prefixed destination addr to user-land FAITH daemon. */ fp_str = getenv("GAI"); if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { u_int32_t v4a; u_int8_t v4a_top; memcpy(&v4a, addr, sizeof v4a); v4a_top = v4a >> IN_CLASSA_NSHIFT; if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && v4a_top != 0 && v4a != IN_LOOPBACKNET) { afd = &afdl[N_INET6]; memcpy(&faith_prefix.s6_addr[12], addr, sizeof(struct in_addr)); translate = 1; } }#endif ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + (afd->a_socklen)); if (ai == NULL) return NULL; memcpy(ai, pai, sizeof(struct addrinfo)); ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); memset(ai->ai_addr, 0, (size_t)afd->a_socklen); ai->ai_addrlen = afd->a_socklen; ai->ai_addr->sa_family = ai->ai_family = afd->a_af; p = (char *)(void *)(ai->ai_addr);#ifdef FAITH if (translate == 1) memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen); else#endif memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); return ai;}static intget_portmatch(ai, servname) const struct addrinfo *ai; const char *servname;{ /* get_port does not touch first argument. when matchonly == 1. */ /* LINTED const cast */ return get_port((struct addrinfo *)ai, servname, 1);}static intget_port(ai, servname, matchonly) struct addrinfo *ai; const char *servname; int matchonly;{ const char *proto; struct servent *sp; int port; int allownumeric; if (servname == NULL) return 0; switch (ai->ai_family) { case AF_INET:#ifdef AF_INET6 case AF_INET6:#endif break; default: return 0; } switch (ai->ai_socktype) { case SOCK_RAW: return EAI_SERVICE; case SOCK_DGRAM: case SOCK_STREAM: allownumeric = 1; break; case ANY: allownumeric = 0; break; default: return EAI_SOCKTYPE; } if (str_isnumber(servname)) { if (!allownumeric) return EAI_SERVICE; port = htons(atoi(servname)); if (port < 0 || port > 65535) return EAI_SERVICE; } else { switch (ai->ai_socktype) { case SOCK_DGRAM: proto = "udp"; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -