Files
TrustTunnel/tools/setup_wizard/template_settings.rs
Aleksei Zhavoronkov a89bf60aaf Pull request 179: [Github PR] Add destination port filtering to rules engine
Squashed commit of the following:

commit 7cac1197ad
Merge: b6dc6ed 3a47cb7
Author: Zhavoronkov Aleksei <a.zhavoronkov@adguard.com>
Date:   Wed Mar 25 19:29:35 2026 +0300

    Merge remote-tracking branch 'origin/dev-1.1' into feat/TRUST-414

commit b6dc6ed622
Merge: 6ac0e50 984817f
Author: Zhavoronkov Aleksei <a.zhavoronkov@adguard.com>
Date:   Mon Mar 16 15:49:26 2026 +0300

    Merge branch 'dev-1.1' of https://bit.int.agrd.dev/scm/adguard-core-libs/vpn-libs-endpoint into feat/TRUST-414

commit 6ac0e506f7
Merge: cbd0181 962fc27
Author: Zhavoronkov Aleksei <a.zhavoronkov@adguard.com>
Date:   Tue Mar 10 19:15:30 2026 +0300

    Merge branch 'dev-1.1' of https://bit.int.agrd.dev/scm/adguard-core-libs/vpn-libs-endpoint into feat/TRUST-414

commit cbd0181763
Author: Zhavoronkov Aleksei <a.zhavoronkov@adguard.com>
Date:   Tue Mar 10 18:58:12 2026 +0300

    Mention user changes in changelog and add some fixed

commit d5e0dc5fb3
Author: Alexander Novikov <alnovis@gmail.com>
Date:   Mon Mar 9 22:48:37 2026 +0300

    Add destination IP (CIDR) filtering to outbound rules engine
    
    Extend OutboundRule with optional destination_cidr field (IpNet),
    allowing outbound rules to filter by destination IP range, destination
    port, or both (AND logic). At least one filter must be present.

commit 5d1b167724
Author: Alexander Novikov <alnovis@gmail.com>
Date:   Wed Mar 4 13:46:35 2026 +0700

    Improve rules engine: pre-parse port filters, validate config at load time, add legacy format support
    
    - Parse DestinationPortFilter at config load instead of on every request
    - Add warnings for invalid rules (bad CIDR, client_random_prefix, ports, missing action)
    - Support legacy flat [[rule]] format with deprecation warning
    - Restore explanatory comments in mask matching tests
    - Document default_action = "deny" implications and port-only outbound limitation

commit 0cfeb55bd5
Author: Alexander Novikov <alnovis@gmail.com>
Date:   Wed Mar 4 11:49:38 2026 +0700

    Fix markdown-lint: add blank line before list in CONFIGURATION.md

commit 77655d9ddf
Author: Alexander Novikov <alnovis@gmail.com>
Date:   Mon Mar 2 23:57:09 2026 +0700

    Split rules into [inbound] and [outbound] sections
    
    Separate client filtering (TLS handshake) from destination filtering
    (per-request) with independent default_action for each section,
    so inbound defaults don't leak into outbound evaluation and vice versa.

commit a03e6a0d35
Author: Alexander Novikov <alnovis@gmail.com>
Date:   Sun Mar 1 15:38:46 2026 +0700

    Remove duplicate code block in CONFIGURATION.md

commit 909c05161e
Author: Alexander Novikov <alnovis@gmail.com>
Date:   Sun Mar 1 06:56:00 2026 +0700

    Fix rustfmt and markdown-lint issues

commit 44e026ab93
Author: Alexander Novikov <alnovis@gmail.com>
Date:   Sun Mar 1 03:09:01 2026 +0700

    Fix Dockerfile: add missing deeplink crate COPY

commit 6ca87cc9e9
Author: Alexander Novikov <alnovis@gmail.com>
Date:   Sun Mar 1 02:46:04 2026 +0700

    Add destination port filtering to rules engine
    
    Block connections to specific ports (e.g. BitTorrent 6881-6889, 6969)
    to prevent DMCA complaints. Rules with destination_port are evaluated
    per TCP CONNECT / UDP request, while existing cidr/client_random_prefix
    rules continue to be evaluated at TLS handshake.
2026-04-17 12:37:59 +00:00

313 lines
9.0 KiB
Rust

use once_cell::sync::Lazy;
use trusttunnel::settings::{
ForwardProtocolSettings, Http1Settings, Http2Settings, IcmpSettings, ListenProtocolSettings,
MetricsSettings, QuicSettings, Settings, Socks5ForwarderSettings,
};
use trusttunnel::utils::ToTomlComment;
pub static MAIN_TABLE: Lazy<String> = Lazy::new(|| {
format!(
r#"{}
listen_address = ""
# The path to a TOML file in the following format:
#
# ```
# [[client]]
# username = "a"
# password = "b"
#
# [[client]]
# ...
# ```
credentials_file = "{}"
# The path to a TOML file for connection filtering rules in the following format:
#
# ```
# [inbound]
# default_action = "allow"
#
# [[inbound.rule]]
# cidr = "192.168.0.0/16"
# action = "deny"
#
# [[inbound.rule]]
# client_random_prefix = "aabbcc"
# action = "allow"
#
# [outbound]
# default_action = "allow"
#
# [[outbound.rule]]
# destination_port = "6881-6889"
# action = "deny"
#
# [[outbound.rule]]
# destination_cidr = "10.0.0.0/8"
# action = "deny"
#
# If no rules file, all connections are allowed by default.
# ```
rules_file = "{}"
{}
ipv6_available = {}
{}
allow_private_network_connections = {}
{}
tls_handshake_timeout_secs = {}
{}
client_listener_timeout_secs = {}
{}
connection_establishment_timeout_secs = {}
{}
tcp_connections_timeout_secs = {}
{}
udp_connections_timeout_secs = {}
{}
speedtest_enable = {}
{}
speedtest_path = "{}"
{}
ping_enable = {}
{}
ping_path = "{}"
{}
auth_failure_status_code = {}
"#,
Settings::doc_listen_address().to_toml_comment(),
crate::library_settings::DEFAULT_CREDENTIALS_PATH,
crate::library_settings::DEFAULT_RULES_PATH,
Settings::doc_ipv6_available().to_toml_comment(),
Settings::default_ipv6_available(),
Settings::doc_allow_private_network_connections().to_toml_comment(),
Settings::default_allow_private_network_connections(),
format!("{}. In seconds.", Settings::doc_tls_handshake_timeout()).to_toml_comment(),
Settings::default_tls_handshake_timeout().as_secs(),
format!("{}. In seconds.", Settings::doc_client_listener_timeout()).to_toml_comment(),
Settings::default_client_listener_timeout().as_secs(),
format!(
"{} In seconds.",
Settings::doc_connection_establishment_timeout()
)
.to_toml_comment(),
Settings::default_connection_establishment_timeout().as_secs(),
format!("{}. In seconds.", Settings::doc_tcp_connections_timeout()).to_toml_comment(),
Settings::default_tcp_connections_timeout().as_secs(),
format!("{}. In seconds.", Settings::doc_udp_connections_timeout()).to_toml_comment(),
Settings::default_udp_connections_timeout().as_secs(),
Settings::doc_speedtest_enable().to_toml_comment(),
Settings::default_speedtest_enable(),
Settings::doc_speedtest_path().to_toml_comment(),
Settings::default_speedtest_path().unwrap(),
Settings::doc_ping_enable().to_toml_comment(),
Settings::default_ping_enable(),
Settings::doc_ping_path().to_toml_comment(),
Settings::default_ping_path().unwrap(),
Settings::doc_auth_failure_status_code().to_toml_comment(),
Settings::default_auth_failure_status_code(),
)
});
pub static FORWARD_PROTOCOL_COMMON_TABLE: Lazy<String> = Lazy::new(|| {
format!(
r#"{}.
# Possible values:
# * direct: a direct forwarder routes a connection directly to its target host,
# * socks5: a SOCKS5 forwarder routes a connection though a SOCKS5 proxy.
# Default is direct
[forward_protocol]
"#,
ForwardProtocolSettings::doc().to_toml_comment(),
)
});
pub static DIRECT_FORWARDER_TABLE: Lazy<String> = Lazy::new(|| {
format!(
r#"{}.
[forward_protocol.direct]"#,
ForwardProtocolSettings::doc_direct().to_toml_comment(),
)
});
pub static SOCKS_FORWARDER_TABLE: Lazy<String> = Lazy::new(|| {
format!(
r#"{}.
[forward_protocol.socks5]
{}
address = "127.0.0.1:1080"
{}
extended_auth = false"#,
ForwardProtocolSettings::doc_socks5().to_toml_comment(),
Socks5ForwarderSettings::doc_address().to_toml_comment(),
Socks5ForwarderSettings::doc_extended_auth().to_toml_comment(),
)
});
pub static LISTENER_COMMON_TABLE: Lazy<String> = Lazy::new(|| {
format!(
r#"{}.
# Possible values:
# * http1: enables HTTP1 codec,
# * http2: enables HTTP2 codec,
# * quic: enables QUIC/HTTP3 codec.
# At least one listener codec MUST be specified.
[listen_protocols]
"#,
ListenProtocolSettings::doc().to_toml_comment(),
)
});
pub static HTTP1_LISTENER_TABLE: Lazy<String> = Lazy::new(|| {
format!(
r#"{}.
[listen_protocols.http1]
{}
upload_buffer_size = {}
"#,
Http1Settings::doc().to_toml_comment(),
Http1Settings::doc_upload_buffer_size().to_toml_comment(),
Http1Settings::default_upload_buffer_size(),
)
});
pub static HTTP2_LISTENER_TABLE: Lazy<String> = Lazy::new(|| {
format!(
r#"{}.
[listen_protocols.http2]
{}
initial_connection_window_size = {}
{}
initial_stream_window_size = {}
{}
max_concurrent_streams = {}
{}
max_frame_size = {}
{}
header_table_size = {}
"#,
Http2Settings::doc().to_toml_comment(),
Http2Settings::doc_initial_connection_window_size().to_toml_comment(),
Http2Settings::default_initial_connection_window_size(),
Http2Settings::doc_initial_stream_window_size().to_toml_comment(),
Http2Settings::default_initial_stream_window_size(),
Http2Settings::doc_max_concurrent_streams().to_toml_comment(),
Http2Settings::default_max_concurrent_streams(),
Http2Settings::doc_max_frame_size().to_toml_comment(),
Http2Settings::default_max_frame_size(),
Http2Settings::doc_header_table_size().to_toml_comment(),
Http2Settings::default_header_table_size(),
)
});
pub static QUIC_LISTENER_TABLE: Lazy<String> = Lazy::new(|| {
format!(
r#"{}.
[listen_protocols.quic]
{}
recv_udp_payload_size = {}
{}
send_udp_payload_size = {}
{}
initial_max_data = {}
{}
initial_max_stream_data_bidi_local = {}
{}
initial_max_stream_data_bidi_remote = {}
{}
initial_max_stream_data_uni = {}
{}
initial_max_streams_bidi = {}
{}
initial_max_streams_uni = {}
{}
max_connection_window = {}
{}
max_stream_window = {}
{}
disable_active_migration = {}
{}
enable_early_data = {}
{}
message_queue_capacity = {}
"#,
QuicSettings::doc().to_toml_comment(),
QuicSettings::doc_recv_udp_payload_size().to_toml_comment(),
QuicSettings::default_recv_udp_payload_size(),
QuicSettings::doc_send_udp_payload_size().to_toml_comment(),
QuicSettings::default_send_udp_payload_size(),
QuicSettings::doc_initial_max_data().to_toml_comment(),
QuicSettings::default_initial_max_data(),
QuicSettings::doc_initial_max_stream_data_bidi_local().to_toml_comment(),
QuicSettings::default_initial_max_stream_data_bidi_local(),
QuicSettings::doc_initial_max_stream_data_bidi_remote().to_toml_comment(),
QuicSettings::default_initial_max_stream_data_bidi_remote(),
QuicSettings::doc_initial_max_stream_data_uni().to_toml_comment(),
QuicSettings::default_initial_max_stream_data_uni(),
QuicSettings::doc_initial_max_streams_bidi().to_toml_comment(),
QuicSettings::default_initial_max_streams_bidi(),
QuicSettings::doc_initial_max_streams_uni().to_toml_comment(),
QuicSettings::default_initial_max_streams_uni(),
QuicSettings::doc_max_connection_window().to_toml_comment(),
QuicSettings::default_max_connection_window(),
QuicSettings::doc_max_stream_window().to_toml_comment(),
QuicSettings::default_max_stream_window(),
QuicSettings::doc_disable_active_migration().to_toml_comment(),
QuicSettings::default_disable_active_migration(),
QuicSettings::doc_enable_early_data().to_toml_comment(),
QuicSettings::default_enable_early_data(),
QuicSettings::doc_message_queue_capacity().to_toml_comment(),
QuicSettings::default_message_queue_capacity(),
)
});
pub static ICMP_TABLE: Lazy<String> = Lazy::new(|| {
format!(
r#"{}
[icmp]
{}
interface_name = "{}"
{}
request_timeout_secs = {}
{}
recv_message_queue_capacity = {}
"#,
IcmpSettings::doc().to_toml_comment(),
IcmpSettings::doc_interface_name().to_toml_comment(),
IcmpSettings::default_interface_name(),
IcmpSettings::doc_request_timeout().to_toml_comment(),
IcmpSettings::default_request_timeout().as_secs(),
IcmpSettings::doc_recv_message_queue_capacity().to_toml_comment(),
IcmpSettings::default_message_queue_capacity(),
)
});
pub static METRICS_TABLE: Lazy<String> = Lazy::new(|| {
format!(
r#"{}
[metrics]
{}
address = "{}"
{}
request_timeout_secs = {}
"#,
MetricsSettings::doc().to_toml_comment(),
MetricsSettings::doc_address().to_toml_comment(),
MetricsSettings::default_listen_address(),
MetricsSettings::doc_request_timeout().to_toml_comment(),
MetricsSettings::default_request_timeout().as_secs(),
)
});