📄 dns_ho.c
字号:
RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); errno = ENOMEM; goto cleanup; } memset(q, 0, sizeof(q2)); memset(q2, 0, sizeof(q2)); switch (pai->ai_family) { case AF_UNSPEC: /* prefer IPv6 */ q->qclass = C_IN; q->qtype = T_AAAA; q->answer = q->qbuf.buf; q->anslen = sizeof(q->qbuf); q->next = q2; q->action = RESTGT_DOALWAYS; q2->qclass = C_IN; q2->qtype = T_A; q2->answer = q2->qbuf.buf; q2->anslen = sizeof(q2->qbuf); q2->action = RESTGT_DOALWAYS; break; case AF_INET: q->qclass = C_IN; q->qtype = T_A; q->answer = q->qbuf.buf; q->anslen = sizeof(q->qbuf); q->action = RESTGT_DOALWAYS; break; case AF_INET6: q->qclass = C_IN; q->qtype = T_AAAA; q->answer = q->qbuf.buf; q->anslen = sizeof(q->qbuf); q->action = RESTGT_DOALWAYS; break; default: RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /* better error? */ goto cleanup; } /* * if there aren't any dots, it could be a user-level alias. * this is also done in res_nquery() since we are not the only * function that looks up host names. */ if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name, tmp, sizeof tmp))) name = cp; for (p = q; p; p = p->next) { struct addrinfo *ai; switch(p->action) { case RESTGT_DOALWAYS: break; case RESTGT_AFTERFAILURE: if (querystate == RESQRY_SUCCESS) continue; break; case RESTGT_IGNORE: continue; } if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype, p->answer, p->anslen)) < 0) { querystate = RESQRY_FAIL; continue; } (void)gethostans(this, p->answer, n, name, p->qtype, pai->ai_family, /* XXX: meaningless */ 0, &ai, pai); if (ai) { querystate = RESQRY_SUCCESS; cur->ai_next = ai; while (cur && cur->ai_next) cur = cur->ai_next; } else querystate = RESQRY_FAIL; } cleanup: if (q != NULL) memput(q, sizeof(*q)); if (q2 != NULL) memput(q2, sizeof(*q2)); return(sentinel.ai_next);}static voidho_res_set(struct irs_ho *this, struct __res_state *res, void (*free_res)(void *)) { struct pvt *pvt = (struct pvt *)this->private; if (pvt->res && pvt->free_res) { res_nclose(pvt->res); (*pvt->free_res)(pvt->res); } pvt->res = res; pvt->free_res = free_res;}/* Private. */static struct hostent *gethostans(struct irs_ho *this, const u_char *ansbuf, int anslen, const char *qname, int qtype, int af, int size, /* meaningless for addrinfo cases */ struct addrinfo **ret_aip, const struct addrinfo *pai){ struct pvt *pvt = (struct pvt *)this->private; int type, class, ancount, qdcount, n, haveanswer, had_error; int error = NETDB_SUCCESS, arcount; int (*name_ok)(const char *); const HEADER *hp; const u_char *eom; const u_char *eor; const u_char *cp; const char *tname; const char *hname; char *bp, *ep, **ap, **hap; char tbuf[MAXDNAME+1]; struct addrinfo sentinel, *cur, ai; if (pai == NULL) abort(); if (ret_aip != NULL) *ret_aip = NULL; memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; tname = qname; eom = ansbuf + 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; case T_PTR: name_ok = res_dnok; break; default: abort(); } pvt->host.h_addrtype = af; pvt->host.h_length = size; hname = pvt->host.h_name = NULL; /* * Find first satisfactory answer. */ if (ansbuf + HFIXEDSZ > eom) { RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } hp = (const HEADER *)ansbuf; ancount = ntohs(hp->ancount); qdcount = ntohs(hp->qdcount); arcount = ntohs(hp->arcount); bp = pvt->hostbuf; ep = pvt->hostbuf + sizeof(pvt->hostbuf); cp = ansbuf + HFIXEDSZ; if (qdcount != 1) { RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } n = dn_expand(ansbuf, eom, cp, bp, ep - bp); if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) { RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } cp += n + QFIXEDSZ; if (cp > eom) { RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { /* res_nsend() 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) { RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } pvt->host.h_name = bp; hname = bp; bp += n; /* The qname can be abbreviated, but hname is now absolute. */ qname = pvt->host.h_name; } ap = pvt->host_aliases; *ap = NULL; pvt->host.h_aliases = pvt->host_aliases; hap = pvt->h_addr_ptrs; *hap = NULL; pvt->host.h_addr_list = pvt->h_addr_ptrs; haveanswer = 0; had_error = 0; while (ancount-- > 0 && cp < eom && !had_error) { n = dn_expand(ansbuf, eom, cp, bp, ep - bp); if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) { had_error++; continue; } cp += n; /* name */ BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); type = ns_get16(cp); cp += INT16SZ; /* type */ class = ns_get16(cp); cp += INT16SZ + INT32SZ; /* class, TTL */ n = ns_get16(cp); cp += INT16SZ; /* len */ BOUNDS_CHECK(cp, n); if (class != C_IN) { cp += n; continue; } eor = cp + n; if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && type == T_CNAME) { if (haveanswer) { int level = LOG_CRIT;#ifdef LOG_SECURITY level |= LOG_SECURITY;#endif syslog(level, "gethostans: possible attempt to exploit buffer overflow while looking up %s", *qname ? qname : "."); } n = dn_expand(ansbuf, eor, cp, tbuf, sizeof tbuf); if (n < 0 || !maybe_ok(pvt->res, tbuf, name_ok)) { had_error++; continue; } cp += n; /* Store alias. */ if (ap >= &pvt->host_aliases[MAXALIASES-1]) continue; *ap++ = bp; n = strlen(bp) + 1; /* for the \0 */ bp += n; /* Get canonical name. */ n = strlen(tbuf) + 1; /* for the \0 */ if (n > (ep - bp) || n > MAXHOSTNAMELEN) { had_error++; continue; } strcpy(bp, tbuf); /* (checked) */ pvt->host.h_name = bp; hname = bp; bp += n; continue; } if (qtype == T_PTR && type == T_CNAME) { n = dn_expand(ansbuf, eor, cp, tbuf, sizeof tbuf); if (n < 0 || !maybe_dnok(pvt->res, tbuf)) { had_error++; continue; } cp += n;#ifdef RES_USE_DNAME if ((pvt->res->options & RES_USE_DNAME) != 0U)#endif { /* * We may be able to check this regardless * of the USE_DNAME bit, but we add the check * for now since the DNAME support is * experimental. */ if (ns_samename(tname, bp) != 1) continue; } /* Get canonical name. */ n = strlen(tbuf) + 1; /* for the \0 */ if (n > (ep - bp)) { had_error++; continue; } strcpy(bp, tbuf); /* (checked) */ tname = bp; bp += n; continue; } if (qtype == T_ANY) { if (!(type == T_A || type == T_AAAA)) { cp += n; continue; } } else if (type != qtype) { cp += n; continue; } switch (type) { case T_PTR: if (ret_aip != NULL) { /* addrinfo never needs T_PTR */ cp += n; continue; } if (ns_samename(tname, bp) != 1) { cp += n; continue; } n = dn_expand(ansbuf, eor, cp, bp, ep - bp); if (n < 0 || !maybe_hnok(pvt->res, bp) || n >= MAXHOSTNAMELEN) { had_error++; break; } cp += n; if (!haveanswer) { pvt->host.h_name = bp; hname = bp; } else if (ap < &pvt->host_aliases[MAXALIASES-1]) *ap++ = bp; else n = -1; if (n != -1) { n = strlen(bp) + 1; /* for the \0 */ bp += n; } break; case T_A: case T_AAAA: if (ns_samename(hname, bp) != 1) { cp += n; continue; } if (type == T_A && n != INADDRSZ) { cp += n; continue; } if (type == T_AAAA && n != IN6ADDRSZ) { cp += n; continue; } /* make addrinfo. don't overwrite constant PAI */ ai = *pai; ai.ai_family = (type == T_AAAA) ? AF_INET6 : AF_INET; cur->ai_next = addr2addrinfo( (const struct addrinfo *)&ai, (const char *)cp); if (cur->ai_next == NULL) had_error++; if (!haveanswer) { int nn; nn = strlen(bp) + 1; /* for the \0 */ if (nn >= MAXHOSTNAMELEN) { cp += n; had_error++; continue; } pvt->host.h_name = bp; hname = bp; bp += nn; } /* Ensure alignment. */ bp = (char *)(((u_long)bp + (sizeof(align) - 1)) & ~(sizeof(align) - 1)); /* Avoid overflows. */ if (bp + n >= &pvt->hostbuf[sizeof pvt->hostbuf]) { had_error++; continue; } if (ret_aip) { /* need addrinfo. keep it. */ while (cur && cur->ai_next) cur = cur->ai_next; } else if (cur->ai_next) { /* need hostent */ struct addrinfo *aip = cur->ai_next; for (aip = cur->ai_next; aip; aip = aip->ai_next) { int m; m = add_hostent(pvt, bp, hap, aip); if (m < 0) { had_error++; break; } if (m == 0) continue; if (hap < &pvt->h_addr_ptrs[MAXADDRS-1]) hap++; *hap = NULL; bp += m; } freeaddrinfo(cur->ai_next); cur->ai_next = NULL; } cp += n; break; default: abort(); } if (!had_error) haveanswer++; } if (haveanswer) { if (ret_aip == NULL) { *ap = NULL; *hap = NULL; if (pvt->res->nsort && haveanswer > 1 && qtype == T_A) addrsort(pvt->res, pvt->h_addr_ptrs, haveanswer); if (pvt->host.h_name == NULL) { n = strlen(qname) + 1; /* for the \0 */ if (n > (ep - bp) || n >= MAXHOSTNAMELEN) goto no_recovery; strcpy(bp, qname); /* (checked) */ pvt->host.h_name = bp; bp += n; } if (pvt->res->options & RES_USE_INET6) map_v4v6_hostent(&pvt->host, &bp, ep); RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); return (&pvt->host); } else { if ((pai->ai_flags & AI_CANONNAME) != 0) { if (pvt->host.h_name == NULL) { sentinel.ai_next->ai_canonname = strdup(qname); } else { sentinel.ai_next->ai_canonname = strdup(pvt->host.h_name); } } *ret_aip = sentinel.ai_next; return(NULL); } } no_recovery: if (sentinel.ai_next) { /* this should be impossible, but check it for safety */ freeaddrinfo(sentinel.ai_next); } if (error == NETDB_SUCCESS) RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); else RES_SET_H_ERRNO(pvt->res, error); return(NULL);}static intadd_hostent(struct pvt *pvt, char *bp, char **hap, struct addrinfo *ai){ int addrlen; char *addrp; const char **tap; char *obp = bp; switch(ai->ai_addr->sa_family) { case AF_INET6: addrlen = IN6ADDRSZ; addrp = (char *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; break; case AF_INET: addrlen = INADDRSZ; addrp = (char *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr; break; default: return(-1); /* abort? */ } /* Ensure alignment. */ bp = (char *)(((u_long)bp + (sizeof(align) - 1)) & ~(sizeof(align) - 1)); /* Avoid overflows. */ if (bp + addrlen >= &pvt->hostbuf[sizeof pvt->hostbuf]) return(-1); if (hap >= &pvt->h_addr_ptrs[MAXADDRS-1]) return(0); /* fail, but not treat it as an error. */ /* Suppress duplicates. */ for (tap = (const char **)pvt->h_addr_ptrs; *tap != NULL; tap++) if (memcmp(*tap, addrp, addrlen) == 0) break; if (*tap != NULL) return (0); memcpy(*hap = bp, addrp, addrlen); return((bp + addrlen) - obp);}static voidmap_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) { char **ap; if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) return; hp->h_addrtype = AF_INET6; hp->h_length = IN6ADDRSZ; for (ap = hp->h_addr_list; *ap; ap++) { int i = (u_long)*bpp % sizeof(align); if (i != 0) i = sizeof(align) - i; if ((ep - *bpp) < (i + IN6ADDRSZ)) { /* Out of memory. Truncate address list here. */ *ap = NULL; return; } *bpp += i; map_v4v6_address(*ap, *bpp); *ap = *bpp; *bpp += IN6ADDRSZ; }}static voidaddrsort(res_state statp, char **ap, int num) { int i, j, needsort = 0, aval[MAXADDRS]; char **p; p = ap; for (i = 0; i < num; i++, p++) { for (j = 0 ; (unsigned)j < statp->nsort; j++) if (statp->sort_list[j].addr.s_addr == (((struct in_addr *)(*p))->s_addr & statp->sort_list[j].mask)) break; aval[i] = j; if (needsort == 0 && i > 0 && j < aval[i-1]) needsort = i; } if (!needsort) return; while (needsort < num) { for (j = needsort - 1; j >= 0; j--) { if (aval[j] > aval[j+1]) { char *hp; i = aval[j]; aval[j] = aval[j+1]; aval[j+1] = i; hp = ap[j]; ap[j] = ap[j+1]; ap[j+1] = hp; } else break; } needsort++; }}static intinit(struct irs_ho *this) { struct pvt *pvt = (struct pvt *)this->private; if (!pvt->res && !ho_res_get(this)) return (-1); if (((pvt->res->options & RES_INIT) == 0U) && res_ninit(pvt->res) == -1) return (-1); return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -