Discord через IPv6 прокси: обход блокировок голосовых каналов
Содержание
- Почему голос в Discord ломается при блокировках
- Как Discord устанавливает голосовое соединение
- SOCKS5 с UDP: что реально поддерживается
- Настройка IPv6-прокси для Discord
- Проблема MTU и фрагментации
- Кейс: провайдер режет UDP по портам
- Кейс: подмена DNS для голосовых доменов
- Кейс: rate-limit по IP для WebRTC
- Почему IPv6, а не IPv4
- Проверка работоспособности
- Ограничения и подводные камни
- Итоговая конфигурация
Почему голос в Discord ломается при блокировках
Discord — это не один сервис, а зоопарк из десятка подсистем. Текстовые сообщения идут через HTTPS на `discord.com` (порт 443). Голос и видео — совсем другая история. Тут WebRTC, UDP, динамические порты в диапазоне 50000–65535, и STUN/TURN для NAT traversal. Блокировка текстового трафика обычно тривиальна: РКН или провайдер режет по SNI или IP. С голосом сложнее — он идёт не на `discord.com`, а на отдельные медиасерверы, чьи IP меняются.
Когда провайдер начинает фильтровать UDP или подменять DNS для голосовых доменов, картина типичная: чат работает, участники видны, а при заходе в канал — «RTC Connecting» навсегда, либо слышно робота, либо тебя не слышат. Discord в логах клиента пишет `ICE connection failed` или `DTLS handshake timeout`. Это не баг клиента, это сетевая фильтрация.
Проксирование голоса через IPv6 даёт обходной путь. Многие провайдеры фильтруют IPv4-трафик к Discord жёстко, а IPv6 либо не фильтруют, либо фильтруют частично. Плюс IPv6 даёт огромный пул адресов — можно балансировать нагрузку и обходить rate-limit по IP.
Как Discord устанавливает голосовое соединение
Разберём последовательность, чтобы понимать, где именно вклинивается прокси.
Клиент запрашивает у `discord.com/api/v9/channels/{id}/call` параметры RTC-сервера. Сервер возвращает список endpoint'ов — обычно 2-3 региона, каждый с IP и портом. Клиент начинает ICE gathering: собирает кандидатов (host, srflx, relay). Для srflx нужен STUN-запрос на `stun.l.google.com:19302` или собственный STUN Discord. Затем идёт проверка пар кандидатов, DTLS-рукопожатие, SRTP для медиа.
Ключевой момент: если UDP полностью заблокирован, Discord падает на TCP-режим через порт 443. Работает, но с задержкой 150-300 мс вместо 30-50. Если заблокирован только диапазон 50000-65535, ICE не находит рабочих кандидатов, и соединение не устанавливается вообще.
Прокси должен уметь пробрасывать UDP. SOCKS5 с поддержкой UDP ASSOCIATE — минимальное требование. HTTP-прокси тут бесполезен, он работает только с TCP.
SOCKS5 с UDP: что реально поддерживается
Не все SOCKS5-прокси умеют UDP. Спецификация RFC 1928 описывает команду `UDP ASSOCIATE`, но реализуют её не все. Проверить просто:
```bash
curl --socks5-hostname proxy.example.com:1080 https://discord.com/api/v9/gateway
```
Это проверит только TCP. Для UDP нужен отдельный тест. Python + PySocks:
```python
import socks
import socket
s = socks.socksocket(socket.AF_INET, socket.SOCK_DGRAM)
s.set_proxy(socks.SOCKS5, "proxy.example.com", 1080)
s.settimeout(5)
try:
s.sendto(b"\x00\x01\x00\x00\x00\x00\x00\x00", ("stun.l.google.com", 19302))
data, addr = s.recvfrom(1024)
print(f"UDP works, got {len(data)} bytes from {addr}")
except Exception as e:
print(f"UDP failed: {e}")
```
Если получили ответ — прокси годится для голоса. Если timeout — только текст.
Настройка IPv6-прокси для Discord
Discord-клиент не имеет встроенной настройки прокси для голоса. Он читает системные настройки или переменные окружения. На Linux проще всего через `proxychains-ng` с патчем под UDP, но это костыль. Надёжнее — поднять локальный SOCKS5-реверс, который принимает трафик на localhost и уходит через IPv6.
Пример конфига для `sing-box` (актуальная замена v2ray):
```json
{
"inbounds": [
{
"type": "socks",
"listen": "127.0.0.1",
"listen_port": 1080,
"users": []
}
],
"outbounds": [
{
"type": "socks",
"server": "2a01:4f8:c17:1234::1",
"server_port": 1080,
"version": "5"
}
]
}
```
Клиент Discord настраивается через переменные окружения или системный прокси. На Windows — `netsh winhttp set proxy`, но Discord использует Chromium Embedded Framework и читает настройки из реестра Internet Explorer. Проще всего запустить через `proxifier` или аналог с правилом на `Discord.exe`.
Проблема MTU и фрагментации
IPv6 не поддерживает фрагментацию на маршрутизаторах — только на источнике. Минимальный MTU для IPv6 — 1280 байт. Если туннель до прокси имеет MTU 1400, а Discord шлёт пакеты по 1500, они дропаются молча. Симптом: рукопожатие проходит, но голос рвётся каждые 2-3 секунды.
Проверить MTU до прокси:
```bash
ping6 -M do -s 1400 2a01:4f8:c17:1234::1
```
Если `Frag needed` — уменьшайте размер. Оптимально 1360-1400 для туннелей поверх IPv4.
В конфиге sing-box можно задать MSS-клампинг:
```json
{
"type": "socks",
"server": "2a01:4f8:c17:1234::1",
"server_port": 1080,
"tcp_fast_open": true,
"udp_fragment": true
}
```
`udp_fragment` критичен — без него большие UDP-пакеты от Discord (а голос использует пакеты до 1200 байт) будут теряться.
Кейс: провайдер режет UDP по портам
Ростовский провайдер, 2023 год. Пользователь жалуется: голос работает только в режиме «Push to Talk», и то с задержкой. Диагностика показала: провайдер дропает UDP-пакеты с destination port в диапазоне 50000-60000, но пропускает 443 и 3478.
Discord при ICE gathering выбирает порт из диапазона 50000-65535. Все кандидаты отбрасываются. Клиент падает на TCP-режим, но и там проблемы — провайдер шейпит TCP на 443 до 500 кбит/с, чего не хватает для Opus 64 кбит/с + overhead.
Решение: IPv6-прокси на сервере в Германии, порт 1080, UDP ASSOCIATE. Весь голосовой трафик пошёл через IPv6-туннель. Задержка выросла с 40 мс (локальный сервер) до 85 мс (Франкфурт), но голос стал стабильным. Потери пакетов: 0.2% против 15% до прокси.
Кейс: подмена DNS для голосовых доменов
Москва, 2024. Провайдер подменяет DNS-ответы для `*.discord.gg` и `*.discord.media` на 127.0.0.1. Текстовый чат работает через DoH (Discord использует Cloudflare DNS), а голос — нет. Клиент резолвит `discord.media` через системный DNS, получает заглушку, ICE не стартует.
Причина: Discord для голоса использует отдельный резолвер, который не ходит через DoH. Он берёт системный DNS. Подмена ломает всё.
Решение: прописать статический маршрут для голосовых подсетей Discord через IPv6-прокси. Список подсетей Discord для голоса (актуален на момент статьи):
| Подсеть | Назначение |
|---------|-----------|
| 66.22.192.0/18 | Голосовые серверы US |
| 162.159.128.0/18 | Голосовые серверы EU |
| 2606:4700::/32 | Cloudflare (STUN/TURN) |
Трафик к этим подсетям заворачивается в туннель, DNS-резолвинг идёт через прокси. Подмена на стороне провайдера перестаёт влиять.
Кейс: rate-limit по IP для WebRTC
Корпоративная сеть, 500+ сотрудников за одним NAT. Discord видит всех с одного IPv4. Голосовые соединения начинают отклоняться с кодом 4006 (rate limited). Текстовый чат работает, голос — нет.
Причина: Discord лимитирует количество одновременных RTC-сессий с одного IP. При 50+ активных голосовых каналах с одного адреса — блок.
Решение: IPv6-прокси с пулом адресов. Каждый клиент получает свой IPv6 из /64. NAT исчезает, лимиты не срабатывают. Настройка в sing-box:
```json
{
"type": "socks",
"server": "2a01:4f8:c17:1234::1",
"server_port": 1080,
"outbound_bind": {
"ipv6": "2a01:4f8:c17:1234::/64",
"strategy": "random"
}
}
```
Каждое новое соединение уходит с нового IPv6. Discord видит разные адреса, rate-limit не срабатывает.
Почему IPv6, а не IPv4
IPv4-прокси для Discord работает, но есть нюансы. Пул IPv4 ограничен, провайдеры продают их дорого. IPv6 даёт /64 бесплатно с любым VPS. Плюс многие блокировки в РФ настроены на IPv4-подсети Discord — IPv6-трафик часто идёт мимо фильтров.
Ещё момент: Discord сам поддерживает IPv6 для голоса с 2021 года. Если клиент и сервер оба на IPv6, NAT traversal не нужен — прямой маршрут. Задержка падает на 20-40 мс по сравнению с IPv4+NAT.
Сервисы вроде lexic.ml дают IPv6-прокси с поддержкой UDP ASSOCIATE, что как раз закрывает потребность в голосовом трафике. Не реклама, просто техническое соответствие требованиям.
Проверка работоспособности
После настройки прокси нужно убедиться, что голос идёт через него. Discord не показывает в UI, какой маршрут используется. Проверяем через `netstat` или `ss`:
```bash
ss -u -a -p | grep -i discord
```
Если видим UDP-соединения на порт 1080 (локальный SOCKS) — трафик идёт через прокси. Если напрямую на IP Discord — настройка не применилась.
Ещё способ — `tcpdump` на интерфейсе:
```bash
sudo tcpdump -i any -n udp port 1080 -c 100
```
Должны видеть пакеты от Discord к localhost:1080 и обратно. Если пакетов нет — клиент игнорирует прокси.
Для теста задержки используем встроенный в Discord индикатор (в голосовом канале правый клик по себе → Debug → Voice). Там видно RTT, jitter, packet loss. Норма: RTT < 100 мс, jitter < 30 мс, loss < 1%.
Ограничения и подводные камни
IPv6-прокси не панацея. Если провайдер блокирует IPv6 целиком (такое бывает у Ростелекома в некоторых регионах), метод не работает. Нужен fallback на IPv4-туннель.
Второй момент: не все VPS-провайдеры дают IPv6 с нормальным MTU. У Hetzner MTU 1500, у некоторых — 1280. Проверяйте перед покупкой.
Третий: Discord может детектить прокси по TLS-фингерпринту. Если используете sing-box с дефолтными настройками, fingerprint может не совпадать с реальным Discord-клиентом. В логах сервера Discord это видно как `suspicious client`. Не блокируют, но могут ограничить функциональность.
Решение — использовать `uTLS` с профилем `chrome`:
```json
{
"tls": {
"enabled": true,
"server_name": "discord.com",
"utls": {
"enabled": true,
"fingerprint": "chrome"
}
}
}
```
Это маскирует TLS-рукопожатие под обычный Chrome. Discord не отличает прокси от браузера.
Итоговая конфигурация
Собираем всё вместе. Локальный sing-box, IPv6-выход, UDP ASSOCIATE, MSS-клампинг, uTLS. Discord запускается с системным прокси на 127.0.0.1:1080. Голос идёт через IPv6-туннель, текст — тоже (не помешает).
Проверка: заходим в голосовой канал, смотрим Debug → Voice. RTT должен быть стабильным, loss — нулевым. Если RTT скачет — проблема с MTU, уменьшайте. Если loss — проверяйте UDP ASSOCIATE на прокси.
Работает не всегда и не у всех. Но когда работает — голос стабильнее, чем через TCP-фоллбэк Discord. И точно лучше, чем «RTC Connecting» навсегда.