Module Name:    src
Committed By:   christos
Date:           Fri Feb 15 14:08:25 UTC 2013

Modified Files:
        src/lib/libc/resolv: res_send.c

Log Message:
- make all filedescriptors close-on-exec
- use SOCK_NOSIGPIPE.
- add kqueue handling (not enabled by default, from FreeBSD)
- add RES_INSECURE1 handling (from FreeBSD)


To generate a diff of this commit:
cvs rdiff -u -r1.25 -r1.26 src/lib/libc/resolv/res_send.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/resolv/res_send.c
diff -u src/lib/libc/resolv/res_send.c:1.25 src/lib/libc/resolv/res_send.c:1.26
--- src/lib/libc/resolv/res_send.c:1.25	Tue Mar 20 20:34:54 2012
+++ src/lib/libc/resolv/res_send.c	Fri Feb 15 09:08:25 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: res_send.c,v 1.25 2012/03/21 00:34:54 christos Exp $	*/
+/*	$NetBSD: res_send.c,v 1.26 2013/02/15 14:08:25 christos Exp $	*/
 
 /*
  * Portions Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
@@ -93,7 +93,7 @@
 static const char sccsid[] = "@(#)res_send.c	8.1 (Berkeley) 6/4/93";
 static const char rcsid[] = "Id: res_send.c,v 1.22 2009/01/22 23:49:23 tbox Exp";
 #else
-__RCSID("$NetBSD: res_send.c,v 1.25 2012/03/21 00:34:54 christos Exp $");
+__RCSID("$NetBSD: res_send.c,v 1.26 2013/02/15 14:08:25 christos Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -104,13 +104,18 @@ __RCSID("$NetBSD: res_send.c,v 1.25 2012
 
 #include "namespace.h"
 #include "port_before.h"
+#ifndef USE_KQUEUE
 #include "fd_setsize.h"
+#endif /* USE_KQUEUE */
 
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/socket.h>
 #include <sys/uio.h>
+#ifdef USE_KQUEUE
+#include <sys/event.h>
+#endif /* USE_KQUEUE */
 
 #include <netinet/in.h>
 #include <arpa/nameser.h>
@@ -122,6 +127,7 @@ __RCSID("$NetBSD: res_send.c,v 1.25 2012
 #include <resolv.h>
 #include <signal.h>
 #include <stdio.h>
+#include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -139,6 +145,12 @@ __weak_alias(res_nsend,__res_nsend)
 #endif
 #endif
 
+#ifndef SOCK_NOSIGPIPE
+#define SOCK_NOSIGPIPE 0
+#endif
+#ifndef SOCK_NOCLOEXEC
+#define SOCK_NOCLOEXEC 0
+#endif
 
 #ifdef USE_POLL
 #ifdef HAVE_STROPTS_H
@@ -156,7 +168,7 @@ __weak_alias(res_nsend,__res_nsend)
 
 #define EXT(res) ((res)->_u._ext)
 
-#ifndef USE_POLL
+#if !defined(USE_POLL) && !defined(USE_KQUEUE)
 static const int highestFD = FD_SETSIZE - 1;
 #endif
 
@@ -166,14 +178,18 @@ static int		get_salen(const struct socka
 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,
+#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 *);
@@ -330,6 +346,9 @@ res_nsend(res_state statp,
 	  const u_char *buf, int buflen, u_char *ans, int anssiz)
 {
 	int gotsomewhere, terrno, tries, v_circuit, resplen, ns, n;
+#ifdef USE_KQUEUE
+	int kq;
+#endif
 	char abuf[NI_MAXHOST];
 
 	(void)res_check(statp, NULL);
@@ -349,6 +368,12 @@ res_nsend(res_state statp,
 	gotsomewhere = 0;
 	terrno = ETIMEDOUT;
 
+#ifdef USE_KQUEUE
+	if ((kq = kqueue1(O_CLOEXEC)) == -1) {
+		return (-1);
+	}
+#endif
+
 	/*
 	 * If the ns_addr_list in the resolver context has changed, then
 	 * invalidate our cached copy and the associated timing data.
@@ -464,6 +489,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 */
@@ -497,8 +525,12 @@ res_nsend(res_state statp,
 			resplen = n;
 		} else {
 			/* Use datagrams. */
-			n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
-				    ns, tries, &v_circuit, &gotsomewhere);
+			n = send_dg(statp,
+#ifdef USE_KQUEUE
+			    kq,
+#endif
+			    buf, buflen, ans, anssiz, &terrno,
+			    ns, tries, &v_circuit, &gotsomewhere);
 			if (n < 0)
 				goto fail;
 			if (n == 0)
@@ -556,11 +588,17 @@ 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 */
@@ -571,6 +609,9 @@ res_nsend(res_state statp,
 	return (-1);
  fail:
 	res_nclose(statp);
+#ifdef USE_KQUEUE
+	close(kq);
+#endif
 	return (-1);
 }
 
@@ -633,7 +674,7 @@ send_vc(res_state statp,
 	u_short len;
 	u_char *cp;
 	void *tmp;
-#ifdef SO_NOSIGPIPE
+#if defined(SO_NOSIGPIPE) && SOCK_NOSIGPIPE == 0
 	int on = 1;
 #endif
 
@@ -661,8 +702,12 @@ send_vc(res_state statp,
 		if (statp->_vcsock >= 0)
 			res_nclose(statp);
 
-		statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
-#ifndef USE_POLL
+		statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM
+			| SOCK_NOSIGPIPE | SOCK_CLOEXEC, 0);
+#if SOCK_CLOEXEC == 0
+		fcntl(statp->_vcsock, F_SETFD, FD_CLOEXEC);
+#endif
+#if !defined(USE_POLL) && !defined(USE_KQUEUE)
 		if (statp->_vcsock > highestFD) {
 			res_nclose(statp);
 			errno = ENOTSOCK;
@@ -683,7 +728,7 @@ send_vc(res_state statp,
 				return (-1);
 			}
 		}
-#ifdef SO_NOSIGPIPE
+#if defined(SO_NOSIGPIPE) && SOCK_NOSIGPIPE == 0
 		/*
 		 * Disable generation of SIGPIPE when writing to a closed
 		 * socket.  Write should return -1 and set errno to EPIPE
@@ -692,7 +737,7 @@ send_vc(res_state statp,
 		 * Push on even if setsockopt(SO_NOSIGPIPE) fails.
 		 */
 		(void)setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on,
-				 (unsigned int)sizeof(on));
+				 (socklen_t)sizeof(on));
 #endif
 		errno = 0;
 		if (connect(statp->_vcsock, nsap, (socklen_t)nsaplen) < 0) {
@@ -820,7 +865,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 tries, int *v_circuit,
 	int *gotsomewhere)
 {
@@ -833,18 +882,26 @@ send_dg(res_state statp, const u_char *b
 	ISC_SOCKLEN_T fromlen;
 	ssize_t resplen;
 	int 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, (size_t)ns);
 	nsaplen = get_salen(nsap);
 	if (EXT(statp).nssocks[ns] == -1) {
-		EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0);
-#ifndef USE_POLL
+		EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM
+			| SOCK_CLOEXEC, 0);
+#if SOCK_CLOEXEC == 0
+		fcntl(EXT(statp)nssocks[ns], F_SETFD, FD_CLOEXEC);
+#endif
+#if !defined(USE_POLL) && !defined(USE_KQUEUE)
 		if (EXT(statp).nssocks[ns] > highestFD) {
 			res_nclose(statp);
 			errno = ENOTSOCK;
@@ -876,8 +933,16 @@ send_dg(res_state statp, const u_char *b
 		 * socket operation, and select returns if the
 		 * error message is received.  We can thus detect
 		 * the absence of a nameserver without timing out.
-		 */
-		if (connect(EXT(statp).nssocks[ns], nsap, (socklen_t)nsaplen) < 0) {
+		 *
+		 * 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 (!(statp->options & RES_INSECURE1) &&
+		    connect(EXT(statp).nssocks[ns], nsap, (socklen_t)nsaplen) < 0) {
 			Aerror(statp, stderr, "connect(dg)", errno, nsap,
 			    nsaplen);
 			res_nclose(statp);
@@ -889,13 +954,20 @@ send_dg(res_state statp, const u_char *b
 	}
 	s = EXT(statp).nssocks[ns];
 #ifndef CANNOT_CONNECT_DGRAM
-	if (send(s, (const char*)buf, (size_t)buflen, 0) != buflen) {
+	if (statp->options & RES_INSECURE1) {
+		if (sendto(s,
+		    (const char*)buf, buflen, 0, nsap, (socklen_t)nsaplen) != buflen) {
+			Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
+			res_nclose(statp);
+			return (0);
+		}
+	} else if (send(s, (const char*)buf, (size_t)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, (socklen_t)nsaplen) != buflen)
 	{
 		Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
 		res_nclose(statp);
@@ -919,13 +991,18 @@ send_dg(res_state statp, const u_char *b
 	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(0L, 0L);
+#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)
@@ -943,16 +1020,23 @@ send_dg(res_state statp, const u_char *b
 		return (0);
 	}
 	if (n < 0) {
+#if defined(USE_POLL)
+		static const char *fun = "poll";
+#elif defined(USE_SELECT)
+		static const char *fun = "select";
+#elif defined(USE_KQUEUE)
+		static const char *fun = "kevent";
+#endif
 		if (errno == EINTR)
 			goto wait;
-#ifndef USE_POLL
-		Perror(statp, stderr, "select", errno);
-#else
-		Perror(statp, stderr, "poll", errno);
-#endif /* USE_POLL */
+		Perror(statp, stderr, fun, errno);
 		res_nclose(statp);
 		return (0);
 	}
+#ifdef USE_KQUEUE
+	if ((int)kv.ident != s)
+		goto wait;
+#endif
 	errno = 0;
 	fromlen = sizeof(from);
 	resplen = recvfrom(s, (char*)ans, (size_t)anssiz,0,
@@ -1118,7 +1202,7 @@ sock_eq(struct sockaddr *a, struct socka
 	}
 }
 
-#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,

Reply via email to