Zoom через IPv6 прокси: обход региональных ограничений и парсинг вебинаров
Содержание
- Почему Zoom вообще упирается в регион
- Как Zoom резолвит серверы
- Почему IPv6-прокси, а не v4
- Настройка прокси для Zoom-клиента
- Парсинг вебинаров: где начинаются грабли
- Кейс: вебинар на 500 человек из России
- Кейс: лаги в конференции через туннель
- Кейс: парсинг 200 вебинаров параллельно
- Что ломается чаще всего
- Сравнение подходов
- Итог по архитектуре
Почему Zoom вообще упирается в регион
Zoom — не самый очевидный кандидат для проксирования. Люди привыкли гонять через прокси браузерные сессии, парсеры, ботов. А тут видеоконференции. Но у Zoom есть несколько слоёв, которые зависят от геолокации: региональные дата-центры (US, EU, APAC, China), политики аккаунта, привязанные к billing-региону, и — самое интересное — ограничения на доступ к записям вебинаров и API.
Когда вы подключаетесь к встрече, клиент сначала стучится на `zoom.us` за конфигом, потом получает список медиа-серверов (MMR — Multimedia Router), и уже к ним идёт RTP/RTMP-поток. MMR выбирается по latency и по региону. Если ваш IP резолвится в Россию или в страну под санкциями — часть серверов просто не отдаётся в конфиге. Отсюда «не удаётся подключиться к конференции» или падение в 1-2 секунды после старта.
IPv6 здесь даёт неожиданное преимущество. У Zoom большие IPv6-пулы, и маршрутизация по v6 часто идёт мимо тех же гео-фильтров, что стоят на v4. Плюс сам IPv6-адрес можно взять из нужного региона — и для Zoom вы будете выглядеть как пользователь из Амстердама или Франкфурта.
Как Zoom резолвит серверы
Разберём цепочку. Клиент делает запрос:
```
GET https://zoom.us/v2/config?...
Host: zoom.us
```
В ответ приходит JSON с полями `mmr`, `rwg`, `zm` — списки хостов. Дальше клиент пингует их и выбирает по RTT. Если вы за прокси, RTT считается от прокси, а не от вашего реального адреса. Значит, вы можете управлять тем, какой дата-центр выберется.
Проверить, что вам отдаёт конфиг, можно так:
```bash
curl -6 -s "https://zoom.us/v2/config" \
-H "User-Agent: Zoom/5.16.0" \
| jq '.mmr[] | {host, ipv6}'
```
Флаг `-6` заставляет curl идти по IPv6. Если в ответе пусто или только v4-адреса — значит, ваш IPv6-префикс не в whitelist региона, либо провайдер режет маршрут. Через прокси-пул с европейскими v6-адресами этот же запрос вернёт 4-6 MMR-хостов во Франкфурте и Амстердаме.
Почему IPv6-прокси, а не v4
IPv4-прокси в 2024-2025 годах — это лотерея. Большинство дата-центровых пулов уже в чёрных списках Zoom. Адрес, который использовался под VPN, помечается, и клиент получает ошибку `Error 1001` или бесконечный «Connecting…».
IPv6-пулы чище по одной причине: их сложнее сканировать целиком. Префикс /64 — это 18 квинтиллионов адресов. Zoom не может забанить весь /64, потому что под ним сидят легитимные корпоративные сети. Он банит конкретные /128, но ротация внутри /64 обходит это.
Второй момент — стоимость. IPv6-адреса дешевле. Пул из 1000 v6-адресов стоит в разы меньше, чем пул из 100 v4. Для парсинга вебинаров, где нужно параллельно держать десятки сессий, это критично.
Третий момент — MTU. У IPv6 минимальный MTU 1280 байт, и если туннель настроен криво, вы получите фрагментацию и потерю RTP-пакетов. Об этом ниже.
Настройка прокси для Zoom-клиента
Zoom desktop-клиент не поддерживает SOCKS5 напрямую через настройки. Но есть обходной путь — системный прокси или прозрачное перенаправление. На Linux проще всего через `redsocks` или через `tun2socks`.
Пример конфига для `tun2socks` с IPv6-выходом:
```bash
ip -6 route add default dev tun0 table 100
ip -6 rule add from all fwmark 0x1 lookup 100
ip -6 route flush cache
```
И сам туннель:
```bash
tun2socks -device tun0 \
-proxy socks5://[2a01:4f8:1c1c:abcd::1]:1080 \
-loglevel warn
```
Здесь `2a01:4f8:...` — это IPv6-адрес прокси в Германии (Hetzner, Франкфурт). После поднятия туннеля весь Zoom-трафик идёт через него. Проверить можно через `curl -6 ifconfig.co` — должен вернуть немецкий адрес.
Важный нюанс: Zoom использует UDP для медиа (порты 8801-8810) и TCP 443 для сигналинга. Если ваш SOCKS5-прокси не умеет UDP ASSOCIATE, медиа пойдёт напрямую, и вы получите рассинхрон: сигналинг через Германию, медиа через Россию. Zoom это заметит и уронит сессию. Убедитесь, что прокси поддерживает UDP.
Парсинг вебинаров: где начинаются грабли
Вебинары Zoom — это отдельная история. Записи хранятся не у вас, а на серверах Zoom, и доступ к ним идёт через `Recording API`. Проблема в том, что для скачивания записи клиент получает временный токен, привязанный к IP. Если IP сменился между запросом токена и скачиванием — 403.
Второй слой — сам плеер. Веб-плеер Zoom отдаёт `.m3u8` плейлист с сегментами по 6 секунд. Сегменты лежат на CDN, который тоже проверяет гео. Через IPv6-прокси это обходится, но нужно держать одну и ту же сессию.
Пример на Python, который получает список записей и качает их через прокси:
```python
import requests
PROXY = "socks5h://[2a01:4f8:1c1c:abcd::1]:1080"
BASE = "https://api.zoom.us/v2"
def list_recordings(user_id, token):
r = requests.get(
f"{BASE}/users/{user_id}/recordings",
headers={"Authorization": f"Bearer {token}"},
proxies={"https": PROXY},
timeout=30,
)
r.raise_for_status()
return r.json()["meetings"]
def download(url, path):
with requests.get(url, proxies={"https": PROXY}, stream=True) as r:
r.raise_for_status()
with open(path, "wb") as f:
for chunk in r.iter_content(8192):
f.write(chunk)
```
Ключевой момент — `socks5h`, а не `socks5`. Буква `h` означает, что DNS-резолвинг идёт на стороне прокси. Иначе Zoom-домены резолвятся локально, и вы снова упираетесь в гео-фильтр.
Кейс: вебинар на 500 человек из России
Клиент — онлайн-школа. Вебинар на 500 участников, спикер в Москве, запись нужна для монтажа. Zoom-аккаунт зарегистрирован на европейское юрлицо, billing-регион — Нидерланды. При попытке скачать запись из Москвы — `403 Forbidden`, в логах `geo_restricted`.
Причина: Zoom проверяет IP при выдаче download-токена. Токен живёт 15 минут, но привязан к IP-подсети. Из Москвы подпись не проходит.
Решение: подняли IPv6-прокси в Амстердаме на /64-префиксе, настроили `socks5h` в скрипте загрузки. Запись на 2 часа 40 минут (около 1.8 ГБ) скачалась за 11 минут со средней скоростью 22 Мбит/с. Ошибок не было. Через v4-прокси та же задача падала на 40-й секунде — CDN отдавал `403` после первых сегментов.
Кейс: лаги в конференции через туннель
Другая история. Инженер поднял IPv6-туннель через `tun2socks`, зашёл в Zoom-встречу. Видео шло, но звук отставал на 2-3 секунды, периодически пропадал. Пинг до MMR — 18 мс, потери — 0.2%. Вроде нормально.
Причина оказалась в MTU. Туннель имел MTU 1280, а Zoom пытался слать пакеты по 1400 байт. Фрагментация на входе в туннель, reassembly на выходе, задержка на каждом пакете. RTP не любит фрагментацию — он и так маленький, а тут ещё и очередь.
Решение: уменьшили MTU на интерфейсе до 1280 и включили MSS clamping:
```bash
ip link set dev tun0 mtu 1280
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
```
После этого задержка звука упала до 40-60 мс, потери — 0. Видео 720p шло стабильно.
Кейс: парсинг 200 вебинаров параллельно
Задача — собрать метаданные 200 вебинаров (длительность, число участников, список записей) для аналитики. Через один прокси — 200 последовательных запросов, каждый по 300-500 мс, плюс rate limit Zoom (30 запросов в секунду на аккаунт, но 5 в секунду на IP).
Причина тормозов: Zoom режет по IP. Один адрес — 5 rps, дальше `429 Too Many Requests`.
Решение: развернули пул из 40 IPv6-адресов в одном /64. Распараллелили через `asyncio` и `aiohttp-socks`. Каждый воркер держит свой адрес из пула. Итог: 200 запросов за 8 секунд вместо 100+ секунд. Ошибок 429 — ноль, потому что каждый IP делал не больше 5 запросов.
```python
import asyncio
from aiohttp import ClientSession
from aiohttp_socks import ProxyConnector
IPS = [f"2a01:4f8:1c1c:abcd::{i}" for i in range(1, 41)]
async def fetch(session, url):
async with session.get(url) as r:
return await r.json()
async def worker(ip, urls):
connector = ProxyConnector.from_url(f"socks5://[{ip}]:1080")
async with ClientSession(connector=connector) as s:
return await asyncio.gather(*[fetch(s, u) for u in urls])
async def main(urls):
chunks = [urls[i::len(IPS)] for i in range(len(IPS))]
results = await asyncio.gather(*[worker(ip, c) for ip, c in zip(IPS, chunks)])
return [item for sub in results for item in sub]
```
Здесь каждый воркер биндится на свой IPv6-адрес. Прокси-сервер должен поддерживать привязку исходящего адреса — это настраивается в `3proxy` или `dante`.
Что ломается чаще всего
Список грабель, на которые наступают почти все.
Первое — DNS. Если используете `socks5` вместо `socks5h`, Zoom-домены резолвятся локально. В России `zoom.us` может резолвиться в другой IP, чем в Европе. Результат — коннект идёт не туда.
Второе — UDP. Zoom шлёт медиа по UDP. SOCKS5 поддерживает UDP ASSOCIATE, но многие прокси-серверы его не включают. Проверяйте через `nc -u -6` или через сам Zoom: если в статистике встречи `Connection Type: TCP` — UDP не работает.
Третье — таймауты. Zoom держит WebSocket-соединение для сигналинга. Если прокси рвёт idle-соединения через 60 секунд, встреча упадёт. Ставьте `timeout 300` минимум.
Четвёртое — IPv6-фрагментация. Уже разобрали выше. MTU 1280 и MSS clamping обязательны.
Пятое — гео-фильтр на CDN записей. Иногда Zoom отдаёт плейлист, но сегменты лежат на `*.cloudfront.net` с гео-блоком. Тут помогает только прокси в правильном регионе, причём тот же, что выдал токен.
Сравнение подходов
| Подход | Работает с Zoom | UDP | Ротация | Стоимость |
|---|---|---|---|---|
| IPv4 DC-прокси | Часто блокируется | Да | Сложно | Высокая |
| IPv6 DC-прокси | Стабильно | Да | Легко внутри /64 | Низкая |
| Residential v4 | Стабильно | Да | Дорого | Очень высокая |
| VPN | Нестабильно | Да | Нет | Средняя |
| Tor | Нет | Нет | Да | Бесплатно |
Residential-прокси для Zoom работают, но цена кусается: \$15-25 за гигабайт. Вебинар на 2 часа — это 1.5-2 ГБ. При парсинге 200 вебинаров счёт уходит в сотни долларов. IPv6-пул в /64 обходится в фиксированную сумму за сервер, независимо от трафика.
Итог по архитектуре
Схема, которая работает: IPv6-прокси в нужном регионе, `socks5h` с поддержкой UDP, MTU 1280 на туннеле, пул адресов внутри /64 для параллельных задач. Для скачивания записей — одна сессия на один адрес, без ротации в процессе. Для парсинга метаданных — ротация по адресам, лимит 5 rps на IP.
lexic.ml даёт IPv6-пулы с ротацией внутри /64 и поддержкой UDP ASSOCIATE — как раз то, что нужно для медиа-трафика Zoom. Проверить можно на тестовом вебинаре: если в статистике встречи соединение идёт через ваш прокси и потери меньше 0.5%, архитектура собрана правильно.
Остальное — детали настройки. Главное не пытаться гнать медиа через TCP-прокси без UDP и не забывать про MTU. Эти две вещи ломают больше Zoom-сессий, чем все гео-блоки вместе взятые.