← Назад в базу знаний

WebRTC в Firefox: почему IPv6-прокси течёт и как это заткнуть

Что вообще происходит при WebRTC-запросе

Firefox при инициализации RTCPeerConnection собирает ICE-кандидатов. Это адреса, по которым браузер предлагает установить P2P-соединение. Собираются они с каждого сетевого интерфейса — включая те, что не идут через прокси. Дальше кандидаты уходят в SDP-оффер и попадают к удалённой стороне. Даже если вы сидите за SOCKS5-прокси, браузер честно скажет собеседнику: «я доступен по адресу 2a01:4f8:...».

Механика простая до безобразия. STUN-запрос уходит на сервер (по умолчанию stun.l.google.com:19302), сервер возвращает публичный адрес — тот, с которого пришёл пакет. Если пакет ушёл напрямую, минуя прокси, — вы получаете свой реальный IPv6. Прокси тут ни при чём, он просто не участвует в этом обмене.

Ключевой момент: WebRTC-трафик в Firefox исторически не подчинялся настройкам прокси так, как обычный HTTP. Настройка `network.proxy.socks_remote_dns` решает DNS-утечки, но UDP-трафик ICE идёт отдельным маршрутом. Поэтому SOCKS5-прокси блокирует TCP, а WebRTC спокойно пробивает UDP-дыру.

Почему IPv6 особенно болезненный

IPv4-утечки через WebRTC известны давно, и большинство гайдов сводятся к «отключите WebRTC». С IPv6 ситуация хуже по трём причинам. Первая — двойной стек. У машины одновременно есть IPv4 и IPv6, и ICE собирает кандидатов с обоих. Даже если IPv4 у вас замаскирован, IPv6 может торчать наружу в исходном виде.

Вторая — многие VPN/прокси-клиенты по умолчанию не трогают IPv6. Трафик v6 идёт мимо туннеля, потому что клиент настроен только на v4. Пользователь думает, что защищён, а браузер рапортует глобальный IPv6-адрес провайдера.

Третья — IPv6-адреса часто выглядят «менее подозрительно» для антифрод-систем. Диапазоны вроде `2a01:4f8::/32` (Hetzner) или `2604:a880::/32` (DigitalOcean) прямо указывают на датацентр, но некоторые сервисы фильтруют только IPv4-диапазоны VPS, а v6 пропускают. Это палка о двух концах: и утечка опасна, и прокси-адрес может палиться.

Как выглядит утечка в цифрах

Проверить просто. Открываете `about:config`, ищете `media.peerconnection.enabled`, ставите `false` — и вот у вас уже другой fingerprint. Но давайте по порядку.

Типичный сценарий: браузер за SOCKS5-прокси на `[2a01:4f8:c17:1234::1]:1080`. Открываем https://browserleaks.com/webrtc. Видим публичный IPv4 прокси — хорошо. И тут же видим `2a01:4f8:c17:1234::1` — тоже прокси, тоже хорошо. А теперь другой сценарий: тот же прокси, но клиент настроен только на IPv4-маршрут через туннель. Результат — IPv4 прокси плюс реальный IPv6 вида `2001:db8:a1b2::cafe` от домашнего провайдера. Вот это и есть утечка.

В логах STUN-сервера видно два пакета с разницей в миллисекунды: один пришёл с IP прокси, второй — с реального. Атакующий (или рекламный трекер) просто сопоставляет их по времени и получает связку «прокси ↔ реальный адрес».

Настройки about:config, которые реально работают

Открывайте `about:config`, принимайте риск и правьте. Основная связка:

```

media.peerconnection.enabled = false

media.peerconnection.ice.default_address_only = true

media.peerconnection.ice.no_host = true

media.peerconnection.ice.proxy_only_if_behind_proxy = true

```

Первая настройка убивает WebRTC целиком. Вторая заставляет ICE использовать только дефолтный адрес (без сбора со всех интерфейсов). Третья запрещает host-кандидатов — те самые локальные адреса вроде `fe80::1%eth0`, которые тоже утекают. Четвёртая работает только когда браузер явно за прокси.

Есть ещё `media.peerconnection.ice.obfuscate_host_addresses` — маскирует host-кандидатов через mDNS (`.local`-имена). Полезно, если WebRTC нужен для работы (видеозвонки), но утечки недопустимы.

Проверка после правок:

```bash

curl -6 --socks5-hostname 2a01:4f8:c17:1234::1:1080 https://ifconfig.co

```

Если вернёт IPv6 прокси — маршрут v6 идёт через SOCKS. Если ошибка или пусто — прокси не поддерживает v6, и WebRTC найдёт обходной путь. Проверяйте именно `--socks5-hostname`, а не `--socks5`, иначе DNS резолвится локально.

Почему одного about:config мало

Правки в браузере не отменяют того факта, что операционная система маршрутизирует IPv6 в обход туннеля. Firefox может быть настроен идеально, но если вы запускаете второй браузер, Electron-приложение или обновляете что-то через `apt` — трафик v6 уходит напрямую.

Правильный подход — два уровня. На уровне ОС отключить IPv6 полностью или завернуть его в туннель. На уровне браузера — задать `network.proxy.socks_version = 5` и `network.proxy.socks_remote_dns = true`. Плюс проверить, что в `network.proxy.no_proxies_on` нет `::1` и локальных v6-подсетей, иначе браузер будет ходить мимо прокси на localhost-сервисы.

Для продакшена, где нужен стабильный IPv6-выход без утечек, обычно берут пул адресов и заверяют маршрутизацию на уровне ядра. Например, сервис вроде lexic.ml выдаёт IPv6-прокси с 2015 года — там маршрут уже настроен так, что весь v6-трафик клиента идёт через пул, без «дырявых» интерфейсов. Это снимает головную боль с about:config, но настройки браузера всё равно надо проверить.

Кейс: Firefox 121 за SOCKS5, v6 утекает

Проблема: пользователь настроил SOCKS5-прокси в Firefox 121, проверил на browserleaks — IPv4 чистый, IPv6 показывает домашний адрес `2001:470:1f0a::42`. Прокси-сервер работает, TCP идёт через него, но UDP-пакеты ICE уходят напрямую.

Причина: SOCKS5 в Firefox по умолчанию передаёт только TCP. UDP ASSOCIATE поддерживается не всеми прокси-серверами, и Firefox не пытается его использовать, если сервер не заявил поддержку. ICE-кандидаты собираются с реального интерфейса и уходят в SDP.

Технические детали: в `about:webrtc` видно два ICE-кандидата — `typ host` с адресом `2001:470:1f0a::42` и `typ srflx` с адресом прокси. STUN-запросы к `stun.l.google.com:19302` уходят через UDP-сокет, привязанный к физическому интерфейсу. SOCKS5-обёртка их не перехватывает.

Решение: `media.peerconnection.enabled = false` плюс `media.peerconnection.ice.no_host = true`. После перезапуска `about:webrtc` показывает пустой список кандидатов, browserleaks — только адрес прокси. Если WebRTC нужен — `media.peerconnection.ice.proxy_only_if_behind_proxy = true` и проверка, что прокси поддерживает UDP ASSOCIATE (большинство коммерческих SOCKS5 — нет).

Кейс: двойной стек и mDNS-маскировка

Проблема: корпоративный ноутбук, Firefox 115 ESR, IPv4 и IPv6 одновременно. WebRTC нужен для внутренних видеозвонков, отключать нельзя. После подключения к SOCKS5 в логах STUN видно утечку v6.

Причина: `media.peerconnection.ice.obfuscate_host_addresses = true` маскирует host-кандидатов через mDNS, но srflx-кандидаты (публичные, полученные от STUN) всё равно содержат реальный адрес. mDNS работает только для локальных адресов, публичный IPv6 от провайдера он не спрячет.

Технические детали: в `about:webrtc` видно `typ srflx` с адресом `2a02:2f0a:...` — это публичный v6 от провайдера, полученный напрямую от STUN-сервера. Прокси не участвует. Firefox 115 ESR не поддерживает `ice.proxy_only_if_behind_proxy` в полном объёме — настройка есть, но работает только для host-кандидатов.

Решение: обновиться до Firefox 121+, где `ice.proxy_only_if_behind_proxy` фильтрует и srflx. Плюс на уровне ОС отключить IPv6 на физическом интерфейсе (`sysctl net.ipv6.conf.eth0.disable_ipv6=1`) и оставить только loopback v6. После этого WebRTC работает через v4-прокси, утечек нет, звонки не ломаются.

Кейс: прокси без UDP, браузер упрямо стучится

Проблема: SOCKS5-прокси на базе `dante` не поддерживает UDP ASSOCIATE. Firefox 120 за ним. WebRTC-звонки в Google Meet не работают, но при этом в `about:webrtc` видны кандидаты с реального адреса.

Причина: Firefox пытается собрать srflx-кандидатов через STUN, получает таймаут по UDP через SOCKS (сервер отвечает `0x07 Command not supported`), и переключается на сбор host-кандидатов напрямую. Это документированное поведение ICE: если relay недоступен, используется прямой путь.

Технические детали: в логах dante `sockd` видно `udp.associate: not supported`. Firefox в `about:webrtc` показывает `ICE failed` для srflx, но host-кандидаты с реального IPv6 присутствуют. В SDP-оффере они уходят собеседнику.

Решение: `media.peerconnection.ice.no_host = true` и `media.peerconnection.ice.default_address_only = true`. Meet заработает через TURN-сервер Google (он есть по умолчанию), а host-кандидаты исчезнут. Если TURN тоже недоступен — только отключать WebRTC целиком и использовать отдельный браузер для звонков.

Проверка: что смотреть после правок

Первый чекпоинт — `about:webrtc`. Открываете, смотрите список ICE-кандидатов. Если там есть адреса, не совпадающие с прокси, — правки не применились или нужен рестарт. Второй — https://browserleaks.com/webrtc, смотрите колонку «Public IP». Третий — `about:networking#dns`, проверяете, что DNS-запросы идут через прокси.

Для автоматизации проверки можно гонять headless Firefox с playwright:

```python

from playwright.sync_api import sync_playwright

with sync_playwright() as p:

browser = p.firefox.launch(

firefox_user_prefs={

"media.peerconnection.enabled": False,

"network.proxy.type": 1,

"network.proxy.socks": "2a01:4f8:c17:1234::1",

"network.proxy.socks_port": 1080,

"network.proxy.socks_version": 5,

"network.proxy.socks_remote_dns": True,

}

)

page = browser.new_page()

page.goto("https://ifconfig.co/json")

print(page.inner_text("body"))

browser.close()

```

Скрипт покажет, какой IP видит внешний сервис. Если в JSON `ip` совпадает с адресом прокси — маршрут работает. Если нет — где-то дыра.

Таблица: что блокирует какой тип утечки

| Настройка | host-кандидаты | srflx (STUN) | relay (TURN) |

|---|---|---|---|

| `peerconnection.enabled=false` | блокирует | блокирует | блокирует |

| `ice.no_host=true` | блокирует | пропускает | пропускает |

| `ice.default_address_only=true` | частично | пропускает | пропускает |

| `ice.proxy_only_if_behind_proxy=true` | блокирует | блокирует (FF 121+) | пропускает |

| `ice.obfuscate_host_addresses=true` | маскирует mDNS | не трогает | не трогает |

Комбинация `no_host + default_address_only + proxy_only_if_behind_proxy` закрывает всё, кроме relay. Relay-кандидаты идут через TURN-сервер, который вы сами указали, — это контролируемый канал.

Что делать, если WebRTC нужен, а утечки нет

Сценарий: видеоконференции, P2P-передача файлов, торренты в браузере. Отключать WebRTC нельзя. Тогда настраиваем TURN-сервер, который будет единственным путём для медиа. В `about:config`:

```

media.peerconnection.ice.relay_only = true

```

Эта настройка заставляет ICE использовать только relay-кандидатов. Все медиа-пакеты идут через TURN, реальный адрес не светится. Минус — задержка. TURN добавляет 20–80 мс в зависимости от расстояния до сервера. Для видеозвонков терпимо, для игр — нет.

TURN-сервер поднимается на том же хосте, что и прокси, или отдельно. Конфиг coturn:

```

listening-port=3478

tls-listening-port=5349

fingerprint

lt-cred-mech

realm=turn.example.com

user=user:pass

external-ip=2a01:4f8:c17:1234::1

```

`external-ip` указывает на IPv6-адрес, который увидят клиенты. Если сервер за NAT — указывайте публичный адрес, иначе ICE не соберёт relay-кандидатов.

Грабли с IPv6-префиксами и privacy extensions

Linux по умолчанию использует privacy extensions (`net.ipv6.conf.all.use_tempaddr=2`). Это значит, что IPv6-адрес меняется каждые несколько часов. Для прокси это катастрофа: маршрут настроен на один адрес, а интерфейс уже получил другой. Firefox собирает кандидатов с текущего адреса, и если он не совпадает с тем, что прописан в прокси, — утечка или полный отказ.

Проверяйте `ip -6 addr show`. Если видите `temporary` рядом с адресом — отключайте: `sysctl -w net.ipv6.conf.all.use_tempaddr=0`. Для прокси-хостов это обязательно. Для клиентских машин — по ситуации: privacy extensions защищают от трекинга, но ломают стабильность соединений.

Вторые грабли — `accept_ra`. Если роутер раздаёт IPv6 через RA, а вы думаете, что v6 отключён, — сюрприз. Проверяйте `sysctl net.ipv6.conf.all.accept_ra`. На прокси-клиентах ставьте `0`, если не хотите случайных адресов.

Итог по настройкам

Минимальный набор для параноика: `media.peerconnection.enabled=false`. Для тех, кому WebRTC нужен: `ice.no_host=true`, `ice.default_address_only=true`, `ice.proxy_only_if_behind_proxy=true`, `ice.relay_only=true` плюс свой TURN. Для корпоративных сетей с двойным стеком: отключить IPv6 на физическом интерфейсе, оставить loopback.

Проверяйте после каждого обновления Firefox. Настройки `about:config` иногда сбрасываются при мажорных апдейтах, а новые версии добавляют свои `ice.*`-ключи. `about:webrtc` — ваш главный инструмент диагностики. Если там чисто, значит и снаружи чисто.

✔️Купить прокси