diff options
Diffstat (limited to 'lib/libc/resolv/res_send.c')
-rw-r--r-- | lib/libc/resolv/res_send.c | 194 |
1 files changed, 131 insertions, 63 deletions
diff --git a/lib/libc/resolv/res_send.c b/lib/libc/resolv/res_send.c index 39dc998..455599e 100644 --- a/lib/libc/resolv/res_send.c +++ b/lib/libc/resolv/res_send.c @@ -10,10 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -70,17 +66,21 @@ #if defined(LIBC_SCCS) && !defined(lint) static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; -static const char rcsid[] = "$Id: res_send.c,v 1.9.18.8 2006/10/16 23:00:58 marka Exp $"; +static const char rcsid[] = "$Id: res_send.c,v 1.5.2.2.4.9 2006/10/16 23:00:50 marka Exp $"; #endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); -/*! \file - * \brief +/* * Send query to name server and wait for reply. */ #include "port_before.h" +#ifndef USE_KQUEUE #include "fd_setsize.h" +#endif +#include "namespace.h" #include <sys/types.h> #include <sys/param.h> #include <sys/time.h> @@ -104,12 +104,18 @@ static const char rcsid[] = "$Id: res_send.c,v 1.9.18.8 2006/10/16 23:00:58 mark #include "port_after.h" +#ifdef USE_KQUEUE +#include <sys/event.h> +#else #ifdef USE_POLL #ifdef HAVE_STROPTS_H #include <stropts.h> #endif #include <poll.h> #endif /* USE_POLL */ +#endif + +#include "un-namespace.h" /* Options. Leave them on. */ #define DEBUG @@ -118,26 +124,28 @@ static const char rcsid[] = "$Id: res_send.c,v 1.9.18.8 2006/10/16 23:00:58 mark #define EXT(res) ((res)->_u._ext) -#ifndef USE_POLL +#if !defined(USE_POLL) && !defined(USE_KQUEUE) static const int highestFD = FD_SETSIZE - 1; -#else -static int highestFD = 0; #endif /* Forward. */ -static int get_salen __P((const struct sockaddr *)); -static struct sockaddr * get_nsaddr __P((res_state, size_t)); +static int get_salen(const struct sockaddr *); +static struct sockaddr * get_nsaddr(res_state, size_t); static int send_vc(res_state, const u_char *, int, u_char *, int, int *, int); -static int send_dg(res_state, const u_char *, int, +static int send_dg(res_state, +#ifdef USE_KQUEUE + int kq, +#endif + const u_char *, int, u_char *, int, int *, int, int, int *, int *); static void Aerror(const res_state, FILE *, const char *, int, const struct sockaddr *, int); static void Perror(const res_state, FILE *, const char *, int); static int sock_eq(struct sockaddr *, struct sockaddr *); -#if defined(NEED_PSELECT) && !defined(USE_POLL) +#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE) static int pselect(int, void *, void *, void *, struct timespec *, const sigset_t *); @@ -148,15 +156,14 @@ static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; /* Public. */ -/*% +/* int + * res_isourserver(ina) * looks up "ina" in _res.ns_addr_list[] - * * returns: - *\li 0 : not found - *\li >0 : found - * + * 0 : not found + * >0 : found * author: - *\li paul vixie, 29may94 + * paul vixie, 29may94 */ int res_ourserver_p(const res_state statp, const struct sockaddr *sa) { @@ -199,19 +206,17 @@ res_ourserver_p(const res_state statp, const struct sockaddr *sa) { return (0); } -/*% +/* int + * res_nameinquery(name, type, class, buf, eom) * look for (name,type,class) in the query section of packet (buf,eom) - * * requires: - *\li buf + HFIXEDSZ <= eom - * + * buf + HFIXEDSZ <= eom * returns: - *\li -1 : format error - *\li 0 : not found - *\li >0 : found - * + * -1 : format error + * 0 : not found + * >0 : found * author: - *\li paul vixie, 29may94 + * paul vixie, 29may94 */ int res_nameinquery(const char *name, int type, int class, @@ -239,17 +244,16 @@ res_nameinquery(const char *name, int type, int class, return (0); } -/*% +/* int + * res_queriesmatch(buf1, eom1, buf2, eom2) * is there a 1:1 mapping of (name,type,class) * in (buf1,eom1) and (buf2,eom2)? - * * returns: - *\li -1 : format error - *\li 0 : not a 1:1 mapping - *\li >0 : is a 1:1 mapping - * + * -1 : format error + * 0 : not a 1:1 mapping + * >0 : is a 1:1 mapping * author: - *\li paul vixie, 29may94 + * paul vixie, 29may94 */ int res_queriesmatch(const u_char *buf1, const u_char *eom1, @@ -294,11 +298,10 @@ res_nsend(res_state statp, const u_char *buf, int buflen, u_char *ans, int anssiz) { int gotsomewhere, terrno, try, v_circuit, resplen, ns, n; - char abuf[NI_MAXHOST]; - -#ifdef USE_POLL - highestFD = sysconf(_SC_OPEN_MAX) - 1; +#ifdef USE_KQUEUE + int kq; #endif + char abuf[NI_MAXHOST]; /* No name servers or res_init() failure */ if (statp->nscount == 0 || EXT(statp).ext == NULL) { @@ -315,6 +318,13 @@ res_nsend(res_state statp, gotsomewhere = 0; terrno = ETIMEDOUT; +#ifdef USE_KQUEUE + if ((kq = kqueue()) < 0) { + Perror(statp, stderr, "kqueue", errno); + return (-1); + } +#endif + /* * If the ns_addr_list in the resolver context has changed, then * invalidate our cached copy and the associated timing data. @@ -338,7 +348,7 @@ res_nsend(res_state statp, if (EXT(statp).nssocks[ns] == -1) continue; peerlen = sizeof(peer); - if (getsockname(EXT(statp).nssocks[ns], + if (_getsockname(EXT(statp).nssocks[ns], (struct sockaddr *)&peer, &peerlen) < 0) { needclose++; break; @@ -430,6 +440,9 @@ res_nsend(res_state statp, res_nclose(statp); goto next_ns; case res_done: +#ifdef USE_KQUEUE + _close(kq); +#endif return (resplen); case res_modified: /* give the hook another try */ @@ -463,7 +476,11 @@ res_nsend(res_state statp, resplen = n; } else { /* Use datagrams. */ - n = send_dg(statp, buf, buflen, ans, anssiz, &terrno, + n = send_dg(statp, +#ifdef USE_KQUEUE + kq, +#endif + buf, buflen, ans, anssiz, &terrno, ns, try, &v_circuit, &gotsomewhere); if (n < 0) goto fail; @@ -522,21 +539,30 @@ res_nsend(res_state statp, } while (!done); } +#ifdef USE_KQUEUE + _close(kq); +#endif return (resplen); next_ns: ; } /*foreach ns*/ } /*foreach retry*/ res_nclose(statp); +#ifdef USE_KQUEUE + _close(kq); +#endif if (!v_circuit) { if (!gotsomewhere) - errno = ECONNREFUSED; /*%< no nameservers found */ + errno = ECONNREFUSED; /* no nameservers found */ else - errno = ETIMEDOUT; /*%< no answer obtained */ + errno = ETIMEDOUT; /* no answer obtained */ } else errno = terrno; return (-1); fail: res_nclose(statp); +#ifdef USE_KQUEUE + _close(kq); +#endif return (-1); } @@ -558,10 +584,10 @@ get_salen(sa) else if (sa->sa_family == AF_INET6) return (sizeof(struct sockaddr_in6)); else - return (0); /*%< unknown, die on connect */ + return (0); /* unknown, die on connect */ } -/*% +/* * pick appropriate nsaddr_list for use. see res_init() for initialization. */ static struct sockaddr * @@ -614,7 +640,7 @@ send_vc(res_state statp, struct sockaddr_storage peer; ISC_SOCKLEN_T size = sizeof peer; - if (getpeername(statp->_vcsock, + if (_getpeername(statp->_vcsock, (struct sockaddr *)&peer, &size) < 0 || !sock_eq((struct sockaddr *)&peer, nsap)) { res_nclose(statp); @@ -626,11 +652,13 @@ send_vc(res_state statp, if (statp->_vcsock >= 0) res_nclose(statp); - statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0); + statp->_vcsock = _socket(nsap->sa_family, SOCK_STREAM, 0); +#if !defined(USE_POLL) && !defined(USE_KQUEUE) if (statp->_vcsock > highestFD) { res_nclose(statp); errno = ENOTSOCK; } +#endif if (statp->_vcsock < 0) { switch (errno) { case EPROTONOSUPPORT: @@ -647,7 +675,7 @@ send_vc(res_state statp, } } errno = 0; - if (connect(statp->_vcsock, nsap, nsaplen) < 0) { + if (_connect(statp->_vcsock, nsap, nsaplen) < 0) { *terrno = errno; Aerror(statp, stderr, "connect/vc", errno, nsap, nsaplen); @@ -664,7 +692,7 @@ send_vc(res_state statp, iov[0] = evConsIovec(&len, INT16SZ); DE_CONST(buf, tmp); iov[1] = evConsIovec(tmp, buflen); - if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) { + if (_writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) { *terrno = errno; Perror(statp, stderr, "write failed", errno); res_nclose(statp); @@ -676,7 +704,7 @@ send_vc(res_state statp, read_len: cp = ans; len = INT16SZ; - while ((n = read(statp->_vcsock, (char *)cp, (int)len)) > 0) { + while ((n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) { cp += n; if ((len -= n) == 0) break; @@ -722,7 +750,8 @@ send_vc(res_state statp, return (0); } cp = ans; - while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){ + while (len != 0 && + (n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) { cp += n; len -= n; } @@ -741,8 +770,8 @@ send_vc(res_state statp, while (len != 0) { char junk[PACKETSZ]; - n = read(statp->_vcsock, junk, - (len > sizeof junk) ? sizeof junk : len); + n = _read(statp->_vcsock, junk, + (len > sizeof junk) ? sizeof junk : len); if (n > 0) len -= n; else @@ -772,7 +801,11 @@ send_vc(res_state statp, } static int -send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans, +send_dg(res_state statp, +#ifdef USE_KQUEUE + int kq, +#endif + const u_char *buf, int buflen, u_char *ans, int anssiz, int *terrno, int ns, int try, int *v_circuit, int *gotsomewhere) { @@ -784,21 +817,28 @@ send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans, struct sockaddr_storage from; ISC_SOCKLEN_T fromlen; int resplen, seconds, n, s; +#ifdef USE_KQUEUE + struct kevent kv; +#else #ifdef USE_POLL int polltimeout; struct pollfd pollfd; #else fd_set dsmask; #endif +#endif nsap = get_nsaddr(statp, ns); nsaplen = get_salen(nsap); if (EXT(statp).nssocks[ns] == -1) { - EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0); + EXT(statp).nssocks[ns] = _socket(nsap->sa_family, + SOCK_DGRAM, 0); +#if !defined(USE_POLL) && !defined(USE_KQUEUE) if (EXT(statp).nssocks[ns] > highestFD) { res_nclose(statp); errno = ENOTSOCK; } +#endif if (EXT(statp).nssocks[ns] < 0) { switch (errno) { case EPROTONOSUPPORT: @@ -825,8 +865,16 @@ send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans, * socket operation, and select returns if the * error message is received. We can thus detect * the absence of a nameserver without timing out. + * + * When the option "insecure1" is specified, we'd + * rather expect to see responses from an "unknown" + * address. In order to let the kernel accept such + * responses, do not connect the socket here. + * XXX: or do we need an explicit option to disable + * connecting? */ - if (connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) { + if (!(statp->options & RES_INSECURE1) && + _connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) { Aerror(statp, stderr, "connect(dg)", errno, nsap, nsaplen); res_nclose(statp); @@ -838,13 +886,20 @@ send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans, } s = EXT(statp).nssocks[ns]; #ifndef CANNOT_CONNECT_DGRAM - if (send(s, (const char*)buf, buflen, 0) != buflen) { + if (statp->options & RES_INSECURE1) { + if (_sendto(s, + (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) { + Aerror(statp, stderr, "sendto", errno, nsap, nsaplen); + res_nclose(statp); + return (0); + } + } else if (send(s, (const char*)buf, buflen, 0) != buflen) { Perror(statp, stderr, "send", errno); res_nclose(statp); return (0); } #else /* !CANNOT_CONNECT_DGRAM */ - if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) + if (_sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) { Aerror(statp, stderr, "sendto", errno, nsap, nsaplen); res_nclose(statp); @@ -868,13 +923,18 @@ send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans, now = evNowTime(); nonow: #ifndef USE_POLL - FD_ZERO(&dsmask); - FD_SET(s, &dsmask); if (evCmpTime(finish, now) > 0) timeout = evSubTime(finish, now); else timeout = evConsTime(0, 0); +#ifdef USE_KQUEUE + EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0); + n = _kevent(kq, &kv, 1, &kv, 1, &timeout); +#else + FD_ZERO(&dsmask); + FD_SET(s, &dsmask); n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL); +#endif #else timeout = evSubTime(finish, now); if (timeout.tv_sec < 0) @@ -894,17 +954,25 @@ send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans, if (n < 0) { if (errno == EINTR) goto wait; +#ifdef USE_KQUEUE + Perror(statp, stderr, "kevent", errno); +#else #ifndef USE_POLL Perror(statp, stderr, "select", errno); #else Perror(statp, stderr, "poll", errno); #endif /* USE_POLL */ +#endif res_nclose(statp); return (0); } +#ifdef USE_KQUEUE + if (kv.ident != s) + goto wait; +#endif errno = 0; fromlen = sizeof(from); - resplen = recvfrom(s, (char*)ans, anssiz,0, + resplen = _recvfrom(s, (char*)ans, anssiz,0, (struct sockaddr *)&from, &fromlen); if (resplen <= 0) { Perror(statp, stderr, "recvfrom", errno); @@ -1067,7 +1135,7 @@ sock_eq(struct sockaddr *a, struct sockaddr *b) { } } -#if defined(NEED_PSELECT) && !defined(USE_POLL) +#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE) /* XXX needs to move to the porting library. */ static int pselect(int nfds, void *rfds, void *wfds, void *efds, |