Skip to content

Commit

Permalink
Added set-routing-domains option. Fixes #79
Browse files Browse the repository at this point in the history
  • Loading branch information
ancwrd1 committed Feb 18, 2025
1 parent 2a57ac4 commit 76a87c1
Show file tree
Hide file tree
Showing 13 changed files with 111 additions and 65 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## v3.0.7 (unreleased)
- Added `password-factor=N` option to determine which authentication factor is the password.
## v3.1.0 (unreleased)
- Added `password-factor=N` option to determine which authentication factor is the password. Default is 1 (first).
- Added `set-routing-domains=true|false` option to treat the received search domains as [routing domains](https://systemd.io/RESOLVED-VPNS/).

## v3.0.6 (2025-02-16)
- Improved authentication prompts by displaying a header retrieved from VPN server
Expand Down
32 changes: 16 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ members = ["snxcore", "snxctl", "snx-rs", "snx-rs-gui"]
resolver = "2"

[workspace.package]
version = "3.0.7"
version = "3.1.0"
license = "AGPL-3.0"
edition = "2021"
authors = ["Dmitry Pankratov <dmitry@pankratov.net>"]
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ This project contains the source code for an unofficial Linux client for Check P
* D-Bus
* GTK3 and libappindicator3 for the GUI frontend

## DNS resolver configuration
## DNS resolver configuration and privacy

By default, if systemd-resolved is not detected as a global DNS resolver, snx-rs will fall back
to modify the /etc/resolv.conf file directly and DNS servers acquired from the tunnel will be used globally.
For better privacy, use the split-dns provided by systemd-resolved.
For better privacy, use the split DNS provided by systemd-resolved.

In order to find out whether it is already enabled, check the /etc/resolv.conf file:

Expand All @@ -62,6 +62,8 @@ With `systemd-resolved` it is also possible to use **routing domains** (as oppos
Routing domains are prefixed with `~` character and when configured only requests for the fully-qualified domains
will be forwarded through the tunnel. For further explanation please check [this article](https://systemd.io/RESOLVED-VPNS/).

The `set-routing-domains=true|false` option controls whether to treat all acquired search domains as routing domains.

## Differences between SSL and IPSec tunnels

IPSec is recommended for all connections because of the performance and feature set. However, in certain situations,
Expand Down
45 changes: 23 additions & 22 deletions options.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,31 @@
| Option | Description |
|-------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
| `server-name=<ip_or_address>` | VPN server to connect to, this is a required parameter |
| `login-type=vpn_xxx` | authentication method, acquired from the server, this is a required parameter |
| `user-name=<username>` | user name to authenticate, not used for SAML or certificate authentication |
| `password=<pass>` | optional password in base64 encoding |
| `password-factor=<1..N>` | index of the password authentication factor which is used for keychain storage and for reading the password from config file. Default is 1 (first). |
| `cert-type=<cert_type>` | enable certificate-based authentication using given type: pkcs8, pkcs11, pkcs12, none |
| `cert-path=<cert_path>` | path to PEM file for PKCS8, path to PFX file for PKCS12, path to driver file for PKCS11 |
| `cert-password=<cert_password>` | password for PKCS12 or pin for PKCS11 |
| `cert-id=<cert_id>` | hexadecimal ID of PKCS11 certificate, bytes could be optionally separated with colon |
| `search-domains=<search_domains>` | additional search domains for DNS resolver, comma-separated |
| `ignore-search-domains=<ignored_domains>` | acquired search domains to ignore |
| `dns-servers=<dns_servers>` | additional DNS servers, comma-separated |
| `ignore-dns-servers=<ignored_dns>` | acquired DNS servers to ignore, comma-separated |
| `default-route=true\|false` | set default route through the VPN tunnel, default is false |
| `no-routing=true\|false` | ignore all routes acquired from the VPN server, default is false |
| `add-routes=<routes>` | additional static routes, comma-separated, in the format of x.x.x.x/x |
| `ignore-routes=<routes>` | ignore the specified routes acquired from the VPN server |
| `no-dns=true\|false` | do not change DNS resolver configuration, default is false |
| `login-type=vpn_xxx` | Authentication method, acquired from the server, this is a required parameter |
| `user-name=<username>` | User name to authenticate, not used for SAML or certificate authentication |
| `password=<pass>` | Optional password in base64 encoding |
| `password-factor=<1..N>` | Index of the password authentication factor which is used for keychain storage and for reading the password from config file. Default is 1 (first). |
| `cert-type=<cert_type>` | Enable certificate-based authentication using given type: pkcs8, pkcs11, pkcs12, none |
| `cert-path=<cert_path>` | Path to PEM file for PKCS8, path to PFX file for PKCS12, path to driver file for PKCS11 |
| `cert-password=<cert_password>` | Password for PKCS12 or pin for PKCS11 |
| `cert-id=<cert_id>` | Hexadecimal ID of PKCS11 certificate, bytes could be optionally separated with colon |
| `search-domains=<search_domains>` | Additional search domains for DNS resolver, comma-separated |
| `ignore-search-domains=<ignored_domains>` | Acquired search domains to ignore |
| `dns-servers=<dns_servers>` | Additional DNS servers, comma-separated |
| `ignore-dns-servers=<ignored_dns>` | Acquired DNS servers to ignore, comma-separated |
| `set-routing-domains=true\|false` | Treat received search domains as routing domains. This option prevents DNS requests for unqualified domains to be sent through the tunnel. |
| `default-route=true\|false` | Set default route through the VPN tunnel, default is false |
| `no-routing=true\|false` | Ignore all routes acquired from the VPN server, default is false |
| `add-routes=<routes>` | Additional static routes, comma-separated, in the format of x.x.x.x/x |
| `ignore-routes=<routes>` | Ignore the specified routes acquired from the VPN server |
| `no-dns=true\|false` | Do not change DNS resolver configuration, default is false |
| `no-cert-check=true\|false` | do not check server certificate common name, default is false |
| `ignore-server-cert=true\|false` | disable all certificate checks, default is false |
| `ignore-server-cert=true\|false` | Disable all certificate checks, default is false |
| `ca-cert=<ca_certs>` | One or more comma-separated custom CA root certificates used to validate TLS connection and optionally IPSec certificates. |
| `ipsec-cert-check=true\|false` | enable IPSec certificate check during IKE identity protection phase. Requires custom CA root certificate to be specified. |
| `tunnel-type=ipsec\|ssl` | tunnel type, default is ipsec |
| `no-keychain=true\|false` | do not store password in the OS keychain, default is false |
| `server-prompt=true\|false` | retrieve MFA prompts from the server, default is false |
| `ipsec-cert-check=true\|false` | Enable IPSec certificate check during IKE identity protection phase. Requires custom CA root certificate to be specified. |
| `tunnel-type=ipsec\|ssl` | Tunnel type, default is ipsec |
| `no-keychain=true\|false` | Do not store password in the OS keychain, default is false |
| `server-prompt=true\|false` | Retrieve MFA prompts from the server, default is false |
| `esp-lifetime=3600` | ESP SA lifetime in seconds, default is 3600 |
| `esp-transport=udp\|tcpt` | Select network transport for ESP packets. UDP is the default and standard, TCPT is the Check Point proprietary protocol and is much slower. |
| `ike-lifetime=28800` | IKE SA lifetime in seconds, default is 28800. Set to higher value to extend IPSec session duration |
Expand Down
8 changes: 8 additions & 0 deletions snx-rs-gui/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct MyWidgets {
ignored_domains: gtk::Entry,
dns_servers: gtk::Entry,
ignored_dns_servers: gtk::Entry,
set_routing_domains: gtk::CheckButton,
no_routing: gtk::CheckButton,
default_routing: gtk::CheckButton,
add_routes: gtk::Entry,
Expand Down Expand Up @@ -180,6 +181,7 @@ impl SettingsDialog {
let password_factor = gtk::Entry::builder().text(params.password_factor.to_string()).build();

let no_dns = gtk::CheckButton::builder().active(params.no_dns).build();
let set_routing_domains = gtk::CheckButton::builder().active(params.set_routing_domains).build();

let search_domains = gtk::Entry::builder()
.placeholder_text("Comma-separated domains")
Expand Down Expand Up @@ -408,6 +410,7 @@ impl SettingsDialog {
ignored_domains,
dns_servers,
ignored_dns_servers,
set_routing_domains,
no_routing,
default_routing,
add_routes,
Expand Down Expand Up @@ -479,6 +482,7 @@ impl SettingsDialog {
params.password = self.widgets.password.text().into();
params.password_factor = self.widgets.password_factor.text().parse()?;
params.no_dns = self.widgets.no_dns.is_active();
params.set_routing_domains = self.widgets.set_routing_domains.is_active();
params.search_domains = self
.widgets
.search_domains
Expand Down Expand Up @@ -709,6 +713,10 @@ impl SettingsDialog {
ignored_domains.pack_start(&self.widgets.ignored_domains, false, true, 0);
dns_box.pack_start(&ignored_domains, false, true, 6);

let set_routing_domains = self.form_box("Treat received search domains as routing domains");
set_routing_domains.pack_start(&self.widgets.set_routing_domains, false, true, 0);
dns_box.pack_start(&set_routing_domains, false, true, 6);

dns_box
}

Expand Down
11 changes: 11 additions & 0 deletions snx-rs/src/cmdline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ pub struct CmdlineParams {
)]
pub ignore_dns_servers: Vec<Ipv4Addr>,

#[clap(
long = "set-routing-domains",
short = 'Z',
help = "Treat received search domains as routing domains"
)]
pub set_routing_domains: Option<bool>,

#[clap(
long = "default-route",
short = 't',
Expand Down Expand Up @@ -256,6 +263,10 @@ impl CmdlineParams {
other.ignore_dns_servers = self.ignore_dns_servers;
}

if let Some(set_routing_domains) = self.set_routing_domains {
other.set_routing_domains = set_routing_domains;
}

if let Some(default_route) = self.default_route {
other.default_route = default_route;
}
Expand Down
4 changes: 4 additions & 0 deletions snxcore/src/model/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ pub struct TunnelParams {
pub no_keepalive: bool,
pub icon_theme: IconTheme,
pub ike_transport: TransportType,
pub set_routing_domains: bool,
pub config_file: PathBuf,
}

Expand Down Expand Up @@ -333,6 +334,7 @@ impl Default for TunnelParams {
no_keepalive: false,
icon_theme: IconTheme::default(),
ike_transport: TransportType::default(),
set_routing_domains: false,
config_file: Self::default_config_path(),
}
}
Expand Down Expand Up @@ -396,6 +398,7 @@ impl TunnelParams {
"no-keepalive" => params.no_keepalive = v.parse().unwrap_or_default(),
"icon-theme" => params.icon_theme = v.parse().unwrap_or_default(),
"client-mode" => params.client_mode = v,
"set-routing-domains" => params.set_routing_domains = v.parse().unwrap_or_default(),
other => {
warn!("Ignoring unknown option: {}", other);
}
Expand Down Expand Up @@ -497,6 +500,7 @@ impl TunnelParams {
writeln!(buf, "no-keepalive={}", self.no_keepalive)?;
writeln!(buf, "icon-theme={}", self.icon_theme)?;
writeln!(buf, "ike-transport={}", self.ike_transport.as_str())?;
writeln!(buf, "set-routing-domains={}", self.set_routing_domains)?;

PathBuf::from(&self.config_file).parent().iter().for_each(|dir| {
let _ = fs::create_dir_all(dir);
Expand Down
3 changes: 2 additions & 1 deletion snxcore/src/platform/linux/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ impl ResolvConfConfigurator {
.map(ToOwned::to_owned)
.collect::<Vec<_>>();

let search_domains = config.search_domains.join(" ");
// resolv.conf has no concept of routing domains
let search_domains = config.search_domains.join(" ").replace('~', "");

if configure {
if search.is_empty() {
Expand Down
Loading

0 comments on commit 76a87c1

Please sign in to comment.