Довольно часто в последнее время на разных форумах и чатах люди жалуются, что когда они пользуются VPN или прокси, то у них после подключения на устройствах как-то странно начинают работать некоторые приложения. Например, не приходят сообщения в WhatsApp, не загружаютя сторис в Instagram, и другие подобные вещи. Причем нередко проблема чинится сама по себе спустя 10-15 минут после подключения, но после переподключения или переоткрытия клиента начинается снова. Иные жалобы состоят в том, что не смотря на то, что пользователь выходит в интернет через VPN или прокси, некоторые заблокированные сервисы и сайты у него все равно не открываются. И в том и в том обычно винят баги прокси/VPN-клиентов, администраторов серверов, и кого угодно еще. И я вам скажу: зря. Все гораздо проще и гораздо сложнее одновременно.

Давайте начнем с основ. Современный интернет построен на протоколе связи, который так и называется, Internet Protocol, сокращенно IP. В настоящее время используются две его версии, IPv4 из 70-х годов, и более современная IPv6. Основная разница между ними - в длине адреса, и соответственно, в максимальном количестве возможных IP-адресов. IPv6, собственно, и появился, когда стало ясно, что устройств, подключенных к интернету, в мире становится сильно больше, чем доступных адресов, а городить костыли в виде NAT'а бесконечно не получится и надо что-то с этим делать. IPv6 поддерживается уже многими популярными сервисами и сайтами, и активно распространяется по всему миру, что явно видно, например, из статистики Google:

Россия, к сожалению, довольно серьезно отстает от других стран в этом плане, но даже в РФ некоторые мелкие и крупные операторы связи предоставляют своим клиентам IPv6-связность.

Как все это работает на деле? Когда ваш браузер, мессенджер или клиент какого-нибудь сервиса хочет соединиться с сервером, он в большинстве случаев делает это по доменному имени. Клиент обращается к DNS-серверу с просьбой сообщить ему IP-адреса, закрепленные за данным доменом. Сервер возвращает ему записи типа A (содержащие IPv4-адреса) и AAAA (IPv6-адреса). Если у удаленного сервера есть IPv6-адрес, а на устройстве, где работает клиент, на сетевых интерфейсах есть назначенный IPv6-адрес и IPv6-маршруты, то в большинстве случаев клиент пытается подключиться сначала по IPv6.

Мы же рассматриваем случай с VPN или с прокси, и тут возможных вариантов может быть гораздо больше. Когда вы подключаетесь к VPN-серверу или к прокси-серверу (в режиме TUN, он практически всегда используется, например, в мобильных клиентах), клиент создает в системе так называемый TUN-интерфейс, виртуальный сетевой адаптер. Через какой именно сетевой интерфейс пойдет трафик в другие сети (например в интернет) определяют маршруты в системе. Например, маршрут 0.0.0.0/0 буквально означает "до всех IPv4-адресов иди через отсюда". Изначально у вас на устройстве есть Ethernet- или WiFi-интерфейс, и чаще всего маршрут по умолчанию (тот самый "до всего") настроен через него (ваше устройство получает его от роутера или сразу от провайдера). Когда VPN-клиент или прокси-клиент-с-TUN-режимом поднимает в системе свой виртуальный интерфейс, он должен добавить маршруты через него с более высоким приоритетом, чтобы весь трафик шел в интернет не напрямую, а через прокси/VPN. И вот тут есть важная деталь: маршруты для IPv4 и IPv6 задаются по-отдельности. В итоге с VPN/прокси у нас может быть довольно много разных комбинаций. IPv6 может быть или не быть на клиентском устройстве от оператора связи. IPv6 может быть или не быть на VPN/прокси сервере. IPv6 может быть или не быть включен в прокси/VPN-клиенте. Могут быть еще разные вариации, например, IPv6-адрес выдается устройству роутером, но реальной IPv6-связности с интернетом нет. И так далее. Что же будет в каждом из этих случаев? Давайте рассмотрим варианты.

1. У провайдера нет IPv6 _и_ VPN/прокси-клиент не добавляет IPv6-маршруты = весь трафик идет на прокси/VPN, всё неплохо, приложения даже не пытаются никуда идти по IPv6, а сразу идут куда им надо по IPv4;

2. Не важно, есть ли у провайдера IPv6, VPN/прокси-клиент добавляет IPv6-маршруты и на сервере есть IPv6-связность = весь трафик идет на прокси/VPN, всё отлично, даже если у вас не было IPv6, теперь он есть, все работает как надо и даже лучше, весь трафик идет через прокси/VPN;

3. Не важно, есть ли у провайдера IPv6, VPN/прокси-клиент добавляет IPv6-маршруты, но на сервере нет IPv6-связности = весь трафик идет на прокси/VPN, но при попытке соединиться с IPv6-серверами ничего хорошего не выйдет;

4. Провайдер/роутер дает вам IPv6-адрес и маршруты, но реальной связности нет, VPN/прокси-клиент не добавляет IPv6-маршруты = то же самое как в прошлом пункте, при попытке соединиться с IPv6-серверами ничего не выйдет;

5. У провайдера есть IPv6 _и_ VPN/прокси-клиент не добавляет IPv6-маршруты = ваш IPv4-трафик пойдет через прокси/VPN, а вот трафик до IPv6-серверов пойдет напрямую;

Итак. Варианты 1 и 2 самые хорошие - никаких проблем, все работает как надо. Вариант 5 довольно опасный - часть ресурсов у вас открывается через прокси/VPN, а к части ресурсов трафик пойдет напрямую без прокси/VPN. В итоге, если вы пытаетесь подключиться к заблокированному сайту/сервису, то вам не дадут это сделать фильтры Роскомнадзора, и что еще хуже - если вы, используя прокси/VPN рассчитываете скрыть свой настоящий IP-адрес, например, оставляя сообщения на каких-либо форумах или в комментариях, то в этом случае есть риск засветить ваш настоящий IP от провайдера или мобильного оператора.

Варианты 3 и 4, казалось бы, не должны повлечь ничего ужасного. Для таких случаев существует так называемый механизм fallback. Когда клиент, например, браузер, пытается подключиться к удаленному серверу по IPv6, если подключение не было успешно установлено за определенное время (например, 500 миллисекунд), то клиент пробует подключиться еще раз, но через IPv4 вместо IPv6. Но есть одно но. Приготовьтесь... В Instagram и WhatsApp сломан механизм IPv6-fallback! Наглухо сломан. Если вы наберёте в Гугле "instagram IPv6 problem", то найдете огромное количество обсуждений не эту тему. Судя по всему, глюк есть только в версиях для iOS (по крайней мере, большинство жалоб именно от пользователей Apple). Учитывая, что оба приложени разработатываются одной компанией, весьма вероятно что там используется одна и та же библиотека или один и тот же код, и в нем есть этот баг. Проявляется он просто: при наличии IPv6-адреса в системе, но отсутствии реальной связности по IPv6, WhatsApp и Instagram не откатываются сразу же на IPv4, а начинают отчаянно тупить. В Whatsapp не доходят сообщения, в Instagram не грузятся сторис и фотографии, и т.д. Минут через 10-15 до них все-таки доходит, что связности нет, они наконец-то переключаются на IPv4, и все начинает работать как надо... до следущего переподключения или перезапуска приложения.

Да, и ещё важно сказать, что вышеперечисленные проблемы можно словить даже если вы в прокси-приложении настроите routing (иногда ещё называется split tunneling) чтобы, например, трафик до WhatsApp шел напрямую. Почему? Потому что все равно сначала все подключения прилетят по дефолтному маршруту на TUN-интерфейс, а уже потом клиент будет из разгуливать в соответствии с правилами, что-то отправляя на прокси, а что-то пропуская напрямую. IPv6 на TUN-интерфейсе есть, а реальной связности (у провайдера) нет - WhatsApp будет тупить.

Что же со всем этим можно сделать?
Если у вас или ваших клиентов тупит инстаграм/ватсап, или каким-то из онлайновых сервисов проверки IPv6-адреса вы видите айпишник из диапазона своего провайдера даже когда вы подключены к прокси/VPN, то нужно что-то делать.

Для VPN и для прокси рекомендации будут немного различаться, поэтому я разделю их на две части.

Для VPN.

Вариант 0, наиболее правильный. Настройте IPv6-связность на сервере, выдавайте клиентам IPv6-адреса и default route IPv6.

Иногда начинающие админы начинают читать документацию и советы про IPv6 и утопают в его глубинах. Мол, если мы получаем от хостера префикс, то надо и каждому клиенту раздавать индивидуальные адреса из этого префикса, и тому подобное. После настройки, как правило, ничего не работает, потому что у хостеров обычно не-routed префиксы и нужно использовать что-то типа radvd ndppd.

Это все не обязательно! Меня сейчас наверное побьют в комментах, но я скажу страшную вещь - если вам просто надо, чтобы у ваших клиентов была IPv6-связность с минимальными усилиями, простой настройте такой же NAT для IPv6, как вы это делали для IPv4, и пусть они все выходят в интернет с одного адреса (это называется NAT6). Да, не красиво, да, не используются все возможности, но оно настраивается одной командой и сразу работает.

Вариант 1, кривой. Не выдавать клиентам IPv6-адреса и маршруты, и на всех клиентских устройства отключить IPv6 где только можно. Вариант так себе. Если на десктопах поотключать IPv6 везде где можно довольно просто, то на мобильных устройствах это делается нетривиально, а то и не всегда возможно. Впрочем, если ни у одного из ваших используемых провайдеров нет IPv6 и не предвидится, то это делать не обязательно и жить можно.

Вариант 2, замудренный. Иногда у хостеров не бывает IPv6 на сервере (бегите от таких!), например, есть баг ломающий IPv6 в известной платформе виртуализации OpenVZ. Тогда можно сделать так: установить на сервер DNS-сервер (например, dnsmasq), и настроить в нем, чтобы он выдавал только A-записи, без AAAA. И присылайте его в параметрах подключениях своим VPN-клиентам. Тогда проблемные приложения типа Instagram и Whatsapp просто не будут знать, что у их серверов есть IPv6-адреса, и не будут пытаться их использовать. Останется только проблема с DNS-кэшем (если AAAA-записи прилетели еще когда юзер не был подключен к вам).

Для прокси (сервера Shadowsocks, XRay, Sing-box, клиенты Streisand, v2rayNG, Nekobox, Hiddify-Next и другие)

Тут все немного отличается от VPN, потому что галочка "Use IPv6" в разных клиентах может обозначать разное. В каких-то случаях оно означает, назначить ли клиент IPv6-адрес и маршруты на свой TUN-интерфейс, а в каких-то случаях он это делает всегда, а галочка тупо режет IPv6-связность, либо определяет, будет ли встроенный DNS-клиент воспринимать AAAA-записи.

Вариант 0, наиболее правильный. Настройте IPv6-связность на сервере, включите IPv6 в прокси-клиенте. На сервере, как только у вас появился IPv6-адрес и ходят пинги, даже больше настраивать ничего скорее всего не надо будет.

Вариант 1. Выключить в прокси-клиенте все что связано с IPv6 (иногда этот режим называется IPv4-only). Если прокси-клиент достаточно умный, то он заодно будет перехватывать DNS-запросы и выдавать только A-записи вместо AAAA, либо будет делать сниффинг (об этом чуть позже), и в том и в том случае Инстаграм и Ватсап будут счастливы. И если клиент достаточно умный, он все равно назначит IPv6 на TUN-интерфейс, и у вас ничего не утечет напрямую. И то и то нужно внимательно проверить.
Если клиент тупой и отключение IPv6 в настройках не назначает его на интерфейс, то возможна утечка трафика, придется отключить IPv6 в системе на клиенте где только можно. Недостатки в этом случае будут те же, что и в пункте 0 для VPN, см. выше

Вариант 2. Если нет IPv6 на сервере, трюк с DNS как для VPN, но немного другой. Рассмотрим его на примере популярного сервера XRay. У него есть встроенный DNS-сервер, настроим его в конфиге:

{
  ...
  "dns": {
    "servers": [
      "1.1.1.1",
      "9.9.9.9",
    ],
    "queryStrategy": "UseIPv4",
    "tag": "dns"
  },
  ...
}

Обратите внимание на опцию "UseIPv4", она означает то, что встроенный DNS будет оперировать только A-записями, а не AAAA, то есть только IPv4-адресами.

Далее, в "routing" в начале списка добавим правило, что все, что от клиента идет куда угодно на 53 порт (и TCP, и UDP), мы перехватим и перешлем на встроенный сервер, который обработает наш запрос, но вернет клиенту только IPv4-адрес домена, а не IPv6:

"routing":
{
  "rules": [
  ...
  {
        "type": "field",
        "inboundTag": [...],
        "port": 53,
        "outboundTag": "dns"
  },
  ...
  ]
}

И в заключение, для каждого (если их несколько, надо продублировать) вашего inbound'а включим sniffing вот таким образом:

"inbounds":
[
  ...
  {
    ...
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls",
          "quic"
        ]
      }
    ...
  }
  ...
]

Это нужно на случай, когда клиент получил IPv6-адрес нужного ему сервера каким-то еще образом (достав из кэша или через DoH, который мы не можем перехватить). XRay-сервер "подслушает" имя хоста (для голого HTTP) или поле SNI для TLS/HTTPS/QUIC, еще раз отрезолвит нужный домен и отправит подключение не туда, куда хочет клиент (IPv6), а туда, куда посчитает правильным (IPv4, у нас так настроен встроенный DNS).

На клиентах, скорее всего, надо включить IPv6, хоть по факту он использоваться не будет, важно чтобы у нас были IPv6-маршруты и трафик не пошел напрямую, если вдруг у вашего провайдера есть IPv6. Некоторые прокси-клиенты, как я уже выше сказал, добавляют IPv6 и маршруты для него в TUN всегда, тогда галочку включать не обязательно, итак будет работать нормально.

Вариант 3. Примерно то же самое что и вариант 2, но на клиенте.

Тут у каждого клиента пусть будет свой, но общий принцип такой же - включить в настройках Sniffing, включить его как "Sniff for destination", "Override destination" или что-то в этом роде, и в настройках локального DNS выбрать что-то типа UseIPv4 (или просто отключить IPv6 везде). Короче, нужно экспериментировать.

В некоторых клиентах вы получите то же самое сделав вариант 1.

Заключение

Теперь, если ы увидите, что кто-то жалуется на тупняк Instagram/WhatsApp через прокси/VPN, или на то, что у него через прокси/VPN по-прежнему не открываются заблокированные сайты, скиньте ему ссылку на эту статью.

TLDR: Настройте и на клиенте и на сервере IPv6, и все будет хорошо. Если у вас говнохостинг или руки не оттуда, то отключите везде IPv6, будет хуже, но хотя бы должно работать.

P.S. Моя предыдущая большая статья про обход блокировок в 2024 была заблокирована Хабром по требованию Роскомнадзора, но по-прежнему доступная из-за границы, а также через зарубежные прокси/VPN. Если вы сохраняли к себе ее копию локально - пересохраните, там много исправлений ошибок и полезных дополнений.

Комментарии (45)


  1. FSA
    30.04.2024 18:16
    +12

    Это все не обязательно! Меня сейчас наверное побьют в комментах, но я скажу страшную вещь - если вам просто надо, чтобы у ваших клиентов была IPv6-связность с минимальными усилиями, простой настройте такой же NAT для IPv6, как вы это делали для IPv4, и пусть они все выходят в интернет с одного адреса (это называется NAT6). Да, не красиво, да, не используются все возможности, но оно настраивается одной командой и сразу работает.

    Бить особо не собираюсь. К тому же мы находимся в ситуации, когда инструментами чиним сеть, которую кто-то сломал. Поэтому я не против NAT. Но при использовании IPv6 нужно учитывать одну вещь. Нельзя просто так взять и назначить клиентам адрес из диапазона fd00::/7 и ждать что у всех всё заработает. Некоторые клиенты не будут пользоваться IPv6 по той причине, что сеть fd00::/7 не маршрутизируется в интернете, а значит использовать адрес из этого диапазона для исходящего соединения на публичный адрес бессмысленно. Поэтому к вашему NAT теперь придётся ещё и прикрутить какую-то фиктивную адресацию с GUA адресами, чтобы у клиентов всё заработало. В такой ситуации вообще непонятно зачем нам использовать NAT, если мы и так будем выдавать GUA адреса клиентам. Разве что NAT нужен, чтобы сокрыть реальный адрес клиента... Короче, тут NAT не для функционирования сети нужен, поэтому я такое вполне допускаю.

    Мол, если мы получаем от хостера префикс, то надо и каждому клиенту раздавать индивидуальные адреса из этого префикса, и тому подобное. После настройки, как правило, ничего не работает, потому что у хостеров обычно не-routed префиксы и нужно использовать что-то типа radvd.

    radvd тут совершенно ни при чём. radvd рассылает анонсы машрутизатора в сеть, которые нужны для автоматического конфигурирования IPv6. Для того же Wireguard он совершенно бесполезен.

    Проблема тут в другом. Провайдерский маршрутизатор при запросах извне на вашу адресацию посылает вашему серверу запрос - «кто там у нас владеет этим адресом?». Если вы не присвоили этот адрес вашей машине на интерфейс, который смотрит в сторону провайдера, то ваша машина отвечать не будет. У неё же нет этого адреса. Нам нужно заставить нашу машину отвечать на запросы поиска соседей. Этим занимается ndppd. Он проксирует запросы поиска соседей туда, куда мы скажем, или вообще просто будет отвечать безусловно, что да, это мой адрес и шли мне все пакеты для этого адреса. А ещё NDP proxy можно настроить через sysctl, но я глубоко в тему не вникал.

    Вообще, IPv6 у разных провайдеров по разному настроен. Нужно индивидуально смотреть каждого. Но почти для всех есть свои решения, кроме разве что тех, кто поштучно раздают IPv6 адреса. От таких провайдеров надо уходить.


    1. UranusExplorer Автор
      30.04.2024 18:16

      Некоторые клиенты не будут пользоваться IPv6 по той причине, что сеть fd00::/7 не маршрутизируется в интернете, а значит использовать адрес из этого диапазона для исходящего соединения на публичный адрес бессмысленно.

      Там вроде как довольно много всяких зарезервированных диапазонов. Некоторые из них уже не рекомендуются к использованию, но на современных ОС работают и обеспечивают связность без проблем при назначении их клиентам, всякие там fec0::/10

      radvd тут совершенно ни при чём. radvd рассылает анонсы машрутизатора в сеть, которые нужны для автоматического конфигурирования IPv6. Для того же Wireguard он совершенно бесполезен.

      В обратную сторону. Чтобы когда из внешнего интернета кто-то решит послать IP-пакет в ответ вашему клиенту, этот самый пакет с оборудования хостера в дата-центре прилетел к вам на VPS, а не куда-нибудь ещё. Возможно для этого действительно достаточно ndppd, но я встречал инструкции именно про radvd


      1. FSA
        30.04.2024 18:16
        +3

        ravdv - это ничто иное как Router Advertisement Daemon, т.е. демон, который обеспечивает рассылку анонсов маршрутизатора. Это нужно только в сетях, где вам необходимо автоматическое конфигурирование клиентов. Если вы используете Wireguard, то он вообще, в силу своей простоты, никак с этим работать не может. OpenVPN обычно раздаёт адреса из указанного ему диапазона. Т.е. для него radvd не нужен. Может быть их как-то и можно скрестить, но и без него всё работает.

        В нашем случае нужно не анонсами маршрутизатора заниматься, а обеспечивать пересылку на себя пакетов с помощью механизма поиска соседей, раз провайдер не смаршрутизировал их на вашу машину. А для этого нужен именно NDP proxy. ndppd - один из вариантов реализации.


        1. UranusExplorer Автор
          30.04.2024 18:16
          +1

          Ага, теперь понятно


      1. ValdikSS
        30.04.2024 18:16
        +1

        Там вроде как довольно много всяких зарезервированных диапазонов. Некоторые из них уже не рекомендуются к использованию, но на современных ОС работают и обеспечивают связность без проблем при назначении их клиентам, всякие там fec0::/10

        Unique local address-диапазоны, а fec0::/10 относится именно к таким, при обращении к GUA-адресам имеют приоритет ниже, чем IPv4. Можете хоть нерабочие адреса выдавать клиентам VPN, чтобы они вообще не пытались использовать IPv6.

        https://blogs.infoblox.com/ipv6-coe/ula-is-broken-in-dual-stack-networks/
        https://blog.ipspace.net/2022/05/ipv6-ula-made-useless.html

        Не знаю, как ULA на одном интерфейсе и GUA на другом поведут себя при наличии двух маршрутов по умолчанию, нужно проверять.

        UPD: проверил, при такой конфигурации будет использоваться интерфейс провайдера (не VPN), даже если метрика у маршрута по умолчанию через VPN ниже. ULA добавляются только со scope: site.


    1. andrewz13
      30.04.2024 18:16

      Я недавно писал ndp proxy себе для VPN. Алгоритм работы примерно следующий:

      • отслеживается conntrack и если адрес (src или dst) попадает в указанную сеть периодически (10 секунд) выполняется unsolicited neigh advert этого адреса с mac интерфейса.

      • unsolicited neigh advert прекращается если событий conntrack для этого адреса не было 1 час.

      • прослушивается трафик neigh solicit и при получении запроса из искомой сети отправляется ответ с mac интерфейса.

      • периодически (10 секунд) отсылается neigh solicit на default gw и при получении ответа обновляется его адрес в таблице - сделано скорее для надежности и почему-то на одном из хостингов сеть /80 и мак gw часто пропадает.

      могу немного причесать и выложить на github если кому-то будет полезно...


  1. vadimk91
    30.04.2024 18:16

    У меня провайдер не поддерживает ipv6, использовал туннель поверх ipv4. Несколько месяцев бился с прошивкой Keenetic-а и надоело. На самом роутере все работает, проходят пинги v6, а клиент выдает "общую ошибку" на интерфейсе. В какой-то момент начинает работать, а через неделю отключили свет и все по новой. Разные версии прошивок, разные клиенты (win8,10,11). Может быть тоже какая-то ошибка в некоей популярной нынче библиотеке... А вот на старом Asus с кастомной прошивкой кажется 2013 года ipv6 работал как часы, но роутер тот устал и сказал "я больше не могу".


    1. Heggi
      30.04.2024 18:16

      У меня на Кинетике через туннель от HE нормально ipv6 работает. Настроил штатными средствами через морду.

      Помнится были проблемы с DNS (не отдавали AAAA-записи, только А), но это полечилось добавлением ipv6 гугловых DNS на интерфейс провайдера (вроде бы через консоль делал, но это не точно)


  1. Dmitri-D
    30.04.2024 18:16
    +2

    IPv6 не просто замена IPv4, он еще отменяет ARP и использует NDP (aka NP), который использует подмножество сообщений ICMPv6. Если ICMP заблокирован то... вот еще один вариант выстрелить себе в ногу.

    NDP позволяет адаптеру самому себе выбрать случайный адрес из соответствующего диапазона для локальной связности - это т.н. local-link адреса, они не раутятся. Поэтому если вы видите только один IPv6 на адаптере - это верный признак отсутствия раутров по IPv6.

    NAT для IPv6 - это скорее gateway в IPv4 мир и обратно, чем его аналог в IPv4 мире. Т.е. трансляцию IPv6 в IPv6 (обычно) никто не делает. А IPv6 -> IPv4 конечно делают.

    Перехват SNI - норм. но только если это не ESNI. И Retry Client Hello одычно криво обрабатывают...А они возникает если сервер не поддерживает нужные клиенту cypher, что например возникает если клиент на openssl 3.0, а сервер на openssl 1.1. Казалось бы. И там и тут TLS 1.3, но retry.