diff --git a/TODO b/TODO
index f2d515ad78..3b3fe2e323 100644
--- a/TODO
+++ b/TODO
@@ -125,9 +125,6 @@ Deprecations and removals:
Features:
-* in pid1, name Accept=yes service instances after the socket cookie. Also, set
- $SO_COOKIE env var or so for executed services.
-
* loginctl: show argv[] of "leader" process in tabular list-sessions output
* loginctl: show "service identifier" in tabular list-sessions output, to make
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 62c59308ef..a63700afb3 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -4409,7 +4409,18 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
in case of an unnamed socket. $REMOTE_PORT is not set for AF_UNIX
sockets.
-
+
+
+
+
+ $SO_COOKIE
+
+ If this is a unit started via per-connection socket activation (i.e. via a socket
+ unit with Accept=yes), this environment variable contains the Linux socket
+ cookie, formatted as decimal integer. The socket cookie can otherwise be acquired via getsockopt7.
+
+
diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index f20c5fc2ef..39bd0dd626 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -425,14 +425,19 @@
above for a more detailed discussion of the naming rules of triggered services.
For IPv4 and IPv6 connections, the $REMOTE_ADDR environment variable will
- contain the remote IP address, and $REMOTE_PORT will contain the remote port. This
- is the same as the format used by CGI. For SOCK_RAW, the port is the IP
- protocol.
+ contain the remote IP address, and $REMOTE_PORT will contain the remote port
+ number. These two variables correspond to those defined by the CGI interface for web services (see
+ RFC 3875).
For AF_UNIX socket connections, the $REMOTE_ADDR
environment variable will contain either the remote socket's file system path starting with a slash
(/) or its address in the abstract namespace starting with an at symbol
- (@). If the socket is unnamed, $REMOTE_ADDR will not be set.
+ (@). If the socket is unnamed, $REMOTE_ADDR will not be
+ set.
+
+ The $SO_COOKIE environment variable is set to the Linux socket cookie,
+ formatted as decimal integer. The socket cookie can otherwise be acquired via getsockopt7.
It is recommended to set CollectMode=inactive-or-failed for service
instances activated via Accept=yes, to ensure that failed connection services are
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index c5499d6e48..919884ba47 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -1959,3 +1959,18 @@ finalize:
return 0;
}
+
+int socket_get_cookie(int fd, uint64_t *ret) {
+ assert(fd >= 0);
+
+ uint64_t cookie = 0;
+ socklen_t cookie_len = sizeof(cookie);
+ if (getsockopt(fd, SOL_SOCKET, SO_COOKIE, &cookie, &cookie_len) < 0)
+ return -errno;
+
+ assert(cookie_len == sizeof(cookie));
+ if (ret)
+ *ret = cookie;
+
+ return 0;
+}
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index 830b48e435..dea93dbde8 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -354,3 +354,5 @@ int socket_address_equal_unix(const char *a, const char *b);
int vsock_get_local_cid(unsigned *ret);
int netlink_socket_get_multicast_groups(int fd, size_t *ret_len, uint32_t **ret_groups);
+
+int socket_get_cookie(int fd, uint64_t *ret);
diff --git a/src/core/service.c b/src/core/service.c
index 141c85745a..46e8ff6239 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1749,7 +1749,7 @@ static int service_spawn_internal(
if (r < 0)
return r;
- our_env = new0(char*, 15);
+ our_env = new0(char*, 16);
if (!our_env)
return -ENOMEM;
@@ -1821,6 +1821,14 @@ static int service_spawn_internal(
our_env[n_env++] = t;
}
}
+
+ uint64_t cookie;
+ if (socket_get_cookie(s->socket_fd, &cookie) >= 0) {
+ char *t;
+ if (asprintf(&t, "SO_COOKIE=%" PRIu64, cookie) < 0)
+ return -ENOMEM;
+ our_env[n_env++] = t;
+ }
}
Service *env_source = NULL;
diff --git a/src/core/socket.c b/src/core/socket.c
index af67ac3d06..1ce6bc1ba6 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -830,7 +830,11 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
cgroup_context_dump(UNIT(s), f, prefix);
}
-static int instance_from_socket(int fd, unsigned nr, char **ret) {
+static int instance_from_socket(
+ int fd,
+ unsigned nr,
+ char **ret) {
+
union sockaddr_union local, remote;
socklen_t l;
int r;
@@ -846,6 +850,11 @@ static int instance_from_socket(int fd, unsigned nr, char **ret) {
if (getpeername(fd, &remote.sa, &l) < 0)
return -errno;
+ uint64_t cookie;
+ r = socket_get_cookie(fd, &cookie);
+ if (r < 0)
+ return r;
+
char *s;
switch (local.sa.sa_family) {
@@ -856,8 +865,9 @@ static int instance_from_socket(int fd, unsigned nr, char **ret) {
b = be32toh(remote.in.sin_addr.s_addr);
if (asprintf(&s,
- "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
+ "%u-%" PRIu64 "-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
nr,
+ cookie,
a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
be16toh(local.in.sin_port),
b >> 24, (b >> 16) & 0xFF, (b >> 8) & 0xFF, b & 0xFF,
@@ -879,8 +889,9 @@ static int instance_from_socket(int fd, unsigned nr, char **ret) {
*b = remote.in6.sin6_addr.s6_addr+12;
if (asprintf(&s,
- "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
+ "%u-%" PRIu64 "-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
nr,
+ cookie,
a[0], a[1], a[2], a[3],
be16toh(local.in6.sin6_port),
b[0], b[1], b[2], b[3],
@@ -888,8 +899,9 @@ static int instance_from_socket(int fd, unsigned nr, char **ret) {
return -ENOMEM;
} else {
if (asprintf(&s,
- "%u-%s:%u-%s:%u",
+ "%u-%" PRIu64 "-%s:%u-%s:%u",
nr,
+ cookie,
IN6_ADDR_TO_STRING(&local.in6.sin6_addr),
be16toh(local.in6.sin6_port),
IN6_ADDR_TO_STRING(&remote.in6.sin6_addr),
@@ -909,19 +921,20 @@ static int instance_from_socket(int fd, unsigned nr, char **ret) {
uint64_t pidfd_id;
if (pidfd >= 0 && pidfd_get_inode_id(pidfd, &pidfd_id) >= 0)
- r = asprintf(&s, "%u-" PID_FMT "_%" PRIu64 "-" UID_FMT,
- nr, ucred.pid, pidfd_id, ucred.uid);
+ r = asprintf(&s, "%u-%" PRIu64 "-" PID_FMT "_%" PRIu64 "-" UID_FMT,
+ nr, cookie, ucred.pid, pidfd_id, ucred.uid);
else
- r = asprintf(&s, "%u-" PID_FMT "-" UID_FMT,
- nr, ucred.pid, ucred.uid);
+ r = asprintf(&s, "%u-%" PRIu64 "-" PID_FMT "-" UID_FMT,
+ nr, cookie, ucred.pid, ucred.uid);
if (r < 0)
return -ENOMEM;
} else if (r == -ENODATA) {
/* This handles the case where somebody is connecting from another pid/uid namespace
* (e.g. from outside of our container). */
if (asprintf(&s,
- "%u-unknown",
- nr) < 0)
+ "%u-%" PRIu64 "-unknown",
+ nr,
+ cookie) < 0)
return -ENOMEM;
} else
return r;
@@ -931,8 +944,9 @@ static int instance_from_socket(int fd, unsigned nr, char **ret) {
case AF_VSOCK:
if (asprintf(&s,
- "%u-%u:%u-%u:%u",
+ "%u-%" PRIu64 "-%u:%u-%u:%u",
nr,
+ cookie,
local.vm.svm_cid, local.vm.svm_port,
remote.vm.svm_cid, remote.vm.svm_port) < 0)
return -ENOMEM;
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index 274719c296..252bb46b6e 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -717,9 +717,7 @@ TEST(sock_diag_unix) {
ASSERT_OK_ERRNO(fstat(unix_fd, &st));
uint64_t cookie;
- socklen_t cookie_len = sizeof(cookie);
- ASSERT_OK_ERRNO(getsockopt(unix_fd, SOL_SOCKET, SO_COOKIE, &cookie, &cookie_len));
- ASSERT_EQ(cookie_len, sizeof(cookie));
+ ASSERT_OK(socket_get_cookie(unix_fd, &cookie));
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
ASSERT_OK(sd_sock_diag_message_new_unix(nl, &message, st.st_ino, cookie, UDIAG_SHOW_RQLEN));
diff --git a/src/shared/socket-netlink.c b/src/shared/socket-netlink.c
index 1ecb2284fe..a810e1c1f3 100644
--- a/src/shared/socket-netlink.c
+++ b/src/shared/socket-netlink.c
@@ -504,12 +504,10 @@ int af_unix_get_qlen(int fd, uint32_t *ret) {
if (r < 0)
return r;
- uint64_t cookie = 0;
- socklen_t cookie_len = sizeof(cookie);
- if (getsockopt(fd, SOL_SOCKET, SO_COOKIE, &cookie, &cookie_len) < 0)
- return -errno;
-
- assert(cookie_len == sizeof(cookie));
+ uint64_t cookie;
+ r = socket_get_cookie(fd, &cookie);
+ if (r < 0)
+ return r;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
r = sd_sock_diag_message_new_unix(nl, &message, st.st_ino, cookie, UDIAG_SHOW_RQLEN);