0

I have a simple systemd service that is activated by system socket.

It's as simple as that (a little simplified):

$ systemctl cat example.socket 
# /usr/lib/systemd/system/example.socket
[Unit]
Description=Example Server socket

[Socket]
ListenStream=80
Accept=true

[Install]
WantedBy=sockets.target
$ systemctl cat [email protected] 
# /usr/lib/systemd/system/[email protected]
[Unit]
Description=Example Server

[Service]
StandardInput=socket
StandardOutput=socket
StandardError=journal
ExecStart=/usr/libexec/example
User=example

Now what I want is to implement a basic access restriction by time. I.e. I want to limit the time a day the socket/service can be activated/reached from the outside, so it's only available at certain times a day, e.g.

I know I can use systemctl edit to override the options, but I did not found an option to set, actually. I looked through the man page regarding system sockets and the only options regarding times are TriggerLimitIntervalSec or so, which do not do what I want.

To compare this, the little oldish tool xinetdx, which can do the same i.e. listen on a socket and start a process (server) on demand has an option called access_times, which can be used to specify when a service should be available. But using this as another tool (/dependency) is not a thing I'd like. I'd aim for an integrated way into systemd.

rugk
  • 2,806
  • 6
  • 28
  • 58
  • 1
    As a completely alternate solution you could use a firewall rule. There does exist a match that compares the time of day with some values both in iptables and nftables. – A.B May 14 '21 at 20:48
  • have you considered using a cron job to stop and start the service at the required times? – cas May 15 '21 at 07:43
  • @cas It's a socket. and I want to use socket activation. Maybe I could though enable/disable the socket at the required times, but I'm not sure whether that is the most elegant solution – considering e.g. what happens if the device is down at the time and only start later or so. But if you want to submit this as an answer, feel free to do so. – rugk May 15 '21 at 11:01
  • @A.B Yeah good idea, but I use `firewall-cmd` (Fedora system), and as far as I see it does not support that and so resorting to some lower-level tool for that is well… maybe not so nice, yet again. – rugk May 15 '21 at 11:02
  • firewalld doesn't have to support it: *nftables* can use separate tables (eg: firewalld chooses its own `firewalld` table) and when a packet is dropped it won't come back. Anyway that was a suggestion, I'm not trying to convince. – A.B May 15 '21 at 11:46
  • Yeah thanks, it's a good suggestion, but actually I'm still looking for something better. – rugk May 15 '21 at 12:16
  • Given there does not seem to be a built-in way in systemd, I [raised a feature request](https://github.com/systemd/systemd/issues/19620). – rugk May 15 '21 at 12:24
  • @rugk yes, it's a socket. systemd can still start and stop listening on that port with `systemctl start example.socket` and `systemctl stop example.socket`. – cas May 15 '21 at 12:54

1 Answers1

1

You can use some systemd timers to start/stop the socket at the required times.

To wakeup mysocket.socket every morning at 06:00 and put it to bed at 23:00 every night try this:

# mysocket.timer
[Unit]
Description=Socket Wakeup

[Timer]
OnCalendar=6:00
Unit=mysocket.socket

[Install]
WantedBy=timers.target
# mysocket-bedtime.timer
[Unit]
Description=Socket Bedtime

[Timer]
OnCalendar=23:00
Unit=mysocket-bedtime.service

[Install]
WantedBy=timers.target
# mysocket-bedtime.service
[Unit]
Description=MySocket bedtime enforcer
Conflicts=mysocket.socket

[Service]
Type=oneshot
ExecStart=/bin/true

mysocket.timer is pretty straight forward. It start Unit=mysocket.socket at 06:00 every morning. Stopping your socket is a little more difficult. It requires a Conflicts= relationship. We create mysocket-bedtime.timer to wake up that conflicting unit at 23:00 every night. mysocket-bedtime.service is that conflicting unit. For it to start, it will shut down anything it Conflicts= with (your socket). Then when your socket has stopped, it simply executes true and then stops itself.

Stewart
  • 12,628
  • 1
  • 37
  • 80
  • Okay, nice one. But (how) is this better than just having two timers running `systemctl start/stop example.socket` or so manually? – rugk May 19 '21 at 19:51
  • 1
    Well, if you were to do that, you'd need `mysocket-wakeup.timer` with `mysocket-wakeup.service` and `mysocket-sleep.timer` with `mysocket-sleep.service`. This solution uses one fewer units. Also, you are using native systemd unit relationships instead of `systemctl`. The native systemd relationships are designed for these situations and probably cover some edge cases better than using `systemctl` (which is not really designed to be invoked from a service). Finally, this is what the devs recommended when they closed your feature request. – Stewart May 19 '21 at 20:22