Мне не удается настроить IPtables для выполнения DNAT, а затем перенаправления TPROXY на прослушивающий прокси-сервер на маршрутизаторе.
Конечный результат должен быть следующим:
Входящее TCP или UDP-соединение от A.A.A.A -> B.B.B.B: 25 передается через DNAT на C.C.C.C: 25, а затем через TPROXY на слушающий сервер, который видит и перехватывает входящее соединение с C.C.C.C НЕ B.B.B.B.
Обычно с прозрачными TCP-прокси, использующими IPtables, используется цель REDIRECT, а затем исходное место назначения принимается прокси-сервером с использованием параметра сокета so_originalDestination. Это работает только для TCP-соединений, но не для UDP. Для прозрачного проксирования UDP-соединений обычно используется TPROXY.
ОДНАКО, некоторые из распространенных прозрачных прокси-решений, включая V2RAY и REDSOCKS2, могут использовать TPROXY для перехвата TCP-трафика, и это прекрасно работает.
Рабочий пример использования TPROXY:
// Добавить локальную исходную таблицу маршрутизации для маршрутизации всего, что помечено FW mark 1, на localhost, таблица 66 - произвольный выбор неиспользуемой таблицы маршрутизации
ip route add local default dev lo table 66
ip rule add fwmark 1 lookup 66
// Используем TPROXY для перехвата трафика на TCP-порт 25 и перенаправления на прослушивающий прозрачный прокси, использование DPORT = 25 - это просто способ легко перехватить трафик, который мы ищем, как если бы мы использовали правила IP, тогда возникает двусмысленность перехватываем ли мы BBBB или CCCC
iptables -t mangle -A PREROUTING -p tcp --dport 25 -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A PREROUTING -p udp --dport 25 -j TPROXY --on-port 12345 --tproxy-mark 1
Если у нас есть локальный прозрачный прокси, прослушивающий порт 12345, мы получаем трафик, как и ожидалось. Традиционные инструкции по настройке обычно также включают перехват трафика, генерируемого HOST, путем применения метки FW = 1 к исходящей цепочке, хотя это не обязательно для перехвата внешнего трафика, направляемого на этот хост.
Кроме того, в инструкциях по настройке TPROXY часто можно увидеть конфигурацию IPtables, аналогичную следующей:
iptables -t mangle -N DIVERT
iptables -t mangle -A DIVERT -j MARK --set-mark 1
iptables -t mangle -A DIVERT -j ACCEPT
iptables -t mangle -I PREROUTING -p tcp -m socket -j DIVERT
Которая перехватывает любые СУЩЕСТВУЮЩИЕ TCP-соединения с локальными сокетами, сразу же отмечает и принимает их, не пересекая полную цепочку PREROUTING. Это также кажется ненужным, и вышеуказанная конфигурация УСПЕШНО работает при тестировании на ядре 4.19.
Что мне теперь нужно сделать, так это избирательный трафик DNAT до того, как он будет TPROXY'ed, чтобы прозрачный прокси увидел, что соединение происходит с адреса POST DNAT.
Итак, добавляем:
iptables -t nat -I PREROUTING -p tcp -d B.B.B.B --dport 25 -j DNAT --to-destination C.C.C.C:25
Я ожидал, что теперь входящие TCP-соединения с B.B.B.B будут DNAT-привязаны к C.C.C.C, а затем попадут в TPROXY, так что прозрачный прокси получит соединение с TPROXY, но увидит его как исходящее TO C.C.C.C НЕ B.B.B.B.
Проблема в том, что эта конфигурация вообще не работает для TCP-трафика, при регистрации захвата пакета происходит следующее:
Флаги TCP отображаются в столбце БОЛЬШЕ ДЕТАЛЕЙ как S (yn), A (ck), R (eset).
На этом изображении показан захват пакета с исходным IP-адресом (AAAA = 192.168.0.10), инициирующим TCP-соединение с BBBB (2.2.2.2), с правилом DNAT, установленным на DNAT to CCCC (3.3.3.3 в примере, хотя и не видно). как и ожидалось в Pcap).
Я ДУМАЮ, что мы видим здесь следующее:
1) Первый пакет (Syn) проходит через DNAT, потому что это первый пакет в соединении и проходит через таблицу NAT, потому что мы видим ответ SYN / ACK от 2.2.2.2.
2) 192.168.0.10 затем отвечает Ack, как ожидалось, но этот пакет, похоже, НЕ был успешно обработан DNAT, потому что в пакетах 4 и 5 мы видим, что 2.2.2.2 отвечает тем же SYN / ACK в пакете 2, теперь вместе с Reset по какой-то причине (возможно, из-за того, что пакет 2 не был назначен DNAT, и поэтому маршрутизатор видит случайный SYN / ACK и отвечает сбросом.
3) Впоследствии 192.168.0.10 отвечает собственным сбросом, потому что он видел сброс из 2.2.2.2 в пакете 4.
4) В пакетах 7,9,11: 2.2.2.2 продолжает повторно отправлять неподтвержденные SYN / ACK первоначально в пакете 2, потому что последующие DNAT не работают, и поэтому он не получает Acks 192.168.0.10.
5) В пакетах 6,8,10,12: 192.168.0.10 продолжает повторно отправлять его Reset в ответ на сброс из 2.2.2.2 в пакете 4.
Моя интерпретация состоит в том, что это настоятельно предполагает, что только начальный SYN проходит через DNAT, вероятно, потому, что CONNTRACK не отслеживает успешно соединение, которое DNAT'ed, а затем TPROXYied. Это также, кажется, объясняет, почему UDP через ту же схему, похоже, работает, потому что, если CONNTRACK не может отслеживать, тогда каждый пакет UDP будет рассматриваться как новое соединение и попадет в DNAT в таблице Mangle.
Тестирование UDP-трафика через этот DNAT-> Tproxy, похоже, работает, но я подозреваю, что это связано с тем, что каждый UDP-пакет рассматривается как новое соединение, которое не может быть отслежено, и поэтому каждый пакет попадает в правило DNAT, а не транслируется ConnTrack.
Таким образом, возникает вопрос: ПОЧЕМУ это работает не так, как ожидалось, заключается в том, что Conntrack не может отслеживать соединение с DNAT и Tproxy, и что необходимо для того, чтобы эта схема заработала.
Этот вопрос был задан на #NetFilter безуспешно, хотя в качестве предложения использовать сетевые пространства имен для маршрутизации трафика DNAT в новое сетевое пространство имен, а затем зацикливать его обратно в основное пространство имен для выполнения Tproxy - это не помогло работают и генерирует ТОЧНО такой же захват пакетов.
Спасибо!