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:
Hello World example¶
/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=yescauses systemd to accept() incoming connections directly. This could also be done by the service later on.
/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=socketwill redirect any input from the socket to the program.
StandardError=nullwill redirect any error output to /dev/null.
DynamicUser=trueis 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).
systemd can also drop permissions in the usual way, by specifying a fixed user and group:
#!/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: ● firstname.lastname@example.org:31337-220.127.116.11: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: 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.