- Подавляющее большинство Интернет-клиентов и сервисов не имеет публичных Интернет-адресов
и подключается к Интернет-ресурсам через маршрутизаторы с поддержкой 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(),
а полученный результат передать на вход интерпретатора команд, который их и выполнит.