Commit graph

235 commits

Author SHA1 Message Date
Alexandr Stelnykovych
ee8cde31f6 feat: Add Split Tunnel feature (Windows PoC)
Implement initial proof-of-concept for split tunnel functionality on Windows,
allowing applications to route traffic through a designated network interface
while bypassing default system routing.

Features:
- Split tunnel module with TCP/UDP proxy infrastructure
- Firewall integration with split tunnel verdict handling
- SplitTunneling context attached to connections
- Configuration options: enable toggle, interface selection, and policy rules
- UI display of split tunnel connection details in connection info panel
- Subsystem configuration for user-level access

Windows-specific implementation:
- Uses proxy-based interface routing on Windows
- Automatic or manual interface detection and binding
- Support for IPv4 and IPv6 traffic

Note: Linux implementation is under development. SPN takes precedence over
split tunnel when both are enabled, ensuring SPN connections bypass this feature.
2026-04-24 18:04:01 +03:00
Alexandr Stelnykovych
29cc58fecb refactor(proxy): simplify source address binding to use net.IP instead of strings 2026-04-24 17:58:21 +03:00
Alexandr Stelnykovych
52a3b9256a netenv: enhance interface detection with physical adapter selection
- Refactor GetInterface* functions to return InterfaceInfo with IPv4/IPv6
  addresses instead of just net.Interface
- Add pre-caching of first routable IPv4/IPv6 per interface to avoid repeated
  address list scans
- Skip loopback interfaces in cache refresh
- Add GetBestPhysicalDefaultInterfaces() to detect which physical adapters
  carry the default route per IP family, excluding VPNs/tunnels
- Implement platform-specific physical interface detection:
  * Linux: reads /proc/net/route and /proc/net/ipv6_route, uses
    /sys/class/net/*/device to identify real hardware
  * Windows: uses GetAdaptersAddresses with IfType filtering
  * Other platforms: returns not-supported error
- Add helper functions: buildInterfaceInfo, interfaceToInfo, buildInterfaceInfoDirect,
  hasRoutableIPv4, hasRoutableIPv6
- Update tests to work with new InterfaceInfo return type and add coverage
  for new features
2026-04-24 17:55:32 +03:00
Alexandr Stelnykovych
fdd04e1dd0 netenv: add cached network interface lookup
Add interfaces.go with GetInterface, GetInterfaceByIP, GetInterfaceByMAC
and GetInterfaceByName for resolving local network interfaces by IP, MAC,
or name.

- Lazy init: no work until first call
- sync.RWMutex with double-checked locking for concurrent read throughput
- Refresh throttled to once per second to absorb rapid interface churn
  (same NetworkChangedFlag pattern used across netenv)
- Only live, routable interfaces cached: FlagUp required; link-local and
  address-less interfaces excluded as unsuitable for TCP/UDP tunneling
2026-04-23 17:32:31 +03:00
Alexandr Stelnykovych
933323d5f9 feat: add VerdictRerouteToSplitTun verdict type
Add a new verdict (value 8) for routing connections through the split
tunnel. This prepares the infrastructure for the upcoming split-tunneling
feature without implementing the full feature yet.

Changes:
- Define VerdictRerouteToSplitTun in network/status.go with String() and Verb()
- Add RerouteToSplitTun() to the Packet interface and InfoPacket stub
- Implement RerouteToSplitTun() for windowskext (v1) and windowskext2 (v2) packets
- Map VerdictRerouteToSplitTun to KextVerdict 11 in kextinterface and kext2
- Handle the verdict in packet_handler.go dispatch, connection.go, api.go,
  metrics.go and nameserver.go
- Add VerdictRerouteToSplitTun = 8 to Angular Verdict enum and update
  stats counting, filter queries and verdict CSS class

(WIP) Note: Linux (nfq) implementation not updated yet. Therefore Linux build will fail.
2026-04-17 20:48:48 +03:00
Alexandr Stelnykovych
52bfe1750f service/splittun/proxy: refactor DeciderFunc API and extract session cache
- Change DeciderFunc signature to return (remoteIP net.IP,
  remotePort uint16, localAddr string, extraInfo any, err error)
  instead of a single "host:port" dest string
- Extract ConnContext, Metrics, sessionCache, and idCounter into
  a new cache.go file
- Add a secondary destKey index to sessionCache for O(1)
  FindProxiedEgressConnection lookups by upstream destination
- Attach per-session extraInfo and atomic byte/packet counters
  to ConnContext
- Update TCP and UDP proxies, tests, and README accordingly
2026-04-17 20:30:36 +03:00
Alexandr Stelnykovych
f5bad230fc Merge branch 'development' into feature/split-tunneling 2026-04-14 12:22:48 +03:00
Alexandr Stelnykovych
7fca633cd8 test(resolver): TestResolveIPAndValidate fix
Some checks failed
Go / Linter (push) Has been cancelled
Go / Test & Build (push) Has been cancelled
Release v2.X / Prep (push) Has been cancelled
Release v2.X / Installer linux (push) Has been cancelled
Release v2.X / Installer windows (push) Has been cancelled
2026-04-13 18:17:20 +03:00
Alexandr Stelnykovych
0c83c5c1b9 test(resolver): refresh public suffix expectations after x/net PSL update 2026-04-13 17:22:14 +03:00
Alexandr Stelnykovych
fab4d3e68b fix: fix variable shadowing in copyAndCheckSHA256Sum
Separate variable declaration from assignment in the SHA256 validation
logic to prevent variable shadowing and ensure proper error handling
scope.
2026-04-10 13:30:22 +03:00
Alexandr Stelnykovych
14a8df4b11 Restart UI process (Tauri) after automatic update
https://github.com/safing/portmaster-shadow/issues/40
2026-04-10 13:12:04 +03:00
Alexandr Stelnykovych
b298265c46 fix(updates): prevent downgrade due to CDN caching issues for recent index updates
Some checks failed
Go / Linter (push) Has been cancelled
Go / Test & Build (push) Has been cancelled
Release v2.X / Prep (push) Has been cancelled
Release v2.X / Installer linux (push) Has been cancelled
Release v2.X / Installer windows (push) Has been cancelled
https://github.com/safing/portmaster-shadow/issues/39
2026-04-03 13:26:51 +03:00
Alexandr Stelnykovych
d8cc799203 fix(interop/ivpn): Handle local service port connections
Some checks are pending
Go / Linter (push) Waiting to run
Go / Test & Build (push) Waiting to run
Release v2.X / Installer windows (push) Blocked by required conditions
Release v2.X / Prep (push) Waiting to run
Release v2.X / Installer linux (push) Blocked by required conditions
The changes add support for tracking and properly routing connections to the IVPN client's local service port,
which is needed when the default firewall action is to block unknown connections.
The verdict handler is now registered earlier in the connection flow to handle connections while the client is connecting.

https://github.com/safing/portmaster-shadow/issues/34
2026-04-03 10:13:07 +03:00
Alexandr Stelnykovych
a3f746d2b1 fix: avoid error "config: request for unregistered option: spn/enable"
Some checks failed
Go / Linter (push) Has been cancelled
Go / Test & Build (push) Has been cancelled
Release v2.X / Prep (push) Has been cancelled
Release v2.X / Installer linux (push) Has been cancelled
Release v2.X / Installer windows (push) Has been cancelled
Access option 'spn/enable' only after full initialisation by replacing
the eagerly-initialised struct field (config.GetAsBool called at
construction time) with local variables declared at the call-site of
each function that needs the option.

Affected: service/control, service/interop/ivpn
2026-04-01 15:17:13 +03:00
Alexandr Stelnykovych
b2805d35ae interop/ivpn: suppress network-derived location while VPN is active
Some checks failed
Go / Linter (push) Has been cancelled
Go / Test & Build (push) Has been cancelled
Release v2.X / Prep (push) Has been cancelled
Release v2.X / Installer linux (push) Has been cancelled
Release v2.X / Installer windows (push) Has been cancelled
When IVPN connects, virtual interface IPs can cause netenv to detect
the VPN egress as the device's physical location, leading to a wrong
SPN home hub selection. Fix this by gating interface- and traceroute-
based location methods behind a new flag.

- Add DisableNetworkDerivedLocation(bool) to netenv/location.go backed
  by an atomic.Bool; getLocationFromInterfaces and getLocationFromTraceroute
  return early when the flag is set
- Call DisableNetworkDerivedLocation(true) in onConnectionStarting and
  DisableNetworkDerivedLocation(false) in onConnectionStopped and in the
  connectIvpnClient defer (covers unexpected client disconnects)

https://github.com/safing/portmaster-shadow/issues/34
2026-03-27 17:00:19 +02:00
Alexandr Stelnykovych
e0fc06aa49 interop/ivpn/windows: bind SPN connections to physical interface on Windows
Add a Windows-specific hook that calls conf.SetBindAddr with the default
physical interface's addresses when SPN is connecting. This ensures SPN
hub traffic bypasses the IVPN tunnel rather than being routed through it.

- Add hook_windows.go with spnConnectingHook that reads the default
  interface via netenv.GetDefaultInterface and sets the SPN bind address
- Update hook_default.go build constraint to exclude windows
- Export DefaultNetInterface and GetDefaultInterface in netenv to allow
  cross-package access from the ivpn interop layer

https://github.com/safing/portmaster-shadow/issues/34
2026-03-27 16:04:45 +02:00
Alexandr Stelnykovych
25ce0e545f firewall/Linux: add MarkAcceptFinal to bypass third-party iptables OUTPUT rules for Portmaster-owned connections
Introduce mark 1709 (MarkAcceptFinal) and a corresponding
PermanentAcceptFinal() method that sets this mark on packets belonging
to Portmaster-owned outbound connections.

Add iptables rules (both IPv4 and IPv6, filter and mangle chains) to
ACCEPT packets/connections carrying mark 1709, so  further OUTPUT rules from
third-party software (e.g. iVPN) cannot override the allow decision.

https://github.com/safing/portmaster-shadow/issues/34
2026-03-27 14:04:45 +02:00
Alexandr Stelnykovych
2252fd17ed ivpn/linux: route SPN hub traffic around VPN tunnel (split tunnel)
Add a synchronous HookMgr[T] that lets callers register pre-connect
hooks before SPN dials a home hub. The IVPN interop layer subscribes
to this hook and uses Linux ip-rule/ip-route to steer SPN hub IPs
through a dedicated routing table (717) pointing to the non-VPN default
gateway, preventing SPN control traffic from being tunnelled into IVPN.

- service/mgr: add generic HookMgr[T] (synchronous, cancellable)
- spn/captain: expose HookSPNConnecting; invoke it in connectToHomeHub
- service/netenv: add GatewayInfo + GatewaysInfo() with interface/mask
- service/interop/ivpn: add ensureSpnHubBypassVpnRoutes managing policy
  routing; call it from the SPN pre-connect hook and on VPN stop/connect
- nfq/packet: add hex comments next to mark constants

https://github.com/safing/portmaster-shadow/issues/34
2026-03-26 23:20:34 +02:00
Alexandr Stelnykovych
7523eb038b fix(ivpn): add Linux WireGuard SPN compatibility fallback for iptables raw rules
Some checks failed
Go / Linter (push) Has been cancelled
Go / Test & Build (push) Has been cancelled
Release v2.X / Prep (push) Has been cancelled
Release v2.X / Installer linux (push) Has been cancelled
Release v2.X / Installer windows (push) Has been cancelled
When nft/nftables is unavailable on a Linux host, wg-quick falls back to
installing equivalent kill-switch rules via iptables (raw/PREROUTING).
This change adds support for that fallback path so SPN reverse-NAT loopback
traffic is allowed in both backends, while keeping rule scope narrow and
cleanup idempotent.

- extend SPN compatibility reconcile logic to support both nft and iptables backends
- keep nft path as preferred behavior and continue tracking/removing inserted nft rule by handle
- add strict iptables raw PREROUTING fallback rule for loopback reverse-NAT traffic when nft is unavailable
- make rule lifecycle idempotent by cleaning previously managed rules before re-adding on state changes
- refresh inline documentation to describe dual-backend behavior and safety scope
- ensure compatibility rules are reconciled/removed on IVPN disconnect and failed connection teardown

https://github.com/safing/portmaster-shadow/issues/34
2026-03-25 17:37:45 +02:00
Alexandr Stelnykovych
22e4bd5912 fix(ivpn): add event handlers and Linux WireGuard SPN compatibility nft rule
- split IVPN event handlers into dedicated file and add ConnectedResp handling
- store connected session details in client status for follow-up compatibility logic
- add Linux-only SPN compatibility hook that reconciles an nft allow rule for WG loopback reverse-NAT traffic
- track and clean up inserted nft rule handles to avoid stale rules
- add non-Linux no-op hook implementation and trigger compatibility reconciliation on config changes

https://github.com/safing/portmaster-shadow/issues/34
2026-03-25 16:08:03 +02:00
Alexandr Stelnykovych
368822a17e fix(firewall;interop/ivpn): apply external verdict handler in all connection filtering paths
Some checks failed
Go / Test & Build (push) Failing after 7s
Go / Linter (push) Failing after 4m0s
Release v2.X / Prep (push) Failing after 14m30s
Release v2.X / Installer windows (push) Has been cancelled
Release v2.X / Installer linux (push) Has been cancelled
Previously, the external verdict handler was placed in filterHandler,
which is only called for new packets. This meant it was silently
bypassed when connections were re-evaluated via resetConnectionVerdict.

Move the handler into FilterConnection so it is consistently applied
for all filtering paths, including verdict resets.

https://github.com/safing/portmaster-shadow/issues/34
2026-03-17 15:38:09 +02:00
Alexandr Stelnykovych
26a8c03295 fix(ivpn): update VerdictHandler to return skipTunnel flag for better handling of connections 2026-03-17 13:03:26 +02:00
Alexandr Stelnykovych
15c495f5c9 feat(interception; Linux): ensure iptables jump rules remain at top of chains on startup
Add ensureJumpRulesAtTop and reinsertDisplacedRules to detect and fix
iptables jump rules that have been displaced by other services during
boot. A background worker runs checks at 5s, 15s, and 45s after nfqueue
interception starts, reinserting any out-of-position rules.
2026-03-17 12:08:42 +02:00
Alexandr Stelnykovych
93fb39825d fix(interception): streamline rule insertion logic in activateIPTables 2026-03-17 10:48:55 +02:00
Alexandr Stelnykovych
d301699bd8 fix(updates): improve ShouldUpgradeTo logic
- fixed issue where downgrades were blocked due to an overly broad
  Published date check
- added symmetric version/date mismatch checks for both upgrades and
  downgrades, skipped when current index is locally generated
- locally generated indexes now follow the standard upgrade path;
  upgrading to the same version is explicitly blocked

https://github.com/safing/portmaster-shadow/issues/39
2026-03-17 10:26:21 +02:00
Alexandr Stelnykovych
39a0035c2a fix: correct typo in notification message
https://github.com/safing/portmaster/issues/2113
2026-03-12 15:38:08 +02:00
Alexandr Stelnykovych
971d52b1ec feat(interop/ivpn): Add notification for incompatible IVPN Client version 2026-03-12 15:34:08 +02:00
Alexandr Stelnykovych
d07da4e350 feat(resolver): persist stale cache notification suppression
Add "Don't show again" action to the stale cache notification.
Suppression state is stored in the database and checked on startup.
System notification is shown only on first occurrence.
Reset handler in broadcasts now also clears the suppression record.

https://github.com/safing/portmaster/issues/2061
2026-03-10 00:18:53 +02:00
Alexandr Stelnykovych
183ac069eb feat(interop/ivpn): simplify IVPN detection notification message and update action text 2026-03-10 00:14:08 +02:00
Alexandr Stelnykovych
939010a6ef feat(interop/ivpn): show compatibility notification with persistent suppress option
When Portmaster connects to the IVPN Client, display an info notification
informing the user that IVPN connections are allowed and that DNS will be
handled by Portmaster's local resolver when configured.

The notification includes a "Do not notify me anymore" action that
permanently suppresses future notifications by writing a marker record to
the core database. The check runs before showing the notification on each
subsequent connection.

The "Reset Notification States" API endpoint (and matching UI menu item)
now also clears the IVPN suppression record alongside the broadcast states,
so all suppressed notifications can be restored at once.

- service/interop/ivpn: add notification.go with initAndShowNotification,
  isNotificationSuppressed, and suppressNotification
- service/interop/ivpn/ivpn.go: show notification on connect if not suppressed
- service/broadcasts/api.go: extend reset-state handler to also delete the
  IVPN suppression record; update endpoint name and description
- desktop: rename "Reset Broadcast State" menu item and toast messages to
  "Reset Notifications State"
2026-03-09 22:16:04 +02:00
Alexandr Stelnykovych
2f58deafea service/splittun/proxy: add Layer-4 TCP/UDP proxy package
Introduces a standalone Go module with a minimal Layer-4 proxy used by
the split-tunnelling subsystem:

- DeciderFunc injects routing and optional source-address binding per
  session, enabling per-connection traffic steering.
- TCPProxy: accept loop, bidirectional pipe with pooled 32 KiB buffers,
  rolling read/write deadlines, half-close propagation, and graceful
  shutdown via context cancellation.
- UDPProxy: single listen socket with a NAT-like session table keyed by
  client address, double-checked locking for burst safety, idle eviction
  loop, and per-session upstream sockets.
- Shared Config (MaxSessions, ReadTimeout, WriteTimeout, BufferSize,
  DialTimeout), ConnContext with atomic byte/packet counters, and a
  sessionCache with aggregate Metrics.
- Full test suite (functional + race) and benchmarks for throughput and
  session creation cost.
2026-03-06 17:20:39 +02:00
Alexandr Stelnykovych
73460f522d interop/ivpn: bugfixes and refactor connection state management
Bugs fixed:
- Inbound UDP from VPN server incorrectly blocked
- Firewall verdicts possible before client status initialized

Also: move interop before interception in startup order, simplify DNS state tracking.
2026-03-01 21:00:03 +02:00
Alexandr Stelnykovych
8396300b05 feat(interoperability/ivpn): disable custom DNS when Portmaster interception is paused
Add EventStartStopState event  manager and IsStarted() method
to the Interception module so other modules can react to start/stop state changes.

Update IVPN interop to subscribe to interception start/stop events
and skip applying custom DNS settings when interception is inactive,
ensuring correct behavior when Portmaster is in the Paused state.
2026-02-28 14:34:51 +02:00
Alexandr Stelnykovych
d40d8adbff feat(ivpn): update ivpnclient dependency and enhance hello request with active remote endpoint 2026-02-27 20:43:45 +02:00
Alexandr Stelnykovych
48c44128b6 refactor(interop/ivpn): improve client status handling and avoid stale data in firewall verdicts 2026-02-27 17:47:24 +02:00
Alexandr Stelnykovych
185a71e64b interop/ivpn,firewall: lock-free hot path via atomic.Pointer
Every connection verdict previously acquired an RWMutex to read IVPN
state. Replace it with atomic.Pointer[clientStatus] using an immutable
snapshot (copy-on-write) so reads are a single pointer load with no
locking on the per-packet hot path.

Apply the same pattern to the external verdict handler: replace a
data-racy plain function variable and two auxiliary atomic.Bool flags
with a single atomic.Pointer[ExtVerdictHandlerFunc]. Use CompareAndSwap
for set-once semantics. Move the load into the default branch of
filterHandler so pre-authenticated and DNS-redirect connections pay zero
cost.
2026-02-27 13:20:19 +02:00
Alexandr Stelnykovych
168c6ac3b5 service/interop: IVPN client interoperability
Allow Portmaster to cooperate with the IVPN client:
- Accept IVPN VPN tunnel and service process connections
- Delegate DNS control to Portmaster when custom DNS is configured
- Auto-connect to IVPN daemon on startup and on ping
- Hook into firewall verdict pipeline via new ExtVerdictHandler
2026-02-27 00:32:33 +02:00
Alexandr Stelnykovych
9af071ef17 fix(control): ensure wall-clock comparison for resume worker deadline
Some checks failed
Go / Test & Build (push) Has been cancelled
Release v2.X / Prep (push) Has been cancelled
Go / Linter (push) Has been cancelled
Release v2.X / Installer linux (push) Has been cancelled
Release v2.X / Installer windows (push) Has been cancelled
2025-12-01 13:32:46 +02:00
Alexandr Stelnykovych
aa507572d0 fix(group): correct IsStopped logic to use local state variable 2025-11-28 13:34:07 +02:00
Alexandr Stelnykovych
569e0a70dd fix(control): wait for SPN to fully stop before completing pause operation 2025-11-28 13:26:14 +02:00
Alexandr Stelnykovych
b12729cb3a Permanent verdict for accepted API outbound packets 2025-11-27 16:36:49 +02:00
Alexandr Stelnykovych
b43905aac5 Refactor resume worker to handle unexpected wall-clock changes and improve SPN auto-resume logic 2025-11-27 16:27:59 +02:00
Alexandr Stelnykovych
1208783f34 Enhance fast-tracking for API connections to maintain seamless UI experience after pause
Some checks failed
Go / Linter (push) Has been cancelled
Go / Test & Build (push) Has been cancelled
Release v2.X / Prep (push) Has been cancelled
Release v2.X / Installer windows (push) Has been cancelled
Release v2.X / Installer linux (push) Has been cancelled
2025-11-26 17:39:42 +02:00
Alexandr Stelnykovych
d635db77c2 Improve pause info display and error handling
Some checks failed
Go / Linter (push) Waiting to run
Go / Test & Build (push) Waiting to run
Release v2.X / Prep (push) Waiting to run
Release v2.X / Installer linux (push) Blocked by required conditions
Release v2.X / Installer windows (push) Blocked by required conditions
Angular / Lint (push) Has been cancelled
Angular / Build (push) Has been cancelled
Tauri / Build (push) Has been cancelled
Tauri / Linter (push) Has been cancelled
2025-11-26 13:01:24 +02:00
Alexandr Stelnykovych
4913147dd5 (UI) minor update of update pause notification messages
Some checks failed
Angular / Lint (push) Has been cancelled
Angular / Build (push) Has been cancelled
Go / Linter (push) Has been cancelled
Go / Test & Build (push) Has been cancelled
Release v2.X / Prep (push) Has been cancelled
Tauri / Build (push) Has been cancelled
Tauri / Linter (push) Has been cancelled
Release v2.X / Installer linux (push) Has been cancelled
Release v2.X / Installer windows (push) Has been cancelled
2025-11-21 14:07:57 +02:00
Alexandr Stelnykovych
063fa7f115 fix(interception): ensure metrics are stopped on failed module start 2025-11-12 14:24:24 +02:00
Alexandr Stelnykovych
14be84d2d0 fix(instance): re-add dnsmonitor to serviceGroupInterception module 2025-11-11 18:20:10 +02:00
Alexandr Stelnykovych
83fb71b4bc Merge branch 'development' into feature/2050-pause 2025-11-11 17:33:28 +02:00
Alexandr Stelnykovych
2009dcf9c8 fix: DNSMonitor module crash on stop
Some checks are pending
Go / Linter (push) Waiting to run
Go / Test & Build (push) Waiting to run
Release v2.X / Prep (push) Waiting to run
Release v2.X / Installer linux (push) Blocked by required conditions
Release v2.X / Installer windows (push) Blocked by required conditions
Add traceEnded channel to ETWSession for better session management

https://github.com/safing/portmaster/issues/2065
2025-11-11 17:32:56 +02:00
Alexandr Stelnykovych
3abb2b3c69 feat(control): add notification for automatic resume from pause state 2025-11-11 17:18:58 +02:00