YeenDeer softness blog (programming and electronics)

Ellie the Yeen is a soft YeenDeer that mweeoops and does programming

View on GitHub About Bots Projects Tags

Systemd sockets

You might have heard about inetd which is often called a super-server according to Wikipedia. But did you know the systemd can do the same thing using something called systemd sockets. I will show you how to use them.

At first we are going to start with how to actually set them up and how they work.

The first thing to do is to create the socket unit which looks like this

testsocket.socket

[Unit]
Description=Test socket

[Socket]
ListenStream=1024
Accept=yes

[Install]
WantedBy=default.target

To create a unit you can use the command

systemctl --user edit --full --force testsocket.socket # For user unit
sudo systemctl edit --full --force testsocket.socket # For system unit

Which will open up an editor like nano but if you have not selected an editor I recommend using nano which you can set using

select-editor

Except this unit you also need to define a second unit that is a service

testsocket@.service

[Unit]
Description=Test socket service

[Service]
ExecStart=/home/yeen/blep.sh

And do note that there is an @ in the name just like in the Failure handler guide from a while ago.

Not to take a look what the started script actually does using lsof -p $$ inside the script. As you can probably see a socket is open in file descriptor 3 and I have no idea what the pipe in 4 is but that does not matter much.

COMMAND  PID USER   FD   TYPE             DEVICE SIZE/OFF     NODE NAME
blep.sh 9877 yeen  cwd    DIR                8,2     4096 50298626 /home/yeen
blep.sh 9877 yeen  rtd    DIR                8,2     4096        2 /
blep.sh 9877 yeen  txt    REG                8,2   125688   262951 /usr/bin/dash
blep.sh 9877 yeen  mem    REG                8,2  2220400   263025 /usr/lib/x86_64-linux-gnu/libc.so.6
blep.sh 9877 yeen  mem    REG                8,2   240936   263020 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
blep.sh 9877 yeen    0r   CHR                1,3      0t0        5 /dev/null
blep.sh 9877 yeen    1u  unix 0x0000000000000000      0t0   120353 type=STREAM
blep.sh 9877 yeen    2u  unix 0x0000000000000000      0t0   120353 type=STREAM
blep.sh 9877 yeen    3u  IPv6             121878      0t0      TCP localhost:1024->localhost:42958 (ESTABLISHED)
blep.sh 9877 yeen    4r  FIFO               0,13      0t0   117586 pipe
blep.sh 9877 yeen   10r   REG                8,2       81 50333753 /home/yeen/blep.sh

The script itself used to test it is here

``blep.sh`

#!/bin/sh
a="$(lsof -p $$)"
echo "$a" > ~/sdfdfg.txt
echo "$a" >&3
env > env.txt

What the >&3 does is tell it to write to file descriptor 3 so the lsof output from above is emitted from netcat connecting to the systemd socket.

The reason for env to be there is that some variables set there might be very useful and we can take a look at them here filtered from what usually exists in the env vars of systemd units being run.

12,13c12,13
< INVOCATION_ID=2106c6f489634605b77ec4c53b18e6ad
< JOURNAL_STREAM=8:139232
---
> INVOCATION_ID=10f97a5493074bf8b914b8bbbcd421c2
> JOURNAL_STREAM=8:120353
23a24,26
> LISTEN_FDNAMES=connection
> LISTEN_FDS=1
> LISTEN_PID=9877
29a33,34
> REMOTE_ADDR=127.0.0.1
> REMOTE_PORT=42958
32c37
< SHLVL=1
---
> SHLVL=0
34c39
< SYSTEMD_EXEC_PID=11197
---
> SYSTEMD_EXEC_PID=9877
36c41
< _=/usr/bin/env
---
> _=/usr/bin/dbus-update-activation-environment

As you see there are some things to take note of like REMOTE_ADDR=127.0.0.1 and REMOTE_PORT=42958 which were from a run where I just ran nc localhost 1024 which is netcat.

If you wonder how to get this diff do something like

systemd-run --user bash -c 'env > enva.txt'
diff <(sort enva.txt) <(sort env.txt)

And you will get a good diff.

Now we can test with python too by making a script in it that receives the invocation.

blep.py

#!/usr/bin/python3
import socket
s = socket.fromfd(3, socket.AF_INET, socket.SOCK_STREAM, proto=0)
s.send(b"Blep I am cat meow\n")
s.close()

And as you can guess it will send Blep I am cat meow to anyone who connects to the socket.

One last note is that you might have to use a command like

systemctl --user status testsocket@\*

and scroll a bit up and down to find the status as it creates a temporary service for every invocation that you can find in the logs.

Anyway now you know the basics of systemd sockets so you can have fun with them.

Added later

2024-10-11 23:30

So apparently you can set stdin and stdout to be used to write to the socket. Here is an example. Start by changing your testsocket@.service

[Unit]
Description=Test socket

[Service]
ExecStart=/home/yeen/blep.sh
StandardInput=socket
StandardOutput=socket
StandardError=journal

It is possible to set all 3 to socket but you should generally set the error one specifically to journal since otherwise it will write stderr to the socket too instead of into the journal.

Now we can update the blep.sh

#!/bin/sh
lsof -p $$
echo log something here >&2

And now you can log things while also using stdout to write to the socket.

It is also very useful to start another terminal and use the following command to follow everything that happens in the log.

journalctl --user -f

*Mweeoops*

By ellietheyeen 11 October 2024 Permalink Tags: python shell sockets systemd


Instance: