Bypass should apply to every launch of a listed app, not only launches from the GUI #67

Closed
opened 2026-08-19 14:22:14 -04:00 by mysticalsoap · 4 comments
Owner

Current behavior: an app on the bypass list is only actually bypassed when launched from the GUI's list (or via the manual console trick) -- bypass_tunnel() reads the .desktop Exec= line and starts the app inside the bypass cgroup. Launching the same app from the desktop launcher, taskbar or a terminal ignores the list entirely.

Wanted UX (ProtonVPN-style): mark an app once; every future launch, from anywhere, lands in the bypass automatically. If the app is running when its setting changes, prompt to restart it.

Hard constraint: ProtonVPN implements this with a system-wide eBPF exec/fork watcher classifying every process launch -- the lossy-event-buffer architecture whose dropped fork events are the reason this fork exists. No process-event watcher, eBPF or proc-events, gets reintroduced for this. The UX has to come from deterministic launch-time placement instead.

Candidate design -- launcher shims:

  • Factor the GUI's cgroup-join launch (join-then-exec subshell + reclaim_strays sweep) into a small CLI, e.g. aqomui-bypass <command>.
  • For each listed app, write a user-local .desktop override (~/.local/share/applications/<same-id>.desktop shadows the system entry per XDG precedence) whose Exec= wraps the original command with that CLI. Covers launcher/taskbar/krunner launches -- the normal path for GUI apps. Delete the override when the app is removed from the list.
  • Terminal launches use the same CLI explicitly.
  • Overrides need regenerating when the underlying package's .desktop changes; regenerate on connect or on a list edit.

Restart prompting: only needed when an app's bypass setting changes while it runs (detectable from the process list). Unlike Proton, nothing needs restarting on disconnect/reconnect -- cgroup membership survives, the service just rebuilds rules -- which is worth keeping and stating in the UI.

Considered and rejected: watching the user systemd manager's D-Bus for new app-*.scope units and migrating matches. Lossless transport (unlike perf buffers), but it adds a session daemon and depends on unit-naming conventions -- the same fragility already rejected for the Electron stray sweep.

**Current behavior:** an app on the bypass list is only actually bypassed when launched from the GUI's list (or via the manual console trick) -- `bypass_tunnel()` reads the .desktop `Exec=` line and starts the app inside the bypass cgroup. Launching the same app from the desktop launcher, taskbar or a terminal ignores the list entirely. **Wanted UX (ProtonVPN-style):** mark an app once; every future launch, from anywhere, lands in the bypass automatically. If the app is running when its setting changes, prompt to restart it. **Hard constraint:** ProtonVPN implements this with a system-wide eBPF exec/fork watcher classifying every process launch -- the lossy-event-buffer architecture whose dropped fork events are the reason this fork exists. No process-event watcher, eBPF or proc-events, gets reintroduced for this. The UX has to come from deterministic launch-time placement instead. **Candidate design -- launcher shims:** - Factor the GUI's cgroup-join launch (join-then-exec subshell + `reclaim_strays` sweep) into a small CLI, e.g. `aqomui-bypass <command>`. - For each listed app, write a user-local .desktop override (`~/.local/share/applications/<same-id>.desktop` shadows the system entry per XDG precedence) whose `Exec=` wraps the original command with that CLI. Covers launcher/taskbar/krunner launches -- the normal path for GUI apps. Delete the override when the app is removed from the list. - Terminal launches use the same CLI explicitly. - Overrides need regenerating when the underlying package's .desktop changes; regenerate on connect or on a list edit. **Restart prompting:** only needed when an app's bypass setting changes while it runs (detectable from the process list). Unlike Proton, nothing needs restarting on disconnect/reconnect -- cgroup membership survives, the service just rebuilds rules -- which is worth keeping and stating in the UI. **Considered and rejected:** watching the user systemd manager's D-Bus for new `app-*.scope` units and migrating matches. Lossless transport (unlike perf buffers), but it adds a session daemon and depends on unit-naming conventions -- the same fragility already rejected for the Electron stray sweep.
Author
Owner

worth cleaning up the bypass section of the README when this gets touched. I think it's a good idea to just not mention the command as a support way to get bypass. It should just be done through the UI. Then read the severfault page for any ideas and remove it because it's fluff.

Maybe worth emphasizing the use case of making it an opt-in system as well. Below is how proton vpn handles it. I don't think we want to completely copy this idea because it would lose the feature of setting up a 2nd tunnel?

Lastly with this feature implemented we might want to collapse the bypass/split-tunnel feature into the main settings page similar to how it's done here. And we'll want to cull the long winded explanation in app down to simpler terms.

image

worth cleaning up the bypass section of the README when this gets touched. I think it's a good idea to just not mention the command as a support way to get bypass. It should just be done through the UI. Then read the severfault page for any ideas and remove it because it's fluff. Maybe worth emphasizing the use case of making it an opt-in system as well. Below is how proton vpn handles it. I don't think we want to completely copy this idea because it would lose the feature of setting up a 2nd tunnel? Lastly with this feature implemented we might want to collapse the bypass/split-tunnel feature into the main settings page similar to how it's done here. And we'll want to cull the long winded explanation in app down to simpler terms. ![image](/attachments/09cec534-10b4-4825-b444-23092b0350c0)
Author
Owner

maybe it should be exclude mode, include mode (where we then treat the main server as a bypass server), and bypass mode where the current 2nd connection feature would live

maybe it should be exclude mode, include mode (where we then treat the main server as a bypass server), and bypass mode where the current 2nd connection feature would live
Author
Owner

the whole launch from gui thing can probably be removed, but like proton vpn it can be replaced with an inline removal option rather than the two click solution we have now.

And the connect button for the bypass server should probably be removed? When the option is selected and applied it should auto connect/disconnect based off the setting

the whole launch from gui thing can probably be removed, but like proton vpn it can be replaced with an inline removal option rather than the two click solution we have now. And the connect button for the bypass server should probably be removed? When the option is selected and applied it should auto connect/disconnect based off the setting
Author
Owner

unless it's heavily fought for the whole UX rework is probably gonna involve slowing bringing every option into a single page? Current vision is one "page" which is status/server list combined, with the option page gotten to from a burger menu, again similar to proton vpn. Since options aren't really something users will interact with daily in the same way status/server page will be. Might still be worth having tabs in options just to make it more readable. or at least headers for different logical sections.

unless it's heavily fought for the whole UX rework is probably gonna involve slowing bringing every option into a single page? Current vision is one "page" which is status/server list combined, with the option page gotten to from a burger menu, again similar to proton vpn. Since options aren't really something users will interact with daily in the same way status/server page will be. Might still be worth having tabs in options just to make it more readable. or at least headers for different logical sections.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
mysticalsoap/aqomui#67
No description provided.