Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] [Enhancement] Systemd service file #1018

Open
TriMoon opened this issue Aug 15, 2023 · 5 comments
Open

[Feature Request] [Enhancement] Systemd service file #1018

TriMoon opened this issue Aug 15, 2023 · 5 comments
Labels
feature a whole new feature

Comments

@TriMoon
Copy link

TriMoon commented Aug 15, 2023

Summary:

The systemd service unit can be enhanced to start BEFORE any network is configured, and thus allow interception and protection at an earlier stage...

Service file:

Below is my crafted service file:

# /etc/systemd/system/opensnitchd.service
[Unit]
Description=Application firewall OpenSnitch
Documentation=https://github.com/gustavo-iniguez-goya/opensnitch/wiki
Documentation=man:systemd.special
Documentation=man:systemd.service
Documentation=man:systemd.exec
Documentation=man:systemd.unit

DefaultDependencies=no
Before=network-pre.target shutdown.target
Wants=network-pre.target
Conflicts=shutdown.target
# Don't start when 'no-appfw` is in kernel command-line, to allow booting without it.
ConditionKernelCommandLine=!no-appfw

[Service]
Type=exec
ConfigurationDirectory=%N/rules
ConfigurationDirectoryMode=0700

Environment='custom_cfg=%E/%N/rules'
# Environment='opts=-debug'

ExecCondition=%N -check-requirements
ExecStart=%N -rules-path $custom_cfg $opts

# Signal-info was taken from the init.d script, but it just exits and then systemd restarts the service...
ExecReload=kill -HUP $MAINPID
Restart=always
RestartSec=30
TimeoutStopSec=10
# Ensure it is not killed by the Linux kernel's Out-Of-Memory (OOM) killer.
# https://www.freedesktop.org/software/systemd/man/systemd.exec.html#OOMScoreAdjust=
OOMScoreAdjust=-1000

[Install]
WantedBy=basic.target

Notable changes/additions:

  1. Unit filename:
    ⚠️ The service filename was changed to opensnitchd.service !!!
    This was needed for automatically using the unit name in the service definition using the %N specifier...
    See: Specifiers@man systemd.unit#Specifiers

    • The previous filename was lacking the d in it's name !
    • Thus if you want to use this service file while at same time having the currently distributed unit file in your system you need to "mask" the old one to prevent it from being used and started:
      sudo systemctl mask --now opensnitch.service
  2. Unit ordering:
    Made sure the daemon starts before any network related devices or services are created/started by using network-pre.target, See:

  3. Startup target / run-level:
    Changed the default install target to basic.target instead of multi-user.target.
    This will allow it to run in any "run-level" in SysV terms.
    See: Units managed by the system service manager@man systemd.special#basic.target

  4. Automatically disable using a kernel-command-line option:
    Just in case it is needed, i added the ability to disable the daemon using a kernel-command-line option using the ConditionKernelCommandLine directive.
    When the no-appfw option is present in the kernel-command-line, the daemon will not startup.
    This option functions same as the well-known quite option. (only applies when present as a separate word)

  5. Automatically create rules directory:
    Let systemd automatically create the "rules" directory with proper mode, when non-existent yet, upon starting the daemon service by using the ConfigurationDirectory and ConfigurationDirectoryMode directives.

  6. Automatically check for kernel support before starting:
    Automatically prevent startup when required kernel support is not present by using the -check-requirements flag in a ExecCondition directive.
    (This assumes the command returns a non-zero exit status when not satisfied.)

  7. Reload functionality:
    Added support for reloading the daemon using the ExecReload directive.
    Signal-info was taken from the init.d script, but it just exits and then systemd restarts the service...
    So this functionality either needs to be implemented in the daemon's code or a different signal needs to be sent to it.
    But at least the functionality is now present in the unit file.

  8. Prevent from being killed by the OOM-Killer:
    Prevented the daemon to be killed by the Linux kernel's Out-Of-Memory (OOM) killer, using the OOMScoreAdjust=-1000 directive.
    See: OOMScoreAdjust@man systemd.exec#OOMScoreAdjust
    (This will ensure that the protection keeps functioning even when other processes cause an OOM)

  9. Admin overrides using drop-ins:
    Added support for easily adjusting the directory used for rules and extra options by the local admin.
    The local admin can create "drop-in" config(s) under /etc/systemd/system/opensnitchd.service.d/ even when the service file is installed in other places by the package maintainer, See: 16.14. Extending the default unit configuration@redhat.com
    Example drop-in(s) contents that can-be-used:

    • To change the rules directory to be used:

      [Service]
      Environment='custom_cfg=%E/%N/rules-special'
      • The contents of $custom_cfg is supplied as an argument to the -rules-path option of the daemon.
      • See: Specifiers@man systemd.unit#Specifiers
        %E expands to /etc
        %N expands to the unit name opensnitchd
      • Thus the total expansion of the above will become: /etc/opensnitchd/rules-special
    • To enable debug output:

      [Service]
      Environment='opts=-debug'
      • The contents of $opts is supplied as extra argument(s) to the daemon.
    • Combination of both:

      [Service]
      Environment='custom_cfg=%E/%N/rules-special'
      Environment='opts=-debug'

One last thing to improve systemd usage:
Please add a way to prevent timestamps being output at all, when using /dev/stdout as log destination.
Or at least add a syslog option to use as logger, which also doesn't need timestamps because it adds them self.
Look how ugly it is at moment:

$ systemctl status opensnitchd

● opensnitchd.service - Application firewall OpenSnitch
     Loaded: loaded (/etc/systemd/system/opensnitchd.service; enabled; preset: enabled)
     Active: active (running) since Tue 2023-08-15 16:09:57 +03; 1h 47min ago
       Docs: https://github.com/gustavo-iniguez-goya/opensnitch/wiki
             man:systemd.special
             man:systemd.service
             man:systemd.exec
             man:systemd.unit
    Process: 593 ExecCondition=opensnitchd -check-requirements (code=exited, status=0/SUCCESS)
   Main PID: 632 (opensnitchd)
      Tasks: 26 (limit: 38131)
     Memory: 81.4M
        CPU: 1min 42.501s
     CGroup: /system.slice/opensnitchd.service
             └─632 opensnitchd -rules-path /etc/opensnitchd/rules

Aug 15 16:09:57 kubuntu opensnitchd[632]: [2023-08-15 13:09:57]  IMP  Starting opensnitch-daemon v1.6.1
Aug 15 16:09:57 kubuntu opensnitchd[632]: [2023-08-15 13:09:57]  INF  Loading rules from /etc/opensnitchd/rules ...
Aug 15 16:09:57 kubuntu opensnitchd[632]: [2023-08-15 13:09:57]  INF  loading domains lists: lists, lists.domains_regexp, /mnt/LutrisGames/OpenSnitch-Firewall-Lists/WoT-Blitz-allow
Aug 15 16:09:57 kubuntu opensnitchd[632]: [2023-08-15 13:09:57]  INF  monitor lists started: /mnt/LutrisGames/OpenSnitch-Firewall-Lists/WoT-Blitz-allow
Aug 15 16:09:57 kubuntu opensnitchd[632]: [2023-08-15 13:09:57]  INF  loading domains lists: lists, lists.domains_regexp, /mnt/LutrisGames/OpenSnitch-Firewall-Lists/WoT-Blitz-reject
Aug 15 16:09:57 kubuntu opensnitchd[632]: [2023-08-15 13:09:57]  INF  monitor lists started: /mnt/LutrisGames/OpenSnitch-Firewall-Lists/WoT-Blitz-reject
Aug 15 16:09:57 kubuntu opensnitchd[632]: [2023-08-15 16:09:57]  INF  [eBPF] module loaded: /usr/lib/opensnitchd/ebpf/opensnitch.o
Aug 15 16:09:57 kubuntu opensnitchd[632]: [2023-08-15 16:09:57]  INF  [eBPF] module loaded: /usr/lib/opensnitchd/ebpf/opensnitch-procs.o
Aug 15 16:09:57 kubuntu opensnitchd[632]: [2023-08-15 16:09:57]  INF  Process monitor method ebpf
Aug 15 16:09:57 kubuntu opensnitchd[632]: [2023-08-15 16:09:57]  INF  Stats, max events: 25, max stats: 150, max workers: 6
Aug 15 16:09:57 kubuntu opensnitchd[632]: [2023-08-15 16:09:57]  INF  nftables config changed, reloading
Aug 15 16:09:57 kubuntu opensnitchd[632]: [2023-08-15 16:09:57]  INF  fw configuration loaded
Aug 15 16:09:58 kubuntu opensnitchd[632]: [2023-08-15 16:09:58]  INF  Using nftables firewall
Aug 15 16:09:58 kubuntu opensnitchd[632]: [2023-08-15 16:09:58]  INF  Running on netfilter queue #0 ...
Aug 15 16:09:58 kubuntu opensnitchd[632]: [2023-08-15 16:09:58]  INF  [eBPF] module loaded: /usr/lib/opensnitchd/ebpf/opensnitch-dns.o
Aug 15 16:09:58 kubuntu opensnitchd[632]: found /lib/x86_64-linux-gnu/libc.so.6
Aug 15 16:10:03 kubuntu opensnitchd[632]: [2023-08-15 16:10:03]  INF  clearing domains lists: 0 - /mnt/LutrisGames/OpenSnitch-Firewall-Lists/WoT-Blitz-reject
Aug 15 16:10:03 kubuntu opensnitchd[632]: [2023-08-15 16:10:03]  INF  clearing domains lists: 0 - /mnt/LutrisGames/OpenSnitch-Firewall-Lists/WoT-Blitz-allow
Aug 15 16:10:03 kubuntu opensnitchd[632]: [2023-08-15 16:10:03]  INF  6 regexps loaded, /mnt/LutrisGames/OpenSnitch-Firewall-Lists/WoT-Blitz-reject/re.txt
Aug 15 16:10:03 kubuntu opensnitchd[632]: [2023-08-15 16:10:03]  INF  1 lists loaded, 6 domains, 0 duplicated
Aug 15 16:10:03 kubuntu opensnitchd[632]: [2023-08-15 16:10:03]  INF  19 regexps loaded, /mnt/LutrisGames/OpenSnitch-Firewall-Lists/WoT-Blitz-allow/re.txt
Aug 15 16:10:03 kubuntu opensnitchd[632]: [2023-08-15 16:10:03]  INF  1 lists loaded, 19 domains, 0 duplicated
Aug 15 16:10:35 kubuntu opensnitchd[632]: [2023-08-15 16:10:35]  INF  Connected to the UI service on ///tmp/osui.sock
Aug 15 16:10:35 kubuntu opensnitchd[632]: [2023-08-15 16:10:35]  IMP  UI connected, dispathing queued alerts: 0
Aug 15 16:10:35 kubuntu opensnitchd[632]: [2023-08-15 16:10:35]  INF  Start receiving notifications
@TriMoon TriMoon added the feature a whole new feature label Aug 15, 2023
TriMoon added a commit to TriMoon/opensnitch that referenced this issue Aug 15, 2023
@TriMoon
Copy link
Author

TriMoon commented Aug 15, 2023

⚠️
The service files as distributed in the deb package still has WRONG name !!!
Someone needs to fix the packaging script !

@lainedfles
Copy link
Contributor

@TriMoon Thanks for your attention to detail. I've not yet had a chance to test this personally but these are good ideas.

@TriMoon
Copy link
Author

TriMoon commented Sep 3, 2023

You can try the PR, linked above, locally and see if you like it 😉
(I'm running with that version)

@lainedfles
Copy link
Contributor

The version under your merge request did work without modification but here is my critique:

ExecStart=%N without absolute path is bad practice from a security perspective although technically it should be safe under most modern distributions which have "merged" /bin via symbolic links and properly compiled systemd. It does also affect the process list as viewed by ps. My vote will always be to use absolute path if presented with a choice 👍

The present state of Makefile relies upon the OS/user umask for directory permissions during creation or packaging of /etc/opensnitch/rules, for this reason, hard coding ConfigurationDirectoryMode=0700 may not be a good idea as it can produce a mismatch warning. Omission of this statement may be a better option unless creation is also dependent on systemd which likely isn't the reality for most distributions.

WantedBy=basic.target may become problematic for initrd boot because basic.target is reached before any filesystems are mounted. However, I think that the directives under [Unit] should catch this case under most circumstances so it may be a non-issue but worth mention.

There is a benign warning if $opts is unset. I'd recommend setting an empty variable as a better practice. Like: Environment='opts='

The introduction of the custom_config variable may be unnecessary unless use of EnvironmentFile= is planned. The structure of systemd makes it trivial to override ConfigurationDirectory= which, since v240, will expose the $CONFIGURATION_DIRECTORY environment variable automatically that we can re-use.

I'm presently using a modified version incorporating these items. This version produces no systemd warnings under my up-to-date Archlinux system(s):

--- /etc/systemd/system/opensnitchd.service_TriMoon     2023-09-03 19:54:32.833663095 -0600
+++ /etc/systemd/system/opensnitchd.service     2023-09-03 20:18:11.745180152 -0600
@@ -16,13 +16,13 @@
 [Service]
 Type=exec
 ConfigurationDirectory=%N/rules
-ConfigurationDirectoryMode=0700
 
-Environment='custom_cfg=%E/%N/rules'
+# Example to enable daemon debug logging:
 # Environment='opts=-debug'
+Environment='opts='
 
-ExecCondition=%N -check-requirements
-ExecStart=%N -rules-path $custom_cfg $opts
+ExecCondition=/usr/bin/%N -check-requirements
+ExecStart=/usr/bin/%N -rules-path $CONFIGURATION_DIRECTORY $opts
 
 # Signal-info was taken from the init.d script, but it just exits and then systemd restarts the service...
 ExecReload=kill -HUP $MAINPID

Typically the trends set by this project aim for general compatibility and my basic investigation and minimal testing suggest that it will be generally compatible. Nice work, thanks!

One additional note, many of these concepts may be applicable to the UI component. Someday I'd like to try implementing UI control via systemd unless someone beats me to it!

@TriMoon
Copy link
Author

TriMoon commented Sep 4, 2023

@lainedfles please see #1019 and use that in future to suggest changes 😉
I cross-posted and replied there 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature a whole new feature
Projects
None yet
Development

No branches or pull requests

2 participants