Hi,
I've already sent this message to bugs@ list. Based on its mebers' advice I'm 
resending message with inline patches to tech@ list.

I'm current maintainer of netcat package in Fedora. We use OpenBSD's 
implementation and we have some patches included which most likely haven't 
been offered to you yet. Some of them rather old and I'm not even sure they 
will be useful to you. Anyway I'm sending all of them in this email with a 
brief description. I re-wrote them all for current CVS snapshot of netcat. 
Please consider including them in your project, I think some of them offer good 
functionality/bugfixes. Patches have been constructed in order they are 
numbered, so applying them all in that order should work with no problems. 
Patches are also listen in this email in that specific order.

Patch description:
01-pollhup.patch - this patch adds detection of POLLHUP during data sending
02-reuseaddr.patch - activates SO_REUSEADDR socket option
03-connect_with_timeout.patch - implements possibility to set timeout for 
outgoing connection
04-crlf.patch - implements using CRLF as line ending
05-efficient-reads.patch - extends size of buffers for reading
06-crlf-man-page.patch - update of man page to match previous patch
07-improved-udp-scan.patch - improved algorithm performing UDP scan
08-improved-udp-scan-2.patch - complement to previous patch
09-verbose-listen.patch - verbose output when listening on non-unix socket

All patches are available at http://jzeleny.fedorapeople.org/patches/nc/

Thank you and looking forward to further cooperation
-- Jan


diff -Nurp nc-orig/netcat.c nc/netcat.c
--- nc-orig/netcat.c    2010-01-08 17:34:27.000000000 +0100
+++ nc/netcat.c 2010-01-08 18:01:40.000000000 +0100
@@ -660,17 +660,29 @@ readwrite(int nfd)
                                        return;
                        }
                }
+               else if (pfd[0].revents & POLLHUP) {
+                       shutdown(nfd, SHUT_RD);
+                       pfd[0].fd = -1;
+                       pfd[0].events = 0;
+               }
 
-               if (!dflag && pfd[1].revents & POLLIN) {
-                       if ((n = read(wfd, buf, plen)) < 0)
-                               return;
-                       else if (n == 0) {
+               if (!dflag) {
+                       if (pfd[1].revents & POLLIN) {
+                               if ((n = read(wfd, buf, plen)) < 0)
+                                       return;
+                               else if (n == 0) {
+                                       shutdown(nfd, SHUT_WR);
+                                       pfd[1].fd = -1;
+                                       pfd[1].events = 0;
+                               } else {
+                                       if (atomicio(vwrite, nfd, buf, n) != n)
+                                               return;
+                               }
+                       }
+                       else if (pfd[1].revents & POLLHUP) {
                                shutdown(nfd, SHUT_WR);
                                pfd[1].fd = -1;
                                pfd[1].events = 0;
-                       } else {
-                               if (atomicio(vwrite, nfd, buf, n) != n)
-                                       return;
                        }
                }
        }

diff -Nurp nc-orig/netcat.c nc/netcat.c
--- nc-orig/netcat.c    2010-01-08 18:03:26.000000000 +0100
+++ nc/netcat.c 2010-01-08 18:28:54.000000000 +0100
@@ -587,6 +587,10 @@ local_listen(char *host, char *port, str
                                err(1, "setsockopt SO_RDOMAIN");
                }
 
+               ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
+               if (ret == -1)
+                       err(1, NULL);
+
                ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
                if (ret == -1)
                        err(1, NULL);

diff -Nurp nc-orig/netcat.c nc/netcat.c
--- nc-orig/netcat.c    2010-01-11 08:33:51.000000000 +0100
+++ nc/netcat.c 2010-01-11 08:42:34.000000000 +0100
@@ -63,6 +63,10 @@
 #define PORT_MAX       65535
 #define PORT_MAX_LEN   6
 
+#define CONNECTION_SUCCESS 0
+#define CONNECTION_FAILED 1
+#define CONNECTION_TIMEOUT 2
+
 /* Command Line Options */
 int    dflag;                                  /* detached, no stdin */
 unsigned int iflag;                            /* Interval Flag */
@@ -105,6 +109,9 @@ void        set_common_sockopts(int);
 int    parse_iptos(char *);
 void   usage(int);
 
+static int connect_with_timeout(int fd, const struct sockaddr *sa,
+                               socklen_t salen, int ctimeout);
+
 int
 main(int argc, char *argv[])
 {
@@ -535,11 +542,14 @@ remote_connect(const char *host, const c
 
                set_common_sockopts(s);
 
-               if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
+               if ((error = connect_with_timeout(s, res0->ai_addr, 
res0->ai_addrlen, 
timeout)) == CONNECTION_SUCCESS)
                        break;
-               else if (vflag)
+               else if (vflag && error == CONNECTION_FAILED)
                        warn("connect to %s port %s (%s) failed", host, port,
                            uflag ? "udp" : "tcp");
+               else if (vflag && error == CONNECTION_TIMEOUT)
+                               warn("connect to %s port %s (%s) timed out", 
host, port,
+                                       uflag ? "udp" : "tcp");
 
                close(s);
                s = -1;
@@ -550,6 +560,73 @@ remote_connect(const char *host, const c
        return (s);
 }
 
+static int connect_with_timeout(int fd, const struct sockaddr *sa,
+                               socklen_t salen, int ctimeout)
+{
+       int err;
+       struct timeval tv, *tvp = NULL;
+       fd_set connect_fdset;
+       socklen_t len;
+       int orig_flags;
+
+       orig_flags = fcntl(fd, F_GETFL, 0);
+       if (fcntl(fd, F_SETFL, orig_flags | O_NONBLOCK) < 0 ) {
+               warn("can't set O_NONBLOCK - timeout not avaliable");
+               if (connect(fd, sa, salen) == 0)
+                       return CONNECTION_SUCCESS;
+               else
+                       return CONNECTION_FAILED;
+       }
+
+       /* set connect timeout */
+       if (ctimeout > 0) {
+               tv.tv_sec = (time_t)ctimeout/1000;
+               tv.tv_usec = 0;
+               tvp = &tv;
+       }
+
+       /* attempt the connection */
+       err = connect(fd, sa, salen);
+
+       if (err != 0 && errno == EINPROGRESS) {
+               /* connection is proceeding
+                * it is complete (or failed) when select returns */
+
+               /* initialize connect_fdset */
+               FD_ZERO(&connect_fdset);
+               FD_SET(fd, &connect_fdset);
+
+               /* call select */
+               do {
+                       err = select(fd + 1, NULL, &connect_fdset,
+                                       NULL, tvp);
+               } while (err < 0 && errno == EINTR);
+
+               /* select error */
+               if (err < 0)
+                       errx(1,"select error: %s", strerror(errno));
+
+               /* we have reached a timeout */
+               if (err == 0)
+                       return CONNECTION_TIMEOUT;
+
+               /* select returned successfully, but we must test socket
+                * error for result */
+               len = sizeof(err);
+               if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0)
+                       errx(1, "getsockopt error: %s", strerror(errno));
+
+               /* setup errno according to the result returned by
+                * getsockopt */
+               if (err != 0)
+                       errno = err;
+       }
+
+       /* return aborted if an error occured, and valid otherwise */
+       fcntl(fd, F_SETFL, orig_flags);
+       return (err != 0)? CONNECTION_FAILED : CONNECTION_SUCCESS;
+}
+
 /*
  * local_listen()
  * Returns a socket listening on a local port, binds to specified source

diff -Nurp nc-orig/netcat.c nc/netcat.c
--- nc-orig/netcat.c    2010-01-11 08:43:26.000000000 +0100
+++ nc/netcat.c 2010-01-11 09:57:25.000000000 +0100
@@ -88,6 +88,7 @@ int   Iflag;                                  /* TCP receive 
buffer siz
 int    Oflag;                                  /* TCP send buffer size */
 int    Sflag;                                  /* TCP MD5 signature option */
 int    Tflag = -1;                             /* IP Type of Service */
+int    Cflag = 0;                              /* CRLF line-ending */
 u_int  rdomain;
 
 int timeout = -1;
@@ -133,7 +134,7 @@ main(int argc, char *argv[])
        sv = NULL;
 
        while ((ch = getopt(argc, argv,
-           "46DdhI:i:jklnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) {
+           "46DdhI:i:jklnO:P:p:rSs:tT:UuV:vw:X:x:zC")) != -1) {
                switch (ch) {
                case '4':
                        family = AF_INET;
@@ -239,6 +240,9 @@ main(int argc, char *argv[])
                case 'T':
                        Tflag = parse_iptos(optarg);
                        break;
+               case 'C':
+                       Cflag = 1;
+                       break;
                default:
                        usage(1);
                }
@@ -756,8 +760,16 @@ readwrite(int nfd)
                                        pfd[1].fd = -1;
                                        pfd[1].events = 0;
                                } else {
-                                       if (atomicio(vwrite, nfd, buf, n) != n)
-                                               return;
+                                       if ((Cflag) && (buf[n-1]=='\n')) {
+                                               if (atomicio(vwrite, nfd, buf, 
n-1) != (n-1))
+                                                       return;
+                                               if (atomicio(vwrite, nfd, 
"\r\n", 2) != 2)
+                                                       return;
+                                       }
+                                       else {
+                                               if (atomicio(vwrite, nfd, buf, 
n) != n)
+                                                       return;
+                                       }
                                }
                        }
                        else if (pfd[1].revents & POLLHUP) {
@@ -947,6 +959,7 @@ help(void)
        fprintf(stderr, "\tCommand Summary:\n\
        \t-4            Use IPv4\n\
        \t-6            Use IPv6\n\
+       \t-C            Send CRLF as line-ending\n\
        \t-D            Enable the debug socket option\n\
        \t-d            Detach from stdin\n\
        \t-h            This help text\n\
@@ -979,7 +992,7 @@ void
 usage(int ret)
 {
        fprintf(stderr,
-           "usage: nc [-46DdhklnrStUuvz] [-I length] [-i interval] [-O 
length]\n"
+           "usage: nc [-46CDdhklnrStUuvz] [-I length] [-i interval] [-O 
length]\n"
            "\t  [-P proxy_username] [-p source_port] [-s source_ip_address] 
[-T 
ToS]\n"
            "\t  [-V rdomain] [-w timeout] [-X proxy_protocol]\n"
            "\t  [-x proxy_address[:port]] [hostname] [port]\n");

diff -Nurp nc-orig/netcat.c nc/netcat.c
--- nc-orig/netcat.c    2010-01-11 10:00:39.000000000 +0100
+++ nc/netcat.c 2010-01-11 10:02:44.000000000 +0100
@@ -334,11 +334,11 @@ main(int argc, char *argv[])
                         */
                        if (uflag) {
                                int rv, plen;
-                               char buf[8192];
+                               char buf[16384];
                                struct sockaddr_storage z;
 
                                len = sizeof(z);
-                               plen = jflag ? 8192 : 1024;
+                               plen = jflag ? 16384 : 2048;
                                rv = recvfrom(s, buf, plen, MSG_PEEK,
                                    (struct sockaddr *)&z, &len);
                                if (rv < 0)
@@ -704,12 +704,12 @@ void
 readwrite(int nfd)
 {
        struct pollfd pfd[2];
-       unsigned char buf[8192];
+       unsigned char buf[16384];
        int n, wfd = fileno(stdin);
        int lfd = fileno(stdout);
        int plen;
 
-       plen = jflag ? 8192 : 1024;
+       plen = jflag ? 16384 : 2048;
 
        /* Setup Network FD */
        pfd[0].fd = nfd;

diff -Nurp nc-orig/nc.1 nc/nc.1
--- nc-orig/nc.1        2010-01-08 17:34:27.000000000 +0100
+++ nc/nc.1     2010-01-11 10:09:38.000000000 +0100
@@ -25,7 +25,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: October 22 2009 $
+.Dd $Mdocdate: January 11, 2010 $
 .Dt NC 1
 .Os
 .Sh NAME
@@ -34,7 +34,7 @@
 .Sh SYNOPSIS
 .Nm nc
 .Bk -words
-.Op Fl 46DdhklnrStUuvz
+.Op Fl 46CDdhklnrStUuvz
 .Op Fl I Ar length
 .Op Fl i Ar interval
 .Op Fl O Ar length
@@ -96,6 +96,8 @@ to use IPv4 addresses only.
 Forces
 .Nm
 to use IPv6 addresses only.
+.It Fl C
+Send CRLF as line-ending
 .It Fl D
 Enable debugging on the socket.
 .It Fl d
@@ -329,7 +331,7 @@ More complicated examples can be built u
 of requests required by the server.
 As another example, an email may be submitted to an SMTP server using:
 .Bd -literal -offset indent
-$ nc localhost 25 \*(Lt\*(Lt EOF
+$ nc [-C] localhost 25 \*(Lt\*(Lt EOF
 HELO host.example.com
 MAIL FROM:\*(ltu...@host.example.com\*(Gt
 RCPT TO:\*(ltus...@host.example.com\*(Gt
diff -Nurp nc-orig/netcat.c nc/netcat.c
--- nc-orig/netcat.c    2010-01-11 10:04:12.000000000 +0100
+++ nc/netcat.c 2010-01-11 10:56:38.000000000 +0100
@@ -67,6 +67,8 @@
 #define CONNECTION_FAILED 1
 #define CONNECTION_TIMEOUT 2
 
+#define UDP_SCAN_TIMEOUT 3     /* Seconds */
+
 /* Command Line Options */
 int    dflag;                                  /* detached, no stdin */
 unsigned int iflag;                            /* Interval Flag */
@@ -396,7 +398,7 @@ main(int argc, char *argv[])
                                continue;
 
                        ret = 0;
-                       if (vflag || zflag) {
+                       if ((vflag && !uflag) || zflag) {
                                /* For UDP, make sure we are connected. */
                                if (uflag) {
                                        if (udptest(s) == -1) {
@@ -887,15 +889,20 @@ build_ports(char *p)
 int
 udptest(int s)
 {
-       int i, ret;
+       int i, t;
 
-       for (i = 0; i <= 3; i++) {
-               if (write(s, "X", 1) == 1)
-                       ret = 1;
-               else
-                       ret = -1;
+       if ((write(s, "X", 1) != 1) ||
+                       ((write(s, "X", 1) != 1) && (errno == ECONNREFUSED)))
+               return -1;
+
+       /* Give the remote host some time to reply. */
+       for (i = 0, t = (timeout == -1) ? UDP_SCAN_TIMEOUT : (timeout / 1000);
+                       i < t; i++) {
+               sleep(1);
+               if ((write(s, "X", 1) != 1) && (errno == ECONNREFUSED))
+                       return -1;
        }
-       return (ret);
+       return 1;
 }
 
 void

diff -Nurp nc-orig/netcat.c nc/netcat.c
--- nc-orig/netcat.c    2010-01-11 10:57:43.000000000 +0100
+++ nc/netcat.c 2010-01-11 11:05:54.000000000 +0100
@@ -752,6 +752,9 @@ readwrite(int nfd)
                        pfd[0].fd = -1;
                        pfd[0].events = 0;
                }
+               else if (pfd[0].revents & POLLERR)
+                       if (write(nfd, "", 1) == -1)
+                               warn("Write error");
 
                if (!dflag) {
                        if (pfd[1].revents & POLLIN) {

diff -Nurp nc-orig/netcat.c nc/netcat.c
--- nc-orig/netcat.c    2010-01-11 11:56:07.000000000 +0100
+++ nc/netcat.c 2010-01-11 13:51:34.000000000 +0100
@@ -357,6 +357,21 @@ main(int argc, char *argv[])
                                    &len);
                        }
 
+                       if(vflag && family != AF_UNIX) {
+                               /* Don't look up port if -n. */
+                               if (nflag)
+                                       sv = NULL;
+                               else
+                                       sv = getservbyport(ntohs(atoi(uport)),
+                                                       uflag ? "udp" : "tcp");
+
+                               fprintf(stderr, "Connection from %s port %s 
[%s/%s] accepted\n",
+                                               inet_ntoa(((struct sockaddr_in 
*)(&cliaddr))->sin_addr),
+                                               uport,
+                                               uflag ? "udp" : "tcp",
+                                               sv ? sv->s_name : "*");
+                       }
+
                        readwrite(connfd);
                        close(connfd);
                        if (family != AF_UNIX)

Reply via email to