diff options
author | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2009-03-03 14:31:51 +0300 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2009-03-03 14:31:51 +0300 |
commit | 5424cc32d47c5e98b9edfb2b342d9d98d97a1175 (patch) | |
tree | bd4a0d4418b71d0024f5d66d07de2cc24aded7ec /src | |
parent | 3ff032cf72164dc9aa8575c0a631f7c7b0079f46 (diff) | |
download | rspamd-5424cc32d47c5e98b9edfb2b342d9d98d97a1175.tar.gz rspamd-5424cc32d47c5e98b9edfb2b342d9d98d97a1175.zip |
* Unify socket creation and accepting by using utility functions
* Check SO_ERROR on socket immideately after connect/bind to avoid resourses allocation for
unsuccessful connections
* Avoid descriptors leakage when we create sockets and have errors on them
* Set on all socket descriptors FD_CLOEXEC flag to avoid problems with executing LDA
Diffstat (limited to 'src')
-rw-r--r-- | src/controller.c | 12 | ||||
-rw-r--r-- | src/lmtp.c | 20 | ||||
-rw-r--r-- | src/lmtp_proto.c | 17 | ||||
-rw-r--r-- | src/main.c | 4 | ||||
-rw-r--r-- | src/plugins/surbl.c | 24 | ||||
-rw-r--r-- | src/util.c | 119 | ||||
-rw-r--r-- | src/util.h | 10 | ||||
-rw-r--r-- | src/worker.c | 16 |
8 files changed, 133 insertions, 89 deletions
diff --git a/src/controller.c b/src/controller.c index b02782caf..26c773cff 100644 --- a/src/controller.c +++ b/src/controller.c @@ -477,13 +477,11 @@ accept_socket (int fd, short what, void *arg) socklen_t addrlen = sizeof(ss); int nfd; - if ((nfd = accept (fd, (struct sockaddr *)&ss, &addrlen)) == -1) { + if ((nfd = accept_from_socket (fd, (struct sockaddr *)&ss, &addrlen)) == -1) { + msg_warn ("accept_socket: accept failed: %s", strerror (errno)); return; } - if (event_make_socket_nonblocking(fd) < 0) { - return; - } - + new_session = g_malloc (sizeof (struct controller_session)); if (new_session == NULL) { msg_err ("accept_socket: cannot allocate memory for task, %s", strerror (errno)); @@ -527,14 +525,14 @@ start_controller (struct rspamd_worker *worker) signal_add (&worker->sig_ev, NULL); if (worker->srv->cfg->control_family == AF_INET) { - if ((listen_sock = make_socket (&worker->srv->cfg->control_addr, worker->srv->cfg->control_port)) == -1) { + if ((listen_sock = make_tcp_socket (&worker->srv->cfg->control_addr, worker->srv->cfg->control_port, TRUE)) == -1) { msg_err ("start_controller: cannot create tcp listen socket. %s", strerror (errno)); exit(-errno); } } else { un_addr = (struct sockaddr_un *) alloca (sizeof (struct sockaddr_un)); - if (!un_addr || (listen_sock = make_unix_socket (worker->srv->cfg->control_host, un_addr)) == -1) { + if (!un_addr || (listen_sock = make_unix_socket (worker->srv->cfg->control_host, un_addr, TRUE)) == -1) { msg_err ("start_controller: cannot create unix listen socket. %s", strerror (errno)); exit(-errno); } diff --git a/src/lmtp.c b/src/lmtp.c index aa5c034ff..276aad0cb 100644 --- a/src/lmtp.c +++ b/src/lmtp.c @@ -209,22 +209,12 @@ accept_socket (int fd, short what, void *arg) struct worker_task *new_task; struct rspamd_lmtp_proto *lmtp; socklen_t addrlen = sizeof(ss); - int nfd, on = 1; - struct linger linger; + int nfd; - if ((nfd = accept (fd, (struct sockaddr *)&ss, &addrlen)) == -1) { + if ((nfd = accept_from_socket (fd, (struct sockaddr *)&ss, &addrlen)) == -1) { + msg_warn ("accept_socket: accept failed: %s", strerror (errno)); return; } - if (event_make_socket_nonblocking(fd) < 0) { - return; - } - - /* Socket options */ - setsockopt (nfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)); - setsockopt (nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); - linger.l_onoff = 1; - linger.l_linger = 2; - setsockopt (nfd, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); lmtp = g_malloc (sizeof (struct rspamd_lmtp_proto)); new_task = g_malloc (sizeof (struct worker_task)); @@ -276,14 +266,14 @@ start_lmtp_worker (struct rspamd_worker *worker) /* Create listen socket */ if (worker->srv->cfg->lmtp_family == AF_INET) { - if ((listen_sock = make_socket (&worker->srv->cfg->lmtp_addr, worker->srv->cfg->lmtp_port)) == -1) { + if ((listen_sock = make_tcp_socket (&worker->srv->cfg->lmtp_addr, worker->srv->cfg->lmtp_port, TRUE)) == -1) { msg_err ("start_lmtp: cannot create tcp listen socket. %s", strerror (errno)); exit(-errno); } } else { un_addr = (struct sockaddr_un *) alloca (sizeof (struct sockaddr_un)); - if (!un_addr || (listen_sock = make_unix_socket (worker->srv->cfg->lmtp_host, un_addr)) == -1) { + if (!un_addr || (listen_sock = make_unix_socket (worker->srv->cfg->lmtp_host, un_addr, TRUE)) == -1) { msg_err ("start_lmtp: cannot create unix listen socket. %s", strerror (errno)); exit(-errno); } diff --git a/src/lmtp_proto.c b/src/lmtp_proto.c index 42bf3560a..ab20e41a8 100644 --- a/src/lmtp_proto.c +++ b/src/lmtp_proto.c @@ -416,31 +416,20 @@ mta_err_socket (GError *err, void *arg) static int lmtp_deliver_mta (struct worker_task *task) { - int sock, on = 1; - struct linger linger; + int sock; struct sockaddr_un *un; struct mta_callback_data *cd; if (task->cfg->deliver_family == AF_UNIX) { un = alloca (sizeof (struct sockaddr_un)); - sock = make_unix_socket (task->cfg->deliver_host, un); - if (event_make_socket_nonblocking (sock) < 0) { - return -1; - } + sock = make_unix_socket (task->cfg->deliver_host, un, FALSE); } else { - sock = make_socket (&task->cfg->deliver_addr, task->cfg->deliver_port); + sock = make_tcp_socket (&task->cfg->deliver_addr, task->cfg->deliver_port, FALSE); } if (sock == -1) { msg_warn ("lmtp_deliver_mta: cannot create socket for %s, %s", task->cfg->deliver_host, strerror (errno)); } - - /* Socket options */ - setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)); - setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); - linger.l_onoff = 1; - linger.l_linger = 2; - setsockopt (sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); cd = memory_pool_alloc (task->task_pool, sizeof (struct mta_callback_data)); cd->task = task; diff --git a/src/main.c b/src/main.c index da142d6a7..1e9ba6788 100644 --- a/src/main.c +++ b/src/main.c @@ -354,14 +354,14 @@ main (int argc, char **argv, char **env) sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL); if (rspamd->cfg->bind_family == AF_INET) { - if ((listen_sock = make_socket (&rspamd->cfg->bind_addr, rspamd->cfg->bind_port)) == -1) { + if ((listen_sock = make_tcp_socket (&rspamd->cfg->bind_addr, rspamd->cfg->bind_port, TRUE)) == -1) { msg_err ("main: cannot create tcp listen socket. %s", strerror (errno)); exit(-errno); } } else { un_addr = (struct sockaddr_un *) g_malloc (sizeof (struct sockaddr_un)); - if (!un_addr || (listen_sock = make_unix_socket (rspamd->cfg->bind_host, un_addr)) == -1) { + if (!un_addr || (listen_sock = make_unix_socket (rspamd->cfg->bind_host, un_addr, TRUE)) == -1) { msg_err ("main: cannot create unix listen socket. %s", strerror (errno)); exit(-errno); } diff --git a/src/plugins/surbl.c b/src/plugins/surbl.c index 1e466719c..6798d17e4 100644 --- a/src/plugins/surbl.c +++ b/src/plugins/surbl.c @@ -596,33 +596,19 @@ redirector_callback (int fd, short what, void *arg) static void register_redirector_call (struct uri *url, struct worker_task *task) { - struct sockaddr_in sc; - int ofl, r, s; + int s; struct redirector_param *param; struct timeval timeout; - bzero (&sc, sizeof (struct sockaddr_in *)); - sc.sin_family = AF_INET; - sc.sin_port = htons (surbl_module_ctx->redirector_port); - memcpy (&sc.sin_addr, &surbl_module_ctx->redirector_addr, sizeof (struct in_addr)); - - s = socket (PF_INET, SOCK_STREAM, 0); + s = make_tcp_socket (&surbl_module_ctx->redirector_addr, htons (surbl_module_ctx->redirector_port), FALSE); if (s == -1) { - msg_info ("register_redirector_call: socket() failed: %s", strerror (errno)); + msg_info ("register_redirector_call: cannot create tcp socket failed: %s", strerror (errno)); + task->save.saved --; + make_surbl_requests (url, task); return; } - /* set nonblocking */ - ofl = fcntl (s, F_GETFL, 0); - fcntl (s, F_SETFL, ofl | O_NONBLOCK); - - if ((r = connect (s, (struct sockaddr*)&sc, sizeof (struct sockaddr_in))) == -1) { - if (errno != EINPROGRESS) { - close (s); - msg_info ("register_redirector_call: connect() failed: %s", strerror (errno)); - } - } param = memory_pool_alloc (task->task_pool, sizeof (struct redirector_param)); param->url = url; param->task = task; diff --git a/src/util.c b/src/util.c index fac109c78..6a107436a 100644 --- a/src/util.c +++ b/src/util.c @@ -39,10 +39,10 @@ event_make_socket_nonblocking (int fd) } int -make_socket (struct in_addr *addr, u_short port) +make_tcp_socket (struct in_addr *addr, u_short port, gboolean is_server) { struct linger linger; - int fd, on = 1, r; + int fd, on = 1, r, optlen, s_error; int serrno; struct sockaddr_in sin; @@ -55,45 +55,97 @@ make_socket (struct in_addr *addr, u_short port) if (event_make_socket_nonblocking(fd) < 0) { goto out; } - - if (fcntl(fd, F_SETFD, 1) == -1) { + + /* Set close on exec */ + if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) { goto out; } /* Socket options */ - setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)); - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); + setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)); + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); linger.l_onoff = 1; linger.l_linger = 5; - setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); + setsockopt (fd, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); /* Bind options */ sin.sin_family = AF_INET; sin.sin_port = htons (port); sin.sin_addr.s_addr = addr->s_addr; - r = bind(fd, (struct sockaddr *)&sin, sizeof (struct sockaddr_in)); + if (is_server) { + r = bind (fd, (struct sockaddr *)&sin, sizeof (struct sockaddr_in)); + } + else { + r = connect (fd, (struct sockaddr *)&sin, sizeof (struct sockaddr_in)); + } if (r == -1) { if (errno != EINPROGRESS) { goto out; } } + else { + /* Still need to check SO_ERROR on socket */ + optlen = sizeof(s_error); + getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&s_error, &optlen); + if (s_error) { + errno = s_error; + goto out; + } + } + return (fd); out: serrno = errno; - close(fd); + close (fd); errno = serrno; return (-1); } int -make_unix_socket (const char *path, struct sockaddr_un *addr) +accept_from_socket (int listen_sock, struct sockaddr *addr, socklen_t *len) +{ + struct linger linger; + int nfd, on = 1; + int serrno; + + if ((nfd = accept (listen_sock, addr, len)) == -1) { + return -1; + } + if (event_make_socket_nonblocking(nfd) < 0) { + goto out; + } + + /* Set close on exec */ + if (fcntl (nfd, F_SETFD, FD_CLOEXEC) == -1) { + goto out; + } + + /* Socket options */ + setsockopt (nfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)); + setsockopt (nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); + linger.l_onoff = 1; + linger.l_linger = 2; + setsockopt (nfd, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); + + return (nfd); + + out: + serrno = errno; + close (nfd); + errno = serrno; + return (-1); + +} + +int +make_unix_socket (const char *path, struct sockaddr_un *addr, gboolean is_server) { size_t len = strlen (path); - int sock; + int fd, s_error, r, optlen, serrno; if (len > sizeof (addr->sun_path) - 1) return -1; @@ -105,13 +157,50 @@ make_unix_socket (const char *path, struct sockaddr_un *addr) strncpy (addr->sun_path, path, len); - sock = socket (PF_LOCAL, SOCK_STREAM, 0); + fd = socket (PF_LOCAL, SOCK_STREAM, 0); + + if (fd == -1) { + return -1; + } + + if (event_make_socket_nonblocking(fd) < 0) { + goto out; + } + + /* Set close on exec */ + if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) { + goto out; + } + if (is_server) { + r = bind (fd, (struct sockaddr *)&sin, sizeof (struct sockaddr_in)); + } + else { + r = connect (fd, (struct sockaddr *)&sin, sizeof (struct sockaddr_in)); + } - if (sock != -1) { - if (bind (sock, (struct sockaddr *) addr, sizeof (struct sockaddr_un)) == -1) return -1; + if (r == -1) { + if (errno != EINPROGRESS) { + goto out; + } + } + else { + /* Still need to check SO_ERROR on socket */ + optlen = sizeof(s_error); + getsockopt (fd, SOL_SOCKET, SO_ERROR, (void *)&s_error, &optlen); + if (s_error) { + errno = s_error; + goto out; + } } - return sock; + + return (fd); + + out: + serrno = errno; + close (fd); + errno = serrno; + return (-1); } void diff --git a/src/util.h b/src/util.h index 69ae0fe92..f0764b960 100644 --- a/src/util.h +++ b/src/util.h @@ -6,10 +6,12 @@ struct config_file; -/* Create socket and bind it to specified address and port */ -int make_socket(struct in_addr *, u_short ); -/* Create and bind unix socket */ -int make_unix_socket (const char *, struct sockaddr_un *); +/* Create socket and bind or connect it to specified address and port */ +int make_tcp_socket (struct in_addr *, u_short, gboolean is_server); +/* Accept from socket */ +int accept_from_socket (int listen_sock, struct sockaddr *addr, socklen_t *len); +/* Create and bind or connect unix socket */ +int make_unix_socket (const char *, struct sockaddr_un *, gboolean is_server); /* Parse command line arguments using getopt (3) */ void read_cmd_line (int , char **, struct config_file *); /* Write pid to file */ diff --git a/src/worker.c b/src/worker.c index dee49ef4d..8e1225024 100644 --- a/src/worker.c +++ b/src/worker.c @@ -215,22 +215,12 @@ accept_socket (int fd, short what, void *arg) struct sockaddr_storage ss; struct worker_task *new_task; socklen_t addrlen = sizeof(ss); - int nfd, on = 1; - struct linger linger; + int nfd; - if ((nfd = accept (fd, (struct sockaddr *)&ss, &addrlen)) == -1) { + if ((nfd = accept_from_socket (fd, (struct sockaddr *)&ss, &addrlen)) == -1) { + msg_warn ("accept_socket: accept failed: %s", strerror (errno)); return; } - if (event_make_socket_nonblocking(fd) < 0) { - return; - } - - /* Socket options */ - setsockopt (nfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)); - setsockopt (nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); - linger.l_onoff = 1; - linger.l_linger = 2; - setsockopt (nfd, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); new_task = g_malloc (sizeof (struct worker_task)); |