Project

General

Profile

Actions

Serving applications as TCP sockets

systemd has become the standard init system on most Linux machines.
One lesser known feature is ability to serve TCP sockets and launch arbitrary services on connection.
This was usually done using inetd/xinetd in the past.

More information about inetd-replacement of systemd can be found at:
http://0pointer.de/blog/projects/inetd.html

Hello World example

Create /etc/systemd/system/octoi-helloworld.socket with the following content:

[Unit]
Description=OCTOI HelloWorld Socket for Per-Connection Servers

[Socket]
ListenStream=31337
Accept=yes

[Install]
WantedBy=sockets.target

ListenStream= is the TCP port on which the service should run.
Accept=yes causes systemd to accept() incoming connections directly. This could also be done by the service later on.

Create /etc/systemd/system/octoi-helloworld@.service with the following content:

[Unit]
Description=OCTOI HelloWorld Socket Per-Connection Server

[Service]
ExecStart=-/opt/octoi-helloworld.sh
StandardInput=socket
StandardError=null
DynamicUser=true

ExecStart= is the program that will be executed. Notice the - at the beginning, which will get systemd to ignore any non-zero return codes.
StandardInput=socket will redirect any input from the socket to the program.
StandardError=null will redirect any error output to /dev/null.
DynamicUser=true is a very useful feature that will dynamically create a new system user and group , with a new PID/GID for each incoming connection. This is done internally without touching the /etc/passwd file.
If the application allows for this, it can be a powerful tool for security (by isolating the processes and minimizing permissions).
Warning: Applications with DynamicUser enabled run with their own private /tmp directories. Don't try to exchange files/sockets with other processes there.

systemd can also drop permissions in the usual way, by specifying a fixed user and group:

User=helloworld
Group=helloworld

Create /opt/octoi-helloworld.sh:

#!/bin/bash
echo "Hello World" 

# Sleep before closing the session to give PortMaster time to flush
# all data onto the connection.
sleep 5

Don't forget to set +x permissions on the shell script.

Reload systemds configuration, then enable and start the socket:

systemctl daemon-reload
systemctl enable --now octoi-helloworld.socket

systemd is now listening to the TCP port:

# netstat -tulpen
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode      PID/Program name    
tcp6       0      0 :::13063                :::*                    LISTEN      0          2674600    1/systemd           

You can check the status (and the number of past connections) with:

# systemctl status octoi-helloworld.socket
● octoi-helloworld.socket - OCTOI HelloWorld Socket for Per-Connection Servers
     Loaded: loaded (/etc/systemd/system/octoi-helloworld.socket; enabled; vendor preset: enabled)
     Active: active (listening) since Mon 2022-05-02 01:11:11 CEST; 29min ago
   Triggers: ● octoi-helloworld@8-123.123.123.85:31337-123.123.123.123:1091.service
     Listen: [::]:31337 (Stream)
   Accepted: 8; Connected: 1;
      Tasks: 0 (limit: 1131)
     Memory: 4.0K
        CPU: 4ms
     CGroup: /system.slice/octoi-helloworld.socket

Mai 02 01:11:11 communityisdn systemd[1]: Listening on OCTOI HelloWorld Socket for Per-Connection Servers.

For each open connection, you can see the "Triggers:" line, with the service which has been started for that connection.

Files (0)

Updated by manawyrm almost 2 years ago · 4 revisions

Add picture from clipboard (Maximum size: 48.8 MB)