Guidance for AI coding agents (Claude Code, Copilot, Cursor, etc.) working in the snx-rs repository.
snx-rs is an unofficial open-source client for Check Point VPN tunnels, written in Rust. It speaks both the IPsec and SSL flavors of Check Point's remote access protocol and supports the full matrix of authentication flows the official Windows client supports (password + MFA, certificate, HSM token, browser-based SSO / identity provider, Mobile Access web portal, hybrid machine-certificate + user).
Repository: https://github.com/ancwrd1/snx-rs
License: AGPL-3.0 (see COPYING)
Author: Dmitry Pankratov dmitry@pankratov.net
Currently supported platforms: Linux, Windows, macOS. All platform-specific code must be isolated under platform submodule.
This is a Cargo workspace (resolver = "2", edition = "2024") declared in the root Cargo.toml. Members:
| Member | Path | Kind | Purpose |
|---|---|---|---|
snxcore |
crates/snxcore |
library | All protocol, platform, tunnel, and controller logic. Everything non-trivial lives here. |
i18n |
crates/i18n |
library | Fluent-based localization. Wraps fluent-templates and exposes tr!/translate helpers. |
snx-rs |
apps/snx-rs |
binary | The service / daemon. Runs in standalone or command mode; needs root for tunnel setup. |
snxctl |
apps/snxctl |
binary | Thin CLI that talks to snx-rs in command mode (connect/disconnect/status/info). |
snx-rs-gui |
apps/snx-rs-gui |
binary | Slint-based GUI with tray icon. Linux uses KSNI; macOS/Windows use the tray-icon crate. Talks to snx-rs over IPC. |
Top-level directories:
crates/— library crates.apps/— the three binary crates.docs/— user-facing Markdown docs (docs/README.mdis the index). Keep in sync when changing user-visible behavior.package/— packaging assets: systemd unit (snx-rs.service), desktop file, Debian and RPM packaging, installer script, LTO build script..github/workflows/—ci.yml(fmt + clippy + test),release.yml,automerge.yml,pages.yml.i18n.md— canonical instructions for translation tasks. Re-read before doing any locale work.CHANGELOG.md— hand-maintained. Add a user-visible entry for any user-visible change.
crates/snxcore/src/:
lib.rs— crate root. Historically carried#![deny(unsafe_code)]; this was relaxed when Windows and macOS platform support landed (both need FFI). Keepunsafeconfined toplatform/windows/andplatform/macos/; justify any new usage.server.rs— command-mode server (unix socket on Linux / named pipe on Windows).controller.rs— connection lifecycle orchestration.browser.rs— browser-based SAML/IdP flow.otp.rs— OTP listener (used by browser / MFA flows).profiles.rs— saved connection profiles.prompt.rs— tty and secure prompt abstractions.sexpr.rs+sexpr.pest— parser for Check Point's S-expression wire format (pestgrammar).model.rs+model/— protocol types:params.rs(tunnel config /TunnelParams),proto.rs(wire structs),wrappers.rs.platform.rs+platform/—Platformtrait abstraction seam plus per-OS implementations (see below).tunnel/— transport implementations:connector.rs— common tunnel connector trait.gateway.rs— Check Point command/gateway HTTPS client (CCC protocol).device.rs— tun device abstraction.ipsec/— IPsecconnector.rs,natt.rs,keepalive.rs, SCV policy emulation (scv.rs), plus theimp/impls selected at runtime (kernel XFRM vs. userspace TUN/TCPT).ssl/— SSL tunnelcodec.rs,connector.rs,keepalive.rs(legacy fallback transport).
util.rs— misc helpers.tests/— integration fixtures (*.txtcaptured wire payloads) and integration tests.
Per-OS platform modules under crates/snxcore/src/platform/:
linux/—keychain.rs(Secret Service),resolver.rs(systemd-resolved via D-Bus),routing.rs(rtnetlink),xfrm.rs(xfrmnetlink / netlink-packet-xfrm),net.rs,stats.rs(interface stats poller).windows/—firewall.rs,ipsec_stub.rs(IPsec is not yet implemented on Windows),keychain.rs(Credential Manager),machine_uuid.rs,net.rs,nrpt.rs(Name Resolution Policy Table for split DNS),resolver.rs,routing.rs,single_instance.rs,stats.rs. Marked#![allow(unsafe_code)]because the Windows APIs require FFI.macos/—command_socket.rs(filesystem-pinned local socket),ipsec_stub.rs(IPsec native kernel path not implemented; userspace TUN/ESP used instead),keychain.rs(Security.framework),machine_uuid.rs(gethostuuid),net.rs(utun device, ioctl SIOCAIFADDR/SIOCSIFMTU, interface stats via NET_RT_IFLIST2),resolver.rs(SCDynamicStore / SystemConfiguration split DNS),routing.rs(PF_ROUTE: split/full-route, IPv6 blackhole, ip.forwarding),single_instance.rs(flock guard),stats.rs. Marked#![allow(unsafe_code)]because the macOS APIs require FFI. IPsec keepalive is disabled (the gateway echoes the UDP checksum, which the kernel drops; macOS lacks SO_NO_CHECK).
The external isakmp crate (git dep: https://github.com/ancwrd1/isakmp.git) provides IKE/ISAKMP primitives used by the IPsec tunnel.
Minimum supported Rust: 1.88. Workspace edition is 2024.
# Debug build (whole workspace)
cargo build
# Release build
cargo build --release
# Release build with mobile-access (embedded WebKit for Mobile Access portal flow)
cargo build --release --features mobile-access
# Static musl build (matches release pipeline; requires cross-rs and docker/podman)
cross build --target=x86_64-unknown-linux-musl \
--features snxcore/vendored-openssl,snxcore/vendored-sqlite \
-p snx-rs --profile lto
# CI gate — always run these three before declaring work done:
cargo fmt --check
cargo clippy --workspace --features mobile-access -- -D warnings
cargo test --workspace --features mobile-accessCI runs on ubuntu-latest / x86_64-unknown-linux-gnu / stable for Linux, and on macos-latest / aarch64-apple-darwin / stable for macOS (whole workspace including the GUI, with vendored-openssl and mobile-access). Clippy is -D warnings — do not land new warnings.
Required for the default Linux build: C toolchain, OpenSSL, SQLite3, fontconfig. GTK 4.10+ and WebKit 6.0+ are required only when the mobile-access feature is enabled.
- Debian/Ubuntu:
build-essential libssl-dev libfontconfig1-dev libsqlite3-dev libgtk-4-dev libwebkitgtk-6.0-dev libsoup-3.0-dev libjavascriptcoregtk-6.0-dev - openSUSE:
libopenssl-3-devel sqlite3-devel fontconfig-devel gtk4-devel webkit2gtk4-devel
On Windows, use vendored-openssl and vendored-sqlite features to avoid system library dependencies. The mobile-access feature on Windows pulls in WebView2 via the webview2-com crate (no extra system package needed; WebView2 runtime ships with modern Windows).
On macOS, use vendored-openssl (and optionally vendored-sqlite); no other system packages are required. The mobile-access feature uses WKWebView via the system WebKit (part of macOS); no extra install is needed.
Defined on snxcore:
vendored-openssl— build OpenSSL from source (used for static/musl builds).vendored-sqlite— bundle SQLite viarusqlite/bundled.
Defined on snx-rs-gui:
mobile-access— enables the embedded browser used for Mobile Access portal login. On Linux pulls ingtk4andwebkit6; on macOS usesWKWebViewvia the system WebKit; on Windows uses WebView2. Off by default in release CI to minimize runtime deps.
release has panic = "abort". There is also an lto profile (inherits release) that adds strip = true, lto = true, codegen-units = 1 — used for packaging.
rustfmt.tomlsetsmax_width = 120. Runcargo fmtbefore committing.- Prefer safe wrapper crates (
nix,rtnetlink,xfrmnetlink,tun, etc.) over raw FFI. The only placesunsafeis expected arecrates/snxcore/src/platform/windows/(Win32 FFI) andcrates/snxcore/src/platform/macos/(macOS system APIs); both opt in via#![allow(unsafe_code)]. Do not introduceunsafeoutside those modules without discussing with maintainers. - Errors flow through
anyhow::Resultat app boundaries; library code also usesanyhow(there is no custom error type at present). - Async runtime is
tokio(multi-thread). Prefertokio::spawn+ channels over ad-hoc threading. - Secrets go through
secrecy::SecretString/ExposeSecret. Do not log, format, or embed passwords / tokens into error strings. - Logging uses
tracing+tracing-subscriber. Respect thelog-levelconfig option.tracelevel is documented as sensitive — do not downgrade that warning. - Platform-specific code belongs under
crates/snxcore/src/platform/<os>/behind#[cfg(target_os = "linux")]/#[cfg(target_os = "windows")]/#[cfg(target_os = "macos")]. ThePlatformtrait inplatform.rsis the abstraction seam; add new functionality there first, then implement for each OS. - Comments: the maintainer's stated AI policy (
docs/contributing.md) is explicit — no redundant per-line or per-function comments. Only comment the non-obvious why. Machine-generated boilerplate comments will be rejected.
All human-readable English strings that reach the user go through the i18n crate's tr! macro or i18n::translate. The canonical source file is crates/i18n/assets/en-US/main.ftl; 16 other locales live alongside it.
Rules (from i18n.md):
- Keys are prefixed by category:
error-*,label-*,info-*,language-*, etc. - When adding a new string: add the
en-USentry and a translated entry in every other locale'smain.ftl. Preserve file grouping and comments. Leave{$placeholder}tokens untranslated. - Never modify existing entries (reword via a new key instead).
- Prefer small Python scripts for bulk locale work over re-reading every file by hand.
- If you add a new locale, also add a
language-<locale>entry to every existingmain.ftl.
Read i18n.md in full before performing any of its three named tasks — it is the source of truth.
User-facing docs are in docs/. If you change a config option, CLI flag, tunnel behavior, or supported auth flow, update the relevant file there:
options.md— all config-file / CLI options table.command-line-usage.md— modes and invocation.features.md— the capability bullet list.tunnel-types.md,dns-configuration.md,certificates.md, etc. — topic deep-dives.troubleshooting.md— add new entries when you diagnose a recurring issue.
Also add a short bullet to CHANGELOG.md for any user-visible change, under the v6.0.0 (TBD) section (or whatever the current in-flight version is).
The snx-rs binary runs in one of two operating modes selected by -m:
standalone— daemon + tunnel in one process. Needs root. Config comes from the CLI or a-cconfig file.command— service mode. Daemon only; establishes tunnels on demand whensnxctl(or the GUI) sends commands over a local unix socket. This is the desktop path.
Plus one-shot utility modes: info (query server for auth methods), certificate enrollment, etc.
The GUI (snx-rs-gui) always runs unprivileged and talks to a command-mode snx-rs service over IPC (interprocess crate). On Linux, D-Bus (zbus) is used for desktop integration (KSNI tray, notifications). On macOS and Windows the tray is provided by the tray-icon crate; on macOS notifications go through UNUserNotificationCenter. The GUI is not a replacement for the service; it's a client of it.
- Don't add redundant comments. The contributing guide says so explicitly; this is the single most common cause of rejected AI patches in this repo.
- Don't hard-code user-visible English strings. Route them through
tr!and update the Fluent files. - Don't run external commands to configure networking. Since v5.3.0 the project deliberately uses OS APIs directly (Linux:
rtnetlink,xfrmnetlink, systemd-resolved over D-Bus,sysctlcrate; Windows: Win32 IpHelper / NRPT / WinSock via thewindowscrate; macOS: ioctl, PF_ROUTE, SystemConfiguration). Do not regress this by shelling out toip,resolvectl,iptables,netsh,route,networksetup, etc. - Don't introduce
unsafeoutsideplatform/windows/orplatform/macos/. Those are the only modules that opt intounsafe(Win32 FFI and macOS system APIs respectively). Everywhere else, use safe wrappers. - Don't add backwards-compat shims for config flags that were renamed (e.g.
no-keychain→keychainwas flipped deliberately in 5.3.0). If you're changing a flag, change it cleanly and document inCHANGELOG.md. - Don't bypass
secrecy. Passwords, IKE keys, tokens, and cert passwords must stay insideSecretStringuntil the exact point of use. - Don't forget MSRV. Edition 2024 features are fine;
rustc 1.88+features are fine; anything newer is not.
- Branch from
main. PRs targetmain. - Before pushing:
cargo fmt --check && cargo clippy --workspace --features mobile-access -- -D warnings && cargo test --workspace --features mobile-access. - Keep commits focused. The recent history is small, well-scoped commits (
git log --onelineto see the style). - Add a
CHANGELOG.mdentry for anything a user would notice. - If a change affects translations, update all locales or explicitly note the gap.
- Upstream repo and issue tracker: https://github.com/ancwrd1/snx-rs
- Sister crate for ISAKMP/IKE: https://github.com/ancwrd1/isakmp
- Slint (GUI framework): https://slint.dev
- Fluent localization: https://projectfluent.org