2026-10-06 18:22:11 +02:00
2026-10-06 18:22:11 +02:00
2026-10-06 18:22:11 +02:00
2026-10-06 18:22:11 +02:00
2026-10-06 18:22:11 +02:00
2026-10-06 18:22:11 +02:00
2026-10-06 18:22:11 +02:00
2026-10-06 18:22:11 +02:00
2026-10-06 18:22:11 +02:00
2026-10-06 18:22:11 +02:00
2026-10-06 18:22:11 +02:00
2026-10-06 18:22:11 +02:00
2026-10-06 18:22:11 +02:00
2026-10-06 18:22:11 +02:00

opensnitch-cli (C) — OpenSnitch komplett in der Konsole

opensnitch-cli ersetzt die Qt-GUI von OpenSnitch durch ein einzelnes C-Programm: einen headless gRPC-UI-Dienst (den der unveränderte opensnitchd genau wie die GUI anspricht), eine Befehlszeile für alles, was die GUI kann, und ein Vollbild-Text-UI (ncurses) mit Tabs für Events, Regeln, Firewall, Nodes, Alerts, Logs und Einstellungen — inklusive Dialog für Verbindungsanfragen.

Der Daemon (opensnitchd, Go) bleibt unverändert; er ist im OpenSnitch-Design der gRPC-Client, die GUI (bzw. hier opensnitch-cli serve) ist der Server.

┌──────────────┐   gRPC (unix socket / TCP / TLS)   ┌───────────────────────────┐
│  opensnitchd │ ─────────────────────────────────▶ │  opensnitch-cli serve     │
│  (Go, root)  │ ◀───────────────────────────────── │  DB (sqlite), Regeln, ... │
└──────────────┘                                    └─────────────┬─────────────┘
                                                    control socket │ (JSON lines)
                        ┌───────────────────────────────────────────┼──────────────┐
                        ▼                        ▼                  ▼              ▼
                 opensnitch-cli tui      opensnitch-cli prompt   opensnitch-cli rules/fw/events/...

Bauen

Abhängigkeiten (Debian/Ubuntu):

sudo apt install gcc make pkg-config libnghttp2-dev libprotobuf-c-dev protobuf-c-compiler \
                 libsqlite3-dev libssl-dev libncurses-dev
make
sudo make install          # /usr/local/bin/opensnitch-cli  (PREFIX=... änderbar)

Fedora: libnghttp2-devel protobuf-c-devel protobuf-c-compiler sqlite-devel openssl-devel ncurses-devel pkgconf-pkg-config. Arch: libnghttp2 protobuf-c sqlite openssl ncurses.

Die Proto-Datei (proto/ui.proto, unverändert aus OpenSnitch) ist bereits mit protoc-c übersetzt (make proto regeneriert sie); cJSON (MIT) ist unter third_party/ mitgeliefert.

make install installiert Binary, Manpage (man opensnitch-cli), Bash-Vervollständigung und die systemd-Benutzer-Unit (PREFIX, DESTDIR werden beachtet).

RPM (Fedora, RHEL, Rocky, Alma)

sudo dnf install rpm-build rpmdevtools gcc make pkgconf-pkg-config libnghttp2-devel protobuf-c-devel \
                 sqlite-devel openssl-devel ncurses-devel systemd-rpm-macros     # EL9: vorher CRB freischalten
rpmdev-setuptree && make dist && cp opensnitch-cli-1.9.1.tar.gz ~/rpmbuild/SOURCES/ && cp packaging/opensnitch-cli.spec ~/rpmbuild/SPECS/
rpmbuild -ba ~/rpmbuild/SPECS/opensnitch-cli.spec
sudo dnf install ~/rpmbuild/RPMS/x86_64/opensnitch-cli-1.9.1-1.*.rpm
systemctl --user enable --now opensnitch-cli

rpmbuild -bs erzeugt daraus auch ein Source-RPM (opensnitch-cli-1.9.1-1.*.src.rpm), das sich mit rpmbuild --rebuild oder mock überall bauen lässt. Details (CRB/EPEL, System-Unit, Laufzeitabhängigkeiten) in packaging/README.md.

Schnellstart

opensnitch-cli tui        # Text-UI; startet `serve` automatisch im Hintergrund, falls noch keiner läuft

Das entspricht dem Start von opensnitch-ui. Alternativ getrennt:

opensnitch-cli serve               # Dienst im Vordergrund; auf einem Terminal fragt er Verbindungen direkt hier ab
opensnitch-cli serve --background  # headless (Log: ~/.config/opensnitch-cli/serve.log), oder als systemd-Unit (siehe unten)
opensnitch-cli prompt              # nur die Pop-ups beantworten (startet serve ebenfalls bei Bedarf; --no-autostart)
opensnitch-cli stop                # Dienst beenden

Ein im Hintergrund gestarteter Dienst läuft nach dem Beenden des TUI weiter. Verbindungsanfragen sieht dann, wer ein tui oder prompt offen hat – und auf dem Desktop zusätzlich eine Benachrichtigung mit den Buttons Allow/Deny/Reject (settings set notifications.type desktop; braucht notify-send aus libnotify ≥ 0.7.10 und einen Notification-Dienst, der Aktionen kann: GNOME, KDE, dunst, mako …). Ein Klick beantwortet die Anfrage mit Standardziel und -dauer; ohne Antwort greift nach prompts.timeout Sekunden die Standardaktion (deny). prompts.timeout 0 heißt „warten, solange der Daemon lässt“ (≈110 s; der Daemon selbst gibt nach 120 s auf). Beachten: Anfragen werden wie in der GUI eine nach der anderen gezeigt. Bei einem Schwall unbeantworteter Anfragen wartet die letzte bis zu (N−1) × Timeout, bis sie überhaupt erscheint – mit 0 also bis zu 110 s je Anfrage davor (der Daemon hat höchstens 6 gleichzeitig offen). Wer „langsame Pop-ups“ sieht, sollte deshalb beim Standard von 30 s bleiben; Anfragen, die der Daemon inzwischen aufgegeben hat, werden sofort übersprungen. Zieht der Daemon eine Anfrage zurück (Timeout auf seiner Seite, Neustart), verschwindet sie auch aus TUI/Prompt. Ohne laufendes serve gilt das DefaultAction des Daemons (siehe Sicherheit).

Der Daemon muss auf denselben Socket zeigen wie serve (Standard unix:///tmp/osui.sock, siehe Server.Address in /etc/opensnitchd/default-config.json). Für TCP/TLS:

opensnitch-cli settings set server.address '[::]:50051'
opensnitch-cli settings set server.auth.type tls-simple      # oder tls-mutual
opensnitch-cli settings set server.auth.cert /etc/opensnitch-cli/server.crt
opensnitch-cli settings set server.auth.certkey /etc/opensnitch-cli/server.key

Welcher Socket ist wo? (Fehlersuche)

Es gibt zwei Sockets:

  1. gRPC-Socket Daemon ↔ serve – der Daemon verbindet sich zum serve. Der Pfad steht beim Daemon in /etc/opensnitchd/default-config.json unter Server.Address (Standard unix:///tmp/osui.sock) und bei serve in settings show server.address. Beide müssen übereinstimmen. Prüfen:
    opensnitch-cli settings show server.address      # was serve öffnet
    sudo grep -A2 '"Server"' /etc/opensnitchd/default-config.json   # was der Daemon sucht
    ss -xlp | grep osui.sock                         # lauscht serve? (bzw. ss -tlnp für TCP)
    sudo journalctl -u opensnitch -n 20              # der Daemon meldet "connected to UI"/"UI not connected"
    
    Die Socket-Datei wird mit Rechten 0660 angelegt; läuft opensnitchd als root und serve als normaler Benutzer, passt das (root darf alles). Umgekehrt (serve als root, Daemon ohne root) muss der Daemon-Benutzer in die Gruppe des Socket-Besitzers.
  2. Control-Socket CLI/TUI ↔ serve – $XDG_RUNTIME_DIR/opensnitch-cli-<uid>.sock (z. B. /run/user/1000/opensnitch-cli-1000.sock); anzeigen mit opensnitch-cli status bzw. beim Start von serve ([serve] control socket: …). Abweichender Pfad: --control-socket PATH bei serve und den Clients oder settings set server.control_socket PATH. Die Fehlermeldung „serve is not running (socket …)“ nennt den Pfad, unter dem der Client gesucht hat.

Keine Pop-ups? → opensnitch-cli doctor

doctor prüft alles, was zwischen einer Verbindung und dem Pop-up liegen kann, und sagt, was zu tun ist: läuft opensnitchd überhaupt, stimmt sein Server.Address mit server.address überein, existiert der Socket mit den richtigen Rechten, ist der Daemon mit serve verbunden, ist das Abfangen an, gibt es eine Catch-all-Regel (die alles erlaubt und deshalb nie fragt), steht DefaultAction auf deny, sind Pop-ups aktiv und hört jemand zu (tui/prompt/serve im Terminal). Als root zeigt es zusätzlich die relevanten Zeilen des Daemon-Logs. serve selbst meldet im Terminal, wenn ein Daemon verbindet oder wegbricht, und warnt nach 5 s, wenn keiner kommt.

Bekannter, behobener Fehler (Build vor dem 5.9.2026): der Daemon verband sich, aber jeder RPC wurde mit PROTOCOL_ERROR abgewiesen, weil grpc-go den Socket-Pfad als HTTP/2-:authority schickt und nghttp2 das nach HTTP/1-Regeln verwarf; im Daemon-Log stand dann Subscribing to GUI ... RST_STREAM ... PROTOCOL_ERROR. Wer das sieht, hat einen alten Build (opensnitch-cli --version).

Die häufigsten Ursachen: der Daemon ist nicht gestartet (systemctl status opensnitchd); die Socket-Adressen passen nicht; die GUI war früher in Benutzung und hat eine Regel wie „allow always *“ hinterlassen; das Abfangen wurde abgeschaltet; die Verbindung kam von einem Prozess, für den schon eine Regel gilt.

Sicherheit: Socket-Rechte und Verhalten ohne verbundenes UI

Socket-Rechte (opensnitch-cli status zeigt beide Sockets mit Modus und Besitzer):

Socket Standardpfad Rechte Wer darf verbinden
gRPC (Daemon → serve) /tmp/osui.sock 0660, Besitzer = serve-Benutzer der Daemon (root darf immer) und Prozesse des serve-Benutzers/-Gruppe. Bestehende fremde Socket-Datei wird nicht übernommen (serve bricht ab), eine lebende serve-Instanz wird nicht verdrängt.
Control (CLI/TUI → serve) $XDG_RUNTIME_DIR/opensnitch-cli-<uid>.sock 0600 in einem 0700-Verzeichnis nur derselbe Benutzer. Läuft serve als root (System-Unit), bedient nur root Regeln/Firewall/Konfiguration.
TCP-Listener z. B. [::]:50051 keine Dateirechte alle, die den Port erreichen – dort server.auth.type tls-mutual mit Client-Zertifikaten verwenden (der Daemon unterstützt das in Server.Authentication).

Wer sich mit dem gRPC-Socket verbinden kann, kann sich als Daemon ausgeben (Ereignisse/Alerts einspeisen, Regeln empfangen); wer den Control-Socket erreicht, verwaltet die Regeln. Beides ist mit den Standardpfaden auf den Besitzer beschränkt. Es wird keine Authentifizierung über den Unix-Socket hinaus gemacht – genau wie bei der GUI.

Ohne verbundenes UI arbeitet der Daemon nach seiner eigenen Konfiguration – und die ist ab Werk fail-open. Vorhandene Regeln (dauerhafte aus /etc/opensnitchd/rules und temporäre im Speicher des Daemons) werden weiter angewendet; für Verbindungen ohne passende Regel gilt DefaultAction aus /etc/opensnitchd/default-config.json, und das ist in der mitgelieferten Konfiguration allow. Das gilt vor dem Start von serve, nach opensnitch-cli stop, bei einem Absturz und bei Socket-Problemen (falscher Pfad, Rechte). Ist serve verbunden, überschreibt es – wie die GUI – die Standardaktion nur im Speicher des Daemons (prompts.default_action, Standard deny); nach der Trennung gilt wieder die Datei. Außerdem bekommen bei InterceptUnknown: false Verbindungen ohne identifizierbaren Prozess die DefaultAction ohne Nachfrage.

Deshalb erzwingt serve fail-closed (nodes.fail_closed, Standard an): wenige Sekunden nach dem Verbinden eines Daemons, dessen DefaultAction noch allow ist, schickt serve ihm seine Konfiguration mit DefaultAction: deny (nodes.fail_closed_action: deny oder reject). Der Daemon schreibt das in /etc/opensnitchd/default-config.json – die Einstellung gilt damit dauerhaft, auch wenn serve nicht läuft, und Verbindungen ohne passende Regel werden geblockt. Mit nodes.intercept_unknown true wird zusätzlich InterceptUnknown eingeschaltet (Verbindungen ohne identifizierbaren Prozess werden abgefragt statt nach Standardaktion behandelt). Dasselbe von Hand: opensnitch-cli config set DefaultAction deny oder im TUI im Nodes-Reiter d. opensnitch-cli status und die Statuszeile des TUI warnen, solange ein verbundener Daemon noch auf allow steht; ausschalten lässt sich die Durchsetzung mit settings set nodes.fail_closed false. Zwei weitere Grenzfälle: Der Daemon wartet auf eine Antwort des UI höchstens 120 s (dann seine Standardaktion) – serve antwortet nach prompts.timeout (30 s) mit der eigenen Standardaktion, also vorher. Und opensnitch-cli interception off schaltet das Abfangen komplett ab (alles erlaubt), bis es wieder eingeschaltet wird; mit interception.persist_state merkt sich serve das.

Das Text-UI (opensnitch-cli tui)

Das TUI ist das GUI-Hauptfenster („Network Statistics“) als Textoberfläche – gleiche Aufteilung, gleiche Reiter, gleiche Dialoge, nur mit Tastatur bedient:

 OpenSnitch Network Statistics                                     Status: ● Connected (1 node)  v1.9.1
 Node: unix:/local (host)   Daemon: 1.9.0   Uptime: 2:13:05   Rules: 12   Connections: 3401   Dropped: 7   Interception: ON
  I Stop interception   F Firewall   P Preferences   N New rule   E Edit   D Delete   S Save CSV   H Help   Q Quit
  Events │ Nodes │ Rules (12) │ Hosts │ Applications │ Addresses │ Ports │ Users │ Alerts
Time                Action Destination            Proto Process             Args                 Rule
2026-09-04 20:59:08 allow  example.com:443        tcp   /usr/bin/curl       curl https://…       allow-curl
...
                 ╭─ OpenSnitch ────────────────────────────────────────────────────────────────╮
                 │ curl                                                                        │
                 │ curl is connecting to example.com on TCP port 443                           │
                 │ Source IP: 192.168.1.10:51234   Destination: 93.184.216.34:443 (example.com)│
                 │ Process ID: 4242   User ID: 1000 (user)   Checksum: d41d8…                  │
                 │ Path: /usr/bin/curl   Command: curl https://example.com                     │
                 │ What to do?   (↑↓)  < from this executable: /usr/bin/curl >   1/13          │
                 │ Advanced:     [i] Dst IP [ ]  [p] Dst port [ ]  [u] User ID [ ]  [s] Checksum [ ]
                 │ Duration:     (←→)  < until reboot >                                        │
                 │     Allow (a)      Deny (d)  23s      Reject (r)     Enter=default  ?=details│
                 ╰─────────────────────────────────────────────────────────────────────────────╯
  • Statuszeile und Buttons wie in der GUI: Node, Daemon-Version, Uptime, Regeln, Verbindungen, Dropped; I Interception starten/stoppen, F Firewall-Dialog, P Preferences, N/E/D Regel neu/bearbeiten/löschen, S Tabelle als CSV speichern, H Hilfe. Suche / und Limit l (50 … alle) wie die Suchleiste/Limit-Box der GUI.
  • Reiter 1–9 oder Tab: Events (live, mit Node-Spalte bei mehreren Daemons), Nodes (alle je gesehenen Nodes wie in der GUI-Tabelle), Rules (links der Regel-Baum All/Allow/Deny/Reject/Temporary/Permanent, ←→), Hosts, Applications, Addresses, Ports, Users (What/Hits/Last seen – Enter zeigt die Events des Eintrags, Esc zurück), Alerts.
  • Vom Event zur Regel: Klick auf den Namen in der Spalte „Rule“, Doppelklick auf ein Event oder r öffnet die zugehörige bestehende Regel zur Bearbeitung. Das funktioniert auch in den Detailansichten von Hosts, Applications usw.; die Regel wird auf dem Node des Events bearbeitet. Für gelöschte Regeln und Events ohne Regel erscheint eine Meldung. Enter bleibt für Prozessdetails, E erstellt eine neue Regel.
  • Host/IP/CIDR auflösen: F3 auf einem Event, Host oder einer Adresse zeigt die Auflösung. Im Regel- und Verbindungsdialog zuerst das Host- oder IP/Netz-Feld auswählen, dann F3: Hostname → IPv4/IPv6, IP → Hostname, CIDR → normalisiertes Netz sowie erste/letzte Adresse. DNS läuft im Hintergrund auf dem Rechner der TUI; Esc bricht die Anzeige ab, nach 8 Sekunden endet das Warten. Regeln werden dadurch nicht umgeschrieben. Ein Netz hat keinen einzelnen DNS-Namen.
  • Mausbedienung: Formularfelder und Auswahllisten anklicken, Checkboxen umschalten, Save/Cancel sowie Allow/Deny/Reject direkt anklicken; das Mausrad scrollt. Auch Firewall-Aktionen und Yes/No-Rückfragen sind anklickbar. Die Tastaturbedienung bleibt verfügbar, auch bei 80 Spalten.
  • Pop-up = Regel-Editor. Eine Verbindungsanfrage öffnet sich als dasselbe Formular wie „Regel bearbeiten“, vorausgefüllt mit den Fakten der Verbindung (Prozess, Kommandozeile, User, PID, IP, Host, Port, Protokoll, Checksum, Prozessbaum) und der Standardbedingung angehakt. Sobald das Formular offen ist, wird die Anfrage für die ganze Zeit gehalten, die der Daemon erlaubt (110 s) – kein Rennen gegen die 30 s. Und das Formular schließt sich nie von selbst: Läuft die Daemon-Frist während des Bearbeitens ab (der Daemon entscheidet die eine Verbindung dann nach seiner Standardaktion, das lässt sich von außen nicht ändern), bleibt das Formular mit allen Eingaben offen, und „Apply“ legt die Regel für die nächsten Verbindungen an. Nichts geht verloren. a/d/r antworten sofort mit den Feldern, wie sie gerade stehen; s/Apply mit dem Action-Feld; Space hakt Bedingungen an oder ab, Enter ändert einen Wert, ←→ wechselt Action/Dauer/Protokoll und das Preset „Domain / Netz / Muster“ (die Ziele des Original-Pop-ups: *.domain, /24-/16-/8-Netze, IP-Muster, AppImage/Snap). Esc fragt: warten (später mit p wieder öffnen; die Kopfzeile zeigt „pending (p)“), Standard sofort anwenden, oder zurück.
  • Regel-Editor (N, E, oder E auf einem Event = Regel aus Event): Formular mit Name, Beschreibung, Enabled, Priority rule, Don't log, Action, Duration und den Bedingungen der GUI (Pfad, Kommandozeile, User ID, PID, Interface, IP/Netz/Alias, Host, Port 80,443 oder 1024-65535, Protokoll, Listen-Verzeichnisse, Checksum). Reguläre Ausdrücke werden wie in der GUI automatisch erkannt. Unveränderte bestehende Bedingungen behalten ihren Typ, ihre Groß-/Kleinschreibungseinstellung und auch mehrfach vorhandene Operanden. Einzelne IPs bleiben dest.ip; CIDR-Netze verwenden dest.network. IPv4-Präfixe sind auf 0–32, IPv6-Präfixe auf 0–128 begrenzt.
  • Firewall-Dialog (F): Firewall an/aus (e), Inbound-/Outbound-Policy (i/o) – wie in der GUI setzt „drop“ die Policy und legt die Regeln an, die established/related- und Loopback-Verkehr weiter durchlassen (dieselben Regeln und UUIDs wie die GUI-Profile); „accept“ entfernt sie wieder. P auf einer anderen Chain ändert nur die Policy (mit Rückfrage). Profile (p), Regeln mit N/E/D, Formular mit Chain, Expressions, Verdict, Parametern. Im Firewall-Dialog öffnet a einen Port (mit optionalem from IP/CIDR), A blockiert einen Port; Deny-/Reject-Regeln werden automatisch vor die Allow-Regeln einsortiert (nftables wertet den ersten Treffer), Loopback und established/related bleiben immer erlaubt.
  • Preferences (P): dieselben Gruppen wie im GUI-Dialog – Pop-ups (Standardaktion/-dauer/-ziel, Timeout, Advanced-Vorgaben), UI (Theme, Limit, Benachrichtigungen), Rules, Nodes, Database, Server.
  • Nodes: Enter Details, c öffnet die Daemon-Konfiguration (JSON) im $EDITOR und schickt sie an den Daemon (wie der Konfig-Editor der GUI), i Interception.
  • Events: Enter Prozessdetails live vom Daemon (Status, Descriptors, Environment, Maps, Stack – der Prozessdialog der GUI), Space Roh-Event.
  • Formulare: ↑↓ bewegen, Space Häkchen, Enter Wert eingeben/auswählen, ←→ Auswahl ändern, s/F2 speichern, Esc abbrechen.

Themes (Preferences › UI › Theme oder settings set ui.theme dark_blue, auch tui --theme NAME): die qt-material-Farbschemata der GUI als Terminalfarben – default (Terminalfarben), dark_blue, dark_teal, dark_amber, dark_cyan, dark_purple, dark_red, dark_pink, dark_yellow, dark_lightgreen und die light_*-Varianten (256-Farben-Terminal; auf 8-Farben-Terminals wird nur die Akzentfarbe übernommen).

Befehle und Unterbefehle sind Groß-/Kleinschreibung-unabhängig (STATUS, Rules LIST, TOP Hosts gehen alle). Maus wird unterstützt (Reiter, Buttons, Zeilen, Doppelklick = Enter, Pop-up-Buttons, Mausrad). Ctrl-C beendet sauber und stellt das Terminal wieder her. Ohne UTF-8-Locale (z. B. LANG=C per SSH) wird auf C.UTF-8 ausgewichen, sonst mit ASCII-Zeichen gezeichnet (OPENSNITCH_CLI_ASCII=1 erzwingt das). Neu gezeichnet wird nur bei Änderungen bzw. einmal pro Sekunde – auch über langsame Verbindungen brauchbar. Es können beliebig viele tui/prompt-Instanzen gleichzeitig laufen (z. B. tmux + SSH); die erste Antwort gewinnt. Die Spalten passen sich der Terminalbreite an (ab 80 Spalten brauchbar, ab 120 mit allen Spalten).

Befehlszeile

Alle Befehle haben --help; die meisten kennen --node NODE (mehrere Daemons), --all, --json, -y.

Verbindungsanfragen

opensnitch-cli prompt                       # interaktiv, blockt bis Ctrl-C
opensnitch-cli prompt --list                # was wartet gerade?
opensnitch-cli prompt --answer "allow host always +uid"

Antwort-Grammatik: <a|allow|d|deny|r|reject> [ziel] [dauer] [+ip +port +uid +sum] [name=..], Ziel als Nummer oder Schlüssel (exe cmd port ip host dom1.. net24 net16 net8 ipre1.. user pid appimage snap alias), Dauer once 30s 5m 15m 30m 1h 12h restart always (GUI-Namen until reboot/forever gehen auch); ? = Details, skip = Standard sofort, list, quit. Ohne Antwort greift nach prompts.timeout Sekunden der Standard (prompts.default_action usw.; 0 = so lange warten, wie der Daemon erlaubt).

Regeln

opensnitch-cli rules list [--filter TEXT] [--enabled|--disabled] [--temporary|--permanent]
opensnitch-cli rules add deny always --op host~'^(|.*\.)ads\.example$' -d "kein Werbe-Tracking"
opensnitch-cli rules add allow 1h --op path=/usr/bin/curl --op port=443 --name curl-https
opensnitch-cli rules add allow always --op net=10.0.0.0/8 --op uid=1000 --precedence --nolog
opensnitch-cli rules edit curl-https --duration always --op path=/usr/bin/curl --op port:range=1024-65535
opensnitch-cli rules enable|disable|delete NAME     rules show NAME
opensnitch-cli rules export ./backup   |   rules import ./backup
opensnitch-cli rules --dir /etc/opensnitchd/rules list|add|edit|delete ...   # offline, ohne serve (Dateien direkt)

Bedingungen (--op, mehrere = UND-Liste): path= cmd= host= host~regexp ip= port= net= uid= pid= proto= md5= iface=, port:range=a-b, domains=/pfad/liste (lists), process.env.NAME=wert, !host= (case-sensitive).

Events, Statistik, Logs

opensnitch-cli events -n 100 --action deny --process curl     # aus der Datenbank
opensnitch-cli events -f                                       # live
opensnitch-cli top hosts|procs|addrs|ports|users|rules|protocols|pids|cmdlines
opensnitch-cli stats            opensnitch-cli alerts [--clear]
opensnitch-cli logs -f          opensnitch-cli logs --daemon -n 200   # /var/log/opensnitchd.log
opensnitch-cli proc PID         node-monitor           netstat --proto tcp        sockets
opensnitch-cli db info | purge --days 7 | vacuum | clean connections

Das serve-Log landet in server.log_file (im Hintergrund automatisch ~/.config/opensnitch-cli/serve.log), die Datenbank wird mit settings set database.type file dauerhaft (database.file, Standard ~/.config/opensnitch-cli/events.db; GUI-Datenbankdateien sind kompatibel).

System-Firewall (nftables, wie der GUI-Firewall-Dialog)

UFW ablösen mit einem Befehl – fertige Policies (fw preset):

opensnitch-cli fw preset server --ports 22,80,443   # deny inbound, allow outbound, established/related bleibt, Ports offen
opensnitch-cli fw allow-port 51820 --proto udp                 # weiteren Port öffnen (WireGuard); --proto tcp,udp = zwei Regeln
opensnitch-cli fw allow-port 22 --from 10.0.0.0/8              # nur aus einem IPv4-Netz (wie UFW: allow from … to port 22)
opensnitch-cli fw deny-port 23     fw reject-port 3389         # blockieren (deny=drop, reject=aktiv ablehnen); stehen vor den allow-Regeln
opensnitch-cli fw delete-port 22                               # entfernt alle Varianten dieses Ports (tcp und udp, alle Quellen)
opensnitch-cli fw preset lockdown                   # auch ausgehend dicht außer established/related + loopback
opensnitch-cli fw preset open                       # alles wieder erlauben (Preset zurücknehmen, auch forward wieder accept)
opensnitch-cli fw repair                            # fehlende Standard-Chains des Daemons neu anlegen (inkl. Interception-Queue)
opensnitch-cli fw preview input-drop                # zeigt die EXAKTE system-fw.json, die gesendet würde (ohne anzuwenden)
opensnitch-cli fw preview server --ports 22,80      # zum Vergleichen/Debuggen auf dem Zielsystem

Wichtig: die Presets fassen die forward-Chain nicht an – OpenSnitch fängt weitergeleitete Verbindungen (Container, VMs, Docker) über die Queue-Regel in mangle_forward ab; diese Chain auf drop zu zwingen bricht geroutet­en/ausgehenden Verkehr auf jedem Host, der routet. ufw-default = deny in / allow out / established+related + loopback (UFWs Standard); server = das plus SSH (und --ports); desktop = ohne offene Ports (Regeln und Pop-ups erledigen den Rest); lockdown = auch ausgehend dicht; open = alles erlauben (Input, Output und Forward wieder accept, Profil-Regeln weg). Profile und Presets legen fehlende Standard-Chains des Daemons vorher automatisch wieder an (auch die Interception-Queue in mangle_forward/mangle_output), sodass eine geleerte oder unvollständige system-fw.json nicht in einem kaputten Zustand endet; fw repair (bzw. R im Firewall-Dialog) macht nur das, ohne die Policy zu ändern – eine neu angelegte filter_input/mangle_output hat dann die Daemon-Voreinstellung (Policy accept, nur die Standardregeln), repair sagt das auch. Von Ports geöffnete Regeln sind Inbound-accept-Regeln, die vor der Drop-Policy stehen. Im TUI: Firewall-Dialog (F) → p (Presets, fragt nach Ports) und a (Port öffnen).

Mehrere Protokolle in einer Port-Regel schreibt die CLI wie die GUI: fw add --expr 'tcp,udp dport 53' wird zu meta l4proto tcp,udp dport 53, woraus der Daemon ein anonymes Protokoll-Set baut (meta l4proto { tcp, udp } th dport 53 in nftables). allow-port --proto tcp,udp legt weiterhin zwei getrennte, einzeln löschbare Regeln an. Regeln ohne Ausdruck lehnt die CLI ab – der Daemon würde sie stillschweigend nicht anlegen, sie sähen aber im fw show wie eine Catch-all-Regel aus. delete-port 22 entfernt nur Port 22, nicht 2200 oder 22-1024.

Reihenfolge in filter_input wie bei UFW (nftables nimmt den ersten Treffer): zuerst die Profil-Regeln (Loopback, established/related – ein deny-port trennt also keine bestehende Sitzung), dann deny/reject, dann allow, dann der Rest der Chain. Was der Daemon kann und was nicht (alles aus daemon/firewall/nftables abgeleitet und gegen opensnitchd 1.8.0 geprüft): --from nimmt eine IPv4-Adresse oder ein IPv4-Netz; CIDR kennt der Daemon nicht, die CLI übersetzt 10.0.0.0/8 in den Bereich 10.0.0.0-10.255.255.255 (auch bei fw add --expr 'ip saddr 10.0.0.0/8'); IPv6-Quellen werden abgelehnt (der Daemon vergleicht nur IPv4-Adressen). --proto tcp,udp erzeugt zwei Regeln, weil nftables die Ausdrücke einer Regel UND-verknüpft und „tcp dport X und udp dport X" nie zutrifft. Die vom Daemon mitgelieferte, deaktivierte Regel „Allow SSH server connections when input policy is DROP" bleibt unangetastet; server legt seine eigene aktive Regel mit stabiler UUID (osn-port-tcp-22-any-accept) an. Der Outbound-Drop (lockdown, fw policy output drop) enthält zusätzlich zum GUI-Profil eine Loopback-Regel (oifname lo), sonst wären neue Verbindungen nach 127.0.0.1/::1 tot, sobald die Interception-Queue nicht davor steht (Interception aus, Daemon weg); output accept entfernt sie mit. Weitergeleiteter Verkehr (net.ipv4.ip_forward, Container, VMs) bleibt von allen Presets unberührt – wer routet und das nicht will: opensnitch-cli fw policy forward drop.

Zwei Eigenheiten des Daemons, die man kennen sollte: (1) Nach jeder Änderung an der System-Firewall lädt er sie neu und kann dabei seine eigenen Interception-Regeln (die queue-Regeln in mangle_output/filter_input) vorübergehend verlieren – beobachtet bei zwei Änderungen kurz hintereinander; sein Prüf-Thread baut sie beim nächsten Intervall (FwOptions.MonitorInterval, Standard 15 s) wieder ein. Solange die Output-Policy auf drop steht (lockdown, fw policy output drop), schlagen neue ausgehende Verbindungen in diesem Fenster fehl – bestehende laufen weiter. Das ist Daemon-Verhalten, die GUI hat es genauso. (2) Fehler beim Laden einzelner Regeln meldet der Daemon asynchron; sie können erst mit der Antwort auf den nächsten Befehl ankommen. serve erkennt solche nachgereichten Meldungen daran, dass sie keine Regel der gerade gesendeten Konfiguration nennen, und protokolliert sie nur (serve.log), statt den Befehl als gescheitert zu melden.

Firewall ausschalten (fw disable) und Chains löschen. Der Daemon fasst Chain-Policies nicht mehr an, sobald die Firewall in der Konfiguration aus ist – er löscht nur die konfigurierten Regeln. Eine Chain, die gerade auf drop steht (preset server, fw policy input drop), bliebe also ohne ihre Allow-Regeln stehen und würde alles verwerfen; auf einem entfernten Rechner heißt das ausgesperrt. fw disable (und fw chain-delete einer Chain mit drop-Policy, und e im Firewall-Dialog) setzt deshalb erst die betroffenen Policies auf accept, schickt das, und schaltet dann ab – genau wie es die Qt-GUI macht. Im Log steht dann „resetting the drop policy …"; nach fw enable sind die Policies auf accept, die gewünschte Policy also neu setzen (fw preset …).

Bekannter, behobener Fehler (Builds bis 49e30ea, 5.9.2026): die CLI nummerierte die Regeln einer Chain als Position 0, 1, 2 … durch. Der Daemon reicht Position aber unverändert als nftables-Handle („füge vor Regel mit diesem Handle ein") an den Kernel weiter, und solche Handles gibt es nicht – jede Regel außer der ersten scheiterte mit rule not added (…) (Daemon-Log: netlink receive: no such file or directory). Nach fw policy input drop oder fw preset server war deshalb nur die erste Regel aktiv, die established/related-Regel fehlte, Antworten auf ausgehende Verbindungen wurden verworfen („Outbound kaputt"). Die Reihenfolge steckt allein in der Reihenfolge der Regeln (so macht es auch die GUI); Position ist jetzt immer 0, pos in fw show ist der Index. Eine mit einem alten Build angelegte system-fw.json heilt jeder fw-Befehl bzw. fw import der exportierten Datei. Meldet der Daemon beim Laden einen Fehler, übernimmt serve die Konfiguration trotzdem als Ist-Zustand (der Daemon hat sie bereits gespeichert) und nennt die betroffenen Regeln; prüfen mit sudo nft list table inet opensnitch.

opensnitch-cli fw show | rules [--hook input]
opensnitch-cli fw add --hook input --expr 'tcp dport 22' --expr 'ct state new' --target accept -d ssh
opensnitch-cli fw add --hook output --type mangle --expr 'meta skuid 1000' --target queue --target-params 'num 0'
opensnitch-cli fw policy input drop      # wie die GUI: Policy DROP + Regeln für established/related und loopback (Profil)
opensnitch-cli fw policy input accept    # entfernt diese Profil-Regeln wieder;  --raw ändert NUR die Chain-Policy (kann aussperren)
opensnitch-cli fw profile input-drop     fw enable|disable
opensnitch-cli fw edit UUID --add-expr 'iifname eth0'   fw move UUID 0   fw disable-rule UUID   fw delete UUID
opensnitch-cli fw chain-add --hook prerouting --type natdest --name nat_pre    fw chain-delete nat_pre
opensnitch-cli fw export system-fw.json   fw import system-fw.json

Daemon- und CLI-Konfiguration, Nodes

opensnitch-cli config show [DefaultAction]   config set DefaultAction deny   config set Stats.MaxEvents 500
opensnitch-cli config loglevel 1             config edit        config apply datei.json
opensnitch-cli settings show|set|reset|edit|path       # ~/.config/opensnitch-cli/config.json
opensnitch-cli interception on|off           nodes [--history] [--show NODE]        status        stop

Integration / Skripting (introspect)

Für die Einbindung in eine Hosting-Umgebung gibt es einen maschinenlesbaren Rundumblick:

opensnitch-cli introspect                 # alles als JSON: version, build, api, sockets, settings, nodes
                                          #   (je Node: config, stats, firewall, rules), letzte events/alerts, database
opensnitch-cli introspect nodes rules     # nur bestimmte Abschnitte
opensnitch-cli introspect --commands      # Liste aller Control-Kommandos
opensnitch-cli introspect nodes | jq '.nodes[].firewall.enabled'

introspect gibt immer JSON aus (unabhängig von --json). Das Feld api ist die Version des Control-Protokolls und wird nur bei inkompatiblen Änderungen erhöht – Skripte können darauf prüfen. Mit --json liefern sowohl die lesenden Befehle (rules list, fw show, status, nodes, events, top, stats, alerts, db info …) als auch die ändernden (rules add/edit/enable/disable/delete, fw policy/preset/allow-port/…/repair/import, config set, interception, db purge/vacuum/clean, stop) die Antwort des Control-Servers als JSON-Objekt, und einen Exit-Code ≠ 0 bei Fehlern. Ausnahmen: fw export FILE/rules export DIR schreiben weiter die Dateien, prompt/events -f/proc/netstat geben mit --json je Ereignis eine JSON-Zeile aus (Hinweise gehen nach stderr, damit die Zeilen für jq -c . sauber bleiben). Der Control-Socket (server.control_socket, Standard $XDG_RUNTIME_DIR/opensnitch-cli-<uid>.sock) ist die Schnittstelle; er spricht zeilenweise JSON, falls jemand direkt integrieren will statt über die CLI.

Bash-Vervollständigung

make install legt completion/opensnitch-cli.bash unter $PREFIX/share/bash-completion/completions/ ab (sonst: source completion/opensnitch-cli.bash). Vervollständigt Befehle, Optionen, Regelnamen und Nodes.

Betrieb als Dienst

make install (bzw. das RPM) legt die Benutzer-Unit opensnitch-cli.service an:

systemctl --user enable --now opensnitch-cli

(ohne Installation: sed 's|@BINDIR@|/usr/local/bin|' systemd/opensnitch-cli.service.in > ~/.config/systemd/user/opensnitch-cli.service) Ohne laufendes serve fällt der Daemon auf sein eigenes DefaultAction zurück (wie ohne GUI). Desktop-Benachrichtigungen für verpasste Anfragen: settings set notifications.type desktop (nutzt notify-send).

Tests

Drei Stufen, alle im Paket unter tests/ und tools/:

Die ergänzten Bedienungs- und Referenztests vom 24.9.2026 sind in docs/WORK-NOTES-2026-09-24.md dokumentiert: python3 tests/tui-interaction.py prüft Maus/Tastatur und den gespeicherten Zustand; bash tests/real-daemon-isolated.sh prüft den echten Daemon mit nftables und einem lokalen HTTP-Server in eigenen Netzwerk-Namensräumen (benötigt root/sudo). tests/qt-reference.py verwendet die originalen Qt-Regeldialoge aus einem separat vorhandenen OpenSnitch-Checkout.

  1. tests/run-tests.sh – Integrationstest ohne echten Daemon. Startet serve, dazu tools/fake-daemon.py (ein kleiner Python-opensnitchd-Ersatz mit grpcio – also ein echter gRPC-Client gegen unseren Server) und fährt alles durch: Subscribe/Ping/Notifications/PostAlert, Pop-up beantworten (auch Timeout und Fehleingaben), Regeln anlegen/ändern/löschen/exportieren/importieren, Firewall, Konfiguration, Interception, Events/Top/Stats/Alerts, Prozess-/Node-/Netstat-Tasks, Logs und das TUI (per Pseudoterminal mit tools/tui-driver.py, das Tasten schickt und den Bildschirm prüft). Braucht python3, grpcio, protobuf und pyte (pip install grpcio protobuf pyte). Endet mit ALL OK.
    make && bash tests/run-tests.sh
    
  2. tests/smoke-real-daemon.sh – gegen den echten opensnitchd (in der VM). Prüft, ob der Daemon verbunden ist, ob DefaultAction auf deny steht (fail-closed), löst mit curl eine echte Verbindungsanfrage aus und beantwortet sie von der Kommandozeile, legt eine Allow- und eine Deny-Regel an und prüft, dass curl entsprechend durchkommt bzw. geblockt wird, kontrolliert die gespeicherten Events, und – mit sudo/nft – dass nach fw policy input drop alle Profil-Regeln (Loopback, established/related) wirklich in nftables stehen (genau die Prüfung, die den Position-Fehler gefunden hätte). Temporäre Regeln und die Firewall-Konfiguration werden wieder hergestellt. Ausgabe PASS/FAIL je Prüfung, Exit-Code ≠ 0 bei Fehlern.
    tests/smoke-real-daemon.sh                 # Ziel-URL optional: tests/smoke-real-daemon.sh https://example.org/
    
  3. tools/go-daemon-sim.py – der Go-Daemon auf Draht-Ebene, ohne Go. Der echte Daemon benutzt grpc-go 1.32, das sich in Details anders verhält als der Python-gRPC-Client (u. a. schickt es beim Unix-Socket den rohen Pfad als :authority). Das Skript spricht rohes HTTP/2 (h2-Bibliothek) genau so wie grpc-go und fährt die Daemon-Sequenz durch: Ping mit 150 Events unter der 1-s-Deadline, Subscribe mit 300 Regeln (mehrere Frames, Flusskontrolle), Notifications-Stream inkl. Antwort, AskRule. Läuft in tests/run-tests.sh mit.
  4. Von Hand im TUI: opensnitch-cli tui, in einem zweiten Terminal curl https://example.com → das Pop-up muss erscheinen; d (oder Klick auf „Deny“) → curl bricht ab; Rules-Reiter zeigt die neue Regel.

Was hier vor Auslieferung getestet wurde: Stufen 1 und 3 komplett (plus AddressSanitizer-Läufe für Trennungen und Abstürze), das RPM-Spec per rpmbuild. Genau Stufe 3 hat den Fehler gefunden, an dem der echte Daemon scheiterte (siehe Abschnitt „Keine Pop-ups?“). Stufe 2 lief am 5.9.2026 in einer WSL2-Ubuntu-VM gegen opensnitchd 1.8.0 (nftables, eBPF-Prozessmonitor): Pop-ups, Regeln, und die komplette Firewall-Reihe (fw policy input|output drop|accept, alle Presets, allow-/deny-/reject-/delete-port, --from, tcp,udp, repair, export/import) mit Kontrolle des echten Rulesets per nft list table inet opensnitch und Verbindungstests mit curl bei ein- und ausgeschalteter Interception. Dabei wurde der Position-Fehler (siehe Firewall-Abschnitt) gefunden und behoben; der Fake-Daemon lehnt seither dieselben Dinge ab wie der echte (Position ≠ 0, CIDR, tcp+udp in einer Regel). Was dabei gefunden und behoben wurde, steht in docs/REAL-DAEMON-FIXES.md.

Nicht portiert

Qt-spezifisches: Themes, Tray-Icon, Plugin-System der GUI, Diagramme. Alles andere (Regeln inkl. Listen/Regex/Netzwerk-Aliase, Firewall-Editor, Prozess-Monitor, Netstat, Nodes, Alerts, Statistiken, DB-Wartung, Version-Warnung, Persistieren des Interception-Zustands) ist vorhanden.

Lizenz: GPL-3.0 (wie OpenSnitch); cJSON: MIT (third_party/LICENSE.cJSON).

S
Description
This is the repository for the OpenSnitch TUI CLI. For simplicity's sake and to keep everything in one place, we'll include the daemon as well as a simple installation tool.
Readme
9.9 MiB
0 Stars 2 Watchers 0 Forks
Languages
C 89%
Python 7.3%
Shell 3.3%
Makefile 0.4%