File: abstract-unix-domain-socket.patch

package info (click to toggle)
netcat-openbsd 1.229-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,560 kB
  • sloc: ansic: 31,646; sh: 678; makefile: 68
file content (157 lines) | stat: -rw-r--r-- 4,397 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
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;