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);