Repository navigation
daemon/rule: atomic rule saves + built-in network aliases fallback - #1705
Open
andrewfader wants to merge 2 commits into
Open
andrewfader wants to merge 2 commits into
andrewfader wants to merge 2 commits into
Conversation
Loader.Save() wrote the rule with ioutil.WriteFile(), which truncates the target first and then writes. If the daemon is killed or the machine loses power between those two steps, the rule file is left empty (or partial). On the next start the loader logs Error parsing rule from /etc/opensnitchd/rules/<name>.json: unexpected end of JSON input and skips it, so a rule the user believes is active is silently gone until they notice the warning. A zero-byte rule file produced this way was found on a production machine. Write to a temporary file in the rules directory, fsync it, and rename it over the target. rename(2) is atomic on the same filesystem, so readers (including the loader's own fsnotify watcher) only ever see the old complete file or the new complete file. Mode stays 0600.
andrewfader
force-pushed
the
rule-atomic-save-and-default-aliases
branch
from
November 5, 2026 00:12
84985c8 to
e137a96
Compare
…ile is missing The UI offers "LAN" and "MULTICAST" as destination networks and writes them verbatim into dest.network rules. The daemon resolves them from /etc/opensnitchd/network_aliases.json; when that file is absent every such rule fails to compile with Operator.Compile() error: CIDR parsing error: invalid CIDR address: LAN and is disabled. v1.7.2 shipped the daemon-side alias code and a UI that emits "LAN", but daemon/data/network_aliases.json was only added for v1.8.0, so no v1.7.2 package could install it (Arch's 1.7.2 package, for example, has nothing to install). That is the root cause of evilsocket#1559, and the same thing happens on any install where the file is missing or damaged. Keep the file as the source of truth, but when it is missing or invalid load DefaultAliases (a copy of daemon/data/network_aliases.json) so the aliases the UI exposes always resolve. While here, accept bare IP addresses in alias lists as /32 or /128: the shipped file contains "::1", which net.ParseCIDR() rejects, so loopback IPv6 was silently dropped from the LAN alias.
andrewfader
force-pushed
the
rule-atomic-save-and-default-aliases
branch
from
November 5, 2026 00:17
e137a96 to
12a02aa
Compare
andrewfader
marked this pull request as ready for review
November 5, 2026 00:20
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two small daemon fixes for problems that showed up as repeated warnings in
/var/log/opensnitchd.logon an Arch Linux install (opensnitch 1.7.2, nftables, eBPF procmon). Each is its own commit with tests.1.
daemon/rule: save rules atomicallyLoader.Save()usedioutil.WriteFile(), which truncates and then writes. A kill or power loss between the two leaves an empty/partial rule file; from then on every daemon start logsand the rule is silently not enforced. I found exactly such a 0-byte rule file on my machine (written 2026-07-21). The fix writes to a temp file in the rules directory, fsyncs, and
rename()s over the target, so readers (including the loader's own fsnotify watcher) only ever see a complete file. Mode stays 0600.2.
daemon/rule: fall back to built-in network aliasesThe UI offers "LAN"/"MULTICAST" as destination networks and the prompt dialog writes them verbatim into
dest.networkrules; the daemon resolves them from/etc/opensnitchd/network_aliases.json. v1.7.2 shipped the daemon-side alias code (daemon/rule/operator_aliases.go) and the UI that emits "LAN", butdaemon/data/network_aliases.jsononly appeared in v1.8.0, so no v1.7.2 package could install it and every such rule fails withand is disabled. That is the root cause behind #1559 (closed with "copy the file"), and it recurs on any install where the file is missing or damaged. This keeps the file as the source of truth but loads
DefaultAliases(a copy ofdaemon/data/network_aliases.json) when it is missing or invalid, so the aliases the UI exposes always resolve. It also accepts bare IPs in alias lists as /32 or /128: the shipped file contains"::1", whichnet.ParseCIDR()rejects, so IPv6 loopback was being dropped from LAN silently.Testing
go build ./...,go vet ./rule/(only the pre-existing copylocks notes inloader.go/rule.go),go test ./rule/all green on Go 1.27 / Linux 7.3.TestLoaderSaveIsAtomic(file complete and parseable after two saves, mode 0600, no temp files left),TestLoaderSaveMissingDir,TestLoadAliasesFallsBackToDefaults(missing file → LAN/MULTICAST resolve and adest.network LANoperator compiles),TestLoadAliasesInvalidFileFallsBack,TestLoadAliasesFromFile(bare IPv4/IPv6 become /32 and /128, unparseable entries skipped, defaults not merged when a file loads).PRIVILEGED_TESTS=1 NETLINK_TESTS=1 go test ./...as root (unrelated packages).