Обратный NAT и с чем его едят.

Обратный NAT и с чем его едят.

Являясь владельцем маршрутизатора ASUS WL500-g и после огромного количества попыток использовать весь потенциал данной поделки китайского радиопрома, я остановился на прошивке со скромным названием

OpenWRT. Как и все открытые продукты данная прошивка была основана на ядре линукс, бизибоксе, аше и прочей дребедени. После множества интересных приключений связанных с юсб, беспроводной сетью, совместимостью версий ядер и модулей к проприетарному железу установленному в эту коробку все наконец заработало. Но возник интересный прецедент. Я использую собственный DNS сервер как примари для обслуживания зоны fomichi.ru. И когда компьютеры внутри сети пытаются правильно разрезолвить адрес сервера фомичей они получают его внешний IP. При попытке обратиться к нему пакет выбирается наружу через роутер, проходит NAT и возвращается обратно в маршрутизатор через внешний интерфейс, который его занатил. При попытки вернуться обратно с правилами по умолчанию пакет теряется и пользователь внутренней сети получает шиш с маслом, а не веб ресурс фомичей, хотя пинги идут исправно. Перекопав километры интернета и исправно и качественно покурив гугль был обнаружен скрипт который достаточно просто реализует так называемый NAT Loopback. Собственно вот он:

Устанавливаем iptables-utils (без этого пакета ничего работать не будет)

Потом создаем скрипт на роутере в любой папке с правами на исполнение. Например 777 😉

#!/bin/sh
#File: natloopback.sh
#Requires iptables-utils package

local WANZONE
local LANZONE
local lan_addr
local lan_net
local CHECKDIFF
local CHKCHAIN
local execute
local DNATS
local MINIUPNPD

. /etc/functions.sh

syntax() {
echo «Syntax: ‘natloopback.sh <wan zone> <lan zone>'»
exit
}

if [ -z $2 ]; then
syntax
fi

WANZONE=$1
LANZONE=$2

config_load «network»
config_get if_wan ${WANZONE:-wan} ifname
config_get wan_ip ${WANZONE:-wan} ipaddr
config_get lan_ip ${LANZONE:-wan} ipaddr
config_get lan_mask ${LANZONE:-wan} netmask

lan_addr=`echo $lan_ip | awk -F «.» ‘{print $1″.»$2″.»$3″.0″}’`
lan_net=$(echo $lan_addr/$lan_mask)

if [ -z «$if_wan» -o -z «$lan_ip» -o -z «$lan_mask» ]; then
syntax
fi

iptables-save -t nat | grep DNAT | grep -v nlb > /tmp/.natloopback.$WANZONE.current

if [ -e «/tmp/.natloopback.${WANZONE}.lastupdate» ]; then
CHECKDIFF=`diff -q /tmp/.natloopback.${WANZONE}.lastupdate /tmp/.natloopback.${WANZONE}.current 2>&1`
else
CHECKDIFF=1
fi

CHKCHAIN=`iptables -L prerouting_rule -t nat | grep nlb_${WANZONE}_pre`

if [ ! -z «$CHECKDIFF» -o -z «$CHKCHAIN» ];
then

if [ -z «$CHKCHAIN» ]; then
iptables -N nlb_${WANZONE}_pre -t nat > /dev/null 2>&1
iptables -A prerouting_rule -t nat -j nlb_${WANZONE}_pre
iptables -N nlb_${WANZONE}_for > /dev/null 2>&1
iptables -A forwarding_rule -j nlb_${WANZONE}_for
iptables -N nlb_${WANZONE}_post -t nat > /dev/null 2>&1
iptables -A postrouting_rule -t nat -j nlb_${WANZONE}_post
fi

iptables -F nlb_${WANZONE}_pre -t nat > /dev/null 2>&1
iptables -F nlb_${WANZONE}_for > /dev/null 2>&1
iptables -F nlb_${WANZONE}_post -t nat > /dev/null 2>&1

DNATS=`cat /tmp/.natloopback.${WANZONE}.current | grep zone_${WANZONE}_prerouting`
MINIUPNPD=`cat /tmp/.natloopback.${WANZONE}.current | grep MINIUPNPD`

nat_loopback() {
iptables -t nat -A nlb_${WANZONE}_pre -d $wan_ip -p $1 —dport $2 -j DNAT —to-destination $3
iptables -A nlb_${WANZONE}_for -p $1 —dport $2 -d $(echo $3 | awk -F «:» ‘{print $1}’) -j ACCEPT
iptables -t nat -A nlb_${WANZONE}_post -s $lan_net -p $1 —dport $2 -d $(echo $3 | awk -F «:» ‘{print $1}’) -j SNAT —to-source $wan_ip
}

if [ ! -z «$DNATS» ]; then
echo «$DNATS» | while read execute
do
SCAN=$(echo ${execute} | awk -F » » ‘{print $4 » » $8 » » $12}’)
nat_loopback $SCAN
done
fi

if [ ! -z «$MINIUPNPD» ]; then
echo «$MINIUPNPD» | while read execute
do
SCAN=$(echo ${execute} | awk -F » » ‘{print $4 » » $8 » » $12}’)
nat_loopback $SCAN
done
fi

mv /tmp/.natloopback.${WANZONE}.current /tmp/.natloopback.${WANZONE}.lastupdate
fi

Запускаем с значениями зоны лан и ван (обычно это lan и wan по умолчанию), то есть если мы назвали скрипт natloop.sh и положили его в etc, то строка запуска будет /etc/natloop.sh lan wan

дописываем в /etc/firewall.user

sh /где_лежит_скрипт/имя_скрипта.sh lan wan

После этого перезапускаем фаервол при помощи скрипта /etc/init.d/firewall restart и если не появилост ошибок, то проверяем как все работает. Обычно все работает.

За скрипт огромное спасибо неизвестному автору с неизвестного форума.

Скрипт писан только под OpenWRT, с другими системами без адаптации скорее всего не заработает.

avatar

Author: AzzBuka