This patch adds unix datagram socket support to nc(1). It's basically
the same patch I sent last June (see
http://marc.info/?l=openbsd-tech&m=127627296925965&w=2), but updated
for -current.
Tested on amd64. Doesn't appear to cause any regressions to existing
support, tested with unix stream and IP stream and datagram sockets.
Looking for OKs.
Jeremy
Index: atomicio.c
===================================================================
RCS file: /cvs/src/usr.bin/nc/atomicio.c,v
retrieving revision 1.9
diff -u -p -r1.9 atomicio.c
--- atomicio.c 7 Sep 2007 14:50:44 -0000 1.9
+++ atomicio.c 6 Jan 2011 21:48:04 -0000
@@ -53,7 +53,7 @@ atomicio(ssize_t (*f) (int, void *, size
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.98
diff -u -p -r1.98 netcat.c
--- netcat.c 3 Jul 2010 04:44:51 -0000 1.98
+++ netcat.c 6 Jan 2011 21:48:04 -0000
@@ -89,6 +89,7 @@ u_int rtableid;
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 remote_connect(const char *, const c
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 @@ main(int argc, char *argv[])
/* 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 @@ main(int argc, char *argv[])
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 @@ main(int argc, char *argv[])
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 @@ main(int argc, char *argv[])
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 @@ main(int argc, char *argv[])
} else
ret = 1;
+ if(uflag)
+ unlink(unix_dg_tmp_socket);
exit(ret);
} else {
@@ -421,18 +441,19 @@ main(int argc, char *argv[])
}
/*
- * 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 @@ unix_connect(char *path)
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 @@ unix_listen(char *path)
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);