[systemd-devel] [PATCH] add REMOTE_ADDR and REMOTE_PORT for Accept=yes

Shawn Landden shawn at churchofgit.com
Sun Mar 8 16:24:39 PDT 2015


---
 TODO                   |  2 --
 man/systemd.socket.xml |  6 +++++-
 src/core/service.c     | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/TODO b/TODO
index ae32388..780084a 100644
--- a/TODO
+++ b/TODO
@@ -164,8 +164,6 @@ Features:
 * as soon as we have kdbus, and sender timestamps, revisit coalescing multiple parallel daemon reloads:
   http://lists.freedesktop.org/archives/systemd-devel/2014-December/025862.html
 
-* set $REMOTE_IP (or $REMOTE_ADDR/$REMOTE_PORT) environment variable when doing per-connection socket activation. use format introduced by xinetd or CGI for this
-
 * the install state probably shouldn't get confused by generated units, think dbus1/kdbus compat!
 
 * in systemctl list-unit-files: show the install value the presets would suggest for a service in a third column
diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index 3938345..20f1e0c 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -357,7 +357,11 @@
         daemons designed for usage with
         <citerefentry><refentrytitle>inetd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
         to work unmodified with systemd socket
-        activation.</para></listitem>
+        activation.</para>
+        <para>For IPv4 and IPv6 connections the <varname>REMOTE_ADDR</varname>
+        environment variable will be set with remote IP, and <varname>REMOTE_PORT</varname>
+        environment variable set to the remote port, similar to CGI
+        (for SOCK_RAW the port is the IP protocol).</para></listitem>
       </varlistentry>
 
       <varlistentry>
diff --git a/src/core/service.c b/src/core/service.c
index cc4ea19..6a690ac 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -22,6 +22,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <unistd.h>
+#include <arpa/inet.h>
 
 #include "async.h"
 #include "manager.h"
@@ -1119,6 +1120,52 @@ static int service_spawn(
                         goto fail;
                 }
 
+        if (s->accept_socket.unit) {
+                union sockaddr_union sa;
+                socklen_t salen = sizeof(sa);
+                _cleanup_free_ char *remote_addr = NULL;
+                char a[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
+
+                r = getpeername(s->socket_fd, &sa.sa, &salen);
+                if (r < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+
+                if (sa.sa.sa_family == AF_INET ||
+                    sa.sa.sa_family == AF_INET6) {
+                        if (inet_ntop(sa.sa.sa_family,
+                                      /* this field of the API is kinda braindead,
+                                       * should take head of struct so it can be passed the union...*/
+                                      sa.sa.sa_family == AF_INET6 ?
+                                        &sa.in6.sin6_addr :
+                                        &sa.in.sin_addr,
+                                      a, sizeof(a)) == NULL) {
+                                r = -errno;
+                                goto fail;
+                        }
+
+                        if (asprintf(our_env + n_env++,
+                                     "REMOTE_ADDR=%s",
+                                     /* musl and glibc inet_ntop() present v4-mapped addresses in ::ffff:a.b.c.d form */
+                                     sa.sa.sa_family == AF_INET6 && strchr(a, '.') ?
+                                       strempty(startswith(a, "::ffff:")) :
+                                       a) < 0) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        if (asprintf(our_env + n_env++,
+                                     "REMOTE_PORT=%u",
+                                     ntohs(sa.sa.sa_family == AF_INET6 ?
+                                             sa.in6.sin6_port :
+                                             sa.in.sin_port)) < 0) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+                }
+        }
+
         final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
         if (!final_env) {
                 r = -ENOMEM;
-- 
2.2.1.209.g41e5f3a



More information about the systemd-devel mailing list