Однострочник для NAT

10 января 2020

  • Подавляющее большинство Интернет-клиентов и сервисов не имеет публичных Интернет-адресов и подключается к Интернет-ресурсам через маршрутизаторы с поддержкой NAT (т.н. «трансляции сетевых адресов»).
  • Linux предоставляет для организации NAT на маршрутизаторе несколько вариантов, в т.ч. модули файрволла iptables — SNAT (“source NAT”) и masquerading.
  • В большинстве случаев используется маскарадинг, т.к. по сравнению с SNAT (а) настраивается более короткой командой и (б) умеет автоматически отслеживать изменение собственного IP-адреса маршрутизатора (например, если маршрутизатор получает IP-адрес динамически от вышестоящего провайдера).
  • SNAT имеет смысл из-за более высокой производительности, если сетевые настройки неизменны.
  • Ниже мы показываем, что SNAT при некотором желании и навыке тоже настраивается в одну строку, причём необходимые для настройки параметры читаются из системы в этой же строке.

Команда разбита на несколько строк для вашего удобства:

ip r g 1 | awk '$4 == "dev" && $6 == "src" { printf(
"iptables -t nat -C POSTROUTING -o %s -j SNAT --to-source %s 2>/dev/null ||\niptables -t nat -A POSTROUTING -o %s -j SNAT --to-source %s\n",
$5, $7, $5, $7); exit; }' | sh

Расшифровка:

  • Современная сетевая подсистема Linux, носящая имя собственное iproute2 и принадлежащая перу нашего великого соотечественника ANK, предоставляет пользователю набор команд, намного превосходящий традиционный.
  • В частности, входящая в неё утилита “ip” умеет показывать не только общий список маршрутов, но и по какому маршруту и с какими параметрами ядро отправит пакет для указанного получателя.
  • Таким образом, указав ей любой IP-адрес из внешней Сети (например, “1.0.0.0”), мы узнаем (а) имя нашего внешнего сетевого интерфейса и (б) его IP-адрес, например:
  • $ ip route get 1.0.0.0
    1.0.0.0 via 100.200.0.1 dev eno1 src 100.200.0.33 uid 1000 
      cache
  • iproute2 позволяет сокращать и имена параметров, и значения, поэтому скучная предыдущая команда превращается в истинно красноглазную “ip r g 1”.
  • awk ищет в её выводе строку с именем сетевого интерфейса и IP-адресом отправителя “dev ... src ...”, обрабатывает её и сразу завершается.

Задача awk:

  • Полученные значения мы должны подставить в команды настройки iptables.
  • Проблема в том, что (а) эти значения должны подставляться в разные места строки вызова и (б) для защиты от повторного добавления желательно вызывать iptables дважды — сначала с ключом “-C” для проверки, что такое правило ещё отсутствует, и затем с “-A” для его создания:
  • iptables -C параметры... 2>/dev/null || iptables -A такиежепараметры...
  • Поэтому имеет смысл полностью сформировать всю команду внутри awk через printf(), а полученный результат передать на вход интерпретатора команд, который их и выполнит.


← Назад в Блог

Подпишитесь на новые статьи: