mirror of
https://github.com/telemt/telemt.git
synced 2026-06-19 01:11:09 +03:00
Exclusive Mask + Startup Speed-up
Signed-off-by: Alexey <247128645+axkurcom@users.noreply.github.com>
This commit is contained in:
@@ -617,6 +617,7 @@ fn warn_non_hot_changes(old: &ProxyConfig, new: &ProxyConfig, non_hot_changed: b
|
||||
|| old.censorship.mask != new.censorship.mask
|
||||
|| old.censorship.mask_host != new.censorship.mask_host
|
||||
|| old.censorship.mask_port != new.censorship.mask_port
|
||||
|| old.censorship.exclusive_mask != new.censorship.exclusive_mask
|
||||
|| old.censorship.mask_unix_sock != new.censorship.mask_unix_sock
|
||||
|| old.censorship.fake_cert_len != new.censorship.fake_cert_len
|
||||
|| old.censorship.tls_emulation != new.censorship.tls_emulation
|
||||
|
||||
@@ -31,6 +31,30 @@ fn is_valid_tls_domain_name(domain: &str) -> bool {
|
||||
.any(|ch| ch.is_whitespace() || matches!(ch, '/' | '\\'))
|
||||
}
|
||||
|
||||
fn parse_exclusive_mask_target(target: &str) -> Option<(&str, u16)> {
|
||||
let target = target.trim();
|
||||
if target.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if target.starts_with('[') {
|
||||
let end = target.find(']')?;
|
||||
if target.get(end + 1..end + 2)? != ":" {
|
||||
return None;
|
||||
}
|
||||
let host = &target[..=end];
|
||||
let port = target[end + 2..].parse::<u16>().ok()?;
|
||||
return (port > 0).then_some((host, port));
|
||||
}
|
||||
|
||||
let (host, port) = target.rsplit_once(':')?;
|
||||
if host.is_empty() || host.contains(':') {
|
||||
return None;
|
||||
}
|
||||
let port = port.parse::<u16>().ok()?;
|
||||
(port > 0).then_some((host, port))
|
||||
}
|
||||
|
||||
const TOP_LEVEL_CONFIG_KEYS: &[&str] = &[
|
||||
"general",
|
||||
"network",
|
||||
@@ -291,6 +315,7 @@ const CENSORSHIP_CONFIG_KEYS: &[&str] = &[
|
||||
"mask",
|
||||
"mask_host",
|
||||
"mask_port",
|
||||
"exclusive_mask",
|
||||
"mask_unix_sock",
|
||||
"fake_cert_len",
|
||||
"tls_emulation",
|
||||
@@ -1923,6 +1948,21 @@ impl ProxyConfig {
|
||||
config.censorship.mask_host = Some(config.censorship.tls_domain.clone());
|
||||
}
|
||||
|
||||
for (domain, target) in &config.censorship.exclusive_mask {
|
||||
if !is_valid_tls_domain_name(domain) {
|
||||
return Err(ProxyError::Config(format!(
|
||||
"Invalid censorship.exclusive_mask domain: '{}'. Must be a valid domain name",
|
||||
domain
|
||||
)));
|
||||
}
|
||||
if parse_exclusive_mask_target(target).is_none() {
|
||||
return Err(ProxyError::Config(format!(
|
||||
"Invalid censorship.exclusive_mask target for '{}': '{}'. Expected host:port with port > 0",
|
||||
domain, target
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize optional TLS fetch scope: whitespace-only values disable scoped routing.
|
||||
config.censorship.tls_fetch_scope = config.censorship.tls_fetch_scope.trim().to_string();
|
||||
|
||||
@@ -2126,6 +2166,21 @@ impl ProxyConfig {
|
||||
}
|
||||
}
|
||||
|
||||
for (domain, target) in &self.censorship.exclusive_mask {
|
||||
if !is_valid_tls_domain_name(domain) {
|
||||
return Err(ProxyError::Config(format!(
|
||||
"Invalid censorship.exclusive_mask domain: '{}'. Must be a valid domain name",
|
||||
domain
|
||||
)));
|
||||
}
|
||||
if parse_exclusive_mask_target(target).is_none() {
|
||||
return Err(ProxyError::Config(format!(
|
||||
"Invalid censorship.exclusive_mask target for '{}': '{}'. Expected host:port with port > 0",
|
||||
domain, target
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
for (user, tag) in &self.access.user_ad_tags {
|
||||
let zeros = "00000000000000000000000000000000";
|
||||
if !is_valid_ad_tag(tag) {
|
||||
@@ -2667,6 +2722,32 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exclusive_mask_parses_domain_target_map() {
|
||||
let cfg = load_config_from_temp_toml(
|
||||
r#"
|
||||
[general]
|
||||
[network]
|
||||
[server]
|
||||
[access]
|
||||
[censorship]
|
||||
tls_domain = "example.com"
|
||||
[censorship.exclusive_mask]
|
||||
"my-site.com" = "127.0.0.1:8443"
|
||||
"ipv6.example" = "[::1]:9443"
|
||||
"#,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
cfg.censorship.exclusive_mask.get("my-site.com"),
|
||||
Some(&"127.0.0.1:8443".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
cfg.censorship.exclusive_mask.get("ipv6.example"),
|
||||
Some(&"[::1]:9443".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn api_gray_action_parses_and_defaults_to_drop() {
|
||||
let cfg_default: ProxyConfig = toml::from_str(
|
||||
|
||||
@@ -1719,6 +1719,10 @@ pub struct AntiCensorshipConfig {
|
||||
#[serde(default = "default_mask_port")]
|
||||
pub mask_port: u16,
|
||||
|
||||
/// Per-SNI TCP mask targets. Keys are SNI domains, values are `host:port`.
|
||||
#[serde(default)]
|
||||
pub exclusive_mask: HashMap<String, String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub mask_unix_sock: Option<String>,
|
||||
|
||||
@@ -1842,6 +1846,7 @@ impl Default for AntiCensorshipConfig {
|
||||
mask: default_true(),
|
||||
mask_host: None,
|
||||
mask_port: default_mask_port(),
|
||||
exclusive_mask: HashMap::new(),
|
||||
mask_unix_sock: None,
|
||||
fake_cert_len: default_fake_cert_len(),
|
||||
tls_emulation: true,
|
||||
|
||||
Reference in New Issue
Block a user