Repository navigation
Conversation
0130654 to
df8bcab
Compare
df8bcab to
5d31123
Compare
|
Hi there, apologies for the slow response on this one, we've been quite busy internally. First, thank you for your contribution. We agree that Steam games are a common use case and that our split tunneling implementation should work with it. Your PR correctly touches on several points and we're grateful for the work you've done. That said, we're unable to accept the patch as it is right now, since it contains various edge case issues:
If you'd like to take a stab at the above, please feel free. I've added this task to our internal board as well, so we'll get to this in a future release, and you'll be credited in the changelog even if we end up implementing it differently. |
Three defects kept Steam games from bypassing the VPN tunnel in exclude mode: * Helper process matching compared readlink(/proc/<pid>/exe) (always a resolved ELF path) against stored app entries by raw string equality, so script-wrapped launchers (/usr/bin/steam) and symlinked paths (~/.steam/steam, usrmerge) could never match. Entries are now preprocessed into raw/canonical/script-interpreter/directory forms: script launchers match via their shebang interpreter plus an argv token, directory entries (game install trees) match by path prefix, and matched launchers pull their already-running process trees into the cgroup. * The GUI app picker resolved every steam://rungameid desktop entry to the Steam launcher script, collapsing all games into a single "steam" row, and games without desktop entries never appeared. Installed games are now enumerated from the Steam libraries themselves (libraryfolders.vdf and appmanifest_*.acf, covering libraries on other drives, flatpak/snap roots and XDG_DATA_HOME) and offered as their install-directory entries. * The exclude-mode firewall accepted reply packets only by "meta cgroup", which cannot match on the input path for unconnected UDP sockets (no early demux) - the pattern game server browsers use (Steam SDR pings) - so replies were dropped by the always-on firewall and every region showed "ping: failed". The bypass mark is now saved on the connection at egress, restored from conntrack at ingress, and accepted by mark, mirroring the include-mode reply handling.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
…p module Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Wine reports the preloader as the process exe, so path rules never matched Proton games; classify them via working directory and the Windows drive-mapped argv[0] instead. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
This reverts commit e14e72d.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Rule construction (realpath/stat on client-supplied paths) can block indefinitely on unresponsive FUSE/SMB/NFS mounts, so it now runs on a dedicated worker thread: setApps swaps in raw entries and wakes the worker, which resolves, swaps in new rules, and rescans /proc so entries added while a game is already running take effect without a relaunch. Rules are also re-resolved periodically so symlink churn from game updates does not go stale. The cwd matching signal is removed entirely: a shell cd'd into an excluded directory would pass the exemption to every child it spawns, letting any executable selectively escape the tunnel; Wine/Proton games remain covered by the wine-exe-gated argv[0] match. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
The removal pass re-read rules_ after apps_ was already swapped, so a worker rebuild landing in between could drop the removed entry's rule and strand its processes in the cgroup until disable. Also drops the write-only lastRulesBuild_ field. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Orphaned when cwd matching was removed; windowsPathMatchesRule handles the /run/host remap inline. The test header still described the removed cwd signal. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
d0ac7a8 to
83f93b5
Compare
|
Hey there Sorry for the unrelated changes, I was using this branch locally for a few things I needed and accidentally pushed changes unrelated to the fix. I've updated the branch to address the issues you've pointed out. Hopefully it looks better now. |
Problem
On Linux, adding Steam games to split tunneling in exclude mode did nothing: game traffic stayed inside the VPN tunnel. In Dota 2 every region showed
ping: FAILEDeven though the game had been added to the exclude list.Root causes
Helper process matching (
src/helper/linux/split_tunneling/process_monitor.*): processes were matched by comparingreadlink(/proc/<pid>/exe)— always a resolved ELF path — against stored entries by raw string equality. Steam picker entries resolve to/usr/bin/steam(a shell script, which/proc/<pid>/exenever shows), and symlinked paths (~/.steam/steam, usrmerge) never compare equal either. Entries are now preprocessed into raw/canonical forms, script launchers match via their shebang interpreter plus an argv token (precise: no basename or arbitrary-token matching), and directory entries (game install trees) match by path prefix. Matched launchers also pull their already-running process trees into the cgroup.App-picker enumeration (
linuxutils.cpp, newsteamgames.*): everysteam://rungameid/<id>desktop entry resolved to the Steam launcher script, collapsing all games into one "steam" row; games without desktop entries never appeared. Installed games are now enumerated from the Steam libraries themselves (libraryfolders.vdf,appmanifest_*.acf), covering libraries on other drives/locations, flatpak and snap roots, andXDG_DATA_HOME, and are offered as their install-directory entries.Firewall reply path (
firewallcontroller.cpp): exclude-mode accepted reply packets only viameta cgroup, which cannot match on the input path for unconnected UDP sockets (no early demux —skb->skis NULL). That is exactly the pattern game server browsers use (Steam SDR pings), so replies to excluded processes were dropped by the always-on firewall. The bypass mark is now saved on the connection at egress, restored from conntrack at ingress, and accepted by mark — mirroring the include-mode reply handling.Testing
The helper-side matching was exercised with a standalone harness against live processes (symlinked paths, script launchers under their interpreter, directory trees, descendant sweeps, snap/flatpak entry shapes preserved, security guards for non-regular files and shebang-interpreter precision), including a live netlink EXEC-event test.
The fixes have been tested manually on my system (Arch-based, CachyOS): the client was built and installed as a package, Steam game entries on a secondary-drive library are matched and moved into the split-tunnel cgroup, marked traffic routes via the physical gateway, and connected vs. unconnected UDP reply paths were verified before and after the firewall fix (Dota 2 region pings now succeed in exclude mode).
Attribution
Most of the work was done with an AI agent (OpenCode); the fixes have been tested manually on my system and verified that they work.