Skip to content

feat(linux): add headless CLI client - #237

Open
mohs3n71 wants to merge 4 commits into
UnboundTechCo:devfrom
mohs3n71:feat/linux-headless-cli
Open

feat(linux): add headless CLI client#237
mohs3n71 wants to merge 4 commits into
UnboundTechCo:devfrom
mohs3n71:feat/linux-headless-cli

Conversation

@mohs3n71

@mohs3n71 mohs3n71 commented Jul 29, 2026

Copy link
Copy Markdown

Change Description

This PR adds an optional terminal-only Linux client for running DefyxVPN on
servers, SSH-only hosts, containers, and minimal installations.

defyxvpn-cli reuses the existing Linux DXcore library without linking Flutter,
GTK, Firebase, or display-server libraries. It runs in the foreground for shell
or systemd supervision. No Dart, GUI, or existing application code is changed.

Main changes

  • Adds C++17 connect, status, and disconnect commands.
  • Retrieves online, encrypted cached, or signed offline flowlines.
  • Derives the default connection pattern from enabled labels in published order,
    matching the desktop client.
  • Handles termination signals and cleans up DXcore and runtime state.
  • Prevents duplicate instances for the same cache directory.
  • Supports connection timeouts, deep scan, logging controls, custom paths, and
    environment variables.
  • Adds configurable SOCKS5 bind address and port.
  • Adds an in-process TCP relay for exposing DXcore's local SOCKS5 endpoint.
  • Preserves TCP half-closes in both directions.
  • Adds opt-in startup and periodic HTTPS data-path validation.
  • Supports automatic connection-method failover at startup and runtime.
  • Includes unit and integration tests, systemd examples, documentation, CI, and
    a Linux x86_64 artifact.

Networking and security

DXcore's 127.0.0.1:5000 SOCKS5 endpoint remains the default. To listen on a
different address or port, the CLI starts an in-process TCP relay:

defyxvpn-cli connect \
  --listen-address 0.0.0.0 \
  --listen-port 1080

The relay preserves TCP half-closes. An EOF from one direction is propagated
with shutdown(SHUT_WR) while the reverse response remains readable.

LAN exposure is opt-in and unauthenticated, so non-loopback binds produce a
warning. Addresses and ports are validated, 0.0.0.0:5000 is rejected because
it conflicts with DXcore's internal listener, and simultaneous relay
connections are limited to 256.

A LAN-facing port should be restricted to trusted clients with the host or
network firewall.

The CLI does not create a TUN interface, modify system routes, install
certificates, or change system proxy settings.

HTTPS health validation and failover

DXcore can report VPN connected even when a selected route cannot transfer a
complete HTTPS response. Small connectivity checks may also pass while larger
TLS responses are truncated.

When --health-check is enabled, the CLI:

  1. Starts one enabled connection-method label at a time in published order.
  2. Keeps the public status at checking after DXcore reports connected.
  3. Downloads a deterministic 64 KiB HTTPS response through the actual SOCKS5
    data path.
  4. Requires curl success, an HTTP 2xx response, and the configured minimum byte
    count.
  5. Rejects truncated responses, TLS errors, timeouts, and non-2xx responses.
  6. Stops an unhealthy startup method and tries the next enabled label.
  7. Reports the proxy as connected only after the startup probe passes.
  8. Repeats the same end-to-end probe at a configurable runtime interval.
  9. Resets the runtime failure counter whenever a probe succeeds.
  10. Fails over after the configured number of consecutive runtime failures.

Example:

defyxvpn-cli connect \
  --pattern "Hive,Xray,Outline,Masque" \
  --listen-address 0.0.0.0 \
  --listen-port 1080 \
  --health-check \
  --health-check-interval 60 \
  --health-check-failures 2 \
  --timeout 90

The defaults are:

  • Health-check URL:
    https://speed.cloudflare.com/__down?bytes=65536
  • Minimum complete response: 65536 bytes
  • Per-check timeout: 20 seconds
  • Runtime interval: 60 seconds
  • Consecutive failures before failover: 2

These settings are configurable through command-line arguments or environment
variables:

--health-check-url              DEFYX_HEALTH_CHECK_URL
--health-check-min-bytes        DEFYX_HEALTH_CHECK_MIN_BYTES
--health-check-timeout          DEFYX_HEALTH_CHECK_TIMEOUT
--health-check-interval         DEFYX_HEALTH_CHECK_INTERVAL
--health-check-failures         DEFYX_HEALTH_CHECK_FAILURES

Setting --health-check-interval 0 keeps startup validation enabled but
disables the CLI's periodic probes.

The probe invokes curl directly with posix_spawnp and fixed arguments,
without a shell. It disables user curl configuration, resolves DNS through the
SOCKS5 proxy, follows HTTPS redirects only, and uses the operating system's CA
certificate store.

DXcore's internal health monitor remains enabled independently.

Runtime failure behavior

A DXcore failed or unexpected stopped event immediately marks the current
method unhealthy without waiting for the next periodic probe.

During runtime failover, the CLI:

  1. Stops the current DXcore attempt.
  2. Clears the previous connection state.
  3. Resets the connection timeout for the new attempt.
  4. Starts the next enabled connection method.

If no methods remain, the CLI exits with code 4. The provided systemd service
uses Restart=on-failure, waits five seconds, and starts again from the first
method.


Related Platforms

  • Android
  • iOS
  • iPad
  • Windows
  • Linux
  • Android TV
  • OpenWrt

Verification Checklist

  • Project builds successfully
  • CLI runs without crashes on the tested platform
  • VPN connection works correctly
  • SOCKS5 proxy works from another LAN device
  • HTTPS traffic works through the proxy
  • Startup method failover works
  • Periodic runtime monitoring works
  • Runtime failure handling has integration coverage
  • No obvious regressions observed in the tested CLI scope
  • Documentation updated
  • Added or updated unit and integration tests
  • Checked security and edge cases

Automated verification

  • Built with GCC 13.3, CMake, and Ninja.
  • Tested with Release and RelWithDebInfo configurations.
  • Built with all configured compiler warnings enabled.
  • CTest result: 2/2 passed using the optimized Linux binary.
  • Tests cover option parsing, flowline handling, runtime status, HTTPS health
    checks, TCP relay half-closes, startup method failover, configurable periodic
    checks, consecutive failure counting, and runtime failure exit code 4.
  • The runtime integration test passes startup validation, simulates two
    consecutive periodic failures, and verifies the expected failover messages
    and exit status.

The GUI and non-Ubuntu distributions were not exercised. The available
production DXcore library currently limits the artifact to Linux x86_64.

@mohs3n71
mohs3n71 marked this pull request as draft July 29, 2026 03:28
@mohs3n71
mohs3n71 marked this pull request as ready for review July 29, 2026 04:10
@mohs3n71

Copy link
Copy Markdown
Author

Update: periodic runtime health monitoring

Follow-up commit bb79d2f adds configurable runtime health checks and automatic
method failover.

  • Runs the existing end-to-end HTTPS probe every 60 seconds by default.
  • Requires two consecutive failures before switching methods.
  • Resets the failure counter after recovery.
  • Immediately fails over when DXcore reports failed or unexpectedly stopped.
  • Supports --health-check-interval and --health-check-failures, with matching
    environment variables.
  • Setting the interval to 0 preserves startup validation while disabling
    periodic CLI checks.
  • Adds unit tests and integration coverage for consecutive runtime failures and
    exit code 4.

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