Discord через IPv6 прокси: стабильный голосовой чат без разрывов соединения
Содержание
- Почему Discord так плохо дружит с прокси
- Что происходит на уровне пакетов
- Настройка SOCKS5 с UDP на стороне сервера
- Проверка UDP через SOCKS5 на Python
- Discord и IPv6: что реально поддерживается
- MTU и фрагментация — где теряются пакеты
- Практика: прокси на lexic.ml для Discord
- TUN-туннель: единственный рабочий способ
- Что ломается на практике
- Сравнение подходов
- Задержки: чего ожидать
- Итог
Discord — это не просто чат. Это WebRTC, UDP, STUN, TURN, шардированные WebSocket-соединения и голосовые серверы, разбросанные по регионам. Проксировать всё это через SOCKS5 с IPv4 — боль. Через IPv6 — тоже боль, но другого сорта. Разберём, где именно рвётся, почему и как это лечить.
Почему Discord так плохо дружит с прокси
Discord использует несколько транспортов одновременно. Текстовые сообщения, presence, гильдии — это WebSocket поверх TLS на порту 443. Голос и видео — RTP/RTCP поверх UDP, обычно порты 50000–65535. Signaling идёт через WebSocket, а сам медиапоток — peer-to-peer или через relay-серверы Discord (SFU).
SOCKS5 умеет TCP и UDP ASSOCIATE. Но большинство SOCKS5-клиентов и серверов UDP не поддерживают или поддерживают криво. HTTP CONNECT — только TCP. Значит, голосовой трафик либо идёт мимо прокси (утечка реального IP), либо не идёт вообще (нет звука).
Вот первый подводный камень. Клиент подключается к прокси, текстовый чат работает, а голос — тишина. Потому что WebRTC не знает про SOCKS5 и пытается пробить NAT напрямую.
Что происходит на уровне пакетов
Discord-клиент при входе в голосовой канал делает следующее. Открывает WebSocket к `gateway.discord.gg` (TCP 443). Получает оттуда voice endpoint — IP и порт голосового сервера. Дальше устанавливает UDP-соединение с этим сервером для передачи RTP.
Если прокси только TCP, UDP-пакеты уходят через физический интерфейс. Discord видит реальный IP. При этом WebSocket-трафик идёт через прокси. Асимметрия маршрутов. Иногда работает, чаще — рвётся при смене сети или при блокировке UDP провайдером.
IPv6 здесь меняет картину. Если у вас есть IPv6-адрес (а в 2024 почти у всех есть), Discord предпочитает IPv6 для медиа. NAT66 не существует в привычном виде, но провайдеры всё равно фильтруют. Прокси на IPv6 позволяет держать весь трафик в одном стеке.
Настройка SOCKS5 с UDP на стороне сервера
Возьмём `danted` — он умеет UDP ASSOCIATE. Конфиг минимальный:
```
logoutput: stderr
internal: eth0 port = 1080
external: eth0
method: username none
user.privileged: root
user.notprivileged: nobody
client pass {
from: 0.0.0.0/0 to: 0.0.0.0/0
log: error
}
socks pass {
from: 0.0.0.0/0 to: 0.0.0.0/0
protocol: tcp udp
log: error
}
```
Ключевая строка — `protocol: tcp udp`. Без неё UDP ASSOCIATE отвалится с кодом 0x07 (Command not supported). Проверить можно так:
```bash
curl -x socks5h://user:pass@[2001:db8::1]:1080 https://discord.com/api/v9/gateway
```
Если ответ `{"url": "wss://gateway.discord.gg"}` — TCP-туннель живой. UDP проверяется отдельно, через `socat` или Python.
Проверка UDP через SOCKS5 на Python
Стандартная библиотека `socket` не умеет SOCKS5. Ставим `PySocks`:
```python
import socks
import socket
s = socks.socksocket(socket.AF_INET6, socket.SOCK_DGRAM)
s.set_proxy(socks.SOCKS5, "2001:db8::1", 1080, username="user", password="pass")
s.connect(("2001:db8::100", 50000))
s.sendto(b"\x80\x00\x00\x01", ("2001:db8::100", 50000))
data, addr = s.recvfrom(1500)
print(f"got {len(data)} bytes from {addr}")
```
Если `recvfrom` висит больше 3 секунд — UDP не проходит. Причины: сервер не поддерживает ASSOCIATE, файрвол режет, или IPv6-маршрут до голосового сервера Discord отсутствует.
Discord и IPv6: что реально поддерживается
Discord официально поддерживает IPv6 с 2018 года. Голосовые серверы имеют AAAA-записи. Но не все. Регион `russia` (да, такой есть) исторически сидит на IPv4. Европейские регионы — почти все dual-stack.
Проверить, куда идёт голос:
```bash
dig +short AAAA discord.gg
dig +short AAAA russia.discord.gg
```
Первый вернёт что-то вроде `2606:4700::6810:2c64` (Cloudflare). Второй может вернуть пустоту. Если голосовой регион без AAAA, IPv6-прокси бесполезен для медиа — трафик уйдёт по IPv4, минуя туннель.
Решение — принудительно выбрать регион с IPv6. В настройках канала: Регион → Europe (Central). Или через API:
```bash
curl -X PATCH https://discord.com/api/v9/channels/{channel_id} \
-H "Authorization: Bot {token}" \
-H "Content-Type: application/json" \
-d '{"rtc_region": "eu-central"}'
```
MTU и фрагментация — где теряются пакеты
IPv6 не делает фрагментацию на роутерах. Только источник. Минимальный MTU для IPv6 — 1280 байт. Если туннель до прокси имеет MTU 1400, а Discord шлёт RTP-пакеты по 1200–1300 байт с заголовками, всё влезает. Но стоит добавить инкапсуляцию (WireGuard, GRE) — и MTU падает до 1420 или ниже.
Симптом: голос работает 5 секунд, потом заикается. Или подключается, но собеседника не слышно.
Проверка:
```bash
ping6 -M do -s 1400 2001:db8::100
ping6 -M do -s 1200 2001:db8::100
```
Первый упадёт с `Message too long`, второй пройдёт. Значит, MTU где-то между. Оптимально — выставить MTU интерфейса на 1280 для туннелей с IPv6, либо включить MSS clamping на роутере.
В `nftables`:
```
nft add rule ip6 mangle forward tcp flags syn tcp option maxseg size set rt mtu
```
Это подрежет MSS до PMTU. Для UDP не работает — RTP сам должен адаптироваться. Discord это умеет, но медленно, за 2–3 секунды.
Практика: прокси на lexic.ml для Discord
Когда нужен стабильный IPv6-выход с поддержкой UDP и без утечек, имеет смысл брать готовую инфраструктуру. На lexic.ml IPv6-прокси работают с 2015 года, поддерживают SOCKS5 с UDP ASSOCIATE и выдают /64-подсеть — это важно, потому что Discord может открывать несколько UDP-сокетов одновременно (signaling + media + stats).
Схема подключения на клиенте (Linux):
```bash
export ALL_PROXY=socks5h://user:pass@[2a01:4f8::1]:1080
export DISCORD_USE_IPV6=1
```
Но переменные окружения Discord не читает (Electron-приложение). Нужен либо `proxychains-ng` с патчем под UDP, либо системный TUN. `proxychains` UDP не умеет. Остаётся TUN.
TUN-туннель: единственный рабочий способ
Создаём TUN-интерфейс, весь IPv6-трафик заворачиваем в SOCKS5. Инструменты: `tun2socks` (badvpn) или `hev-socks5-tunnel`.
Конфиг `hev-socks5-tunnel`:
```yaml
tunnel:
name: tun0
mtu: 1280
ipv4: 198.18.0.1
ipv6: 'fc00::1'
socks5:
address: '2a01:4f8::1'
port: 1080
udp: 'udp'
username: 'user'
password: 'pass'
```
Запуск:
```bash
sudo hev-socks5-tunnel config.yaml &
sudo ip -6 route add default dev tun0
sudo ip -6 rule add not fwmark 1 lookup 100
sudo ip -6 route add default dev tun0 table 100
```
Теперь весь IPv6-трафик, включая UDP Discord, идёт через прокси. MTU 1280 — безопасное значение, фрагментации не будет.
Что ломается на практике
Проблема первая: Discord кэширует IP голосового сервера. Если прокси переподключился и IPv6 сменился, клиент продолжает слать RTP на старый адрес. Решение — перезайти в канал.
Проблема вторая: некоторые антивирусы и «оптимизаторы» сети на Windows перехватывают UDP и ломают TUN. Отключать.
Проблема третья: Discord обновляется и меняет порты. В 2023 были 50000–50004, в 2024 — динамический диапазон. Файрвол на прокси должен разрешать весь диапазон UDP, иначе часть медиапотока отвалится.
Проверить, что UDP реально идёт через туннель:
```bash
sudo tcpdump -i tun0 -n udp portrange 50000-65535 -c 20
```
Если пакеты есть — туннель работает. Если пусто, а голос «работает» — утечка через физический интерфейс.
Сравнение подходов
| Метод | TCP | UDP | Утечка IP | Сложность |
|---|---|---|---|---|
| HTTP CONNECT | да | нет | да (медиа) | низкая |
| SOCKS5 без UDP | да | нет | да (медиа) | низкая |
| SOCKS5 + UDP ASSOCIATE | да | да | нет | средняя |
| TUN + tun2socks | да | да | нет | высокая |
| WireGuard | да | да | нет | средняя |
WireGuard проще TUN+SOCKS5, но требует своего сервера. SOCKS5 с UDP — компромисс: чужая инфраструктура, но нужен TUN на клиенте.
Задержки: чего ожидать
Пинг через IPv6-прокси в Европе: 15–40 мс. Через IPv4 с NAT: 20–60 мс. Разница невелика, но стабильность выше — нет NAT-таблиц, которые переполняются при 50+ UDP-потоках.
Jitter (дрожание) важнее пинга. При прямом подключении jitter 2–5 мс. Через SOCKS5+TUN — 5–15 мс. При 20+ мс Discord начинает роботизировать голос. Порог — примерно 30 мс jitter, дальше Opus-кодек не справляется с коррекцией.
Измерять:
```bash
ping6 -c 100 -i 0.1 2001:db8::100 | tail -3
```
Смотрим `mdev` — это и есть jitter. Больше 20 — ищите проблему в маршруте.
Итог
Discord через IPv6-прокси работает. Но только если прокси умеет UDP ASSOCIATE, а клиент заворачивает UDP в туннель. Голый SOCKS5 без TUN даст текстовый чат и мёртвый голос. TUN с MTU 1280 и правильным маршрутом — даст всё.
IPv6 тут не серебряная пуля, а способ убрать NAT и фрагментацию из уравнения. Если провайдер режет IPv6 или голосовой регион сидит на IPv4 — придётся комбинировать. Иногда проще взять VPS с WireGuard и не мучиться. Но если нужен именно SOCKS5-пул с разными адресами (например, для нескольких аккаунтов), IPv6-прокси — рабочий вариант.