diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 56eb6af872..49099b2ee9 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -4101,8 +4101,17 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
$REMOTE_PORTIf this is a unit started via per-connection socket activation (i.e. via a socket
- unit with Accept=yes), these environment variables contain the IP address and
- port number of the remote peer of the socket connection.
+ unit with Accept=yes), these environment variables contain information about the
+ remote peer of the socket connection.
+
+ For IPv4 and IPv6 connections, $REMOTE_ADDR contains the IP address, and
+ $REMOTE_PORT contains the port number of the remote peer.
+
+ For AF_UNIX socket connections, $REMOTE_ADDR contains
+ either the remote socket's file system path starting with a slash (/), its
+ address in the abstract namespace starting with an at symbol (@), or is unset
+ in case of an unnamed socket. $REMOTE_PORT is not set for AF_UNIX
+ sockets.
diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index a944efad3b..aa0e661002 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -424,11 +424,16 @@
services (in case of Accept=). See the Description section
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
+ 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.
+ 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 won't be set.
+
It is recommended to set CollectMode=inactive-or-failed for service
instances activated via Accept=yes, to ensure that failed connection services are
cleaned up and released from memory, and do not accumulate.
diff --git a/src/core/service.c b/src/core/service.c
index 8ec27c463a..3d27db0272 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1723,27 +1723,32 @@ static int service_spawn_internal(
* in ENOTCONN), and just use whate we can use. */
if (getpeername(s->socket_fd, &sa.sa, &salen) >= 0 &&
- IN_SET(sa.sa.sa_family, AF_INET, AF_INET6, AF_VSOCK)) {
+ IN_SET(sa.sa.sa_family, AF_INET, AF_INET6, AF_VSOCK, AF_UNIX)) {
_cleanup_free_ char *addr = NULL;
char *t;
- unsigned port;
- r = sockaddr_pretty(&sa.sa, salen, true, false, &addr);
+ r = sockaddr_pretty(&sa.sa, salen, /* translate_ipv6= */ true, /* include_port= */ false, &addr);
if (r < 0)
return r;
- t = strjoin("REMOTE_ADDR=", addr);
- if (!t)
- return -ENOMEM;
- our_env[n_env++] = t;
+ if (sa.sa.sa_family != AF_UNIX || IN_SET(addr[0], '/', '@')) {
+ t = strjoin("REMOTE_ADDR=", addr);
+ if (!t)
+ return -ENOMEM;
+ our_env[n_env++] = t;
+ }
- r = sockaddr_port(&sa.sa, &port);
- if (r < 0)
- return r;
+ if (IN_SET(sa.sa.sa_family, AF_INET, AF_INET6, AF_VSOCK)) {
+ unsigned port;
- if (asprintf(&t, "REMOTE_PORT=%u", port) < 0)
- return -ENOMEM;
- our_env[n_env++] = t;
+ r = sockaddr_port(&sa.sa, &port);
+ if (r < 0)
+ return r;
+
+ if (asprintf(&t, "REMOTE_PORT=%u", port) < 0)
+ return -ENOMEM;
+ our_env[n_env++] = t;
+ }
}
}