Погружение в прозрачное проксирование

Что такое прозрачное проксирование?

Проще говоря, прозрачное проксирование не позволяет проксируемому устройству понять, что оно проксируется. Это означает, что на проксируемом устройстве не нужно запускать какое-либо программное обеспечение для проксирования (например, Xray, V2RayNG и т. д.). Когда вы подключаетесь к сети, ваше устройство уже проксируется.

Это также означает, что программное обеспечение прокси работает в другом месте, например, на маршрутизаторе, и устройства, подключенные к Интернету через маршрутизатор, автоматически проксируются.

Реализация прозрачного проксирования

В настоящее время существует два основных способа реализации прозрачного проксирования:

tun2socks

Доступно для Windows/Linux (включая Android). Поскольку процесс реализации относительно прост, существует не так много руководств, поэтому я кратко опишу его здесь.

Windows

  1. Установите NetchОткрыть в новой вкладке, используя режим [3] [TUN/TAP] Обход локальной сети для запуска.

  2. Включите точку доступа.

  3. Откройте Панель управления -> Сеть и Интернет -> Центр управления сетями и общим доступом -> Изменение параметров адаптера, найдите TAP-Windows Adapter и Microsoft Wi-Fi Direct Virtual Adapter.

  4. Щелкните правой кнопкой мыши TAP-Windows Adapter, Свойства -> Доступ, установите флажок Разрешить другим пользователям сети подключаться к Интернету через это подключение к Интернету, в Домашнее сетевое подключение выберите сетевое подключение Microsoft Wi-Fi Direct Virtual Adapter, нажмите ОК.

Android

  1. Настройте подключение V2RayNG.

  2. Включите точку доступа.

  3. Настройки точки доступа -> Разрешить использование VPN для точки доступа (эта опция может отсутствовать в некоторых системах Android).

iptables/nftables

iptables и nftables реализуют прозрачное проксирование по одному и тому же принципу, в дальнейшем мы будем использовать iptables.

Реализация прозрачного проксирования на основе iptables применима только к системам Linux (включая openwrt/Android). Благодаря своей эффективности по сравнению с tun2socks и возможности настройки на маршрутизаторах, она получила широкое распространение.

Существующие три русскоязычных руководства по прозрачному проксированию на самом деле описывают реализацию прозрачного проксирования на основе этого решения: Новое руководство по V2Ray на русском языке - Прозрачное проксированиеОткрыть в новой вкладке, Новое руководство по V2Ray на русском языке - Прозрачное проксирование (TPROXY)Открыть в новой вкладке, Руководство по настройке прозрачного проксирования (TProxy). Первое основано на устаревшем режиме iptables-redirect, который не рекомендуется использовать и приводится только для справки. Второе и третье описывают реализацию прозрачного проксирования на основе режима iptables-tproxy.

Принцип реализации прозрачного проксирования с помощью iptables

Linux использует Netfilter для управления сетью, модель Netfilter выглядит следующим образом:

Netfilter

Предположим, что в качестве шлюза используется маршрутизатор (т. е. наш обычный способ подключения к Интернету), тогда:

Направление трафика от устройств локальной сети к Интернету через маршрутизатор:

Цепочка PREROUTING -> Цепочка FORWARD -> Цепочка POSTINGROUTING

Направление трафика от устройств локальной сети к маршрутизатору (например, вход в веб-интерфейс маршрутизатора/подключение к маршрутизатору по ssh/доступ к DNS-серверу маршрутизатора и т. д.):

Цепочка PREROUTING -> Цепочка INPUT -> Хост шлюза

Направление трафика от маршрутизатора к Интернету:

Хост шлюза -> Цепочка OUTPUT -> Цепочка POSTINGROUTING

Управляя направлением трафика цепочек PREROUTING и OUTPUT с помощью iptables и перенаправляя его на Xray, мы можем проксировать устройства локальной сети и хост шлюза.

В чем сложность прозрачного проксирования?

Сложность прозрачного проксирования заключается в маршрутизации, то есть в различении того, какой трафик должен быть прямым, а какой должен проксироваться, поэтому я лично считаю, что термин разделение трафика более уместен.

Мы можем разделить маршрутизацию на следующие этапы по возрастанию сложности:

  1. Проксирование всех запросов.
  2. Прямое подключение для локальных IP-адресов/многоадресных IP-адресов, проксирование для остальных запросов.
  3. На основе пункта 2, прямое подключение для исходящих запросов, инициированных Xray.
  4. На основе пункта 3, прямое подключение для запросов, адресованных китайским IP-адресам, и выбор внутренних и внешних DNS-серверов для разрешения внутренних и внешних доменных имен.

Три вышеупомянутых руководства описывают четвертый этап. Поэтому новичкам может быть сложно понять их, читая напрямую.

Пошаговая реализация прозрачного проксирования на основе iptables-tproxy с нуля

Прежде чем начать, вам необходимо иметь базовые знания:

  1. Примерное представление о протоколах TCP/IP, доменных именах и DNS-серверах.
  2. Знание того, что такое WAN-порт, LAN-порт, LAN_IP, WAN_IP и DHCP-сервер. Для пограничных маршрутизаторов есть только один сетевой порт, который мы будем называть LAN-портом.
  3. Базовое понимание системы Linux (знание того, как запускать команды).
  4. Умение писать конфигурационные файлы клиента в формате json или, по крайней мере, понимать их.

Предварительная подготовка

Внимание

Перед началом работы не забудьте включить пересылку пакетов ipv4 в Linux с помощью команды sysctl -w net.ipv4.ip_forward=1

1. Подготовьте шлюз под управлением Linux

Например, маршрутизатор с прошивкой OpenWRT.

2. Подготовьте исполняемый файл Xray и конфигурационный файл на шлюзе (маршрутизаторе)

Конфигурационный файл прослушивает порт 12345 и включает tproxy:

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "port": 12345,
      "protocol": "dokodemo-door",
      "settings": {
        "network": "tcp,udp",
        "followRedirect": true
      },
      "streamSettings": {
        "sockopt": {
          "tproxy": "tproxy"
        }
      }
    }
  ],
  "outbounds": [
    {
      // Конфигурация вашего сервера
    }
  ]
}

Мы пойдем от простого к сложному, не будем писать routing, а напишем только один inbound и один outbound.

Сначала давайте попробуем достичь первого этапа

Внимание

Если вы не хотите перезагружать свою машину, лучше сначала попрактиковаться на виртуальной машине

Перенаправьте весь трафик цепочки PREROUTING в Xray.

Запустите Xray и выполните следующие команды:

ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100
iptables -t mangle -N XRAY
iptables -t mangle -A XRAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A XRAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A PREROUTING -j XRAY

После ввода команд, если вы подключены к шлюзу по ssh, вы обнаружите, что соединение ssh разорвано (не беспокойтесь, перезагрузка восстановит его), и прозрачное проксирование не работает; если ваш шлюз - это виртуальная машина, вы обнаружите, что сам шлюз не может получить доступ к Интернету, и в журнале доступа Xray появится множество запросов с исходным адресом, равным целевому адресу, и целевым адресом, равным WAN_IP.

Теоретически доступ хоста шлюза к общедоступной сети должен проходить только через цепочки OUTPUT и POSTINGROUTING, так почему же управление цепочкой PREROUTING приводит к тому, что шлюз не может получить доступ к Интернету? Это связано с тем, что сетевое взаимодействие, как правило, двунаправленное, и хотя доступ шлюза к общедоступному IP-адресу не требует прохождения через цепочку PREROUTING, информация, возвращаемая сервером на шлюз, должна проходить через цепочку PREROUTING, и эта часть перенаправляется на Xray, что приводит к обратным запросам в журнале.

Давайте изменим правило, чтобы возвращать трафик, источник которого не находится в локальной сети. Перезагрузите шлюз, запустите Xray и выполните следующие команды:

ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100
iptables -t mangle -N XRAY
# "Диапазон LAN-адресов шлюза" можно получить, выполнив команду "ip address | grep -w "inet" | awk '{print $2}'", это будет один из адресов
iptables -t mangle -A XRAY ! -s Диапазон LAN-адресов шлюза -j RETURN
iptables -t mangle -A XRAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A XRAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A PREROUTING -j XRAY

Теперь вы обнаружите, что, хотя соединение ssh разорвано, прозрачное проксирование уже работает. Если мы изменим системный DNS на общедоступный DNS, мы сможем нормально просматривать веб-страницы (поскольку в настоящее время шлюз недоступен, мы не можем установить DNS на шлюз).

На этом первый этап завершен. Причина, по которой мы не можем получить доступ к шлюзу, заключается в том, что правило проксирования проксирует весь трафик, включая трафик, адресованный шлюзу. Представьте, что вы пытаетесь получить доступ к своему локальному шлюзу с VPS, вы не сможете этого сделать, поэтому нам нужно сделать этот трафик прямым, смотрите второй этап:

Второй этап

Перезагрузите шлюз, запустите Xray и выполните следующие команды:

ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100
iptables -t mangle -N XRAY

# Прямое подключение для всех запросов, адресованных сегменту сети шлюза
# Получите сегменты сети, выполнив команду "ip address | grep -w "inet" | awk '{print $2}'", как правило, их несколько
iptables -t mangle -A XRAY -d Сегмент сети шлюза 1 -j RETURN
iptables -t mangle -A XRAY -d Сегмент сети шлюза 2 -j RETURN
...

# Прямое подключение для запросов, адресованных многоадресным IP-адресам/адресам класса E/широковещательным IP-адресам
iptables -t mangle -A XRAY -d 224.0.0.0/3 -j RETURN

iptables -t mangle -A XRAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A XRAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A PREROUTING -j XRAY

После использования этого правила предыдущее правило iptables -t mangle -A XRAY ! -s Диапазон LAN-адресов шлюза -j RETURN становится лишним и его можно удалить.

На этом второй этап завершен. Шлюз доступен, ssh не разрывается.

Третий этап

Обычно мы используем DNS, предоставляемый маршрутизатором, но это правило iptables проксирует только устройства в локальной сети, а не сам хост шлюза, поэтому возвращаемые результаты DNS-запросов могут быть неверными или загрязненными.

iptables-tproxy не поддерживает работу с цепочкой OUTPUT, но мы можем настроить маршрутизацию по политике, чтобы перенаправлять соответствующие пакеты из цепочки OUTPUT обратно в цепочку PREROUTING.

# Добавить маршрут по политике: пакеты с меткой 1 направляются в таблицу маршрутизации 100
ip rule add fwmark 1 table 100
# Добавить запись маршрута в таблицу маршрутизации 100: все пакеты направляются локально
ip route add local 0.0.0.0/0 dev lo table 100

Настроив маршрутизацию по политике выше, нам нужно только пометить пакеты, которые необходимо проксировать от хоста шлюза, меткой 1 в цепочке OUTPUT, и соответствующие пакеты будут направлены на сам хост шлюза, то есть в цепочку PREROUTING.

Если мы хотим проксировать все запросы, отправленные хостом шлюза, это вызовет проблему: Xray работает на шлюзе, Xray отправляет запросы на сервер прокси, и эти запросы снова проксируются, образуя петлю.

Поэтому, чтобы проксировать хост шлюза, необходимо избежать зацикливания, то есть исключить трафик запросов Xray из правил проксирования.

Существуют три распространенных метода:

  1. Прямое подключение трафика, адресованного VPS

Перезагрузите шлюз, запустите Xray и выполните следующие команды:

# Проксирование устройств локальной сети
# Наследуем достижения предыдущего этапа
ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100
iptables -t mangle -N XRAY
iptables -t mangle -A XRAY -d Сегмент сети шлюза 1 -j RETURN
iptables -t mangle -A XRAY -d Сегмент сети шлюза 2 -j RETURN
...
iptables -t mangle -A XRAY -d 224.0.0.0/3 -j RETURN
iptables -t mangle -A XRAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A XRAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A PREROUTING -j XRAY

# Проксирование хоста шлюза
iptables -t mangle -N XRAY_MASK
iptables -t mangle -A XRAY_MASK -d Сегмент сети шлюза 1 -j RETURN
iptables -t mangle -A XRAY_MASK -d Сегмент сети шлюза 2 -j RETURN
...
iptables -t mangle -A XRAY_MASK -d 224.0.0.0/3 -j RETURN
iptables -t mangle -A XRAY_MASK -d Общедоступный IP-адрес VPS/32 -j RETURN
iptables -t mangle -A XRAY_MASK -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -p tcp -j XRAY_MASK
iptables -t mangle -A OUTPUT -p udp -j XRAY_MASK

Однако у этого метода есть недостаток: если используется CDN или много VPS, то написание правил становится неудобным.

  1. Исключение с помощью меток

Три вышеупомянутых русскоязычных руководства используют этот метод исключения, обратитесь к ним, мы не будем повторяться здесь.

  1. Исключение с помощью gid (рекомендуется)

См. [Прозрачное проксирование] Исключение трафика Xray с помощью gid

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

Четвертый этап

На самом деле, не всем нужно реализовывать четвертый этап. Глобальное проксирование подходит для большинства случаев.

Особенно для пограничных маршрутизаторов. При необходимости проксирования установите шлюз на IP-адрес пограничного маршрутизатора, при отсутствии необходимости проксирования - на IP-адрес основного маршрутизатора.

Что касается конкретной реализации четвертого этапа, то об этом подробно рассказывается в трех вышеупомянутых русскоязычных руководствах. После того, как вы поймете вышеизложенное, вам будет легче понять эти руководства.

Проксирование IPv6

Вышеуказанные правила действительны только для IPv4, если вы хотите проксировать запросы IPv6, используйте команду ip6tables, ее использование в основном такое же, как и у iptables. См. [[Прозрачное проксирование] Исключение трафика Xray с помощью gid # 4-Настройка правил iptables](../iptables_gid # 4-Настройка правил iptables.md)

Другие замечания по прозрачному проксированию с помощью iptables

  1. Если шлюз, выступающий в качестве прокси, также является основным маршрутизатором, необходимо добавить правило iptables -t mangle -A XRAY ! -s Диапазон LAN-адресов шлюза -j RETURN в цепочку PREROUTING, то есть команду, использованную на первом этапе и удаленную на втором этапе. Если этого не сделать, другие люди в той же подсети, что и WAN-порт, смогут использовать ваш WAN_IP в качестве шлюза, чтобы злоупотреблять вашим прозрачным прокси, что может быть небезопасно.

  2. В [Новое руководство по V2Ray на русском языке - Прозрачное проксирование (TPROXY) # Настройка шлюза](https://guide.v2fly.org/app/tproxy.html # Настройка шлюза) третий пункт гласит: Настройте сеть ПК вручную, указав в качестве шлюза по умолчанию адрес Raspberry Pi, то есть 192.168.1.22. Теперь ПК должен иметь доступ к Интернету (поскольку проксирование еще не настроено, “доступ” означает возможность доступа к внутренним веб-сайтам). На самом деле, даже если включена переадресация IP, ПК под управлением Ubuntu, CentOS, Debian и других систем не смогут получить доступ к Интернету, это нормально. Фактически, только OpenWRT может сделать то, что описано в статье, как указал @BioniCosmosОткрыть в новой вкладке, это связано с тем, что в обычных системах Linux нет правил Masquerade.

  3. Проблема too many open filesОткрыть в новой вкладке, см. решение в [Прозрачное проксирование] Исключение трафика Xray с помощью gid - Настройка максимального количества открытых файлов и запуск клиента Xray

  4. Избегайте повторного прохождения пакетов с существующими подключениями через TPROXY, будет дополнено...

  5. Основной маршрутизатор, однорукий маршрутизатор и пограничный маршрутизатор, будет дополнено...