diff options
author | Jakub Jelinek <jakub@redhat.com> | 2007-07-12 18:26:36 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2007-07-12 18:26:36 +0000 |
commit | 0ecb606cb6cf65de1d9fc8a919bceb4be476c602 (patch) | |
tree | 2ea1f8305970753e4a657acb2ccc15ca3eec8e2c /resolv/res_send.c | |
parent | 7d58530341304d403a6626d7f7a1913165fe2f32 (diff) | |
download | glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar.gz |
2.5-18.1
Diffstat (limited to 'resolv/res_send.c')
-rw-r--r-- | resolv/res_send.c | 123 |
1 files changed, 69 insertions, 54 deletions
diff --git a/resolv/res_send.c b/resolv/res_send.c index 8fb21a9446..887d048e19 100644 --- a/resolv/res_send.c +++ b/resolv/res_send.c @@ -267,8 +267,8 @@ res_nameinquery(const char *name, int type, int class, cp += n; if (cp + 2 * INT16SZ > eom) return (-1); - ttype = ns_get16(cp); cp += INT16SZ; - tclass = ns_get16(cp); cp += INT16SZ; + NS_GET16(ttype, cp); + NS_GET16(tclass, cp); if (ttype == type && tclass == class && ns_samename(tname, name) == 1) return (1); @@ -292,9 +292,6 @@ int res_queriesmatch(const u_char *buf1, const u_char *eom1, const u_char *buf2, const u_char *eom2) { - const u_char *cp = buf1 + HFIXEDSZ; - int qdcount = ntohs(((HEADER*)buf1)->qdcount); - if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2) return (-1); @@ -306,8 +303,16 @@ res_queriesmatch(const u_char *buf1, const u_char *eom1, (((HEADER *)buf2)->opcode == ns_o_update)) return (1); - if (qdcount != ntohs(((HEADER*)buf2)->qdcount)) + /* Note that we initially do not convert QDCOUNT to the host byte + order. We can compare it with the second buffer's QDCOUNT + value without doing this. */ + int qdcount = ((HEADER*)buf1)->qdcount; + if (qdcount != ((HEADER*)buf2)->qdcount) return (0); + + qdcount = htons (qdcount); + const u_char *cp = buf1 + HFIXEDSZ; + while (qdcount-- > 0) { char tname[MAXDNAME+1]; int n, ttype, tclass; @@ -318,8 +323,8 @@ res_queriesmatch(const u_char *buf1, const u_char *eom1, cp += n; if (cp + 2 * INT16SZ > eom1) return (-1); - ttype = ns_get16(cp); cp += INT16SZ; - tclass = ns_get16(cp); cp += INT16SZ; + NS_GET16(ttype, cp); + NS_GET16(tclass, cp); if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) return (0); } @@ -381,7 +386,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen, } } if (needclose) - res_nclose(statp); + __res_iclose(statp, false); } /* @@ -488,7 +493,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen, done = 1; break; case res_nextns: - res_nclose(statp); + __res_iclose(statp, false); goto next_ns; case res_done: return (resplen); @@ -553,7 +558,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen, */ if ((v_circuit && (statp->options & RES_USEVC) == 0) || (statp->options & RES_STAYOPEN) == 0) { - res_nclose(statp); + __res_iclose(statp, false); } if (statp->rhook) { int done = 0, loops = 0; @@ -570,7 +575,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen, done = 1; break; case res_nextns: - res_nclose(statp); + __res_iclose(statp, false); goto next_ns; case res_modified: /* give the hook another try */ @@ -589,7 +594,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen, next_ns: ; } /*foreach ns*/ } /*foreach retry*/ - res_nclose(statp); + __res_iclose(statp, false); if (!v_circuit) { if (!gotsomewhere) __set_errno (ECONNREFUSED); /* no nameservers found */ @@ -632,19 +637,19 @@ send_vc(res_state statp, /* Are we still talking to whom we want to talk to? */ if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) { struct sockaddr_in6 peer; - int size = sizeof peer; + socklen_t size = sizeof peer; if (getpeername(statp->_vcsock, (struct sockaddr *)&peer, &size) < 0 || !sock_eq(&peer, nsap)) { - res_nclose(statp); + __res_iclose(statp, false); statp->_flags &= ~RES_F_VC; } } if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) { if (statp->_vcsock >= 0) - res_nclose(statp); + __res_iclose(statp, false); statp->_vcsock = socket(nsap->sin6_family, SOCK_STREAM, 0); if (statp->_vcsock < 0) { @@ -654,11 +659,13 @@ send_vc(res_state statp, } __set_errno (0); if (connect(statp->_vcsock, (struct sockaddr *)nsap, - sizeof *nsap) < 0) { + nsap->sin6_family == AF_INET + ? sizeof (struct sockaddr_in) + : sizeof (struct sockaddr_in6)) < 0) { *terrno = errno; Aerror(statp, stderr, "connect/vc", errno, (struct sockaddr *) nsap); - res_nclose(statp); + __res_iclose(statp, false); return (0); } statp->_flags |= RES_F_VC; @@ -667,14 +674,14 @@ send_vc(res_state statp, /* * Send length & message */ - putshort((u_short)buflen, (u_char*)&len); + ns_put16((u_short)buflen, (u_char*)&len); evConsIovec(&len, INT16SZ, &iov[0]); evConsIovec((void*)buf, buflen, &iov[1]); if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, 2)) != (INT16SZ + buflen)) { *terrno = errno; Perror(statp, stderr, "write failed", errno); - res_nclose(statp); + __res_iclose(statp, false); return (0); } /* @@ -692,7 +699,7 @@ send_vc(res_state statp, if (n <= 0) { *terrno = errno; Perror(statp, stderr, "read failed", errno); - res_nclose(statp); + __res_iclose(statp, false); /* * A long running process might get its TCP * connection reset if the remote server was @@ -704,10 +711,8 @@ send_vc(res_state statp, */ if (*terrno == ECONNRESET && !connreset) { connreset = 1; - res_nclose(statp); goto same_ns; } - res_nclose(statp); return (0); } resplen = ns_get16(ans); @@ -716,7 +721,7 @@ send_vc(res_state statp, ans = malloc (MAXPACKET); if (ans == NULL) { *terrno = ENOMEM; - res_nclose(statp); + __res_iclose(statp, false); return (0); } anssiz = MAXPACKET; @@ -741,7 +746,7 @@ send_vc(res_state statp, Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", len)); *terrno = EMSGSIZE; - res_nclose(statp); + __res_iclose(statp, false); return (0); } cp = ans; @@ -752,7 +757,7 @@ send_vc(res_state statp, if (n <= 0) { *terrno = errno; Perror(statp, stderr, "read(vc)", errno); - res_nclose(statp); + __res_iclose(statp, false); return (0); } if (truncating) { @@ -809,7 +814,8 @@ send_dg(res_state statp, int ptimeout; struct sockaddr_in6 from; static int socket_pf = 0; - int fromlen, resplen, seconds, n; + socklen_t fromlen; + int resplen, seconds, n; if (EXT(statp).nssocks[ns] == -1) { /* only try IPv6 if IPv6 NS and if not failed before */ @@ -844,7 +850,7 @@ send_dg(res_state statp, sizeof *nsap) < 0) { Aerror(statp, stderr, "connect(dg)", errno, (struct sockaddr *) nsap); - res_nclose(statp); + __res_iclose(statp, false); return (0); } /* Make socket non-blocking. */ @@ -873,10 +879,13 @@ send_dg(res_state statp, pfd[0].events = POLLOUT; wait: if (need_recompute) { + recompute_resend: evNowTime(&now); if (evCmpTime(finish, now) <= 0) { - Perror(statp, stderr, "select", errno); - res_nclose(statp); + poll_err_out: + Perror(statp, stderr, "poll", errno); + err_out: + __res_iclose(statp, false); return (0); } evSubTime(&timeout, &finish, &now); @@ -898,26 +907,18 @@ send_dg(res_state statp, return (0); } if (n < 0) { - if (errno == EINTR) { - recompute_resend: - evNowTime(&now); - if (evCmpTime(finish, now) > 0) { - evSubTime(&timeout, &finish, &now); - goto wait; - } - } - Perror(statp, stderr, "poll", errno); - res_nclose(statp); - return (0); + if (errno == EINTR) + goto recompute_resend; + + goto poll_err_out; } __set_errno (0); if (pfd[0].revents & POLLOUT) { - if (send(pfd[0].fd, (char*)buf, buflen, 0) != buflen) { + if (send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL) != buflen) { if (errno == EINTR || errno == EAGAIN) goto recompute_resend; Perror(statp, stderr, "send", errno); - res_nclose(statp); - return (0); + goto err_out; } pfd[0].events = POLLIN; ++nwritten; @@ -947,8 +948,7 @@ send_dg(res_state statp, goto wait; } Perror(statp, stderr, "recvfrom", errno); - res_nclose(statp); - return (0); + goto err_out; } *gotsomewhere = 1; if (resplen < HFIXEDSZ) { @@ -959,8 +959,7 @@ send_dg(res_state statp, (stdout, ";; undersized: %d\n", resplen)); *terrno = EMSGSIZE; - res_nclose(statp); - return (0); + goto err_out; } if (hp->id != anhp->id) { /* @@ -1007,11 +1006,19 @@ send_dg(res_state statp, DprintQ(statp->options & RES_DEBUG, (stdout, "server rejected query:\n"), ans, (resplen > anssiz) ? anssiz : resplen); - res_nclose(statp); + next_ns: + __res_iclose(statp, false); /* don't retry if called from dig */ if (!statp->pfcode) return (0); } + if (anhp->rcode == NOERROR && anhp->ancount == 0 + && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) { + DprintQ(statp->options & RES_DEBUG, + (stdout, "referred query:\n"), + ans, (resplen > anssiz) ? anssiz : resplen); + goto next_ns; + } if (!(statp->options & RES_IGNTC) && anhp->tc) { /* * To get the rest of answer, @@ -1020,7 +1027,7 @@ send_dg(res_state statp, Dprint(statp->options & RES_DEBUG, (stdout, ";; truncated answer\n")); *v_circuit = 1; - res_nclose(statp); + __res_iclose(statp, false); return (1); } /* @@ -1030,8 +1037,11 @@ send_dg(res_state statp, return (resplen); } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { /* Something went wrong. We can stop trying. */ - res_nclose(statp); - return (0); + goto err_out; + } + else { + /* poll should not have returned > 0 in this case. */ + abort (); } } @@ -1047,8 +1057,13 @@ Aerror(const res_state statp, FILE *file, const char *string, int error, fprintf(file, "res_send: %s ([%s].%u): %s\n", string, - inet_ntop(address->sa_family, address->sa_data, - tmp, sizeof tmp), + (address->sa_family == AF_INET + ? inet_ntop(address->sa_family, + &((const struct sockaddr_in *) address)->sin_addr, + tmp, sizeof tmp) + : inet_ntop(address->sa_family, + &((const struct sockaddr_in6 *) address)->sin6_addr, + tmp, sizeof tmp)), (address->sa_family == AF_INET ? ntohs(((struct sockaddr_in *) address)->sin_port) : address->sa_family == AF_INET6 |