From 3e8899e9ae184d1808ca24e1856315f3f0bf1642 Mon Sep 17 00:00:00 2001 From: Camiel Dobbelaar Date: Thu, 5 Apr 2012 19:08:41 +0000 Subject: Rate-limit accepting of new connections while we are experiencing fd exhaustion. ok deraadt mikeb --- usr.sbin/ftp-proxy/ftp-proxy.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'usr.sbin') diff --git a/usr.sbin/ftp-proxy/ftp-proxy.c b/usr.sbin/ftp-proxy/ftp-proxy.c index 5a0dbb9f5af..0facc4de434 100644 --- a/usr.sbin/ftp-proxy/ftp-proxy.c +++ b/usr.sbin/ftp-proxy/ftp-proxy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ftp-proxy.c,v 1.24 2012/03/04 04:05:15 fgsch Exp $ */ +/* $OpenBSD: ftp-proxy.c,v 1.25 2012/04/05 19:08:40 camield Exp $ */ /* * Copyright (c) 2004, 2005 Camiel Dobbelaar, @@ -113,6 +113,7 @@ size_t linelen; char ntop_buf[NTOP_BUFS][INET6_ADDRSTRLEN]; +struct event listen_ev, pause_accept_ev; struct sockaddr_storage fixed_server_ss, fixed_proxy_ss; char *fixed_server, *fixed_server_port, *fixed_proxy, *listen_ip, *listen_port, *qname, *tagname; @@ -370,7 +371,7 @@ get_line(char *buf, size_t *valid) } void -handle_connection(const int listen_fd, short event, void *ev) +handle_connection(const int listen_fd, short event, void *arg) { struct sockaddr_storage tmp_ss; struct sockaddr *client_sa, *server_sa, *fixed_server_sa; @@ -379,6 +380,12 @@ handle_connection(const int listen_fd, short event, void *ev) socklen_t len; int client_fd, fc, on; + event_add(&listen_ev, NULL); + + if ((event & EV_TIMEOUT)) + /* accept() is no longer paused. */ + return; + /* * We _must_ accept the connection, otherwise libevent will keep * coming back, and we will chew up all CPU. @@ -386,7 +393,18 @@ handle_connection(const int listen_fd, short event, void *ev) client_sa = sstosa(&tmp_ss); len = sizeof(struct sockaddr_storage); if ((client_fd = accept(listen_fd, client_sa, &len)) < 0) { - logmsg(LOG_CRIT, "accept failed: %s", strerror(errno)); + logmsg(LOG_CRIT, "accept() failed: %s", strerror(errno)); + + /* + * Pause accept if we are out of file descriptors, or + * libevent will haunt us here too. + */ + if (errno == ENFILE || errno == EMFILE) { + struct timeval pause = { 1, 0 }; + + event_del(&listen_ev); + evtimer_add(&pause_accept_ev, &pause); + } return; } @@ -589,7 +607,7 @@ main(int argc, char *argv[]) { struct rlimit rlp; struct addrinfo hints, *res; - struct event ev, ev_sighup, ev_sigint, ev_sigterm; + struct event ev_sighup, ev_sigint, ev_sigterm; int ch, error, listenfd, on; const char *errstr; @@ -770,8 +788,9 @@ main(int argc, char *argv[]) signal_add(&ev_sigint, NULL); signal_add(&ev_sigterm, NULL); - event_set(&ev, listenfd, EV_READ | EV_PERSIST, handle_connection, &ev); - event_add(&ev, NULL); + event_set(&listen_ev, listenfd, EV_READ, handle_connection, NULL); + event_add(&listen_ev, NULL); + evtimer_set(&pause_accept_ev, handle_connection, NULL); logmsg(LOG_NOTICE, "listening on %s port %s", listen_ip, listen_port); -- cgit v1.2.3