diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2012-04-11 08:31:38 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2012-04-11 08:31:38 +0000 |
commit | 9ba7887131b0a6530e49cafc7bb341fd45aa6edc (patch) | |
tree | a53064eaf99c3729936760948063107b6aa0a048 | |
parent | c3f334e0473ee4974d78091f9383ff61c27517ca (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.c | 42 | ||||
-rw-r--r-- | usr.sbin/ldapd/control.c | 37 | ||||
-rw-r--r-- | usr.sbin/ldapd/ldapd.h | 7 | ||||
-rw-r--r-- | usr.sbin/ldapd/ldape.c | 5 |
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); } |