It's been about two years since I last sent a version of this
patch, which allows you to use unix datagram sockets with nc(1).
Currently nc(1) supports IP datagram sockets and unix stream
sockets, but not unix datagram sockets, and this limitation is
is not mentioned in the man page.

One main improvement with this patch over previous versions is
that when listing on a unix datagram socket with the -k flag, it
handles connections from separate sending sockets correctly.

I currently have to use the net/socat port for something that
nc(1) with this patch can now handle (controlling the
audio/aqualung port, which listens on a unix datagram socket).

For emails with previous versions of this patch, see:
http://marc.info/?t=119509066400004&r=1&w=2

Is there any interest in modifying nc(1) to support unix datagram
sockets?  Other than a single response from guenther@ a couple
years ago, which had good recommendations that are now included in
this patch, I haven't had any feedback on this.

Thanks,
Jeremy

Index: atomicio.c
===================================================================
RCS file: /cvs/src/usr.bin/nc/atomicio.c,v
retrieving revision 1.9
diff -N -u atomicio.c
--- atomicio.c  7 Sep 2007 14:50:44 -0000       1.9
+++ atomicio.c  11 Jun 2010 16:04:45 -0000
@@ -53,7 +53,7 @@
                case -1:
                        if (errno == EINTR)
                                continue;
-                       if (errno == EAGAIN) {
+                       if ((errno == EAGAIN) || (errno == ENOBUFS)) {
                                (void)poll(&pfd, 1, -1);
                                continue;
                        }
Index: netcat.c
===================================================================
RCS file: /cvs/src/usr.bin/nc/netcat.c,v
retrieving revision 1.97
diff -N -u netcat.c
--- netcat.c    20 Apr 2010 07:28:28 -0000      1.97
+++ netcat.c    11 Jun 2010 16:04:45 -0000
@@ -89,6 +89,7 @@
 int timeout = -1;
 int family = AF_UNSPEC;
 char *portlist[PORT_MAX+1];
+char *unix_dg_tmp_socket;
 
 void   atelnet(int, unsigned char *, unsigned int);
 void   build_ports(char *);
@@ -99,6 +100,7 @@
 int    socks_connect(const char *, const char *, struct addrinfo,
            const char *, const char *, struct addrinfo, int, const char *);
 int    udptest(int);
+int    unix_bind(char *);
 int    unix_connect(char *);
 int    unix_listen(char *);
 void   set_common_sockopts(int);
@@ -241,8 +243,6 @@
 
        /* Cruft to make sure options are clean, and used properly. */
        if (argv[0] && !argv[1] && family == AF_UNIX) {
-               if (uflag)
-                       errx(1, "cannot use -u and -U");
                host = argv[0];
                uport = NULL;
        } else if (argv[0] && !argv[1]) {
@@ -265,6 +265,18 @@
        if (!lflag && kflag)
                errx(1, "must use -l with -k");
 
+       /* Get name of temporary socket for unix datagram client */
+       if ((family == AF_UNIX) && uflag && !lflag) {
+               if(pflag) {
+                       unix_dg_tmp_socket = pflag;
+               } else {
+                       if((unix_dg_tmp_socket = (char *)malloc(19)) == NULL)
+                               errx(1, "not enough memory");
+                       strlcpy(unix_dg_tmp_socket, "/tmp/nc.XXXXXXXXXX", 19);
+                       mktemp(unix_dg_tmp_socket);
+               }
+       }
+
        /* Initialize addrinfo structure. */
        if (family != AF_UNIX) {
                memset(&hints, 0, sizeof(struct addrinfo));
@@ -307,8 +319,12 @@
                int connfd;
                ret = 0;
 
-               if (family == AF_UNIX)
-                       s = unix_listen(host);
+               if (family == AF_UNIX) {
+                       if(uflag)
+                               s = unix_bind(host);
+                       else
+                               s = unix_listen(host);
+               }
 
                /* Allow only one connection at a time, but stay alive. */
                for (;;) {
@@ -337,17 +353,19 @@
                                if (rv < 0)
                                        err(1, "connect");
 
-                               connfd = s;
+                               readwrite(s);
                        } else {
                                len = sizeof(cliaddr);
                                connfd = accept(s, (struct sockaddr *)&cliaddr,
                                    &len);
+                               readwrite(connfd);
+                               close(connfd);
                        }
 
-                       readwrite(connfd);
-                       close(connfd);
                        if (family != AF_UNIX)
                                close(s);
+                       else if (uflag)
+                               connect(s, NULL, 0);
 
                        if (!kflag)
                                break;
@@ -361,6 +379,8 @@
                } else
                        ret = 1;
 
+               if(uflag)
+                       unlink(unix_dg_tmp_socket);
                exit(ret);
 
        } else {
@@ -421,18 +441,19 @@
 }
 
 /*
- * unix_connect()
- * Returns a socket connected to a local unix socket. Returns -1 on failure.
+ * unix_bind()
+ * Returns a unix socket bound to the given path
  */
 int
-unix_connect(char *path)
+unix_bind(char *path)
 {
        struct sockaddr_un sun;
        int s;
 
-       if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+       /* Create unix domain socket. */
+       if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM,
+            0)) < 0)
                return (-1);
-       (void)fcntl(s, F_SETFD, 1);
 
        memset(&sun, 0, sizeof(struct sockaddr_un));
        sun.sun_family = AF_UNIX;
@@ -443,27 +464,32 @@
                errno = ENAMETOOLONG;
                return (-1);
        }
-       if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
+
+       if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
                close(s);
                return (-1);
        }
        return (s);
-
 }
 
 /*
- * unix_listen()
- * Create a unix domain socket, and listen on it.
+ * unix_connect()
+ * Returns a socket connected to a local unix socket. Returns -1 on failure.
  */
 int
-unix_listen(char *path)
+unix_connect(char *path)
 {
        struct sockaddr_un sun;
        int s;
 
-       /* Create unix domain socket. */
-       if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
-               return (-1);
+       if (uflag) {
+               if((s = unix_bind(unix_dg_tmp_socket)) < 0)
+                       return (-1);
+       } else {
+               if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+                       return (-1);
+       }
+       (void)fcntl(s, F_SETFD, 1);
 
        memset(&sun, 0, sizeof(struct sockaddr_un));
        sun.sun_family = AF_UNIX;
@@ -474,11 +500,24 @@
                errno = ENAMETOOLONG;
                return (-1);
        }
-
-       if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
+       if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
                close(s);
                return (-1);
        }
+       return (s);
+
+}
+
+/*
+ * unix_listen()
+ * Create a unix domain socket, and listen on it.
+ */
+int
+unix_listen(char *path)
+{
+       int s;
+       if((s = unix_bind(path)) < 0)
+               return (-1);
 
        if (listen(s, 5) < 0) {
                close(s);

Reply via email to