Hi,
I need a shell utility for sending udp datagrams. Of course netcat is
the tool of choice for this purpose.
But our netcat won't ever terminate when used for sending an udp
datagram:
$ echo 'Hello, World!' |nc -Nu 8.8.8.8 53
also our netcat shows undefined behavior when started with closed
stdin or stdout:
$ nc -l 2000 <&- >&- &
[1] 30593
$ echo 'Hello, World!' |nc localhost 2000
Hello, World!
that's bizarre. The nc -l is dual-using its network socket as stdout or
stdin by accident.
I think the most natural behavior for netcat would be to terminate when
stdout and stdin are closed and to switch to half-duplex when only one
of them is closed.
I believe the two diffs I provide will accomplish this without changing
the current defined behavior of netcat.
I split the diff in two. The first one contains all the code changes
and will apply and compile just fine. The second one contains a
reordering of the main loop which would have made the first diff
unreadable. As a cosmetic change reordered the indices on pfd to match
the filedescriptors. Don't let this confuse you.
I'm not 100% sure whether the new close(lfd); I added is without bad
sideeffects. I added it because the shutdown(lfd, SHUT_WR) only works
for sockets.
OK? comments?
Christopher
--- netcat.c.orig Sun Mar 30 23:05:14 2014
+++ netcat.c Mon Mar 31 19:21:53 2014
@@ -66,7 +66,8 @@
#define UNIX_DG_TMP_SOCKET_SIZE 19
/* Command Line Options */
-int dflag; /* detached, no stdin */
+int nostdin; /* detached, no stdin */
+int nostdout; /* no stdout */
int Fflag; /* fdpass sock to stdout */
unsigned int iflag; /* Interval Flag */
int kflag; /* More than one connect */
@@ -157,7 +158,7 @@
errx(1, "unsupported proxy protocol");
break;
case 'd':
- dflag = 1;
+ nostdin = 1;
break;
case 'F':
Fflag = 1;
@@ -286,6 +287,13 @@
if (!lflag && kflag)
errx(1, "must use -l with -k");
+ if (nostdin) Nflag = 0;
+ /* check if stdin / stdout are open */
+ if (dup2(STDIN_FILENO, STDIN_FILENO) == -1 && errno == EBADF)
+ nostdin = 1;
+ if (dup2(STDOUT_FILENO, STDOUT_FILENO) == -1 && errno == EBADF)
+ nostdout = 1;
+
/* Get name of temporary socket for unix datagram client */
if ((family == AF_UNIX) && uflag && !lflag) {
if (sflag) {
@@ -732,27 +740,34 @@
void
readwrite(int nfd)
{
- struct pollfd pfd[2];
+ struct pollfd pfd[3];
unsigned char buf[16384];
- int n, wfd = fileno(stdin);
+ int n, wfd = nostdin ? -1 : STDIN_FILENO;
- int lfd = fileno(stdout);
+ int lfd = nostdout ? -1 : STDOUT_FILENO;
int plen;
plen = 2048;
/* Setup Network FD */
- pfd[0].fd = nfd;
+ pfd[2].fd = nfd;
- pfd[0].events = POLLIN;
+ pfd[2].events = POLLIN;
/* Set up STDIN FD. */
- pfd[1].fd = wfd;
+ pfd[0].fd = wfd;
- pfd[1].events = POLLIN;
+ pfd[0].events = POLLIN;
+ /* Set up STDOUT FD. */
+ pfd[1].fd = lfd;
+ pfd[1].events = POLLHUP;
+
+ if (nostdin && Nflag) shutdown(nfd, SHUT_WR);
+ if (nostdout) shutdown(nfd, SHUT_RD);
+
- while (pfd[0].fd != -1) {
+ while (pfd[0].fd != -1 || pfd[1].fd != -1) {
if (iflag)
sleep(iflag);
- if ((n = poll(pfd, 2 - dflag, timeout)) < 0) {
+ if ((n = poll(pfd, 3, timeout)) < 0) {
close(nfd);
err(1, "Polling Error");
}
@@ -760,13 +775,16 @@
if (n == 0)
return;
- if (pfd[0].revents & POLLIN) {
+ if (pfd[2].revents & POLLIN) {
if ((n = read(nfd, buf, plen)) < 0)
return;
else if (n == 0) {
shutdown(nfd, SHUT_RD);
+ shutdown(lfd, SHUT_WR);
+ close(lfd);
+ /*if (!Nflag)*/ return;
- pfd[0].fd = -1;
- pfd[0].events = 0;
+ pfd[1].fd = -1;
+ pfd[2].events = POLLHUP;
} else {
if (tflag)
atelnet(nfd, buf, n);
@@ -775,18 +793,30 @@
}
}
- if (!dflag && pfd[1].revents & POLLIN) {
+ if (pfd[0].revents & POLLIN) {
if ((n = read(wfd, buf, plen)) < 0)
return;
else if (n == 0) {
if (Nflag)
shutdown(nfd, SHUT_WR);
+ shutdown(wfd, SHUT_RD);
- pfd[1].fd = -1;
- pfd[1].events = 0;
+ pfd[0].fd = -1;
} else {
if (atomicio(vwrite, nfd, buf, n) != n)
return;
}
+ }
+
+ if (pfd[2].revents & POLLHUP) {
+ shutdown(wfd, SHUT_RD);
+ close(wfd);
+ pfd[2].fd = -1;
+ pfd[0].fd = -1;
+ }
+
+ if (pfd[1].revents & POLLHUP) {
+ shutdown(nfd, SHUT_RD);
+ pfd[1].fd = -1;
}
}
}
--- netcat.c.1 Mon Mar 31 19:21:53 2014
+++ netcat.c Mon Mar 31 19:25:37 2014
@@ -748,10 +748,6 @@
plen = 2048;
- /* Setup Network FD */
- pfd[2].fd = nfd;
- pfd[2].events = POLLIN;
-
/* Set up STDIN FD. */
pfd[0].fd = wfd;
pfd[0].events = POLLIN;
@@ -760,6 +756,10 @@
pfd[1].fd = lfd;
pfd[1].events = POLLHUP;
+ /* Setup Network FD */
+ pfd[2].fd = nfd;
+ pfd[2].events = POLLIN;
+
if (nostdin && Nflag) shutdown(nfd, SHUT_WR);
if (nostdout) shutdown(nfd, SHUT_RD);
@@ -775,6 +775,20 @@
if (n == 0)
return;
+ if (pfd[0].revents & POLLIN) {
+ if ((n = read(wfd, buf, plen)) < 0)
+ return;
+ else if (n == 0) {
+ if (Nflag)
+ shutdown(nfd, SHUT_WR);
+ shutdown(wfd, SHUT_RD);
+ pfd[0].fd = -1;
+ } else {
+ if (atomicio(vwrite, nfd, buf, n) != n)
+ return;
+ }
+ }
+
if (pfd[2].revents & POLLIN) {
if ((n = read(nfd, buf, plen)) < 0)
return;
@@ -789,20 +803,6 @@
if (tflag)
atelnet(nfd, buf, n);
if (atomicio(vwrite, lfd, buf, n) != n)
- return;
- }
- }
-
- if (pfd[0].revents & POLLIN) {
- if ((n = read(wfd, buf, plen)) < 0)
- return;
- else if (n == 0) {
- if (Nflag)
- shutdown(nfd, SHUT_WR);
- shutdown(wfd, SHUT_RD);
- pfd[0].fd = -1;
- } else {
- if (atomicio(vwrite, nfd, buf, n) != n)
return;
}
}
--
http://gmerlin.de
OpenPGP: http://gmerlin.de/christopher.pub
F190 D013 8F01 AA53 E080 3F3C F17F B0A1 D44E 4FEE