Files
netcat-openbsd/abstract-unix-domain-socket.patch

158 lines
4.3 KiB
Diff

From: Dirk Jagdmann <doj@cubic.org>
Date: Sun, 6 Mar 2022 21:26:31 -0800
Subject: Add abstract UNIX domain socket support
When using '-U' to connect() or bind() to a UNIX domain socket, if the
address (path) starts with "@", it is read as an abstract namespace
socket (the leading "@" is replaced with a NUL byte before binding).
This feature is Linux-only.
Forwarded: not-needed
---
nc.1 | 3 +++
netcat.c | 75 ++++++++++++++++++++++++++++++++++++++++++++--------------------
2 files changed, 55 insertions(+), 23 deletions(-)
diff --git a/nc.1 b/nc.1
index d30389a..8285c10 100644
--- a/nc.1
+++ b/nc.1
@@ -235,6 +235,9 @@ Cannot be used together with
.Fl F
or
.Fl x .
+On Linux, if the name starts with an at symbol (`@') it is read as an abstract
+namespace socket: the leading `@' is replaced with a \fBNUL\fR byte
+before binding or connecting. For details, see \fBunix\fR(7).
.It Fl u
Use UDP instead of TCP.
Cannot be used together with
diff --git a/netcat.c b/netcat.c
index 061a774..2f8890b 100644
--- a/netcat.c
+++ b/netcat.c
@@ -98,6 +98,7 @@
#include <netdb.h>
#include <poll.h>
#include <signal.h>
+#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -208,6 +209,7 @@ int timeout_connect(int, const struct sockaddr *, socklen_t);
int socks_connect(const char *, const char *, struct addrinfo,
const char *, const char *, struct addrinfo, int, const char *);
int udptest(int);
+int unix_setup_sockaddr(char *, struct sockaddr_un *, int *);
void connection_info(const char *, const char *, const char *, const char *);
int unix_bind(char *, int);
int unix_connect(char *);
@@ -931,6 +933,46 @@ main(int argc, char *argv[])
return ret;
}
+int
+unix_setup_sockaddr(char *path, struct sockaddr_un *s_un, int *addrlen)
+{
+ int sun_path_len;
+
+ *addrlen = offsetof(struct sockaddr_un, sun_path);
+ memset(s_un, 0, *addrlen);
+ s_un->sun_family = AF_UNIX;
+
+ if (path[0] == '\0') {
+ /* Always reject the empty path, aka NUL abstract socket on
+ * Linux (OTOH the *empty* abstract socket is supported and
+ * specified as @""). */
+ errno = EINVAL;
+ return -1;
+ }
+#ifdef __linux__
+ /* If the unix domain socket path starts with '@',
+ * treat it as a Linux abstract name. */
+ else if (path[0] == '@') {
+ if ((sun_path_len = strlen(path)) <= sizeof(s_un->sun_path)) {
+ s_un->sun_path[0] = '\0';
+ strncpy(s_un->sun_path+1, path+1, sun_path_len-1);
+ *addrlen += sun_path_len;
+ } else {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ }
+#endif
+ else if ((sun_path_len = strlcpy(s_un->sun_path, path, sizeof(s_un->sun_path))) <
+ sizeof(s_un->sun_path))
+ *addrlen += sun_path_len + 1; /* account for trailing '\0' */
+ else {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ return 0;
+}
+
/*
* unix_bind()
* Returns a unix socket bound to the given path
@@ -939,24 +981,17 @@ int
unix_bind(char *path, int flags)
{
struct sockaddr_un s_un;
- int s, save_errno;
+ int s, save_errno, addrlen;
+
+ if (unix_setup_sockaddr(path, &s_un, &addrlen) == -1)
+ return -1;
/* Create unix domain socket. */
if ((s = socket(AF_UNIX, flags | (uflag ? SOCK_DGRAM : SOCK_STREAM),
0)) == -1)
return -1;
- memset(&s_un, 0, sizeof(struct sockaddr_un));
- s_un.sun_family = AF_UNIX;
-
- if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) >=
- sizeof(s_un.sun_path)) {
- close(s);
- errno = ENAMETOOLONG;
- return -1;
- }
-
- if (bind(s, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
+ if (bind(s, (struct sockaddr *)&s_un, addrlen) == -1) {
save_errno = errno;
close(s);
errno = save_errno;
@@ -1066,7 +1101,10 @@ int
unix_connect(char *path)
{
struct sockaddr_un s_un;
- int s, save_errno;
+ int s, save_errno, addrlen;
+
+ if (unix_setup_sockaddr(path, &s_un, &addrlen) == -1)
+ return -1;
if (uflag) {
if ((s = unix_bind(unix_dg_tmp_socket, SOCK_CLOEXEC)) == -1)
@@ -1076,16 +1114,7 @@ unix_connect(char *path)
return -1;
}
- memset(&s_un, 0, sizeof(struct sockaddr_un));
- s_un.sun_family = AF_UNIX;
-
- if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) >=
- sizeof(s_un.sun_path)) {
- close(s);
- errno = ENAMETOOLONG;
- return -1;
- }
- if (connect(s, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
+ if (connect(s, (struct sockaddr *)&s_un, addrlen) == -1) {
save_errno = errno;
close(s);
errno = save_errno;