- make all filedescriptors close-on-exec
- use SOCK_NOSIGPIPE. - add kqueue handling (not enabled by default, from FreeBSD) - add RES_INSECURE1 handling (from FreeBSD)
This commit is contained in:
parent
38e436ce90
commit
650d188146
@ -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/03/21 00:34:54 christos Exp $");
|
||||
|
||||
#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/03/21 00:34:54 christos Exp $");
|
||||
#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 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,
|
||||
#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 *buf, int buflen, u_char *ans,
|
||||
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 *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.
|
||||
*/
|
||||
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 *buf, int buflen, u_char *ans,
|
||||
}
|
||||
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 *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(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 *buf, int buflen, u_char *ans,
|
||||
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 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,
|
||||
|
Loading…
Reference in New Issue
Block a user