Skip to content

Latest commit

 

History

History
679 lines (568 loc) · 36 KB

client-usage.md

File metadata and controls

679 lines (568 loc) · 36 KB

Client Usage

Quick Start

  1. Download http-proxy-cli from releases (choose your platform)
  2. Run: http-proxy-cli -s <server-ip> -c <local-port> --set-system-proxy
  3. Done! The --set-system-proxy flag auto-configures your OS proxy.

Without --set-system-proxy, manually configure system proxy to 127.0.0.1:<local-port>.

CLI Options

Option Description
-s, --server-host Server IP/domain (required)
-c, --client-port Local port (default: 1080)
-p, --server-port Server port (default: 1081)
--transport <tcp|quic> Native upstream carrier; a bare server host defaults to TCP
--quic-ca <PEM> Additional QUIC trust anchor; hostname verification remains required
-k, --key 32-byte encryption key
--set-system-proxy Auto-set OS proxy (Linux/macOS/Windows)
--reverse-geo Reverse geo logic: proxy CN, direct others
-m, --msg-key Enable random message key
--udp <true|false> Enable SOCKS5 UDP ASSOCIATE (default: false)
--tun Capture device traffic with a local TUN interface
--tun-fake-ip true Opt into virtual DNS; defaults to real answers resolved through the proxy
--tun-dns-server <IP> Resolver reached through the proxy for the TUN DNS portal (default: 223.5.5.5)
--tun-udp-direct-fallback <true|false> Send UDP directly when proxy UDP is off; false blocks it (default: true)
--tun-bypass-process <name> Bypass TUN for an executable name (repeatable)
--tun-list-processes List running Windows executable names and exit

SOCKS5 UDP ASSOCIATE

The upstream carrier can be TCP or QUIC independently of this UDP association. See QUIC configuration and live switching.

http-proxy-cli accepts RFC 1928 UDP associations on the same local port used for HTTP and SOCKS5 TCP. The SOCKS5 control connection stays on TCP while the client is given a temporary UDP relay address.

UDP proxying is opt-in. Use --udp true (or udp = true in TOML), configure the application to use 127.0.0.1:<client-port> as a SOCKS5 proxy, and enable UDP in that application. With UDP proxying off, desktop TUN forwards non-DNS UDP directly by default. The SOCKS5 relay does not use Auto or reverse geographic routing: when enabled it uses the selected server, subject to explicit process bypass rules. A minimal flow is:

Application -- SOCKS5 UDP --> http-proxy-cli
            -- framed tunnel --> http-proxy-server -- UDP --> destination

Operational details:

  • Client and server must both contain UDP-association support. Older servers cannot interpret the new udp_associate transport header. If the remote end closes before the readiness byte, the client now reports this as a likely server-version mismatch instead of the unhelpful unexpected end of file.
  • UDP uses the configured remote proxy server unless the local calling process is explicitly excluded. TCP keyword/GeoIP split routing is not applied per UDP datagram.
  • --msg-key enables AES-256-GCM authentication and encryption per UDP frame.
  • socks5:// and socks5h:// upstream proxies support UDP ASSOCIATE when the upstream server implements it. socks5:// resolves domain targets locally; socks5h:// sends domain names to the upstream proxy.
  • HTTP CONNECT upstream proxies do not support UDP.
  • RFC 1928 fragmentation is not reassembled. Packets with FRAG != 0 are dropped to keep association memory bounded.
  • The UDP client address is pinned to the TCP control peer and the first valid UDP endpoint, preventing the local relay from becoming an open UDP proxy.
  • Associations close with their TCP control connection and also expire after 300 seconds without traffic. Set UDP_ASSOCIATION_IDLE_TIMEOUT_SECS on both sides to change the timeout.
  • System HTTP proxy settings, including --set-system-proxy, do not capture UDP automatically. Use an application with SOCKS5 UDP support or a TUN adapter that emits SOCKS5 UDP ASSOCIATE.

TUN Mode

TUN mode sends device traffic to the SOCKS5 listener already hosted on the client port. It does not require a second proxy process:

Application TCP/UDP -> Wintun -> tun2proxy -> 127.0.0.1:<client-port>
                    -> proxy-everything client -> remote server -> destination

On Android, the Flutter client replaces Wintun and desktop route setup with an Android VpnService interface. Kotlin owns the TUN descriptor, Rust forwards a duplicate through the same tun2proxy and local SOCKS5 path, and Android applies capture policy by application package name.

The local port is a protocol-multiplexed HTTP/SOCKS5 listener, but tun2proxy deliberately uses its SOCKS5 endpoint because SOCKS5 preserves both TCP and UDP semantics. A successful local listener bind is therefore a prerequisite for starting TUN. Captured DNS queries (UDP or TCP on port 53) use TCP through the proxy, returning real addresses even when ordinary UDP forwarding is disabled. Keeping DNS inside the proxy prevents incorrect answers from the local network from directing proxied connections to unrelated servers.

Apple packet-tunnel builds apply a fixed UDP destination policy: mainland China and local-network destinations are direct; other destinations receive ICMP port unreachable unless UDP proxy is explicitly enabled. Enabling it requires server UDP readiness and proxies only foreign destinations. TCP Auto and reverse routing do not change this policy. DNS remains available. The old direct-fallback option is not used by Apple packet tunnels; desktop TUN retains its separate policy.

On desktop, DNS sockets owned by explicitly excluded processes instead bind to the physical interface. Their ordered resolvers are AliDNS 223.5.5.5, Tencent DNSPod 119.29.29.29, AliDNS 223.6.6.6, then the physical adapter's DNS and the configured fallback. UDP retries and TCP fallback precede moving to the next resolver; a valid NXDOMAIN is final. On Windows, an observational ETW session identifies the original caller behind the shared DNS service. Matching process exclusions use physical DNS; unmatched or unattributed queries remain proxied. A provider callback timeout keeps the trace alive for late events. Other trace startup failures retry every five seconds in a TUN-owned background task, so existing DNS relays recover without restarting TUN or delaying queries for a retry. Startup failures, pending callbacks, and recovery are logged. Shutdown cancels pending retries and releases only the trace owned by that session. Previously cached answers retain their DNS TTL; this recovery does not flush the system cache. Excluding the shared DNS service itself would send other applications' DNS outside the proxy as well.

Fake-IP is optional: enable Fake-IP DNS in the GUI configuration or pass --tun-fake-ip true to the CLI to allocate virtual addresses and forward the original domain. Missing settings in older configurations default to disabled. Changing this setting requires stopping and restarting the local proxy connection, not just toggling TUN. Android exposes its DNS portal at 172.19.0.2, outside the 198.18.0.0/15 fake-IP pool, so its opportunistic private-DNS probe cannot collide with an allocated application hostname.

TUN DNS resolver IP / --tun-dns-server defaults to 223.5.5.5; saved values are preserved. It is the resolver behind the private TUN DNS portal, reached through the proxy. For explicitly bypassed DNS on desktop it is an additional fallback, not an override of the ordered physical resolvers; split-horizon enterprise DNS is not provided by that policy. Restart the proxy connection after changing it. IPv4-only TUN sessions remove AAAA records from UDP and TCP replies. The physical DNS relay for excluded processes sets DNS truncation when an upstream answer exceeds the client's UDP limit, allowing a retry over TCP. The proxied DNS relay coalesces identical UDP retransmissions while their TCP query is pending. Distinct queries reusing an ID receive separate upstream IDs; responses are validated and restored to the client's ID instead of closing the shared connection.

Native embedders can call the additive proxy_set_tun_dns_server before startup; it accepts a literal IPv4/IPv6 address (null resets the default), rejects invalid input and refuses changes while the listener runs. Existing configuration struct layouts are unchanged. New UI settings default Fake-IP off, while old macOS helper/packet-provider messages without a DNS-policy field retain their historical Fake-IP behavior; current callers send the choice explicitly.

The Flutter client supplies a stable private application-support directory on Android, iOS, Windows, macOS, and Linux. The CLI uses its existing ~/http-proxy-cli-config data directory. TUN virtual-DNS allocations are restored from those locations before capture starts, so cached fake-IP answers remain valid across process restarts and in-place upgrades on every supported client platform. Embedders using the FFI should likewise provide a stable cache_dir; leaving it null intentionally disables persistent client state. Disabling Fake-IP keeps the existing reverse mappings available for applications that still hold cached fake addresses; new DNS answers do not allocate fake IPs. The additive proxy_start_v8 ABI carries this policy explicitly. Existing V1–V7 callers retain their historical virtual-DNS behavior.

Windows keeps %APPDATA%\com.proxyui\proxy_ui as its permanent storage path, regardless of the CipherRelay display name. If that directory has any existing data, it remains authoritative and is never merged with %APPDATA%\com.proxyui\CipherRelay. Two independent Fake-IP journals can map the same address to different domains, so merging them would corrupt cached answers. Only an empty legacy directory can receive a copy of the branded installation’s preferences and cache files together; the source stays intact. Keep the existing directories as backups when trying an upgrade. If both have been used, cached answers created by the discarded generation may need to expire or the affected application may need to be restarted.

On Windows, keep wintun.dll in the same directory as http-proxy-cli.exe or CipherRelay.exe. The supported build and staging scripts place it there automatically.

CLI

Enable complete TCP and UDP capture:

.\http-proxy-cli.exe -s YOUR_SERVER_IP -p 1081 -c 1080 --tun --udp true

List current process names and let selected applications use the physical network directly:

.\http-proxy-cli.exe --tun-list-processes
.\http-proxy-cli.exe -s YOUR_SERVER_IP -c 1080 --tun `
  --tun-bypass-process browser.exe `
  --tun-bypass-process downloader

Equivalent TOML configuration:

tun = true
udp = true
tun_bypass_processes = ["browser.exe", "downloader"]

Executable matching is case-insensitive and a trailing .exe is optional. On Windows, selecting a launcher or Task Manager-style application root also bypasses its live child-process tree. The matcher uses the ToolHelp process snapshot, which remains available when a protected game process rejects direct process-handle access. If the application already cached a virtual-DNS address, the direct route restores the real destination through the physical interface. Explicit child executable selections are retained when a parent is selected or disappears. The mixed checkbox indicates inherited bypass; checking that child explicitly keeps it excluded after the launcher exits. Rules lost by an older version cannot be inferred: add the desired executable again once.

On Windows, Exclude WeGame games and services selects an application family instead of a single launcher. It covers known WeGame/LOL executables, their live descendants, executables under WeGame, WeGameApps and AntiCheatExpert directories, and independent SGuard/ACE services. It does not exclude the shared services.exe parent or generic client.exe/launcher.exe names. Custom game installations whose launcher has already exited may still need an explicit executable rule. Existing saved LOL/WeGame exclusions enable this family on upgrade; a subsequently saved off value is preserved. Native callers can use --tun-bypass-process '@group:wegame' with native 0.6.3 or later. TCP, UDP and process-attributed DNS use the same physical-interface policy, including when ordinary proxy UDP is disabled.

Native 0.6.4 also attributes questions sent by the shared Windows DNS Client service to the original caller using an owned, temporary ETW session. Every process exclusion (including launcher children and the WeGame family) applies to these DNS questions, with AliDNS and Tencent DNS preferred on the physical interface. TCP DNS and Fake-IP mode use the same per-question policy. Other callers retain the configured proxy/Fake-IP DNS path; changing process rules affects subsequent questions without restarting TUN. No domain allowlist is needed, and a shared DNS socket can carry both physical and proxied questions.

The event session requires the administrator access already needed for Windows TUN setup. Its startup or delivery failures are logged explicitly; direct socket attribution continues to work if event attribution is unavailable. Queries performed inside an application's encrypted DNS connection follow that connection's process policy. Windows can share/coalesce answers between applications, and previously cached answers are not rewritten or flushed: after upgrading, reconnect the affected application once its old DNS answers expire. This avoids changing other running applications' caches or connections.

The same explicit rules apply to local HTTP, CONNECT and SOCKS clients, including applications using the Windows system proxy. Their TCP and UDP sockets and hostname lookups bind to the physical interface; loopback destinations stay on loopback. This does not edit the Windows system-proxy bypass list. Remote LAN clients are not attributed to local processes, and this proxy's own PID is excluded before ancestor matching so TUN's internal SOCKS connections retain their original routing decision. Excluded UDP works even when proxy UDP is off. User-selected bypasses apply to new TCP or UDP sessions. On Windows and macOS, Apply evaluates existing sessions against the executable and ancestor identities recorded when each session began. Adding an unrelated application leaves existing bypasses, including the proxy's own connections, intact; it does not rescan the system socket table for every connection. A session whose owner could not be identified keeps its original proxied route until it reconnects.

When a live policy change affects an established session, tun2proxy explicitly resets that TCP connection so the application can reconnect through the new route. This also applies to DNS over TCP. Affected UDP relays are released and the next datagram creates a relay under the updated policy. The TUN adapter, physical egress binding, fake-IP mappings, and system routes remain in place.

Flutter UI

Configuration remains accessible while the proxy is starting or running. Edits and imported configurations are drafts until Apply configuration is pressed. Only applying is disabled during another proxy/TUN operation. Applying only process exclusions updates the live policy without restarting TUN; other connection changes reconnect the listener and active TUN. If startup fails, the previous configuration is restored where possible and the failure is shown. Desktop tray and sign-in preferences are also saved only after confirmation.

Start the local proxy from the primary Proxy page, then enable the top-level TUN Mode switch. The switch is disabled until 127.0.0.1:<client-port> is listening, remains busy until Wintun and route setup report ready, and stays off when native setup fails. Setup errors include the failing stage, the underlying Windows detail, and any tunnel/VPN adapters that were already active. TUN Bypass opens a Task Manager-style Windows picker with executable names, live PIDs, instance counts, executable icons, paths, and expandable launcher/child process trees. Selecting a parent application implicitly selects its descendants because native routing matches the socket owner against its live ancestor chain. The picker is available before startup and while the proxy is connected. Applying a selection updates native routing immediately, reconnects affected established sessions, and does not recreate the TUN adapter.

The Flutter listener is loopback-only by default. Proxy Configuration > Allow LAN explicitly changes the listener to 0.0.0.0:<client-port> so devices on the same network can use its HTTP or SOCKS5 endpoint. This endpoint does not authenticate LAN clients; keep the option disabled on untrusted networks and use the operating-system firewall to limit access. The UI displays the current Wi-Fi address as a copyable http://<address>:<client-port> link after LAN access is enabled.

The current UI executable appears as a required, disabled selection. This is not only a presentation rule: Rust always appends the current executable after every configuration or runtime replacement, so malformed imported settings or an FFI caller cannot remove it.

Android Flutter UI

On Android the desktop process picker is replaced by VPN Applications. Choose All to capture every eligible application, Bypass to let selected applications use the physical network, or Only to capture only selected applications. The picker displays installed application names, package names, icons, and system-app status. Application metadata is cached after the first package query, while icons are loaded only for visible rows in small batches; opening the picker therefore does not decode every installed application icon before showing the list. The refresh button explicitly rebuilds both caches. A live policy change recreates the Android VPN interface while keeping the local proxy listener active.

The CipherRelay package is always outside its own VPN so its upstream socket cannot be captured and returned to the local listener. Android shows its standard one-time VPN consent dialog on first use and a foreground notification while capture is active. See Android VPN Development for the build, descriptor-ownership, application-policy, and emulator workflow.

Privileges and shutdown

Creating Wintun and changing default routes require administrator privileges. The Windows CLI requests UAC elevation and reconnects the elevated child to the original console instead of opening a new terminal. The Windows Flutter runner uses asInvoker, so HTTP/SOCKS5-only operation never prompts. Enabling TUN launches an elevated replacement of the same GUI with ShellExecute runas; no terminal is created. The original process releases the local port and the new process retries the listener handoff before it creates Wintun.

On Windows, setup preserves the existing physical, WSL, and VPN default routes. It captures IPv4 with two more-specific /1 routes plus a session-owned 0.0.0.0/0 compatibility row so forwarding consumers such as WSL HNS NAT select Wintun even when they initialize after TUN startup. The IP Helper transaction also snapshots and enables IPv4 forwarding on Wintun and WSL HNS vEthernet interfaces. Wintun temporarily uses weak-host send/receive so NAT-translated packets whose addresses belong to another interface can traverse the TUN. A monitor applies the policy to WSL interfaces created or replaced after TUN startup. Teardown restores only interface fields and route rows changed by the current session, together with the previous TUN DNS setting. Startup failures roll back the same transaction instead of deleting every 0.0.0.0/0 route or guessing which physical default gateway should be recreated.

Normal cancellation first cancels and drains the TUN TCP, UDP, UdpGW, and socket-transfer tasks, then restores routes, interface settings, and DNS through the setup guard. On Windows a retained Wintun session keeps the adapter alive until that restoration finishes, including when forwarding fails or the outer task is cancelled. Releasing the adapter first makes restoration fail with Windows error 1168 (interface not found). TCP stream destruction cancels its packet worker without synchronously waiting on the runtime. Waiting there can exhaust the blocking worker pool when many sessions close together, preventing both shutdown and its timeout from running and leaving the desktop Stop switch disabled. Session-table removal also runs when a packet worker is cancelled. Normal TCP FIN handling remains in the asynchronous shutdown path. The native log records the child-task count and drain duration before network restoration. The final sessions_at_shutdown field is the count before draining, not a count of leaked or still-running sessions after cleanup. This prevents old relays from surviving a TUN restart while network state is already being replaced. A hard process termination or machine crash can still prevent user-space cleanup; after such an event, inspect and remove only the two /1 rows and the 0.0.0.0/0 row whose interface and next hop identify the proxy-everything Wintun adapter. Never use an unqualified default-route deletion.

On Windows, selecting a node while TUN is running keeps the existing adapter, capture routes, DNS configuration, and local listener. The client resolves the new endpoint, confirms its physical host routes through the TUN's route owner, and checks reachability before atomically publishing the new upstream. Route confirmation has a five-second deadline; TCP reachability has a separate five-second deadline, or a twelve-second UDP association preflight when SOCKS5 UDP is enabled. These bounds apply to the UI switch, not ordinary relay TCP connections. Both probes connect only to the addresses whose bypasses were prepared, including the TCP connection carrying the UDP association. A failed preparation keeps the previous upstream active, rolls back newly created provisional routes, and reports its stage/error. Failed route removals remain owned and are retried by the worker. The FFI work runs off the UI thread and is serialized with start/stop and handle destruction.

Existing connections stay on their original node until they reconnect; new connections use the selected node. Old upstream host routes remain owned by the current TUN session so those connections cannot loop back through capture. They are removed at TUN shutdown only if this session created them. A route operation that finishes after its caller timed out cannot publish a node later. Diagnostic logs distinguish resolve, bypass, connect/udp_preflight, and the final upstream commit. Other platforms retain the capture restart workflow.

Only one application should own the fixed proxy-everything Wintun adapter and its capture routes. If another VPN/TUN application or another proxy-everything instance is already active, startup stops before changing routes and names the detected adapter. Stop it before retrying TUN mode. The GUI error is the authoritative setup result; a generic numeric RuntimeError is retained only for native ABI compatibility.

Loop-prevention invariant

Loop prevention does not depend on one best-effort process lookup. Before the capture routes are installed, the client resolves its remote proxy endpoint and adds each address as a physical route bypass. Live Windows node switches install the new bypass before changing that endpoint. The current executable is also kept in the runtime process-bypass policy and cannot be removed through CLI, TOML, Flutter, or FFI input. Without these protections, the remote connection would be captured by Wintun, returned to the local SOCKS5 listener, and repeated.

The desktop GUI retains the Auto Proxy preference during TUN capture. The mandatory self-process bypass forwards captured client-owned direct sockets through the physical interface instead of sending them into the local SOCKS listener again.

Other bypassed processes connect directly to their original destinations and therefore do not use the proxy. Do not add an application to the bypass list if its traffic should remain proxied.

On Windows, process-bypassed unicast UDP reuses one physical socket across destinations for each application source endpoint. STUN discovery and subsequent P2P probes therefore use the same physical source port. This removes the extra destination-dependent mapping previously introduced by TUN forwarding; it does not change the physical network's NAT or guarantee P2P connectivity. This path applies before the ordinary UDP proxy/block setting. DNS and multicast keep their dedicated handling.

Ownership is checked using the Windows socket's PID and bind timestamp as a best-effort fingerprint. Observed disappearance, ambiguity, or a changed fingerprint retires the mapping. Windows timestamps are not unique socket IDs: a same-process close/rebind between snapshots can be indistinguishable when the timestamp is reused. Polling cannot guarantee isolation of those socket lifetimes. If the initial classification cannot supply an unambiguous owner, forwarding retains the isolated per-destination behavior. An IPv6 wildcard may also own IPv4 traffic; Windows does not expose its V6ONLY flag in this table, so IPv4 sharing remains disabled when such a bind makes ownership uncertain. A single receiver dispatches replies only to active flows for contacted remote endpoints, preserving the original destination seen by the application, including Fake-IP. Packets from uncontacted peers are dropped; unsolicited inbound P2P discovery is not enabled by this change. Two active virtual destinations resolving to the same real peer use isolated sockets when their replies cannot be disambiguated. The same fallback applies when all shared endpoint slots are active. If ownership or policy changes during setup, or cannot be revalidated before the setup timeout, the new flow is rejected rather than inheriting an earlier owner's bypass decision.

Mappings survive individual target flows and expire after 120 seconds of idle time. Socket ownership and physical egress are rechecked every two seconds; an observed owner change, egress change, bypass revocation, or TUN shutdown retires the affected endpoints. Transient snapshot failures preserve existing mappings for at most six seconds; new shared flows still require verification. Policy revocation also closes retained mappings that have no active target flows. A DNS-server-only change does not replace an unchanged UDP interface binding. Normal per-flow UDP idle timeouts still apply: after a target flow expires, its replies are dropped until the application contacts it again, even while the physical mapping is retained. The endpoint pool is capped by the session limit (at most 1024); active peers share the global session limit, with 16 queued replies per peer and 8 MiB of queued payloads across the pool. Under pressure, idle mappings can be reclaimed and excess replies dropped; active mappings are not reassigned to another source.

For excluded local HTTP/SOCKS clients, loopback destinations do not require a physical adapter. localhost supports both loopback families, including an IPv6-only service. Physical DNS resolution and socket binding are deferred until a non-local destination is used. If an IPv4 domain connection fails, the client resolves and tries IPv6; UDP retries the other family only when sending fails, since a successful UDP send cannot confirm that a service is reachable.

The Windows picker combines live processes with installed Win32 applications registered through App Paths, Uninstall metadata, and Start Menu Shell links. For registrations that only expose an application directory, scanning is bounded by depth and entry count rather than walking arbitrary drives. Use the All, Running, and Installed views to control list density. Launcher trees are expanded on first load so protected child processes remain individually selectable. Executable names keep their original casing, and search accepts registered aliases and common initialisms; for example, either lol or 英雄联盟 finds League of Legends.exe even when it is not currently running.

IPv4 and IPv6 multicast UDP is always treated as local-link traffic rather than sent to an Internet proxy. Direct relays select the physical multicast interface explicitly; on Windows, IP_UNICAST_IF is insufficient because it does not control multicast egress. Without the multicast-specific binding, an SSDP packet such as 239.255.255.250:1900 can return through Wintun, create a new proxy-ui UDP socket, and amplify into a self-sustaining relay loop.

TUN TCP continues to work with --udp false. DNS still uses the proxy path described above (or the virtual resolver when Fake-IP is enabled), while other captured UDP is relayed directly instead of being sent to the local SOCKS5 listener. This matches the practical fallback used when a selected outbound cannot carry UDP, but it means non-DNS UDP bypasses the configured proxy. Add --tun-udp-direct-fallback false to block captured non-DNS UDP instead. Both DNS modes remain available in strict mode so TCP applications can still resolve hostnames, including through DNS-over-TCP on port 53. Embedders can declare local DNS portal addresses with repeatable --virtual-dns-portal; opportunistic TLS probes to port 853 on those exact addresses are failed locally so the operating system promptly returns to plain DNS. HTTP upstream proxies cannot relay UDP, while a SOCKS5 upstream must implement UDP ASSOCIATE.

Embedded desktop and Android clients allow up to 1024 concurrent TUN sessions. The standalone tun2proxy CLI keeps its conservative 200-session default. Each session is accounted for by an owned permit so completion, cancellation, and task failure all release capacity. Limit warnings report separate TCP and UDP counts, which distinguishes a genuine TCP connection surge from UDP or QUIC flows consuming the shared budget. UDP proxy setup is bounded by the configured UDP timeout so an unavailable UDP upstream cannot retain a slot indefinitely.

When a direct UDP flow targets a virtual DNS address, tun2proxy resolves its stored hostname with DNS-over-TCP through the working TCP proxy before opening the direct UDP socket. This avoids feeding the hostname back into Android's VPN resolver and receiving a second fake IP.

When UDP is enabled, TUN startup performs an end-to-end SOCKS5 UDP ASSOCIATE preflight before creating Wintun or changing routes. This catches an old remote server, blocked UDP relay, or incompatible upstream immediately. Disable UDP explicitly and select either the default direct fallback or strict blocking.

Desktop log safeguards

The GUI requests native logs at INFO by default. Selecting WARN or ERROR only filters the view; disk diagnostics retain INFO. Selecting a more verbose level lowers the native callback threshold, but burst delivery remains capped and reports how many low-priority records were omitted. The in-memory viewer is an O(1) 1,000-entry queue and refreshes at most ten times per second. Disk logging batches writes, bounds its pending queue, caps each hourly file at 64 MiB, and retains at most 512 MiB across hourly files. These limits keep packet or connection storms from turning diagnostic work into forwarding latency or unbounded memory growth.

Native FFI logs also go to logs/proxy-native-*.log in the existing application support directory, before UI filtering or callback throttling. This independent writer preserves complete request destinations and error chains, uses an 8 MiB bounded queue, and rotates at 64 MiB, retaining eight native log files where possible. Files still owned by a running instance are exempt from cleanup and remain readable; small .log.lock sidecars coordinate ownership. Shutdown waits for queued records and the final flush, even when the queue is full. Queue overflow and disk failures are reported rather than silently truncating records. UDP relay lifecycle logs include the selected interface, socket endpoints, datagram counts and close reason. Receiving a large UDP reply now produces IP fragments of one datagram, rather than splitting it into unrelated UDP messages; empty UDP payloads are data, not stream EOF.


Windows

  1. Download http-proxy-cli-*-x86_64-pc-windows-msvc.zip from releases

  2. Extract and open Command Prompt in that directory:

    .\http-proxy-cli.exe -s YOUR_SERVER_IP -c 7890 --set-system-proxy
  3. (With --set-system-proxy) System proxy is auto-configured. Skip to step 5.

  4. (Without --set-system-proxy) Configure system proxy manually:

    • Open Settings → Network & Internet → Proxy
    • Enable "Use a proxy server"
    • Address: 127.0.0.1, Port: 7890

    Windows Proxy Settings 1 Windows Proxy Settings 2

  5. (Optional) Create start_proxy.bat for quick launch:

    @echo off
    http-proxy-cli.exe -s YOUR_SERVER_IP -c 7890
    pause

Linux

  1. Download http-proxy-cli-*-x86_64-unknown-linux-musl.tar.gz from releases

  2. Extract and run:

    tar -xzf http-proxy-cli-*-linux-musl.tar.gz
    chmod +x http-proxy-cli
    ./http-proxy-cli -s YOUR_SERVER_IP -c 7890 --set-system-proxy
  3. (With --set-system-proxy) System proxy is auto-configured via gsettings (GNOME). For other DEs, configure manually.

  4. (Without --set-system-proxy) Configure system proxy manually:

    GNOME (Ubuntu, Fedora):

    gsettings set org.gnome.system.proxy mode 'manual'
    gsettings set org.gnome.system.proxy.http host '127.0.0.1'
    gsettings set org.gnome.system.proxy.http port 7890
    gsettings set org.gnome.system.proxy.https host '127.0.0.1'
    gsettings set org.gnome.system.proxy.https port 7890

    KDE:

    • System Settings → Network Settings → Proxy → Manual
    • HTTP/HTTPS Proxy: 127.0.0.1:7890

    Terminal only:

    export http_proxy=http://127.0.0.1:7890
    export https_proxy=http://127.0.0.1:7890
  5. (Optional) Create systemd service for auto-start:

    sudo tee /etc/systemd/system/proxy-client.service << EOF
    [Unit]
    Description=Proxy Client
    After=network.target
    
    [Service]
    ExecStart=/path/to/http-proxy-cli -s YOUR_SERVER_IP -c 7890
    Restart=always
    
    [Install]
    WantedBy=multi-user.target
    EOF
    
    sudo systemctl enable --now proxy-client

macOS

  1. Download http-proxy-cli-*-x86_64-apple-darwin.tar.gz from releases

  2. Extract and run:

    tar -xzf http-proxy-cli-*-apple-darwin.tar.gz
    chmod +x http-proxy-cli
    ./http-proxy-cli -s YOUR_SERVER_IP -c 7890 --set-system-proxy
  3. (With --set-system-proxy) System proxy is auto-configured via networksetup.

  4. (Without --set-system-proxy) Configure system proxy manually:

    • System Preferences → Network → Advanced → Proxies
    • Enable "Web Proxy (HTTP)" and "Secure Web Proxy (HTTPS)"
    • Server: 127.0.0.1, Port: 7890

    Or via terminal:

    networksetup -setwebproxy "Wi-Fi" 127.0.0.1 7890
    networksetup -setsecurewebproxy "Wi-Fi" 127.0.0.1 7890

Android

Use the Flutter Android client for whole-device IPv4/IPv6 capture. Configure and start the local proxy, choose an application policy under VPN Applications, then enable VPN Service and approve Android's consent dialog. Manual Wi-Fi proxy settings are not required.

For local builds, physical-device ABIs, package visibility, and 4 KB/16 KB emulator verification, follow Android VPN Development.


iOS

The native Flutter app includes an iOS Packet Tunnel extension. A paid Apple Developer account can sign and install it on registered personal devices without publishing it on the App Store. The app and extension must share a signing team, Network Extensions capability, and Keychain access group.

Build locally on a Mac:

python3 scripts/ios/build.py --team TEAM_ID --install DEVICE_UDID

See iOS development and device installation for prerequisites, simulator builds, signing verification, current feature limits, and physical-device acceptance checks. The simulator cannot validate a real system VPN connection.