summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2012-04-11 08:31:38 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2012-04-11 08:31:38 +0000
commit9ba7887131b0a6530e49cafc7bb341fd45aa6edc (patch)
treea53064eaf99c3729936760948063107b6aa0a048
parentc3f334e0473ee4974d78091f9383ff61c27517ca (diff)
rate limiting of accept() in various cases. Testing by jmatthew. there
maybe still be a corner case where it needs one more file descriptor beyond the limit..
-rw-r--r--usr.sbin/ldapd/conn.c42
-rw-r--r--usr.sbin/ldapd/control.c37
-rw-r--r--usr.sbin/ldapd/ldapd.h7
-rw-r--r--usr.sbin/ldapd/ldape.c5
4 files changed, 72 insertions, 19 deletions
diff --git a/usr.sbin/ldapd/conn.c b/usr.sbin/ldapd/conn.c
index 6936086c221..e2ed882015e 100644
--- a/usr.sbin/ldapd/conn.c
+++ b/usr.sbin/ldapd/conn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conn.c,v 1.8 2010/11/10 08:00:54 martinh Exp $ */
+/* $OpenBSD: conn.c,v 1.9 2012/04/11 08:31:37 deraadt Exp $ */
/*
* Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
@@ -48,6 +48,7 @@ void
conn_close(struct conn *conn)
{
struct search *search, *next;
+ struct listener *l = conn->listener;
log_debug("closing connection %d", conn->fd);
@@ -67,6 +68,13 @@ conn_close(struct conn *conn)
if (conn->bev != NULL)
bufferevent_free(conn->bev);
close(conn->fd);
+
+ /* Some file descriptors are available again. */
+ if (evtimer_pending(&l->evt, NULL)) {
+ evtimer_del(&l->evt);
+ event_add(&l->ev, NULL);
+ }
+
free(conn->binddn);
free(conn->pending_binddn);
free(conn);
@@ -239,7 +247,7 @@ conn_err(struct bufferevent *bev, short why, void *data)
}
void
-conn_accept(int fd, short why, void *data)
+conn_accept(int fd, short event, void *data)
{
int afd;
socklen_t addrlen;
@@ -248,10 +256,24 @@ conn_accept(int fd, short why, void *data)
struct sockaddr_storage remote_addr;
char host[128];
+ event_add(&l->ev, NULL);
+ if ((event & EV_TIMEOUT))
+ return;
+
addrlen = sizeof(remote_addr);
afd = accept(fd, (struct sockaddr *)&remote_addr, &addrlen);
if (afd == -1) {
- log_warn("accept");
+ /*
+ * Pause accept if we are out of file descriptors, or
+ * libevent will haunt us here too.
+ */
+ if (errno == ENFILE || errno == EMFILE) {
+ struct timeval evtpause = { 1, 0 };
+
+ event_del(&l->ev);
+ evtimer_add(&l->evt, &evtpause);
+ } else if (errno != EWOULDBLOCK && errno != EINTR)
+ log_warn("conn_accept");
return;
}
@@ -272,8 +294,7 @@ conn_accept(int fd, short why, void *data)
if ((conn = calloc(1, sizeof(*conn))) == NULL) {
log_warn("malloc");
- close(afd);
- return;
+ goto giveup;
}
conn->ber.fd = -1;
conn->s_l = l;
@@ -288,9 +309,8 @@ conn_accept(int fd, short why, void *data)
conn_err, conn);
if (conn->bev == NULL) {
log_warn("conn_accept: bufferevent_new");
- close(afd);
free(conn);
- return;
+ goto giveup;
}
bufferevent_enable(conn->bev, EV_READ);
bufferevent_settimeout(conn->bev, 0, 60);
@@ -303,6 +323,14 @@ conn_accept(int fd, short why, void *data)
conn->s_flags |= F_SECURE;
++stats.conns;
+ return;
+giveup:
+ close(afd);
+ /* Some file descriptors are available again. */
+ if (evtimer_pending(&l->evt, NULL)) {
+ evtimer_del(&l->evt);
+ event_add(&l->ev, NULL);
+ }
}
struct conn *
diff --git a/usr.sbin/ldapd/control.c b/usr.sbin/ldapd/control.c
index b32a5b1df79..74676e9f84b 100644
--- a/usr.sbin/ldapd/control.c
+++ b/usr.sbin/ldapd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.6 2010/09/01 17:34:15 martinh Exp $ */
+/* $OpenBSD: control.c,v 1.7 2012/04/11 08:31:37 deraadt Exp $ */
/*
* Copyright (c) 2010 Martin Hedenfalk <martin@bzero.se>
@@ -42,7 +42,7 @@
struct ctl_connlist ctl_conns;
struct ctl_conn *control_connbyfd(int);
-void control_close(int);
+void control_close(int, struct control_sock *);
static void control_imsgev(struct imsgev *iev, int code, struct imsg *imsg);
void
@@ -102,9 +102,10 @@ control_listen(struct control_sock *cs)
if (listen(cs->cs_fd, CONTROL_BACKLOG) == -1)
fatal("control_listen: listen");
- event_set(&cs->cs_ev, cs->cs_fd, EV_READ | EV_PERSIST,
+ event_set(&cs->cs_ev, cs->cs_fd, EV_READ,
control_accept, cs);
event_add(&cs->cs_ev, NULL);
+ evtimer_set(&cs->cs_evt, control_accept, cs);
}
void
@@ -112,6 +113,8 @@ control_cleanup(struct control_sock *cs)
{
if (cs->cs_name == NULL)
return;
+ event_del(&cs->cs_ev);
+ event_del(&cs->cs_evt);
(void)unlink(cs->cs_name);
}
@@ -125,10 +128,23 @@ control_accept(int listenfd, short event, void *arg)
struct sockaddr_un sun;
struct ctl_conn *c;
+ event_add(&cs->cs_ev, NULL);
+ if ((event & EV_TIMEOUT))
+ return;
+
len = sizeof(sun);
if ((connfd = accept(listenfd,
(struct sockaddr *)&sun, &len)) == -1) {
- if (errno != EWOULDBLOCK && errno != EINTR)
+ /*
+ * Pause accept if we are out of file descriptors, or
+ * libevent will haunt us here too.
+ */
+ if (errno == ENFILE || errno == EMFILE) {
+ struct timeval evtpause = { 1, 0 };
+
+ event_del(&cs->cs_ev);
+ evtimer_add(&cs->cs_evt, &evtpause);
+ } else if (errno != EWOULDBLOCK && errno != EINTR)
log_warn("control_accept");
return;
}
@@ -159,7 +175,7 @@ control_connbyfd(int fd)
}
void
-control_close(int fd)
+control_close(int fd, struct control_sock *cs)
{
struct ctl_conn *c;
@@ -171,6 +187,13 @@ control_close(int fd)
log_debug("close control fd %i", c->iev.ibuf.fd);
TAILQ_REMOVE(&ctl_conns, c, entry);
imsgev_clear(&c->iev);
+
+ /* Some file descriptors are available again. */
+ if (evtimer_pending(&cs->cs_evt, NULL)) {
+ evtimer_del(&cs->cs_evt);
+ event_add(&cs->cs_ev, NULL);
+ }
+
free(c);
}
@@ -220,7 +243,7 @@ control_imsgev(struct imsgev *iev, int code, struct imsg *imsg)
}
if (code != IMSGEV_IMSG) {
- control_close(fd);
+ control_close(fd, cs);
return;
}
@@ -229,7 +252,7 @@ control_imsgev(struct imsgev *iev, int code, struct imsg *imsg)
case IMSG_CTL_STATS:
if (send_stats(iev) == -1) {
log_debug("%s: failed to send statistics", __func__);
- control_close(fd);
+ control_close(fd, cs);
}
break;
case IMSG_CTL_LOG_VERBOSE:
diff --git a/usr.sbin/ldapd/ldapd.h b/usr.sbin/ldapd/ldapd.h
index d76e6f8ff45..b976ac60459 100644
--- a/usr.sbin/ldapd/ldapd.h
+++ b/usr.sbin/ldapd/ldapd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldapd.h,v 1.21 2010/11/10 08:00:54 martinh Exp $ */
+/* $OpenBSD: ldapd.h,v 1.22 2012/04/11 08:31:37 deraadt Exp $ */
/*
* Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
@@ -200,6 +200,7 @@ struct listener {
int port;
int fd;
struct event ev;
+ struct event evt;
char ssl_cert_name[PATH_MAX];
struct ssl *ssl;
void *ssl_ctx;
@@ -209,8 +210,7 @@ TAILQ_HEAD(listenerlist, listener);
/* An LDAP client connection.
*/
-struct conn
-{
+struct conn {
TAILQ_ENTRY(conn) next;
int fd;
struct bufferevent *bev;
@@ -323,6 +323,7 @@ extern struct ctl_connlist ctl_conns;
struct control_sock {
const char *cs_name;
struct event cs_ev;
+ struct event cs_evt;
int cs_fd;
int cs_restricted;
};
diff --git a/usr.sbin/ldapd/ldape.c b/usr.sbin/ldapd/ldape.c
index e799205be94..433bb2ad64f 100644
--- a/usr.sbin/ldapd/ldape.c
+++ b/usr.sbin/ldapd/ldape.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldape.c,v 1.15 2012/04/01 16:20:00 deraadt Exp $ */
+/* $OpenBSD: ldape.c,v 1.16 2012/04/11 08:31:37 deraadt Exp $ */
/*
* Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
@@ -418,8 +418,9 @@ ldape(struct passwd *pw, char *csockpath, int pipe_parent2ldap[2])
fd_nonblock(l->fd);
- event_set(&l->ev, l->fd, EV_READ|EV_PERSIST, conn_accept, l);
+ event_set(&l->ev, l->fd, EV_READ, conn_accept, l);
event_add(&l->ev, NULL);
+ evtimer_set(&l->evt, conn_accept, l);
ssl_setup(conf, l);
}