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.
Updated by manawyrm over 1 year ago · 4 revisions