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