Я пытаюсь понять ограничения использования iptables DNAT с адресами обратной связи. Допустим, у нас есть приложение, которое может подключаться только к 127.0.0.1; Очевидное решение, позволяющее заставить сервер и клиент работать на разных узлах, - использовать NAT следующим образом:
Убедитесь, что все исходящие пакеты имеют IP-адрес основного клиентского хоста:
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source <CLIENT_IP>
Теперь попробуем обмануть клиента и DNAT установить соединение с внешним миром:
iptables -t nat -A OUTPUT -d 127.0.0.1/32 -p tcp -m tcp --dport <SERVICE_PORT> -j DNAT --to-destination <SERVER_IP>
К сожалению, это просто не работает при попытке подключиться к 127.0.0.1:<SERVICE_PORT>
программа просто зависает connect
системный вызов. Интересно то, что я не вижу SYN-пакетов ни на одном интерфейсе (tcpdump -qn -i any port <SERVICE_PORT>
), однако я вижу, что счетчики пакетов увеличиваются, глядя на статистику iptables (iptables -nvL -t nat
).
Поиск решения в Google. Я нашел вариант сборки ядра. CONFIG_IP_NF_NAT_LOCAL
, который использовался в ядрах 2.6.0–2.6.10 для решения проблемы использования NAT с локальными соединениями. К сожалению, текущее дерево ядра git содержит информацию для версий 2.6.11 и более поздних, поэтому здесь я зашел в тупик.
Глядя дальше, я столкнулся с эта тема, об исправлениях некоторых DNAT для проблем с петлей в 2.6.11; один из патчей удаляет CONFIG_IP_NF_NAT_LOCAL
вариант сборки и включает код безоговорочно (вот реальная разница).
Однако текущее состояние этой проблемы мне не совсем понятно. Я хотел бы найти некоторые объяснения или ссылки, доказывающие, что это ошибка ядра или какая-то не очень хорошо документированная функция. Я знаю, что маршрутизация сети 127.0.0.0/8 обрабатывается ядром особым образом, но из документации iptables ясно, что цепочка OUTPUT nat table - единственное место, которое имеет смысл для таких правил и не указывает никаких исключений или любые примечания относительно сети 127/8.
Пожалуйста, воздержитесь от советов по обходным путям со сторонними инструментами, у меня уже есть некоторые, я просто хочу получить какое-то объяснение, почему эта точная конфигурация не работает и почему она не должна работать. Приветствуются любые примеры того, как этот DNAT может быть реализован с любыми другими правилами iptables.
Приведенная выше конфигурация была протестирована на Debian squeeze и wheezy с ядрами 2.6.32, 3.1.0, 3.2.0.
Если копнуть немного глубже, мы получим некоторое подтверждение того, что вышеупомянутое поведение полностью правильное.
Согласно RFC 5735, сеть 127.0.0.0/8 не должна маршрутизироваться за пределы самого хоста:
127.0.0.0/8 - Этот блок предназначен для использования в качестве адреса обратной связи узла Интернета. Дейтаграмма, отправленная протоколом более высокого уровня на адрес в любом месте этого блока, возвращается в узел. Обычно это реализуется с использованием только 127.0.0.1/32 для обратной связи. Как описано в [RFC1122], раздел 3.2.1.3, адреса в пределах всего блока 127.0.0.0/8 законно не появляются ни в какой сети нигде.
RFC 1700на странице 5 также указано, что эти адреса «никогда не должны появляться вне хоста».
RFC 1812, раздел 5.3.7 Марсианская фильтрация адресов заявляет, что «маршрутизатору НЕ СЛЕДУЕТ пересылать, кроме как через интерфейс обратной связи, любой пакет, имеющий адрес источника в сети 127», что в точности соответствует моему случаю.
Что касается этих ссылок, я предполагаю, что случай из первого сообщения действительно является особенностью, а противоположное поведение будет нарушением стандартов.