Compare commits

...

13 Commits

Author SHA1 Message Date
Alexey
658a565cb3 Merge pull request #770 from konstpic/feat/user-source-deny-list
feat(access): add per-user source IP deny list checks
2026-05-07 11:56:54 +03:00
Alexey
29fabcb199 Merge pull request #772 from agrofx1/user_check
Add root switch or login check
2026-05-07 11:53:50 +03:00
Alexey
efdf3bcc1b Fix root detection by checking UID 2026-05-07 11:53:29 +03:00
Agrofx
66c37ad6fd Merge branch 'flow' into user_check 2026-05-07 10:30:57 +03:00
Agrofx
0fcf67ca34 Update install.sh
Co-authored-by: Dimasssss <Dimasssss2000@gmail.com>
2026-05-07 10:30:47 +03:00
Agrofx
df14762a12 Add root switch or login check 2026-05-07 06:27:51 +03:00
Konstantin Pichugin
b605b1ba7c docs(access): document user_source_deny usage and API path
Add config examples and behavior notes for access.user_source_deny, and clarify that it is configured through config.toml rather than dedicated user API request fields.
2026-05-06 19:17:06 +03:00
Konstantin Pichugin
b859fb95c3 feat(access): add per-user source IP deny list checks
Add access.user_source_deny and enforce it in TLS and MTProto handshake paths after successful authentication to fail closed for blocked source IPs.
2026-05-06 19:11:18 +03:00
Alexey
8c303ab2b6 Merge pull request #765 from Misha20062006/patch-2
Correct saving instructions in QUICK_START_GUIDE.ru.md
2026-05-06 17:13:49 +03:00
Misha20062006
f70c2936c7 Correct saving instructions in QUICK_START_GUIDE.ru.md
Updated instructions for saving changes in the guide.
2026-05-06 00:07:14 +03:00
Alexey
9ee341a94f Merge pull request #757 from Dimasssss/docs
Update CONFIG_PARAMS
2026-05-02 00:36:46 +03:00
Dimasssss
f76c847c44 Update CONFIG_PARAMS.en.md 2026-05-01 21:10:34 +03:00
Dimasssss
1aaa9c0bc6 Update CONFIG_PARAMS.ru.md 2026-05-01 21:09:38 +03:00
7 changed files with 249 additions and 1 deletions

View File

@@ -178,6 +178,21 @@ Notes:
| `data_quota_bytes` | `u64` | no | Per-user traffic quota. |
| `max_unique_ips` | `usize` | no | Per-user unique source IP limit. |
### `access.user_source_deny` via API
- In current API surface, per-user deny-list is **not** exposed as a dedicated field in `CreateUserRequest` / `PatchUserRequest`.
- Configure it in `config.toml` under `[access.user_source_deny]` and apply via normal config reload path.
- Runtime behavior after apply:
- auth succeeds for username/secret
- source IP is checked against `access.user_source_deny[username]`
- on match, handshake is rejected with the same fail-closed outcome as invalid auth
Example config:
```toml
[access.user_source_deny]
alice = ["203.0.113.0/24", "2001:db8:abcd::/48"]
bob = ["198.51.100.42/32"]
```
### `RotateSecretRequest`
| Field | Type | Required | Description |
| --- | --- | --- | --- |

View File

@@ -162,6 +162,8 @@ This document lists all configuration keys accepted by `config.toml`.
| [`log_level`](#log_level) | `"debug"`, `"verbose"`, `"normal"`, or `"silent"` | `"normal"` |
| [`disable_colors`](#disable_colors) | `bool` | `false` |
| [`me_socks_kdf_policy`](#me_socks_kdf_policy) | `"strict"` or `"compat"` | `"strict"` |
| [`me_route_backpressure_enabled`](#me_route_backpressure_enabled) | `bool` | `false` |
| [`me_route_fairshare_enabled`](#me_route_fairshare_enabled) | `bool` | `false` |
| [`me_route_backpressure_base_timeout_ms`](#me_route_backpressure_base_timeout_ms) | `u64` | `25` |
| [`me_route_backpressure_high_timeout_ms`](#me_route_backpressure_high_timeout_ms) | `u64` | `120` |
| [`me_route_backpressure_high_watermark_pct`](#me_route_backpressure_high_watermark_pct) | `u8` | `80` |
@@ -975,6 +977,24 @@ This document lists all configuration keys accepted by `config.toml`.
[general]
me_socks_kdf_policy = "strict"
```
## me_route_backpressure_enabled
- **Constraints / validation**: `bool`.
- **Description**: Enables channel-pressure-aware route send timeouts.
- **Example**:
```toml
[general]
me_route_backpressure_enabled = false
```
## me_route_fairshare_enabled
- **Constraints / validation**: `bool`.
- **Description**: Enables fair-share routing admission across writer workers.
- **Example**:
```toml
[general]
me_route_fairshare_enabled = false
```
## me_route_backpressure_base_timeout_ms
- **Constraints / validation**: Must be within `1..=5000` (milliseconds).
- **Description**: Base backpressure timeout in milliseconds for ME route-channel send.
@@ -1753,6 +1773,7 @@ This document lists all configuration keys accepted by `config.toml`.
| [`metrics_whitelist`](#metrics_whitelist) | `IpNetwork[]` | `["127.0.0.1/32", "::1/128"]` |
| [`max_connections`](#max_connections) | `u32` | `10000` |
| [`accept_permit_timeout_ms`](#accept_permit_timeout_ms) | `u64` | `250` |
| [`listen_backlog`](#listen_backlog) | `u32` | `1024` |
## port
- **Constraints / validation**: `u16`.
@@ -1763,6 +1784,15 @@ This document lists all configuration keys accepted by `config.toml`.
[server]
port = 443
```
## listen_backlog
- **Constraints / validation**: `u32`. `0` uses the OS default backlog behavior.
- **Description**: Listen backlog passed to `listen(2)` for TCP sockets.
- **Example**:
```toml
[server]
listen_backlog = 1024
```
## listen_addr_ipv4
- **Constraints / validation**: `String` (optional). When set, must be a valid IPv4 address string.
- **Description**: IPv4 bind address for TCP listener (omit this key to disable IPv4 bind).
@@ -2005,6 +2035,7 @@ Note: This section also accepts the legacy alias `[server.admin_api]` (same sche
| [`runtime_edge_top_n`](#runtime_edge_top_n) | `usize` | `10` |
| [`runtime_edge_events_capacity`](#runtime_edge_events_capacity) | `usize` | `256` |
| [`read_only`](#read_only) | `bool` | `false` |
| [`gray_action`](#gray_action) | `"drop"`, `"api"`, or `"200"` | `"drop"` |
## enabled
- **Constraints / validation**: `bool`.
@@ -2015,6 +2046,15 @@ Note: This section also accepts the legacy alias `[server.admin_api]` (same sche
[server.api]
enabled = true
```
## gray_action
- **Constraints / validation**: `"drop"`, `"api"`, or `"200"`.
- **Description**: API response policy for gray/limited states: drop request, serve normal API response, or force `200 OK`.
- **Example**:
```toml
[server.api]
gray_action = "drop"
```
## listen
- **Constraints / validation**: `String`. Must be in `IP:PORT` format.
- **Description**: API bind address in `IP:PORT` format.
@@ -2207,6 +2247,15 @@ Note: This section also accepts the legacy alias `[server.admin_api]` (same sche
[timeouts]
client_handshake = 30
```
## client_first_byte_idle_secs
- **Constraints / validation**: `u64` (seconds). `0` disables first-byte idle enforcement.
- **Description**: Maximum idle time to wait for the first client payload byte after session setup.
- **Example**:
```toml
[timeouts]
client_first_byte_idle_secs = 300
```
## relay_idle_policy_v2_enabled
- **Constraints / validation**: `bool`.
- **Description**: Enables soft/hard middle-relay client idle policy.
@@ -2311,6 +2360,7 @@ Note: This section also accepts the legacy alias `[server.admin_api]` (same sche
| [`server_hello_delay_max_ms`](#server_hello_delay_max_ms) | `u64` | `0` |
| [`tls_new_session_tickets`](#tls_new_session_tickets) | `u8` | `0` |
| [`tls_full_cert_ttl_secs`](#tls_full_cert_ttl_secs) | `u64` | `90` |
| [`serverhello_compact`](#serverhello_compact) | `bool` | `false` |
| [`alpn_enforce`](#alpn_enforce) | `bool` | `true` |
| [`mask_proxy_protocol`](#mask_proxy_protocol) | `u8` | `0` |
| [`mask_shape_hardening`](#mask_shape_hardening) | `bool` | `true` |
@@ -2488,6 +2538,15 @@ Note: This section also accepts the legacy alias `[server.admin_api]` (same sche
[censorship]
tls_full_cert_ttl_secs = 90
```
## serverhello_compact
- **Constraints / validation**: `bool`.
- **Description**: Enables compact ServerHello/Fake-TLS profile to reduce response-size signature.
- **Example**:
```toml
[censorship]
serverhello_compact = false
```
## alpn_enforce
- **Constraints / validation**: `bool`.
- **Description**: Enforces ALPN echo behavior based on client preference.
@@ -2827,9 +2886,12 @@ If your backend or network is very bandwidth-constrained, reduce cap first. If p
| [`user_max_unique_ips_global_each`](#user_max_unique_ips_global_each) | `usize` | `0` |
| [`user_max_unique_ips_mode`](#user_max_unique_ips_mode) | `"active_window"`, `"time_window"`, or `"combined"` | `"active_window"` |
| [`user_max_unique_ips_window_secs`](#user_max_unique_ips_window_secs) | `u64` | `30` |
| [`user_source_deny`](#user_source_deny) | `Map<String, IpNetwork[]>` | `{}` |
| [`replay_check_len`](#replay_check_len) | `usize` | `65536` |
| [`replay_window_secs`](#replay_window_secs) | `u64` | `120` |
| [`ignore_time_skew`](#ignore_time_skew) | `bool` | `false` |
| [`user_rate_limits`](#user_rate_limits) | `Map<String, RateLimitBps>` | `{}` |
| [`cidr_rate_limits`](#cidr_rate_limits) | `Map<IpNetwork, RateLimitBps>` | `{}` |
## users
- **Constraints / validation**: Must not be empty (at least one user must exist). Each value must be **exactly 32 hex characters**.
@@ -2929,6 +2991,20 @@ If your backend or network is very bandwidth-constrained, reduce cap first. If p
[access]
user_max_unique_ips_window_secs = 30
```
## user_source_deny
- **Constraints / validation**: Table `username -> IpNetwork[]`. Each network must parse as CIDR (for example `203.0.113.0/24` or `2001:db8::/32`).
- **Description**: Per-user source IP/CIDR deny-list applied **after successful auth** in TLS and MTProto handshake paths. A matched source IP is rejected via the same fail-closed path as invalid auth.
- **Example**:
```toml
[access.user_source_deny]
alice = ["203.0.113.0/24", "2001:db8:abcd::/48"]
bob = ["198.51.100.42/32"]
```
- **How it works (quick check)**:
- connection from user `alice` and source `203.0.113.55` -> rejected (matches `203.0.113.0/24`)
- connection from user `alice` and source `198.51.100.10` -> allowed by this rule set (no match)
## replay_check_len
- **Constraints / validation**: `usize`.
- **Description**: Replay-protection storage length (number of entries tracked for duplicate detection).
@@ -2958,6 +3034,24 @@ If your backend or network is very bandwidth-constrained, reduce cap first. If p
```
## user_rate_limits
- **Constraints / validation**: Table `username -> { up_bps, down_bps }`. At least one direction must be non-zero.
- **Description**: Per-user bandwidth caps in bytes/sec for upload (`up_bps`) and download (`down_bps`).
- **Example**:
```toml
[access.user_rate_limits]
alice = { up_bps = 1048576, down_bps = 2097152 }
```
## cidr_rate_limits
- **Constraints / validation**: Table `CIDR -> { up_bps, down_bps }`. CIDR must parse as `IpNetwork`; at least one direction must be non-zero.
- **Description**: Source-subnet bandwidth caps applied alongside per-user limits.
- **Example**:
```toml
[access.cidr_rate_limits]
"203.0.113.0/24" = { up_bps = 0, down_bps = 1048576 }
```
# [[upstreams]]

View File

@@ -162,6 +162,8 @@
| [`log_level`](#log_level) | `"debug"`, `"verbose"`, `"normal"`, or `"silent"` | `"normal"` |
| [`disable_colors`](#disable_colors) | `bool` | `false` |
| [`me_socks_kdf_policy`](#me_socks_kdf_policy) | `"strict"` or `"compat"` | `"strict"` |
| [`me_route_backpressure_enabled`](#me_route_backpressure_enabled) | `bool` | `false` |
| [`me_route_fairshare_enabled`](#me_route_fairshare_enabled) | `bool` | `false` |
| [`me_route_backpressure_base_timeout_ms`](#me_route_backpressure_base_timeout_ms) | `u64` | `25` |
| [`me_route_backpressure_high_timeout_ms`](#me_route_backpressure_high_timeout_ms) | `u64` | `120` |
| [`me_route_backpressure_high_watermark_pct`](#me_route_backpressure_high_watermark_pct) | `u8` | `80` |
@@ -975,6 +977,24 @@
[general]
me_socks_kdf_policy = "strict"
```
## me_route_backpressure_enabled
- **Ограничения / валидация**: `bool`.
- **Описание**: Включает адаптивные таймауты записи маршрута в зависимости от заполнения канала.
- **Example**:
```toml
[general]
me_route_backpressure_enabled = false
```
## me_route_fairshare_enabled
- **Ограничения / валидация**: `bool`.
- **Описание**: Включает справедливое распределение нагрузки маршрутизации между writer-потоками.
- **Example**:
```toml
[general]
me_route_fairshare_enabled = false
```
## me_route_backpressure_base_timeout_ms
- **Ограничения / валидация**: Должно быть в пределах `1..=5000` (миллисекунд).
- **Описание**: Базовый таймаут (в миллисекундах) ожидания при режиме **backpressure** (ситуация, при которой данные обрабатываются медленне, чем получаются) для отправки через ME route-channel.
@@ -1755,6 +1775,7 @@
| [`metrics_whitelist`](#metrics_whitelist) | `IpNetwork[]` | `["127.0.0.1/32", "::1/128"]` |
| [`max_connections`](#max_connections) | `u32` | `10000` |
| [`accept_permit_timeout_ms`](#accept_permit_timeout_ms) | `u64` | `250` |
| [`listen_backlog`](#listen_backlog) | `u32` | `1024` |
## port
- **Ограничения / валидация**: `u16`.
@@ -1765,6 +1786,15 @@
[server]
port = 443
```
## listen_backlog
- **Ограничения / валидация**: `u32`. `0` использует системный backlog по умолчанию.
- **Описание**: Значение backlog, передаваемое в `listen(2)` для TCP-сокетов.
- **Example**:
```toml
[server]
listen_backlog = 1024
```
## listen_addr_ipv4
- **Ограничения / валидация**: `String` (необязательный параметр). Если задан, должен содержать валидный IPv4-адрес в формате строки.
- **Описание**: Прослушиваемый адрес в формате IPv4 (не задавайте этот параметр, если необходимо отключить прослушивание по IPv4).
@@ -2011,6 +2041,7 @@
| [`runtime_edge_top_n`](#runtime_edge_top_n) | `usize` | `10` |
| [`runtime_edge_events_capacity`](#runtime_edge_events_capacity) | `usize` | `256` |
| [`read_only`](#read_only) | `bool` | `false` |
| [`gray_action`](#gray_action) | `"drop"`, `"api"`, or `"200"` | `"drop"` |
## enabled
- **Ограничения / валидация**: `bool`.
@@ -2021,6 +2052,15 @@
[server.api]
enabled = true
```
## gray_action
- **Ограничения / валидация**: `"drop"`, `"api"` или `"200"`.
- **Описание**: Политика ответа API в «серых» (ограниченных) состояниях: сброс, обычный API-ответ, либо `200 OK`.
- **Example**:
```toml
[server.api]
gray_action = "drop"
```
## listen
- **Ограничения / валидация**: `String`. Должно быть в формате `IP:PORT`.
- **Описание**: Адрес биндинга API в формате `IP:PORT`.
@@ -2213,6 +2253,15 @@
[timeouts]
client_handshake = 30
```
## client_first_byte_idle_secs
- **Ограничения / валидация**: `u64` (секунды). `0` отключает проверку простоя до первого байта.
- **Описание**: Максимальное время ожидания первого байта полезной нагрузки от клиента после установления сессии.
- **Example**:
```toml
[timeouts]
client_first_byte_idle_secs = 300
```
## relay_idle_policy_v2_enabled
- **Ограничения / валидация**: `bool`.
- **Описание**: Включает политику простоя клиента для промежуточного узла.
@@ -2317,6 +2366,7 @@
| [`server_hello_delay_max_ms`](#server_hello_delay_max_ms) | `u64` | `0` |
| [`tls_new_session_tickets`](#tls_new_session_tickets) | `u8` | `0` |
| [`tls_full_cert_ttl_secs`](#tls_full_cert_ttl_secs) | `u64` | `90` |
| [`serverhello_compact`](#serverhello_compact) | `bool` | `false` |
| [`alpn_enforce`](#alpn_enforce) | `bool` | `true` |
| [`mask_proxy_protocol`](#mask_proxy_protocol) | `u8` | `0` |
| [`mask_shape_hardening`](#mask_shape_hardening) | `bool` | `true` |
@@ -2493,6 +2543,15 @@
[censorship]
tls_full_cert_ttl_secs = 90
```
## serverhello_compact
- **Ограничения / валидация**: `bool`.
- **Описание**: Включает компактный профиль ServerHello/Fake-TLS для снижения сигнатуры размера ответа.
- **Example**:
```toml
[censorship]
serverhello_compact = false
```
## alpn_enforce
- **Ограничения / валидация**: `bool`.
- **Описание**: Принудительно изменяет поведение возврата ALPN в соответствии с предпочтениями клиента.
@@ -2837,6 +2896,8 @@
| [`replay_check_len`](#replay_check_len) | `usize` | `65536` |
| [`replay_window_secs`](#replay_window_secs) | `u64` | `120` |
| [`ignore_time_skew`](#ignore_time_skew) | `bool` | `false` |
| [`user_rate_limits`](#user_rate_limits) | `Map<String, RateLimitBps>` | `{}` |
| [`cidr_rate_limits`](#cidr_rate_limits) | `Map<IpNetwork, RateLimitBps>` | `{}` |
## users
- **Ограничения / валидация**: Не должно быть пустым (должен существовать хотя бы один пользователь). Каждое значение должно состоять **ровно из 32 шестнадцатеричных символов**.
@@ -2965,6 +3026,24 @@
```
## user_rate_limits
- **Ограничения / валидация**: Таблица `username -> { up_bps, down_bps }`. Должно быть ненулевое значение хотя бы в одном направлении.
- **Описание**: Персональные лимиты скорости по пользователям в байтах/сек для отправки (`up_bps`) и получения (`down_bps`).
- **Example**:
```toml
[access.user_rate_limits]
alice = { up_bps = 1048576, down_bps = 2097152 }
```
## cidr_rate_limits
- **Ограничения / валидация**: Таблица `CIDR -> { up_bps, down_bps }`. CIDR должен корректно разбираться как `IpNetwork`; хотя бы одно направление должно быть ненулевым.
- **Описание**: Лимиты скорости для подсетей источников, применяются поверх пользовательских ограничений.
- **Example**:
```toml
[access.cidr_rate_limits]
"203.0.113.0/24" = { up_bps = 0, down_bps = 1048576 }
```
# [[upstreams]]

View File

@@ -164,7 +164,7 @@ tls_front_dir = "tlsfront" # Директория кэша для эмуляц
hello = "00000000000000000000000000000000"
```
Затем нажмите Ctrl+S -> Ctrl+X, чтобы сохранить
Затем нажмите Ctrl+O -> Ctrl+X, чтобы сохранить
> [!WARNING]
> Замените значение параметра `hello` на значение, которое вы получили в пункте 0.

View File

@@ -102,6 +102,7 @@ set_language() {
L_OUT_SUCC_H="УСТАНОВКА УСПЕШНО ЗАВЕРШЕНА"
L_OUT_UNINST_H="УДАЛЕНИЕ ЗАВЕРШЕНО"
L_OUT_LINK="Ваша ссылка для подключения к Telegram Proxy:\n"
L_ERR_INCORR_ROOT_LOGIN="Используйте 'su -' или 'sudo -i' для входа под пользователем root"
;;
*)
L_ERR_DOMAIN_REQ="requires a domain argument."
@@ -176,6 +177,7 @@ set_language() {
L_OUT_SUCC_H="INSTALLATION SUCCESS"
L_OUT_UNINST_H="UNINSTALLATION COMPLETE"
L_OUT_LINK="Your Telegram Proxy connection link:\n"
L_ERR_INCORR_ROOT_LOGIN="Use 'su -' or 'sudo -i' to login under root"
;;
esac
}
@@ -388,6 +390,9 @@ verify_common() {
if [ "$(id -u)" -eq 0 ]; then
SUDO=""
if [ "$(id -u)" -ne 0 ]; then
die "$L_ERR_INCORR_ROOT_LOGIN"
fi
else
command -v sudo >/dev/null 2>&1 || die "$L_ERR_ROOT"
SUDO="sudo"

View File

@@ -1893,6 +1893,12 @@ pub struct AccessConfig {
#[serde(default)]
pub cidr_rate_limits: HashMap<IpNetwork, RateLimitBps>,
/// Per-username client source IP/CIDR deny list. Checked after successful
/// authentication; matching IPs get the same rejection path as invalid auth
/// (handshake fails closed for that connection).
#[serde(default)]
pub user_source_deny: HashMap<String, Vec<IpNetwork>>,
#[serde(default)]
pub user_max_unique_ips: HashMap<String, usize>,
@@ -1928,6 +1934,7 @@ impl Default for AccessConfig {
user_data_quota: HashMap::new(),
user_rate_limits: HashMap::new(),
cidr_rate_limits: HashMap::new(),
user_source_deny: HashMap::new(),
user_max_unique_ips: HashMap::new(),
user_max_unique_ips_global_each: default_user_max_unique_ips_global_each(),
user_max_unique_ips_mode: UserMaxUniqueIpsMode::default(),
@@ -1939,6 +1946,15 @@ impl Default for AccessConfig {
}
}
impl AccessConfig {
/// Returns true if `ip` is contained in any CIDR listed for `username` under `user_source_deny`.
pub fn is_user_source_ip_denied(&self, username: &str, ip: IpAddr) -> bool {
self.user_source_deny
.get(username)
.is_some_and(|nets| nets.iter().any(|n| n.contains(ip)))
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct RateLimitBps {
#[serde(default)]

View File

@@ -1450,6 +1450,20 @@ where
validated_secret.copy_from_slice(secret);
}
if config
.access
.is_user_source_ip_denied(validated_user.as_str(), peer.ip())
{
auth_probe_record_failure_in(shared, peer.ip(), Instant::now());
maybe_apply_server_hello_delay(config).await;
warn!(
peer = %peer,
user = %validated_user,
"TLS handshake rejected: client source IP on per-user deny list (access.user_source_deny)"
);
return HandshakeResult::BadClient { reader, writer };
}
// Reject known replay digests before expensive cache/domain/ALPN policy work.
let digest_half = &validation_digest[..tls::TLS_DIGEST_HALF_LEN];
if replay_checker.check_tls_digest(digest_half) {
@@ -1795,6 +1809,20 @@ where
let validation = matched_validation.expect("validation must exist when matched");
if config
.access
.is_user_source_ip_denied(matched_user.as_str(), peer.ip())
{
auth_probe_record_failure_in(shared, peer.ip(), Instant::now());
maybe_apply_server_hello_delay(config).await;
warn!(
peer = %peer,
user = %matched_user,
"MTProto handshake rejected: client source IP on per-user deny list (access.user_source_deny)"
);
return HandshakeResult::BadClient { reader, writer };
}
// Apply replay tracking only after successful authentication.
//
// This ordering prevents an attacker from producing invalid handshakes that
@@ -1873,6 +1901,17 @@ where
.auth_expensive_checks_total
.fetch_add(validation_checks as u64, Ordering::Relaxed);
if config.access.is_user_source_ip_denied(user.as_str(), peer.ip()) {
auth_probe_record_failure_in(shared, peer.ip(), Instant::now());
maybe_apply_server_hello_delay(config).await;
warn!(
peer = %peer,
user = %user,
"MTProto handshake rejected: client source IP on per-user deny list (access.user_source_deny)"
);
return HandshakeResult::BadClient { reader, writer };
}
// Apply replay tracking only after successful authentication.
//
// This ordering prevents an attacker from producing invalid handshakes that