From: Kamil Szczęk Date: Mon, 3 Jun 2024 15:56:42 +0000 (+0200) Subject: core: populate $REMOTE_ADDR for AF_UNIX sockets X-Git-Tag: v257-rc1~1201 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=608bfe76c18ea4ecda0a78a243363eebae032243;p=thirdparty%2Fsystemd.git core: populate $REMOTE_ADDR for AF_UNIX sockets Set the $REMOTE_ADDR environment variable for AF_UNIX socket connections when using per-connection socket activation (Accept=yes). $REMOTE_ADDR will now contain the remote socket's file system path (starting with a slash "/") or its address in the abstract namespace (starting with an at symbol "@"). This information is essential for identifying the remote peer in AF_UNIX socket connections, but it's not easy to obtain in a shell script for example without pulling in a ton of additional tools. By setting $REMOTE_ADDR, we make this information readily available to the activated service. --- diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 56eb6af8728..49099b2ee97 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -4101,8 +4101,17 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX $REMOTE_PORT If 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 a944efad3bd..aa0e661002a 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 8ec27c463a4..3d27db0272f 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; + } } }