From: Aron Xu Date: Mon, 13 Feb 2012 15:16:04 +0800 Subject: New flag '-q' to specify a quit timer --- nc.1 | 10 ++++++++++ netcat.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/nc.1 b/nc.1 index 478fedd..fbcc098 100644 --- a/nc.1 +++ b/nc.1 @@ -41,6 +41,7 @@ .Op Fl O Ar length .Op Fl P Ar proxy_username .Op Fl p Ar source_port +.Op Fl q Ar seconds .Op Fl s Ar sourceaddr .Op Fl T Ar keyword .Op Fl V Ar rtable @@ -167,6 +168,15 @@ Proxy authentication is only supported for HTTP CONNECT proxies at present. Specify the source port .Nm should use, subject to privilege restrictions and availability. +.It Fl q Ar seconds +after EOF on stdin, wait the specified number of +.Ar seconds +and then quit. If +.Ar seconds +is negative, wait forever (default). Specifying a non-negative +.Ar seconds +implies +.Fl N . .It Fl r Choose source and/or destination ports randomly instead of sequentially within a range or in the order that the system diff --git a/netcat.c b/netcat.c index 2f3e9a8..03d339c 100644 --- a/netcat.c +++ b/netcat.c @@ -139,6 +139,7 @@ int Nflag; /* shutdown() network socket */ int nflag; /* Don't do name look up */ char *Pflag; /* Proxy username */ char *pflag; /* Localport flag */ +int qflag = -1; /* Quit after some secs */ int rflag; /* Random ports flag */ char *sflag; /* Source Address */ int tflag; /* Telnet Emulation */ @@ -223,6 +224,7 @@ ssize_t fillbuf(int, unsigned char *, size_t *); #endif static int connect_with_timeout(int, const struct sockaddr *, socklen_t, int); +static void quit(int sig); int main(int argc, char *argv[]) @@ -255,9 +257,9 @@ main(int argc, char *argv[]) while ((ch = getopt(argc, argv, #ifdef HAVE_TLS - "46C:cDde:FH:hI:i:K:klM:m:NnO:o:P:p:R:rSs:T:tUuV:vW:w:X:x:Z:z")) + "46C:cDde:FH:hI:i:K:klM:m:NnO:o:P:p:q:R:rSs:T:tUuV:vW:w:X:x:Z:z")) #else - "46CDdFhI:i:klM:m:NnO:P:p:rSs:T:tUuV:vW:w:X:x:z")) + "46CDdFhI:i:klM:m:NnO:P:p:q:rSs:T:tUuV:vW:w:X:x:z")) #endif != -1) { switch (ch) { @@ -349,6 +351,13 @@ main(int argc, char *argv[]) case 'p': pflag = optarg; break; + case 'q': + qflag = strtonum(optarg, INT_MIN, INT_MAX, &errstr); + if (errstr) + errx(1, "quit timer %s: %s", errstr, optarg); + if (qflag >= 0) + Nflag = 1; + break; #ifdef HAVE_TLS case 'R': tls_cachanged = 1; @@ -1335,15 +1344,27 @@ readwrite(int net_fd) while (1) { /* both inputs are gone, buffers are empty, we are done */ if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1 && - stdinbufpos == 0 && netinbufpos == 0) - return; + stdinbufpos == 0 && netinbufpos == 0) { + if (qflag <= 0) + return; + goto delay_exit; + } /* both outputs are gone, we can't continue */ - if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) - return; + if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) { + if (qflag <= 0) + return; + goto delay_exit; + } /* listen and net in gone, queues empty, done */ if (lflag && pfd[POLL_NETIN].fd == -1 && - stdinbufpos == 0 && netinbufpos == 0) - return; + stdinbufpos == 0 && netinbufpos == 0) { + if (qflag <= 0) + return; +delay_exit: + close(net_fd); + signal(SIGALRM, quit); + alarm(qflag); + } /* poll */ num_fds = poll(pfd, 4, timeout); @@ -1500,6 +1521,13 @@ readwrite(int net_fd) if (pfd[POLL_NETOUT].fd != -1 && Nflag) shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); pfd[POLL_NETOUT].fd = -1; + /* #817050: handle UDP sockets and kflag */ + if ((lflag || uflag) && pfd[POLL_NETIN].fd != -1 && + qflag >= 0 && netinbufpos == 0) { + shutdown(pfd[POLL_NETIN].fd, SHUT_RD); + pfd[POLL_NETIN].fd = -1; + kflag = 0; + } } /* net in gone and queue empty? */ if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) { @@ -2106,6 +2134,7 @@ help(void) \t-O length TCP send buffer length\n\ \t-P proxyuser\tUsername for proxy authentication\n\ \t-p port\t Specify local port for remote connects\n\ + \t-q secs\t quit after EOF on stdin and delay of secs\n\ \t-r Randomize remote ports\n\ \t-S Enable the TCP MD5 signature option\n\ \t-s sourceaddr Local source address\n\ @@ -2130,10 +2159,18 @@ usage(int ret) fprintf(stderr, "usage: nc [-46CDdFhklNnrStUuvz] [-I length] [-i interval] [-M ttl]\n" "\t [-m minttl] [-O length] [-P proxy_username] [-p source_port]\n" - "\t [-s sourceaddr] [-T keyword] [-V rtable] [-W recvlimit] " - "[-w timeout]\n" - "\t [-X proxy_protocol] [-x proxy_address[:port]]\n" + "\t [-q seconds] [-s sourceaddr] [-T keyword] [-V rtable] [-W recvlimit]\n" + "\t [-w timeout] [-X proxy_protocol] [-x proxy_address[:port]]\n" "\t [destination] [port]\n"); if (ret) exit(1); } + +/* + * quit() + * handler for a "-q" timeout (exit 0 instead of 1) + */ +static void quit(__attribute__((unused)) int sig) +{ + exit(0); +}