This allows e.g. a sequence of clients to have 2-way conversations.

Prior to this, server standard input was effectively discarded.

-k -l -u -v reports each time a message comes from a different client
than that from which the previous message came.

Signed-off-by: Duncan Roe <[email protected]>
---
 usr.bin/nc/netcat.c | 96 +++++++++++++++++++++++++++------------------
 1 file changed, 58 insertions(+), 38 deletions(-)

diff --git a/usr.bin/nc/netcat.c b/usr.bin/nc/netcat.c
index 528dbeea678..bccce3d3227 100644
--- a/usr.bin/nc/netcat.c
+++ b/usr.bin/nc/netcat.c
@@ -141,8 +141,11 @@ void       save_peer_cert(struct tls *_tls_ctx, FILE *_fp);
 void   report_sock(const char *, const struct sockaddr *, socklen_t, char *);
 void   report_tls(struct tls *tls_ctx, char * host);
 void   usage(int);
-ssize_t drainbuf(int, unsigned char *, size_t *, struct tls *);
-ssize_t fillbuf(int, unsigned char *, size_t *, struct tls *);
+ssize_t drainbuf(int, unsigned char *, size_t *, struct tls *, int);
+ssize_t fillbuf(int, unsigned char *, size_t *, struct tls *, int);
+static struct sockaddr_storage cliaddr, cliaddr_saved;
+static socklen_t clilen, clilen_saved;
+static char *host;
 void   tls_setup_client(struct tls *, int, char *);
 struct tls *tls_setup_server(struct tls *, int, char *);
 
@@ -150,12 +153,11 @@ int
 main(int argc, char *argv[])
 {
        int ch, s = -1, ret, socksv;
-       char *host, *uport;
+       char *uport;
        char ipaddr[NI_MAXHOST];
        struct addrinfo hints;
        struct servent *sv;
        socklen_t len;
-       struct sockaddr_storage cliaddr;
        char *proxy = NULL, *proxyport = NULL;
        const char *errstr;
        struct addrinfo proxyhints;
@@ -579,45 +581,44 @@ main(int argc, char *argv[])
                        }
                        if (s == -1)
                                err(1, NULL);
-                       if (uflag && kflag) {
+                       if (uflag) {
                                if (family == AF_UNIX) {
                                        if (pledge("stdio unix", NULL) == -1)
                                                err(1, "pledge");
                                }
-                               /*
-                                * For UDP and -k, don't connect the socket,
-                                * let it receive datagrams from multiple
-                                * socket pairs.
-                                */
-                               readwrite(s, NULL);
-                       } else if (uflag && !kflag) {
-                               /*
-                                * For UDP and not -k, we will use recvfrom()
-                                * initially to wait for a caller, then use
-                                * the regular functions to talk to the caller.
-                                */
+                               /* Use recvfrom() initially to wait for a
+                                * caller, whether -k or not */
                                int rv;
                                char buf[2048];
-                               struct sockaddr_storage z;
 
-                               len = sizeof(z);
+                               clilen = sizeof(cliaddr);
                                rv = recvfrom(s, buf, sizeof(buf), MSG_PEEK,
-                                   (struct sockaddr *)&z, &len);
+                                   (struct sockaddr *)&cliaddr, &clilen);
                                if (rv == -1)
                                        err(1, "recvfrom");
 
-                               rv = connect(s, (struct sockaddr *)&z, len);
-                               if (rv == -1)
-                                       err(1, "connect");
-
-                               if (family == AF_UNIX) {
-                                       if (pledge("stdio unix", NULL) == -1)
-                                               err(1, "pledge");
-                               }
-                               if (vflag)
+                               if (vflag) {
                                        report_sock("Connection received from",
-                                           (struct sockaddr *)&z, len,
+                                           (struct sockaddr *)&cliaddr, clilen,
                                            family == AF_UNIX ? host : NULL);
+                                       if (kflag) {
+                                               clilen_saved = clilen;
+                                               memcpy(&cliaddr_saved, &cliaddr,
+                                                   clilen);
+                                       }
+                               }
+                               if (!kflag) {
+                                       /*
+                                        * For UDP and not -k,
+                                        * connect the socket and then use
+                                        * the regular functions to talk
+                                        * to the caller.
+                                        */
+                                       rv = connect(s,
+                                           (struct sockaddr *)&cliaddr,clilen);
+                                       if (rv == -1)
+                                               err(1, "connect");
+                               }
 
                                readwrite(s, NULL);
                        } else {
@@ -1217,7 +1218,7 @@ readwrite(int net_fd, struct tls *tls_ctx)
                /* try to read from stdin */
                if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) {
                        ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf,
-                           &stdinbufpos, NULL);
+                           &stdinbufpos, NULL, 0);
                        if (ret == TLS_WANT_POLLIN)
                                pfd[POLL_STDIN].events = POLLIN;
                        else if (ret == TLS_WANT_POLLOUT)
@@ -1234,7 +1235,7 @@ readwrite(int net_fd, struct tls *tls_ctx)
                /* try to write to network */
                if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) {
                        ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf,
-                           &stdinbufpos, tls_ctx);
+                           &stdinbufpos, tls_ctx, 1);
                        if (ret == TLS_WANT_POLLIN)
                                pfd[POLL_NETOUT].events = POLLIN;
                        else if (ret == TLS_WANT_POLLOUT)
@@ -1251,7 +1252,7 @@ readwrite(int net_fd, struct tls *tls_ctx)
                /* try to read from network */
                if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) {
                        ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf,
-                           &netinbufpos, tls_ctx);
+                           &netinbufpos, tls_ctx, 1);
                        if (ret == TLS_WANT_POLLIN)
                                pfd[POLL_NETIN].events = POLLIN;
                        else if (ret == TLS_WANT_POLLOUT)
@@ -1283,7 +1284,7 @@ readwrite(int net_fd, struct tls *tls_ctx)
                /* try to write to stdout */
                if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) {
                        ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf,
-                           &netinbufpos, NULL);
+                           &netinbufpos, NULL, 0);
                        if (ret == TLS_WANT_POLLIN)
                                pfd[POLL_STDOUT].events = POLLIN;
                        else if (ret == TLS_WANT_POLLOUT)
@@ -1312,7 +1313,8 @@ readwrite(int net_fd, struct tls *tls_ctx)
 }
 
 ssize_t
-drainbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls)
+drainbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls,
+    int is_socket)
 {
        ssize_t n;
        ssize_t adjust;
@@ -1322,7 +1324,11 @@ drainbuf(int fd, unsigned char *buf, size_t *bufpos, 
struct tls *tls)
                if (n == -1)
                        errx(1, "tls write failed (%s)", tls_error(tls));
        } else {
-               n = write(fd, buf, *bufpos);
+               if (is_socket && uflag && kflag)
+                       n = sendto(fd, buf, *bufpos, 0,
+                           (struct sockaddr *)&cliaddr, clilen);
+               else
+                       n = write(fd, buf, *bufpos);
                /* don't treat EAGAIN, EINTR as error */
                if (n == -1 && (errno == EAGAIN || errno == EINTR))
                        n = TLS_WANT_POLLOUT;
@@ -1338,7 +1344,8 @@ drainbuf(int fd, unsigned char *buf, size_t *bufpos, 
struct tls *tls)
 }
 
 ssize_t
-fillbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls)
+fillbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls,
+    int is_socket)
 {
        size_t num = BUFSIZE - *bufpos;
        ssize_t n;
@@ -1348,7 +1355,20 @@ fillbuf(int fd, unsigned char *buf, size_t *bufpos, 
struct tls *tls)
                if (n == -1)
                        errx(1, "tls read failed (%s)", tls_error(tls));
        } else {
-               n = read(fd, buf + *bufpos, num);
+               if (is_socket && uflag && kflag) {
+                       clilen = sizeof(cliaddr);
+                       n = recvfrom(fd, buf + *bufpos, num, 0,
+                           (struct sockaddr *)&cliaddr, &clilen);
+                       if (vflag && n >= 0 && (clilen != clilen_saved ||
+                           memcmp(&cliaddr_saved, &cliaddr, clilen))) {
+                               report_sock("Connection received from",
+                                   (struct sockaddr *)&cliaddr, clilen,
+                                   family == AF_UNIX ? host : NULL);
+                               clilen_saved = clilen;
+                               memcpy(&cliaddr_saved, &cliaddr, clilen);
+                       }
+               } else
+                       n = read(fd, buf + *bufpos, num);
                /* don't treat EAGAIN, EINTR as error */
                if (n == -1 && (errno == EAGAIN || errno == EINTR))
                        n = TLS_WANT_POLLIN;
-- 
2.17.5

Reply via email to