diff --git a/docs/README.md b/docs/README.md
index 54d5c53..0c66825 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -5,7 +5,7 @@
> **USDT (TRC20)**: `TXPnKs2Ww1RD8JN6nChFUVmi5r2hqrWjuu`
> **BTC**: `bc1qr8vd6jelkyyry3m4mq6z5txdx4pl856fu6ss0w`
> **ETH**: `0x1417878fdc5047E670a77748B34819b9A49C72F1`
-> Другие монеты: https://nowpayments.io/donation/flowseal
+> **Другие монеты**: https://nowpayments.io/donation/flowseal
> [!CAUTION]
>
@@ -39,7 +39,9 @@ Telegram Desktop → MTProto Proxy (127.0.0.1:1443) → WebSocket → Telegram D
> [!IMPORTANT]
> ### Не грузит фото/видео?
-> ### Удалите в настройках прокси в DC->IP всё, кроме `4:149.154.167.220`
+> **Удалите в настройках прокси в DC->IP всё, кроме `4:149.154.167.220`**
+> **Если не помогло, то удалите вообще всё из этого поля**
+> ####
> Подобная проблема встречается на аккаунтах без Premium
> Если вам не помогло, то настраивайте свой домен по гайду отсюда: https://github.com/Flowseal/tg-ws-proxy/blob/main/docs/CfProxy.md
@@ -54,6 +56,7 @@ Telegram Desktop → MTProto Proxy (127.0.0.1:1443) → WebSocket → Telegram D
**Меню трея:**
- **Открыть в Telegram** — автоматически настроить прокси через `tg://proxy` ссылку
+- **Скопировать ссылку** — скопировать ссылку для подключения
- **Перезапустить прокси** — перезапуск без выхода из приложения
- **Настройки...** — GUI-редактор конфигурации (в т.ч. версия приложения, опциональная проверка обновлений с GitHub)
- **Открыть логи** — открыть файл логов
@@ -61,6 +64,26 @@ Telegram Desktop → MTProto Proxy (127.0.0.1:1443) → WebSocket → Telegram D
При первом запуске после старта может появиться запрос об открытии страницы релиза, если на GitHub вышла новая версия (отключается в настройках).
+### Настройка Telegram Desktop
+
+### Автоматически:
+
+ПКМ по иконке в трее → **«Открыть в Telegram»**
+Если не сработало (не открылся Telegram с подключением), то:
+1. ПКМ по иконке в трее → **«Скопировать ссылку»**
+2. Отправьте ссылку себе в избранное в Telegram клиенте и нажмите по ней ЛКМ
+3. Подключитесь
+
+### Вручную:
+
+1. Telegram → **Настройки** → **Продвинутые настройки** → **Тип подключения** → **Прокси**
+2. Добавить прокси:
+ - **Тип:** MTProto
+ - **Сервер:** `127.0.0.1` (или переопределенный вами)
+ - **Порт:** `1443` (или переопределенный вами)
+ - **Secret:** из настроек или логов
+
+##
### macOS
Перейдите на [страницу релизов](https://github.com/Flowseal/tg-ws-proxy/releases) и скачайте **`TgWsProxy_macos_universal.dmg`** — универсальная сборка для Apple Silicon и Intel.
@@ -147,6 +170,8 @@ tg-ws-proxy [--port PORT] [--host HOST] [--dc-ip DC:IP ...] [-v]
| `--no-cfproxy` | `false` | Отключить попытку [проксирования через Cloudflare]((https://github.com/Flowseal/tg-ws-proxy/blob/main/docs/CfProxy.md)) |
| `--cfproxy-domain` | | Указать свой домен для проксирования через Cloudfalre. [Подробнее тут](https://github.com/Flowseal/tg-ws-proxy/blob/main/docs/CfProxy.md) |
| `--cfproxy-priority` | `true` | Пробовать проксировать через Cloudflare перед прямым TCP подключением |
+| `--fake-tls-domain` | | Включить Fake TLS (ee-secret) маскировку с указанным SNI-доменом |
+| `--proxy-protocol` | выкл. | Принимать HAProxy PROXY protocol v1 (для работы за nginx/haproxy с `proxy_protocol on`) |
| `--buf-kb` | `256` | Размер буфера в КБ |
| `--pool-size` | `4` | Количество заготовленных соединений на каждый DC |
| `--log-file` | выкл. | Путь до файла, в который сохранять логи |
@@ -165,24 +190,64 @@ tg-ws-proxy --port 9050 --dc-ip 1:149.154.175.205 --dc-ip 2:149.154.167.220
# С подробным логированием
tg-ws-proxy -v
+
+# Fake TLS маскировка (ee-secret)
+tg-ws-proxy --fake-tls-domain example.com
```
-## Настройка Telegram Desktop
+## Fake TLS + nginx upstream
+### Домен (`--fake-tls-domain`) должен указывать на тот же IP, на котором стоит прокси
-### Автоматически
+**Пример `nginx.conf` (stream):**
-ПКМ по иконке в трее → **«Открыть в Telegram»**
+```nginx
+upstream mtproto {
+ server 127.0.0.1:8446;
+}
-### Вручную
+map $ssl_preread_server_name $sni_name {
+ hostnames;
+ example.com mtproto;
+ # if you have xray with selfsni running:
+ # sub.example.com www;
+ # default xray;
+}
-1. Telegram → **Настройки** → **Продвинутые настройки** → **Тип подключения** → **Прокси**
-2. Добавить прокси:
- - **Тип:** MTProto
- - **Сервер:** `127.0.0.1` (или переопределенный вами)
- - **Порт:** `1443` (или переопределенный вами)
- - **Secret:** из настроек или логов
+# upstream xray {
+# server 127.0.0.1:8443;
+# }
+#
+# upstream www {
+# server 127.0.0.1:7443;
+# }
-## Конфигурация
+server {
+ proxy_protocol on;
+ set_real_ip_from unix:;
+ listen 443;
+ proxy_pass $sni_name;
+ ssl_preread on;
+}
+```
+
+**Запуск прокси за nginx:**
+
+```bash
+python3 proxy/tg_ws_proxy.py \
+ --port 8446 \
+ --host 127.0.0.1 \
+ --fake-tls-domain example.com \
+ --proxy-protocol \
+ --secret <32-hex-chars>
+```
+
+Ссылка для подключения будет в формате `ee`-секрета:
+
+```
+tg://proxy?server=your.domain.com&port=443&secret=ee
+```
+
+## Файлы конфигурации Tray-приложения
Tray-приложение хранит данные в:
@@ -203,7 +268,11 @@ Tray-приложение хранит данные в:
"buf_kb": 256,
"pool_size": 4,
"log_max_mb": 5.0,
- "check_updates": true
+ "check_updates": true,
+ "cfproxy": true,
+ "cfproxy_priority": true,
+ "cfproxy_user_domain": "",
+ "appearance": "auto"
}
```
diff --git a/proxy/config.py b/proxy/config.py
index c5f74e8..e9a1bd0 100644
--- a/proxy/config.py
+++ b/proxy/config.py
@@ -47,6 +47,8 @@ class ProxyConfig:
cfproxy_user_domain: str = ''
cfproxy_domains: List[str] = field(default_factory=lambda: list(CFPROXY_DEFAULT_DOMAINS))
active_cfproxy_domain: str = field(default_factory=lambda: random.choice(CFPROXY_DEFAULT_DOMAINS))
+ fake_tls_domain: str = ''
+ proxy_protocol: bool = False
proxy_config = ProxyConfig()
diff --git a/proxy/fake_tls.py b/proxy/fake_tls.py
new file mode 100644
index 0000000..9b7e0b2
--- /dev/null
+++ b/proxy/fake_tls.py
@@ -0,0 +1,256 @@
+from __future__ import annotations
+
+import asyncio
+import hmac
+import hashlib
+import os
+import random
+import struct
+import time
+import logging
+
+from typing import Optional, Tuple
+from .stats import stats
+
+
+log = logging.getLogger('tg-mtproto-proxy')
+
+TLS_RECORD_HANDSHAKE = 0x16
+TLS_RECORD_CCS = 0x14
+TLS_RECORD_APPDATA = 0x17
+
+TLS_VERSION_10 = b'\x03\x01'
+TLS_VERSION_12 = b'\x03\x03'
+TLS_VERSION_13 = b'\x03\x04'
+
+CLIENT_RANDOM_OFFSET = 11
+CLIENT_RANDOM_LEN = 32
+SESSION_ID_OFFSET = 44
+SESSION_ID_LEN = 32
+
+TIMESTAMP_TOLERANCE = 120
+
+TLS_APPDATA_MAX = 16384
+
+
+_CCS_FRAME = b'\x14\x03\x03\x00\x01\x01'
+
+_SERVER_HELLO_TEMPLATE = bytearray(
+ b'\x16\x03\x03\x00\x7a'
+ b'\x02\x00\x00\x76'
+ b'\x03\x03'
+ + b'\x00' * 32
+ + b'\x20'
+ + b'\x00' * 32
+ + b'\x13\x01\x00'
+ + b'\x00\x2e'
+ + b'\x00\x33\x00\x24\x00\x1d\x00\x20'
+ + b'\x00' * 32
+ + b'\x00\x2b\x00\x02\x03\x04'
+)
+
+_SH_RANDOM_OFF = 11
+_SH_SESSID_OFF = 44
+_SH_PUBKEY_OFF = 89
+
+
+def verify_client_hello(data: bytes, secret: bytes) -> Optional[Tuple[bytes, bytes, int]]:
+ n = len(data)
+ # 5 (record hdr) + 6 (hs type+len+version) + 32 (random) = 43
+ if n < 43:
+ return None
+ if data[0] != TLS_RECORD_HANDSHAKE:
+ return None
+ if data[5] != 0x01:
+ return None
+
+ client_random = bytes(data[CLIENT_RANDOM_OFFSET:CLIENT_RANDOM_OFFSET + CLIENT_RANDOM_LEN])
+
+ zeroed = bytearray(data)
+ zeroed[CLIENT_RANDOM_OFFSET:CLIENT_RANDOM_OFFSET + CLIENT_RANDOM_LEN] = b'\x00' * CLIENT_RANDOM_LEN
+
+ expected = hmac.new(secret, bytes(zeroed), hashlib.sha256).digest()
+
+ if not hmac.compare_digest(expected[:28], client_random[:28]):
+ return None
+
+ ts_xor = bytes(client_random[28 + i] ^ expected[28 + i] for i in range(4))
+ timestamp = struct.unpack(' TIMESTAMP_TOLERANCE:
+ return None
+
+ session_id = b'\x00' * SESSION_ID_LEN
+ if n >= SESSION_ID_OFFSET + SESSION_ID_LEN and data[43] == 0x20:
+ session_id = bytes(data[SESSION_ID_OFFSET:SESSION_ID_OFFSET + SESSION_ID_LEN])
+
+ return client_random, session_id, timestamp
+
+
+def build_server_hello(secret: bytes, client_random: bytes, session_id: bytes) -> bytes:
+ sh = bytearray(_SERVER_HELLO_TEMPLATE)
+ sh[_SH_SESSID_OFF:_SH_SESSID_OFF + 32] = session_id
+ sh[_SH_PUBKEY_OFF:_SH_PUBKEY_OFF + 32] = os.urandom(32)
+
+ ccs = _CCS_FRAME
+ encrypted_size = random.randint(1900, 2100)
+ encrypted_data = os.urandom(encrypted_size)
+ app_record = b'\x17\x03\x03' + struct.pack('>H', encrypted_size) + encrypted_data
+
+ response = bytes(sh) + ccs + app_record
+
+ hmac_input = client_random + response
+ server_random = hmac.new(secret, hmac_input, hashlib.sha256).digest()
+
+ final = bytearray(response)
+ final[_SH_RANDOM_OFF:_SH_RANDOM_OFF + 32] = server_random
+
+ return bytes(final)
+
+
+def wrap_tls_record(data: bytes) -> bytes:
+ parts = []
+ offset = 0
+ while offset < len(data):
+ chunk = data[offset:offset + TLS_APPDATA_MAX]
+ parts.append(
+ b'\x17\x03\x03'
+ + struct.pack('>H', len(chunk))
+ + chunk
+ )
+ offset += len(chunk)
+ return b''.join(parts)
+
+
+class FakeTlsStream:
+ __slots__ = ('_reader', '_writer', '_read_buf', '_read_left')
+
+ def __init__(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
+ self._reader = reader
+ self._writer = writer
+ self._read_buf = bytearray()
+ self._read_left = 0
+
+ async def readexactly(self, n: int) -> bytes:
+ while len(self._read_buf) < n:
+ payload = await self._read_tls_payload()
+ if not payload:
+ raise asyncio.IncompleteReadError(bytes(self._read_buf), n)
+ self._read_buf.extend(payload)
+ result = bytes(self._read_buf[:n])
+ del self._read_buf[:n]
+ return result
+
+ async def read(self, n: int) -> bytes:
+ if self._read_buf:
+ chunk = bytes(self._read_buf[:n])
+ del self._read_buf[:n]
+ return chunk
+ payload = await self._read_tls_payload()
+ if not payload:
+ return b''
+ if len(payload) > n:
+ self._read_buf.extend(payload[n:])
+ return payload[:n]
+ return payload
+
+ async def _read_tls_payload(self) -> bytes:
+ if self._read_left > 0:
+ data = await self._reader.read(self._read_left)
+ if not data:
+ return b''
+ self._read_left -= len(data)
+ return data
+
+ while True:
+ hdr = await self._reader.readexactly(5)
+ rtype = hdr[0]
+ rec_len = struct.unpack('>H', hdr[3:5])[0]
+
+ if rtype == TLS_RECORD_CCS:
+ if rec_len > 0:
+ await self._reader.readexactly(rec_len)
+ continue
+
+ if rtype != TLS_RECORD_APPDATA:
+ return b''
+
+ data = await self._reader.read(min(rec_len, 65536))
+ if not data:
+ return b''
+ remaining = rec_len - len(data)
+ if remaining > 0:
+ self._read_left = remaining
+ return data
+
+ def write(self, data: bytes) -> None:
+ self._writer.write(wrap_tls_record(data))
+
+ async def drain(self) -> None:
+ await self._writer.drain()
+
+ def close(self) -> None:
+ self._writer.close()
+
+ async def wait_closed(self) -> None:
+ await self._writer.wait_closed()
+
+ def get_extra_info(self, name, default=None):
+ return self._writer.get_extra_info(name, default)
+
+ @property
+ def transport(self):
+ return self._writer.transport
+
+ def is_closing(self):
+ return self._writer.is_closing()
+
+
+async def proxy_to_masking_domain(reader, writer, initial_data: bytes,
+ domain: str, label: str) -> None:
+ try:
+ up_reader, up_writer = await asyncio.wait_for(
+ asyncio.open_connection(domain, 443), timeout=10)
+ except Exception as exc:
+ log.debug("[%s] masking: cannot connect to %s:443: %s",
+ label, domain, exc)
+ return
+
+ log.debug("[%s] masking -> %s:443", label, domain)
+ stats.connections_masked += 1
+
+ try:
+ if initial_data:
+ up_writer.write(initial_data)
+ await up_writer.drain()
+
+ async def _relay(src, dst):
+ try:
+ while True:
+ chunk = await src.read(16384)
+ if not chunk:
+ break
+ dst.write(chunk)
+ await dst.drain()
+ except (ConnectionResetError, BrokenPipeError, OSError,
+ asyncio.CancelledError):
+ pass
+ finally:
+ try:
+ dst.close()
+ await dst.wait_closed()
+ except Exception:
+ pass
+
+ await asyncio.gather(
+ _relay(reader, up_writer),
+ _relay(up_reader, writer),
+ )
+ except Exception:
+ pass
+ finally:
+ try:
+ up_writer.close()
+ except Exception:
+ pass
diff --git a/proxy/stats.py b/proxy/stats.py
index 3a9e61b..7a7276d 100644
--- a/proxy/stats.py
+++ b/proxy/stats.py
@@ -8,6 +8,7 @@ class _Stats:
self.connections_tcp_fallback = 0
self.connections_cfproxy = 0
self.connections_bad = 0
+ self.connections_masked = 0
self.ws_errors = 0
self.bytes_up = 0
self.bytes_down = 0
@@ -24,6 +25,7 @@ class _Stats:
f"tcp_fb={self.connections_tcp_fallback} "
f"cf={self.connections_cfproxy} "
f"bad={self.connections_bad} "
+ f"masked={self.connections_masked} "
f"err={self.ws_errors} "
f"pool={pool_s} "
f"up={human_bytes(self.bytes_up)} "
diff --git a/proxy/tg_ws_proxy.py b/proxy/tg_ws_proxy.py
index a2b8a31..900fc16 100644
--- a/proxy/tg_ws_proxy.py
+++ b/proxy/tg_ws_proxy.py
@@ -28,6 +28,7 @@ from .stats import stats
from .config import proxy_config, parse_dc_ip_list, start_cfproxy_domain_refresh, CFPROXY_DEFAULT_DOMAINS
from .bridge import MsgSplitter, CryptoCtx, do_fallback, bridge_ws_reencrypt
from .raw_websocket import RawWebSocket, WsHandshakeError, set_sock_opts
+from .fake_tls import proxy_to_masking_domain, verify_client_hello, build_server_hello, FakeTlsStream, TLS_RECORD_HANDSHAKE
log = logging.getLogger('tg-mtproto-proxy')
@@ -214,25 +215,115 @@ async def _handle_client(reader, writer, secret: bytes):
set_sock_opts(writer.transport, proxy_config.buffer_size)
+ tls_stream = None
+ masking = proxy_config.fake_tls_domain
+
try:
+ if proxy_config.proxy_protocol:
+ try:
+ pp_line = await asyncio.wait_for(
+ reader.readline(), timeout=10)
+ except asyncio.IncompleteReadError:
+ log.debug("[%s] disconnected during PROXY header", label)
+ return
+ pp_text = pp_line.decode('ascii', errors='replace').strip()
+ if pp_text.startswith('PROXY '):
+ parts = pp_text.split()
+ if len(parts) >= 6:
+ label = f"{parts[2]}:{parts[4]}"
+ log.debug("[%s] PROXY protocol: %s", label, pp_text)
+ else:
+ log.debug("[%s] expected PROXY header, got: %r", label,
+ pp_text[:60])
+
try:
- handshake = await asyncio.wait_for(
- reader.readexactly(HANDSHAKE_LEN), timeout=10)
+ first_byte = await asyncio.wait_for(
+ reader.readexactly(1), timeout=10)
except asyncio.IncompleteReadError:
log.debug("[%s] client disconnected before handshake", label)
return
+ if first_byte[0] == TLS_RECORD_HANDSHAKE and masking:
+ try:
+ hdr_rest = await asyncio.wait_for(
+ reader.readexactly(4), timeout=10)
+ except asyncio.IncompleteReadError:
+ log.debug("[%s] incomplete TLS record header", label)
+ return
+
+ tls_header = first_byte + hdr_rest
+ record_len = struct.unpack('>H', tls_header[3:5])[0]
+
+ try:
+ record_body = await asyncio.wait_for(
+ reader.readexactly(record_len), timeout=10)
+ except asyncio.IncompleteReadError:
+ log.debug("[%s] incomplete TLS record body", label)
+ return
+
+ client_hello = tls_header + record_body
+
+ tls_result = verify_client_hello(client_hello, secret)
+
+ if tls_result is None:
+ log.debug("[%s] Fake TLS verify failed (size=%d rec=%d) "
+ "-> masking",
+ label, len(client_hello), record_len)
+ await proxy_to_masking_domain(
+ reader, writer, client_hello, masking, label)
+ return
+
+ client_random, session_id, ts = tls_result
+ log.debug("[%s] Fake TLS handshake ok (ts=%d)", label, ts)
+
+ server_hello = build_server_hello(secret, client_random, session_id)
+ writer.write(server_hello)
+ await writer.drain()
+
+ tls_stream = FakeTlsStream(reader, writer)
+
+ try:
+ handshake = await asyncio.wait_for(
+ tls_stream.readexactly(HANDSHAKE_LEN), timeout=10)
+ except asyncio.IncompleteReadError:
+ log.debug("[%s] incomplete obfs2 init inside TLS", label)
+ return
+ elif masking:
+ log.debug("[%s] non-TLS byte 0x%02X -> HTTP redirect", label,
+ first_byte[0])
+ redirect = (
+ f"HTTP/1.1 301 Moved Permanently\r\n"
+ f"Location: https://{masking}/\r\n"
+ f"Content-Length: 0\r\n"
+ f"Connection: close\r\n\r\n"
+ ).encode()
+ writer.write(redirect)
+ await writer.drain()
+ return
+ else:
+ try:
+ rest = await asyncio.wait_for(
+ reader.readexactly(HANDSHAKE_LEN - 1), timeout=10)
+ except asyncio.IncompleteReadError:
+ log.debug("[%s] client disconnected before handshake", label)
+ return
+ handshake = first_byte + rest
+
result = _try_handshake(handshake, secret)
if result is None:
stats.connections_bad += 1
log.debug("[%s] bad handshake (wrong secret or proto)", label)
try:
- while await reader.read(4096):
+ drain_src = tls_stream or reader
+ while await drain_src.read(4096):
pass
except Exception:
pass
return
+ clt_reader = tls_stream or reader
+ clt_writer = tls_stream or writer
+
dc, is_media, proto_tag, client_dec_prekey_iv = result
if proto_tag == PROTO_TAG_ABRIDGED:
@@ -308,7 +399,7 @@ async def _handle_client(reader, writer, secret: bytes):
except Exception:
pass
ok = await do_fallback(
- reader, writer, relay_init, label,
+ clt_reader, clt_writer, relay_init, label,
dc, is_media, media_tag,
ctx, splitter=splitter)
if not ok:
@@ -378,7 +469,7 @@ async def _handle_client(reader, writer, secret: bytes):
except Exception:
pass
ok = await do_fallback(
- reader, writer, relay_init, label,
+ clt_reader, clt_writer, relay_init, label,
dc, is_media, media_tag,
ctx, splitter=splitter_fb)
if ok:
@@ -399,7 +490,7 @@ async def _handle_client(reader, writer, secret: bytes):
await ws.send(relay_init)
- await bridge_ws_reencrypt(reader, writer, ws, label,
+ await bridge_ws_reencrypt(clt_reader, clt_writer, ws, label,
dc=dc, is_media=is_media,
ctx=ctx, splitter=splitter)
@@ -422,6 +513,7 @@ async def _handle_client(reader, writer, secret: bytes):
stats.connections_active -= 1
try:
writer.close()
+ await writer.wait_closed()
except BaseException:
pass
@@ -467,12 +559,23 @@ async def _run(stop_event: Optional[asyncio.Event] = None):
pass
link_host = get_link_host(proxy_config.host)
- tg_link = f"tg://proxy?server={link_host}&port={proxy_config.port}&secret=dd{proxy_config.secret}"
+ ftls = proxy_config.fake_tls_domain
+ dd_link = (f"tg://proxy?server={link_host}"
+ f"&port={proxy_config.port}"
+ f"&secret=dd{proxy_config.secret}")
+ ee_link = ""
+ if ftls:
+ domain_hex = ftls.encode('ascii').hex()
+ ee_link = (f"tg://proxy?server={link_host}"
+ f"&port={proxy_config.port}"
+ f"&secret=ee{proxy_config.secret}{domain_hex}")
log.info("=" * 60)
log.info(" Telegram MTProto WS Bridge Proxy")
log.info(" Listening on %s:%d", proxy_config.host, proxy_config.port)
log.info(" Secret: %s", proxy_config.secret)
+ if ftls:
+ log.info(" Fake TLS: %s", ftls)
log.info(" Target DC IPs:")
for dc in sorted(proxy_config.dc_redirects.keys()):
ip = proxy_config.dc_redirects.get(dc)
@@ -482,8 +585,12 @@ async def _run(stop_event: Optional[asyncio.Event] = None):
user_domain = "user" if proxy_config.cfproxy_user_domain else "auto"
log.info(" CF proxy: enabled (%s | %s)", prio, user_domain)
log.info("=" * 60)
- log.info(" Connect link:")
- log.info(" %s", tg_link)
+ log.info(" Connect links:")
+ if ftls:
+ log.info(" ee (Fake TLS): %s", ee_link)
+ else:
+ log.info(" (standard): %s", proxy_config.secret)
+ log.info(" dd (random padding): %s", dd_link)
log.info("=" * 60)
async def log_stats():
@@ -569,6 +676,13 @@ def main():
help='Disable Cloudflare proxy fallback')
ap.add_argument('--cfproxy-priority', type=bool, default=True,
help='Try cfproxy before tcp fallback (default: true)')
+ ap.add_argument('--fake-tls-domain', type=str, default='',
+ metavar='DOMAIN',
+ help='Enable Fake TLS (ee-secret) masking with the given '
+ 'SNI domain, e.g. example.com')
+ ap.add_argument('--proxy-protocol', action='store_true',
+ help='Accept PROXY protocol v1 header '
+ '(for use behind nginx/haproxy with proxy_protocol on)')
args = ap.parse_args()
if not args.dc_ip:
@@ -603,6 +717,8 @@ def main():
proxy_config.fallback_cfproxy = not args.no_cfproxy
proxy_config.fallback_cfproxy_priority = args.cfproxy_priority
proxy_config.cfproxy_user_domain = args.cfproxy_domain
+ proxy_config.fake_tls_domain = args.fake_tls_domain.strip()
+ proxy_config.proxy_protocol = args.proxy_protocol
log_level = logging.DEBUG if args.verbose else logging.INFO
log_fmt = logging.Formatter('%(asctime)s %(levelname)-5s %(message)s',
@@ -624,6 +740,8 @@ def main():
fh.setFormatter(log_fmt)
root.addHandler(fh)
+ logging.getLogger('asyncio').setLevel(logging.WARNING)
+
try:
asyncio.run(_run())
except KeyboardInterrupt:
diff --git a/utils/tray_common.py b/utils/tray_common.py
index 53facff..ed559fd 100644
--- a/utils/tray_common.py
+++ b/utils/tray_common.py
@@ -153,6 +153,7 @@ def setup_logging(verbose: bool = False, log_max_mb: float = 5) -> None:
level = logging.DEBUG if verbose else logging.INFO
root = logging.getLogger()
root.setLevel(level)
+ logging.getLogger('asyncio').setLevel(logging.WARNING)
fh = logging.handlers.RotatingFileHandler(
str(LOG_FILE),