📄 getaddrinfo.c
字号:
case SOCK_STREAM: proto = "tcp"; break; default: proto = NULL; break; } if ((sp = getservbyname(servname, proto)) == NULL) return EAI_SERVICE; port = sp->s_port; } if (!matchonly) { switch (ai->ai_family) { case AF_INET: ((struct sockaddr_in *)(void *) ai->ai_addr)->sin_port = port; break;#ifdef INET6 case AF_INET6: ((struct sockaddr_in6 *)(void *) ai->ai_addr)->sin6_port = port; break;#endif } } return 0;}static const struct afd *find_afd(af) int af;{ const struct afd *afd; if (af == PF_UNSPEC) return NULL; for (afd = afdl; afd->a_af; afd++) { if (afd->a_af == af) return afd; } return NULL;}/* * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend * will take care of it. * the semantics of AI_ADDRCONFIG is not defined well. we are not sure * if the code is right or not. * * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with * _dns_getaddrinfo. */static intaddrconfig(pai) struct addrinfo *pai;{ int s, af; /* * TODO: * Note that implementation dependent test for address * configuration should be done everytime called * (or apropriate interval), * because addresses will be dynamically assigned or deleted. */ af = pai->ai_family; if (af == AF_UNSPEC) { if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) af = AF_INET; else { close(s); if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) af = AF_INET6; else close(s); } } if (af != AF_UNSPEC) { if ((s = socket(af, SOCK_DGRAM, 0)) < 0) return 0; close(s); } pai->ai_family = af; return 1;}#ifdef INET6/* convert a string to a scope identifier. XXX: IPv6 specific */static intip6_str2scopeid(scope, sin6) char *scope; struct sockaddr_in6 *sin6;{ int scopeid; struct in6_addr *a6 = &sin6->sin6_addr; char *ep; /* empty scopeid portion is invalid */ if (*scope == '\0') return -1; if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { /* * We currently assume a one-to-one mapping between links * and interfaces, so we simply use interface indices for * like-local scopes. */ scopeid = if_nametoindex(scope); if (scopeid == 0) goto trynumeric; return(scopeid); } /* still unclear about literal, allow numeric only - placeholder */ if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) goto trynumeric; if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) goto trynumeric; else goto trynumeric; /* global */ /* try to convert to a numeric id as a last resort */ trynumeric: scopeid = (int)strtoul(scope, &ep, 10); if (*ep == '\0') return scopeid; else return -1;}#endif#ifdef DEBUGstatic const char AskedForGot[] = "gethostby*.getanswer: asked for \"%s\", got \"%s\"";#endifstatic FILE *hostf = NULL;static struct addrinfo *getanswer(answer, anslen, qname, qtype, pai) const querybuf *answer; int anslen; const char *qname; int qtype; const struct addrinfo *pai;{ struct addrinfo sentinel, *cur; struct addrinfo ai; const struct afd *afd; char *canonname; const HEADER *hp; const u_char *cp; int n; const u_char *eom; char *bp; int type, class, buflen, ancount, qdcount; int haveanswer, had_error; char tbuf[MAXDNAME]; int (*name_ok)(const char *); char hostbuf[8*1024]; memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; canonname = NULL; eom = answer->buf + anslen; switch (qtype) { case T_A: case T_AAAA: case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ name_ok = res_hnok; break; default: return (NULL); /* XXX should be abort(); */ } /* * find first satisfactory answer */ hp = &answer->hdr; ancount = ntohs(hp->ancount); qdcount = ntohs(hp->qdcount); bp = hostbuf; buflen = sizeof hostbuf; cp = answer->buf + HFIXEDSZ; if (qdcount != 1) { h_errno = NO_RECOVERY; return (NULL); } n = dn_expand(answer->buf, eom, cp, bp, buflen); if ((n < 0) || !(*name_ok)(bp)) { h_errno = NO_RECOVERY; return (NULL); } cp += n + QFIXEDSZ; if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { /* res_send() has already verified that the query name is the * same as the one we sent; this just gets the expanded name * (i.e., with the succeeding search-domain tacked on). */ n = strlen(bp) + 1; /* for the \0 */ if (n >= MAXHOSTNAMELEN) { h_errno = NO_RECOVERY; return (NULL); } canonname = bp; bp += n; buflen -= n; /* The qname can be abbreviated, but h_name is now absolute. */ qname = canonname; } haveanswer = 0; had_error = 0; while (ancount-- > 0 && cp < eom && !had_error) { n = dn_expand(answer->buf, eom, cp, bp, buflen); if ((n < 0) || !(*name_ok)(bp)) { had_error++; continue; } cp += n; /* name */ type = _getshort(cp); cp += INT16SZ; /* type */ class = _getshort(cp); cp += INT16SZ + INT32SZ; /* class, TTL */ n = _getshort(cp); cp += INT16SZ; /* len */ if (class != C_IN) { /* XXX - debug? syslog? */ cp += n; continue; /* XXX - had_error++ ? */ } if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && type == T_CNAME) { n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); if ((n < 0) || !(*name_ok)(tbuf)) { had_error++; continue; } cp += n; /* Get canonical name. */ n = strlen(tbuf) + 1; /* for the \0 */ if (n > buflen || n >= MAXHOSTNAMELEN) { had_error++; continue; } strcpy(bp, tbuf); canonname = bp; bp += n; buflen -= n; continue; } if (qtype == T_ANY) { if (!(type == T_A || type == T_AAAA)) { cp += n; continue; } } else if (type != qtype) {#ifdef DEBUG if (type != T_KEY && type != T_SIG) syslog(LOG_NOTICE|LOG_AUTH, "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", qname, p_class(C_IN), p_type(qtype), p_type(type));#endif cp += n; continue; /* XXX - had_error++ ? */ } switch (type) { case T_A: case T_AAAA: if (strcasecmp(canonname, bp) != 0) {#ifdef DEBUG syslog(LOG_NOTICE|LOG_AUTH, AskedForGot, canonname, bp);#endif cp += n; continue; /* XXX - had_error++ ? */ } if (type == T_A && n != INADDRSZ) { cp += n; continue; } if (type == T_AAAA && n != IN6ADDRSZ) { cp += n; continue; }#ifdef FILTER_V4MAPPED if (type == T_AAAA) { struct in6_addr in6; memcpy(&in6, cp, sizeof(in6)); if (IN6_IS_ADDR_V4MAPPED(&in6)) { cp += n; continue; } }#endif if (!haveanswer) { int nn; canonname = bp; nn = strlen(bp) + 1; /* for the \0 */ bp += nn; buflen -= nn; } /* don't overwrite pai */ ai = *pai; ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; afd = find_afd(ai.ai_family); if (afd == NULL) { cp += n; continue; } cur->ai_next = get_ai(&ai, afd, (const char *)cp); if (cur->ai_next == NULL) had_error++; while (cur && cur->ai_next) cur = cur->ai_next; cp += n; break; default: abort(); } if (!had_error) haveanswer++; } if (haveanswer) { if (!canonname) (void)get_canonname(pai, sentinel.ai_next, qname); else (void)get_canonname(pai, sentinel.ai_next, canonname); h_errno = NETDB_SUCCESS; return sentinel.ai_next; } h_errno = NO_RECOVERY; return NULL;}/*ARGSUSED*/static int_dns_getaddrinfo(rv, cb_data, ap) void *rv; void *cb_data; va_list ap;{ struct addrinfo *ai; querybuf buf, buf2; const char *name; const struct addrinfo *pai; struct addrinfo sentinel, *cur; struct res_target q, q2; name = va_arg(ap, char *); pai = va_arg(ap, const struct addrinfo *); memset(&q, 0, sizeof(q2)); memset(&q2, 0, sizeof(q2)); memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; switch (pai->ai_family) { case AF_UNSPEC: /* prefer IPv6 */ q.qclass = C_IN; q.qtype = T_AAAA; q.answer = buf.buf; q.anslen = sizeof(buf); q.next = &q2; q2.qclass = C_IN; q2.qtype = T_A; q2.answer = buf2.buf; q2.anslen = sizeof(buf2); break; case AF_INET: q.qclass = C_IN; q.qtype = T_A; q.answer = buf.buf; q.anslen = sizeof(buf); break; case AF_INET6: q.qclass = C_IN; q.qtype = T_AAAA; q.answer = buf.buf; q.anslen = sizeof(buf); break; default: return NS_UNAVAIL; } if (res_searchN(name, &q) < 0) return NS_NOTFOUND; ai = getanswer(&buf, q.n, q.name, q.qtype, pai); if (ai) { cur->ai_next = ai; while (cur && cur->ai_next) cur = cur->ai_next; } if (q.next) { ai = getanswer(&buf2, q2.n, q2.name, q2.qtype, pai); if (ai) cur->ai_next = ai; } if (sentinel.ai_next == NULL) switch (h_errno) { case HOST_NOT_FOUND: return NS_NOTFOUND; case TRY_AGAIN: return NS_TRYAGAIN; default: return NS_UNAVAIL; } *((struct addrinfo **)rv) = sentinel.ai_next; return NS_SUCCESS;}static void_sethtent(){ if (!hostf) hostf = fopen(_PATH_HOSTS, "r" ); else rewind(hostf);}static void_endhtent(){ if (hostf) { (void) fclose(hostf); hostf = NULL; }}static struct addrinfo *_gethtent(name, pai) const char *name; const struct addrinfo *pai;{ char *p; char *cp, *tname, *cname; struct addrinfo hints, *res0, *res; int error; const char *addr; char hostbuf[8*1024]; if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) return (NULL); again: if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) return (NULL); if (*p == '#') goto again; if (!(cp = strpbrk(p, "#\n"))) goto again; *cp = '\0'; if (!(cp = strpbrk(p, " \t"))) goto again; *cp++ = '\0'; addr = p; cname = NULL; /* if this is not something we're looking for, skip it. */ while (cp && *cp) { if (*cp == ' ' || *cp == '\t') { cp++; continue; } tname = cp; if (cname == NULL) cname = cp; if ((cp = strpbrk(cp, " \t")) != NULL) *cp++ = '\0'; if (strcasecmp(name, tname) == 0) goto found; } goto again;found: hints = *pai; hints.ai_flags = AI_NUMERICHOST; error = getaddrinfo(addr, NULL, &hints, &res0); if (error) goto again;#ifdef FILTER_V4MAPPED /* XXX should check all items in the chain */ if (res0->ai_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { freeaddrinfo(res0); goto again; }#endif for (res = res0; res; res = res->ai_next) { /* cover it up */ res->ai_flags = pai->ai_flags;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -