From 5c4207f00903267c19f9fabf395d095636338811 Mon Sep 17 00:00:00 2001 From: david Date: Sun, 30 Jun 2013 06:08:43 +0000 Subject: [PATCH] Ncat: Implement idle timeout option for listen mode This patch implements "-i" (idle timeout) option for listen mode. Signed-off-by: Tomas Hozza --- ncat/ncat_listen.c | 34 +++++++++++++++++++++++++++++++--- ncat/ncat_main.c | 3 --- ncat/ncat_proxy.c | 14 +++++++++++++- ncat/util.c | 11 +++++++++++ ncat/util.h | 3 +++ 5 files changed, 58 insertions(+), 7 deletions(-) diff --git a/ncat/ncat_listen.c b/ncat/ncat_listen.c index ce26587a7..e3ccde4ce 100644 --- a/ncat/ncat_listen.c +++ b/ncat/ncat_listen.c @@ -199,6 +199,8 @@ static int ncat_listen_stream(int proto) { int rc, i, fds_ready; fd_set listen_fds; + struct timeval tv; + struct timeval *tvp = NULL; /* clear out structs */ FD_ZERO(&master_readfds); @@ -254,6 +256,9 @@ static int ncat_listen_stream(int proto) init_fdlist(&broadcast_fdlist, o.conn_limit); + if (o.idletimeout > 0) + tvp = &tv; + while (1) { /* We pass these temporary descriptor sets to fselect, since fselect modifies the sets it receives. */ @@ -266,11 +271,17 @@ static int ncat_listen_stream(int proto) if (o.debug > 1 && o.broker) logdebug("Broker connection count is %d\n", get_conn_count()); - fds_ready = fselect(client_fdlist.fdmax + 1, &readfds, &writefds, NULL, NULL); + if (o.idletimeout > 0) + ms_to_timeval(tvp, o.idletimeout); + + fds_ready = fselect(client_fdlist.fdmax + 1, &readfds, &writefds, NULL, tvp); if (o.debug > 1) logdebug("select returned %d fds ready\n", fds_ready); + if (fds_ready == 0) + bye("Idle timeout expired (%d ms).", o.idletimeout); + /* * FIXME: optimize this loop to look only at the fds in the fd list, * doing it this way means that if you have one descriptor that is very @@ -584,6 +595,8 @@ static int ncat_listen_dgram(int proto) fd_set read_fds; union sockaddr_u remotess; socklen_t sslen = sizeof(remotess.storage); + struct timeval tv; + struct timeval *tvp = NULL; for (i = 0; i < NUM_LISTEN_ADDRS; i++) { sockfd[i] = -1; @@ -618,6 +631,9 @@ static int ncat_listen_dgram(int proto) add_fd(&listen_fdlist, sockfd[i]); } + if (o.idletimeout > 0) + tvp = &tv; + while (1) { int i, j, conn_count, socket_n; @@ -643,11 +659,17 @@ static int ncat_listen_dgram(int proto) if (o.debug > 1) logdebug("selecting, fdmax %d\n", listen_fdlist.fdmax); fds = listen_fds; - fds_ready = fselect(listen_fdlist.fdmax + 1, &fds, NULL, NULL, NULL); + + if (o.idletimeout > 0) + ms_to_timeval(tvp, o.idletimeout); + + fds_ready = fselect(listen_fdlist.fdmax + 1, &fds, NULL, NULL, tvp); if (o.debug > 1) logdebug("select returned %d fds ready\n", fds_ready); + if (fds_ready == 0) + bye("Idle timeout expired (%d ms).", o.idletimeout); /* * Figure out which listening socket got a connection. This loop should @@ -755,7 +777,13 @@ static int ncat_listen_dgram(int proto) if (o.debug > 1) logdebug("udp select'ing\n"); - fds_ready = fselect(fdmax + 1, &fds, NULL, NULL, NULL); + if (o.idletimeout > 0) + ms_to_timeval(tvp, o.idletimeout); + + fds_ready = fselect(fdmax + 1, &fds, NULL, NULL, tvp); + + if (fds_ready == 0) + bye("Idle timeout expired (%d ms).", o.idletimeout); if (FD_ISSET(STDIN_FILENO, &fds)) { nbytes = Read(STDIN_FILENO, buf, sizeof(buf)); diff --git a/ncat/ncat_main.c b/ncat/ncat_main.c index e6aa0c3de..e322c1365 100644 --- a/ncat/ncat_main.c +++ b/ncat/ncat_main.c @@ -822,9 +822,6 @@ static int ncat_listen_mode(void) if (httpconnect.storage.ss_family != AF_UNSPEC || socksconnect.storage.ss_family != AF_UNSPEC) bye("Invalid option combination: --proxy and -l."); - if (o.idletimeout != 0) - bye("An idle timeout only works in connect mode."); - if (o.broker && o.cmdexec != NULL) bye("Invalid option combination: --broker and -e."); diff --git a/ncat/ncat_proxy.c b/ncat/ncat_proxy.c index ec2f9df6f..112b338eb 100644 --- a/ncat/ncat_proxy.c +++ b/ncat/ncat_proxy.c @@ -158,6 +158,8 @@ int ncat_http_server(void) int listen_socket[NUM_LISTEN_ADDRS]; socklen_t sslen; union sockaddr_u conn; + struct timeval tv; + struct timeval *tvp = NULL; #ifndef WIN32 Signal(SIGCHLD, proxyreaper); @@ -194,6 +196,9 @@ int ncat_http_server(void) } + if (o.idletimeout > 0) + tvp = &tv; + for (;;) { fd_set read_fds; @@ -204,11 +209,18 @@ int ncat_http_server(void) if (o.debug > 1) logdebug("selecting, fdmax %d\n", listen_fdlist.fdmax); read_fds = listen_fds; - int fds_ready = fselect(listen_fdlist.fdmax + 1, &read_fds, NULL, NULL, NULL); + + if (o.idletimeout > 0) + ms_to_timeval(tvp, o.idletimeout); + + int fds_ready = fselect(listen_fdlist.fdmax + 1, &read_fds, NULL, NULL, tvp); if (o.debug > 1) logdebug("select returned %d fds ready\n", fds_ready); + if (fds_ready == 0) + bye("Idle timeout expired (%d ms).", o.idletimeout); + for (i = 0; i <= listen_fdlist.fdmax && fds_ready > 0; i++) { /* Loop through descriptors until there is something ready */ if (!FD_ISSET(i, &read_fds)) diff --git a/ncat/util.c b/ncat/util.c index 2e2bd547e..e30581d38 100644 --- a/ncat/util.c +++ b/ncat/util.c @@ -506,6 +506,17 @@ int allow_access(const union sockaddr_u *su) return 1; } +/* + * Fills the given timeval struct with proper + * values based on the given time in milliseconds. + * The pointer to timeval struct must NOT be NULL. + */ +void ms_to_timeval(struct timeval *tv, long ms) +{ + tv->tv_sec = ms / 1000; + tv->tv_usec = (ms - (tv->tv_sec * 1000)) * 1000; +} + /* * ugly code to maintain our list of fds so we can have proper fdmax for * select(). really this should be generic list code, not this silly bit of diff --git a/ncat/util.h b/ncat/util.h index 113b3da68..c0b2b07d5 100644 --- a/ncat/util.h +++ b/ncat/util.h @@ -165,6 +165,9 @@ unsigned char *buildsrcrte(struct in_addr dstaddr, struct in_addr routes[], int allow_access(const union sockaddr_u *su); +void ms_to_timeval(struct timeval *tv, long ms) + __attribute__ ((nonnull)); + struct fdinfo { int fd; union sockaddr_u remoteaddr;