Serving applications as TCP sockets » History » Version 2
manawyrm, 05/01/2022 11:44 PM
1 | 1 | manawyrm | h1. Serving applications as TCP sockets |
---|---|---|---|
2 | |||
3 | systemd has become the standard init system on most Linux machines. |
||
4 | One lesser known feature is ability to serve TCP sockets and launch arbitrary services on connection. |
||
5 | This was usually done using inetd/xinetd in the past. |
||
6 | |||
7 | More information about inetd-replacement of systemd can be found at: |
||
8 | http://0pointer.de/blog/projects/inetd.html |
||
9 | |||
10 | h2. Hello World example |
||
11 | |||
12 | 2 | manawyrm | Create <code>/etc/systemd/system/octoi-helloworld.socket</code> with the following content:<pre><code class="ini"> |
13 | 1 | manawyrm | [Unit] |
14 | Description=OCTOI HelloWorld Socket for Per-Connection Servers |
||
15 | |||
16 | [Socket] |
||
17 | ListenStream=31337 |
||
18 | Accept=yes |
||
19 | |||
20 | [Install] |
||
21 | WantedBy=sockets.target |
||
22 | </code></pre> |
||
23 | <code class="ini">ListenStream=</code> is the TCP port on which the service should run. |
||
24 | <code class="ini">Accept=yes</code> causes systemd to accept() incoming connections directly. This could also be done by the service later on. |
||
25 | 2 | manawyrm | |
26 | Create <code>/etc/systemd/system/octoi-helloworld@.service</code> with the following content:<pre><code class="ini"> |
||
27 | 1 | manawyrm | [Unit] |
28 | Description=OCTOI HelloWorld Socket Per-Connection Server |
||
29 | |||
30 | [Service] |
||
31 | ExecStart=-/opt/octoi-helloworld.sh |
||
32 | StandardInput=socket |
||
33 | StandardError=null |
||
34 | DynamicUser=true |
||
35 | </code></pre> |
||
36 | |||
37 | <code class="ini">ExecStart=</code> is the program that will be executed. Notice the - at the beginning, which will get systemd to ignore any non-zero return codes. |
||
38 | <code class="ini">StandardInput=socket</code> will redirect any input from the socket to the program. |
||
39 | <code class="ini">StandardError=null</code> will redirect any error output to /dev/null. |
||
40 | 2 | manawyrm | <code class="ini">DynamicUser=true</code> 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. |
41 | 1 | manawyrm | If the application allows for this, it can be a powerful tool for security (by isolating the processes and minimizing permissions). |
42 | 2 | manawyrm | +Warning: Applications with <code>DynamicUser</code> enabled run with their own private <code>/tmp</code> directories. Don't try to exchange files/sockets with other processes there.+ |
43 | 1 | manawyrm | |
44 | systemd can also drop permissions in the usual way, by specifying a fixed user and group: |
||
45 | <pre><code class="ini"> |
||
46 | User=helloworld |
||
47 | Group=helloworld |
||
48 | </code></pre> |
||
49 | 2 | manawyrm | |
50 | Create <code>/opt/octoi-helloworld.sh</code>: |
||
51 | <pre><code class="shell"> |
||
52 | #!/bin/bash |
||
53 | echo "Hello World" |
||
54 | |||
55 | # Sleep before closing the session to give PortMaster time to flush |
||
56 | # all data onto the connection. |
||
57 | sleep 5 |
||
58 | </code></pre> |
||
59 | |||
60 | Don't forget to set +x permissions on the shell script. |
||
61 | |||
62 | Reload systemds configuration, then enable and start the socket: |
||
63 | <pre><code class="shell"> |
||
64 | systemctl daemon-reload |
||
65 | systemctl enable --now octoi-phonebook.socket |
||
66 | </code></pre> |
||
67 | |||
68 | systemd is now listening to the TCP port: |
||
69 | <pre><code class="shell"> |
||
70 | # netstat -tulpen |
||
71 | Active Internet connections (only servers) |
||
72 | Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name |
||
73 | tcp6 0 0 :::13063 :::* LISTEN 0 2674600 1/systemd |
||
74 | </code></pre> |
||
75 | |||
76 | You can check the status (and the number of past connections) with: |
||
77 | <pre><code class="shell"> |
||
78 | # systemctl status octoi-phonebook.socket |
||
79 | ● octoi-helloworld.socket - OCTOI HelloWorld Socket for Per-Connection Servers |
||
80 | Loaded: loaded (/etc/systemd/system/octoi-helloworld.socket; enabled; vendor preset: enabled) |
||
81 | Active: active (listening) since Mon 2022-05-02 01:11:11 CEST; 29min ago |
||
82 | Triggers: ● octoi-phonebook@8-123.123.123.85:31337-123.123.123.123:1091.service |
||
83 | Listen: [::]:31337 (Stream) |
||
84 | Accepted: 8; Connected: 1; |
||
85 | Tasks: 0 (limit: 1131) |
||
86 | Memory: 4.0K |
||
87 | CPU: 4ms |
||
88 | CGroup: /system.slice/octoi-helloworld.socket |
||
89 | |||
90 | Mai 02 01:11:11 communityisdn systemd[1]: Listening on OCTOI HelloWorld Socket for Per-Connection Servers. |
||
91 | </code></pre> |
||
92 | |||
93 | For each open connection, you can see the "Triggers:" line, with the service which has been started for that connection. |