Skip to content

feat: Add Portmaster compatibility and extract IPC client into standalone module#485

Merged
stenya merged 16 commits intodevelopmentfrom
feature/pm_compatibility
Mar 10, 2026
Merged

feat: Add Portmaster compatibility and extract IPC client into standalone module#485
stenya merged 16 commits intodevelopmentfrom
feature/pm_compatibility

Conversation

@stenya
Copy link
Member

@stenya stenya commented Mar 10, 2026

Summary

This PR adds compatibility with Portmaster, refactors the daemon IPC client into a standalone Go module, introduces active VPN
remote endpoint tracking, and includes several DNS and UI improvements.

Changes

Portmaster Compatibility

  • Add interoperability layer (daemon/interoperability/portmaster/) to notify Portmaster of VPN
    connect/disconnect lifecycle events
  • Centralize Portmaster connection lifecycle tracking
  • Improve client connection checks for correct coexistence with Portmaster
  • Support Portmaster-controlled DNS: honor temporary DNS overrides set by Portmaster
  • On Linux: adjust firewall rule insertion order so Portmaster and IVPN rules do not conflict

New: ivpnclient Standalone Module

  • Extract the daemon IPC client into a standalone Go module at daemon/protocol/ivpnclient/
  • Implement platform-specific daemon socket/pipe file location resolution (Linux, macOS, Windows)
  • Update CLI and other consumers to use the new module

Active Remote Endpoint Tracking

  • Add protocol support for exposing the active VPN remote endpoint (ActiveRemoteEndpoint)
  • Daemon notifies connected clients of the endpoint upon VPN connection and on request

DNS Refactoring

  • Extract DNS-related logic from service.go into a dedicated service_dns.go
  • CLI enhances DNS state output by prioritizing temporary (override) DNS information
  • UI disables AntiTracker and Custom DNS settings when a prioritized DNS is active

Protocol & UI

  • Add connect timeout to daemon IPC client
  • Add ComponentReplacer.vue UI utility component

stenya and others added 16 commits February 19, 2026 17:24
Move shared protocol primitives (CommandBase, RequestBase, ErrorResp,
Hello, ClientTypeEnum, etc.) out of daemon/protocol/types and into a
new self-contained module at daemon/protocol/ivpnclient.

- Add daemon/protocol/ivpnclient as a separate Go module with its own
  go.mod/go.sum; implement Client, Connection, responseAwaiter, helpers
  and types within the new package
- Refactor cli/protocol/client.go to delegate to ivpnclient.Client,
  removing the hand-rolled receiver/send logic (client_private.go deleted)
- Update daemon/protocol/types to embed ivpnclient types instead of
  redefining them; remove duplicate ErrorResp, Hello, ClientTypeEnum
- Change message index type from int to uint32 throughout the protocol
  layer (ICommandBase, Send, sendResponse, etc.)
- Add replace directives in daemon/go.mod and cli/go.mod pointing to
  the local module path
- Add README for the new ivpnclient module
The ivpnclient module now locates the daemon port file and paranoid-mode
secret file on its own, eliminating the need for callers to supply file
paths, port numbers or secret values at construction time.

Changes:
- ivpnclient: remove port/secret constructor params from NewClient and
  NewClientAsRoot; read port.txt and eaa lazily inside Connect()
- ivpnclient/helpers.go: add getConnectionFiles() with platform-specific
  base-dir logic (macOS, Linux with snap fallback, Windows via registry);
  add linuxSnapCommon() helper
- ivpnclient/helpers_windows.go: new file - reads IVPN install folder
  from HKLM\Software\IVPN Client via golang.org/x/sys/windows/registry
- ivpnclient/client.go: fix getNextMsgIdx() atomic race (use Add return
  value directly); fix recvMessagesHandler defer to log after Unlock
- ivpnclient/README.md: update usage examples for new API
- cli/main.go: remove readDaemonPort()
- cli/protocol/client.go: drop port/secret params from CreateClient and
  the underlying ivpnclient.NewClient call
- Add Portmaster ping on daemon startup to signal IVPN is alive
- Introduce temporary prioritized DNS (TempPrioritizedDns) that overrides all other DNS settings (AntiTracker, manual DNS) for external clients
- Add SetTempPrioritizedDns protocol command; clear temp DNS automatically  on client disconnect
- Add GetBinariesInfo protocol command returning paths of bundled binaries
- Add GetAlternateDnsStatus to Hello request for immediate DNS state sync
- Refactor ConnectedResp/DisconnectedResp/DisconnectionReason from  protocol/types into protocol/ivpnclient for external client reuse
- Refactor SetDnsOverride to accept pointer params for partial updates;  remove stale lastManualDNS global from dns package
- Bind daemon TCP connections and portmaster pings explicitly to 127.0.0.1
- Add ClientPortmaster client type and IsPrioritizedDnsDefined to  connectionInfo; guard SetAlternateDns when temp DNS is active
- UI: add ComponentReplacer overlay component; hide AntiTracker toggle and  overlay DNS/AntiTracker settings pages when temp prioritized DNS is active
- UI: store tempPrioritizedDns state and expose getPrioritizedDNS getter
…: checks

- Add `portmasterDetected` atomic flag to track if Portmaster was previously seen
- Add `pingRunning` concurrency guard to prevent overlapping pings
- Increase Portmaster HTTP timeout from 2s to 5s
- Introduce `pingDetectedInteroperableApps()` and call it on VPN connect/disconnect and unexpected client drop, so Portmaster can reconnect after a dropped connection
- Refactor `IsClientConnected(checkOnlyUiClients bool)` into two explicit methods: `IsClientConnected()` and `IsMainClientConnected()`; update all callers
- Fix CLI `DisconnectedResp` references to use `ivpnclient` package instead of `types`
…e tracking

- Add interoperability/main.go to track Portmaster connect/disconnect state
- Replace WasPortmasterDetected with WasPingSuccessful in portmaster package
- Move pingInteroperableApps/pingDetectedInteroperableApps out of Protocol into
  interoperability package (Ping/PingDetectedApps)
- Hook clientConnected/clientDisconnected in protocol_private.go to notify
  interoperability layer of client lifecycle events
- Trigger PingDetectedApps on VPN CONNECTED and DISCONNECTED state transitions
Introduce OnConnectionStarting/OnConnectionStopped protocol notifications
so external clients (e.g. Portmaster) can react before and after each
connection attempt. Refactor vpn.Process.Destination() to return port and
protocol alongside the IP, and consolidate file-location helpers into a
single cross-platform file.
…on order

- Add `connectTimeout time.Duration` parameter to `Connection.Connect()`
  and `Client.Connect()`, using `net.Dialer.Timeout` for configurable
  TCP dial timeouts
- CLI now passes a 5-second timeout when connecting to the daemon
- send `ActiveRemoteEndpoint` notification to client *before*
  `HelloResponse` instead of after
…y artifact

- block-connection-details: replace v-if hide with lowOpacity class when a
  prioritized DNS is set; disable the toggle and redirect clicks to settings;
  extend tooltip with the prioritized DNS description as a warning note

- ComponentReplacer: hide covered siblings via `visibility: hidden` when the
  overlay is active, eliminating subpixel-AA fringe artifacts and focus-ring
  bleed-through from elements beneath the overlay

safing/portmaster-shadow#34
@stenya stenya added this to the 3.15.x milestone Mar 10, 2026
@stenya stenya self-assigned this Mar 10, 2026
@stenya stenya merged commit 62c0e3e into development Mar 10, 2026
8 checks passed
@stenya stenya modified the milestones: 3.15.x, 3.15.1 Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant