Содержание статьи
У этой технологии есть множество названий — это и трансляция портадреса, и проброс портов, и перенаправление, и буржуйские порт-форвардинг/порт-маппинг, и сокращенные DNAT/PAT. Но как бы она ни называлась, о ее полезности спорить не приходится. Проброс портов — просто спасательный круг для тех, кто хочет показать свой сервер из-за высокой и крепкой стены под названием NAT.
Недостаток сетевых адресов стандарта IPv4 оставил свой отпечаток на топологии современных сетей. Белые адреса слишком дороги, чтобы наделять ими всех, кого попало, поэтому простым смертным приходится ютиться в небольших частных подсетях, а в интернет выходить через один общий сервер, на котором настроен NAT. Благодаря такой схеме пользователи целой подсети могут использовать один внешний IP-адрес, а общая инфраструктура интернета продолжает жить, даже несмотря на очевидную нехватку IP-адресов. Но что если речь идет не о клиентах провайдера, сидящих за NAT'ом, а о локальной сети небольшой компании, многие машины которой должны играть роль не только клиентов, но и серверов. Например, на одной из машин может находиться веб-сервер, а другая должна обслуживать SMTP- и FTP-клиентов, но выделять каждой из них белый IP-адрес — как-то уж слишком расточительно.
Вот здесь нам на помощь и приходит DNAT или, по-простому — проброс портов. С помощью этой технологии можно сделать так, чтобы входящий на шлюз трафик перенаправлялся к одной из внутренних машин сети на основе порта назначения. Другими словами, проброс портов позволяет выставить во внешний мир сервисы локальных ресурсов и создать иллюзию того, что они находятся на шлюзе.
Перед тем, как начать
Эта статья рассказывает о настройке проброса портов в самых разных операционных системах, начиная с Windows и заканчивая ОС, установленными на сетевом оборудовании. В большинстве случаев для реализации проброса портов используются специальные правила брандмауэра, и здесь я должен сделать первое предостережение.
Дело в том, что любой брандмауэр выполняет трансляцию сетевых адресов до их фильтрации, поэтому описанные в статье правила должны находиться в начале. Второе: для успешного прохождения оттранслированных пакетов должны быть добавлены правила, разрешающие входящие подключения на целевой порт шлюза, а также правила, разрешающие обмен данными между внутренней целевой машиной и шлюзом.
Windows
Начнем, как говорится, с азов. Проще всего проброс портов настроить в операционных системах семейства Windows. Здесь все это делается в «Свойствах NAT»:
- Заходим в «Администрирование -> Маршрутизация», выбираем локальную машину, далее «IP-маршрутизация -> NAT».
- Включаем NAT для локального интерфейса.
- Переходим к вкладке «Службы и порты», выбираем интересующую нас службу или добавляем свою.
- В открывшемся окне выбираем протокол, входящий порт (тот, который будет виден извне), адрес машины внутренней сети и ее порт.
LINUX
В Linux все намного сложнее, здесь необходимо оперировать правилами iptables/netfilter, без знания основ которого просто не обойтись. Для осуществления проброса портов предусмотрена цель DNAT, которую необходимо использовать в правилах цепочки PREROUTING. В самом простейшем случае правило будет выглядеть следующим образом:
iptables -t nat -A PREROUTING -p tcp --dst $GATE \
--dport $PORT -j DNAT --to-destination $SERVER:$PORT
Где $GATE — это адрес шлюза, $PORT — пробрасываемый порт, а связка $SERVER:$PORT — это адрес и порт внутреннего сервера. Естественно, чтобы правило сработало, должен быть включен форвардинг (хотя на шлюзе он в любом случае включен):
# echo 1 > /proc/sys/net/ipv4/ip_forward
Проброс портов возможен и с другой машины:
$IPTABLES -t nat -A PREROUTING -p tcp --dst $IP \
--dport $PORT -j DNAT --to-destination $SERVER:$PORT
$IPTABLES -t nat -I POSTROUTING -p tcp --dst $SERVER \
--dport $PORT -j SNAT --to $IP
Это вполне легально, а иногда и просто необходимо. Различные преконфигурированные iptables-скрипты, такие как, например, знакомый пользователям Debian, arno-iptables-firewall, также можно использовать для более простой настройки проброса портов. Например, если ты хочешь пробросить порт 80 на машину 192.168.0.100, для этого достаточно добавить строку NAT_TCP_ FORWARD="80>192.168.0.100" в файл /etc/arno-iptables-firewall/firewall.conf и перезагрузить брандмауэр:
$ sudo /etc/init.d/arno-iptables-firewall restart
FreeBSD
FreeBSD отличается тем, что имеет две независимые реализации механизма NAT (а значит, и технологии проброса портов). Первая носит имя natd и, как можно догадаться из названия, представляет собой демон уровня пользователя, который принимает «сырые» пакеты, выполняет необходимые преобразования адресов и отдает их обратно ядру. Вторую принято называть kernel nat, то есть механизм NAT, реализованный в ядре FreeBSD. Он позволяет выполнять преобразование адресов и проброс портов, используя правила брандмауэра ipfw.
Ясно, что вторая реализация производительнее и удобнее в использовании, и поэтому предпочтительнее. Однако kernel nat появился во FreeBSD не так давно, поэтому мы рассмотрим оба подхода на тот случай, если в твоем расп оряжении оказалась машина, использующая устаревшую версию этой операционной системы. Итак, метод номер один: natd, divert и все-все-все. Для активации NAT и проброса портов с помощью демона natd необходимо проделать следующие шаги:
1. Включить natd и ipfw в /etc/rc.conf:
# vi /etc/rc.conf
# Включаем natd
natd_enable="YES"
# rl0 — внутренний интерфейс шлюза
natd_interface="rl0"
natd_flags="-f /etc/natd.conf"
# Включаем ipfw
firewall_enable="YES"
firewall_type="/etc/ipfw.conf"
2. Настроить NAT и проброс портов в /etc/natd.conf:
# vi /etc/natd.conf
same_ports yes
use_sockets yes
# Проброс портов:
# протокол адрес-сервера-внутри-сети:порт порт-на-шлюзе
redirect_port tcp 192.168.0.100:80 80
3. Чтобы все пакеты, проходящие через внешний интерфейс (rl1) шлюза,
перенаправлялись в natd и обрабатывались им, добавим правило divert
в /etc/ipfw.conf:
ipfw add divert natd ip from any to any in via rl1
Также разрешим общение всех с внутренним сервером:
ipfw allow tcp from any to 192.168.0.100 \
dst-port 80 in via rl0 setup
Далее можно добавить правила фильтрации. Метод номер два: ядерный NAT. Активация NAT с помощью реализации внутри ядра не требует ничего, кроме правильной настройки брандмауэра с помощью двух-трех правил. Не буду расписывать все в деталях, а просто приведу простой пример, демонстрирующий уже обсуждавшийся выше проброс 80-го порта со шлюза на внутренний сервер:
# vi /etc/ipfw.conf
# Настраиваем NAT
nat 1 config log if rl1 reset same_ports \
redirect_port tcp 192.168.0.100:80 80
# Заворачиваем весь трафик через внешний интерфейс в NAT
add nat 1 ip from any to any via rl1
Правила 'nat' имеют несколько опций, большинство из которых совпадает с опциями, используемыми демоном natd. Например, опция same_ports предписывает механизму NAT сохранять оригинальные номера исходящих портов для исходящих пакетов (нужно для правильной работы некоторых RPC-протоколов). Опция rdirect_port имеет тот же синтаксис, что и в файле /etc/natd.conf.
OpenBSD
Наверное, самый логичный и простой в настройке проброс портов получается в ОС OpenBSD. Здесь механизм NAT также реализован в ядре и настраивается с помощью штатного pf, синтаксис которого куда яснее и продуманнее синтаксиса ipfw и, уж тем более, iptables. Все тот же проброс 80-го порта на языке pf будет выглядеть следующим образом:
# vi /etc/pf.conf
# Настраиваем NAT
nat on rl1 from 192.168.10.0/24 to any -> $out_ip
# Настраиваем проброс портов
rdr on rl1 inet proto { tcp, udp } from any \
to $out_ip port 80 -> 192.168.0.100
Как и прежде, rl1 — внешний интерфейс шлюза, 192.168.0.100 — адрес внутреннего сервера, а out_ip — адрес внешнего интерфейса шлюза. При этом, если проброс должен быть сделан на порт, отличный от 80-го, достаточно просто добавить ключевое слово «port» и числовое значение в конец первого правила.
Разрешается использование диапазонов портов, если, конечно же, оно может иметь какой-то смысл:
rdr on rl1 inet proto { tcp, udp } from any \
to $out_ip port 5000:10000 -> 192.168.0.100
Прим. ред.: Например, с помощью этой фичи удобно разрешать прохождение трафика bittorrent:
rdr on $ext_if inet proto tcp from any to $ext_if \
port 6881:6889 -> $myhost port 6881:6889
pass in quick on $ext_if inet proto tcp from any \
to $myhost port 6880 >< 6890 keep state
Как и в других рассмотренных ранее брандмауэрах, принятие решения о дальнейшей судьбе пакетов возлагается на правила фильтрации, через которые пакет будет пропущен уже после перенаправления. Но есть одно маленькое исключение: используя ключевое слово «pass» совместно с правилом rdr можно добиться такого поведения системы, когда пакеты будут отпускаться во внешний мир, минуя правила фильтрации (см. скриншот «Форвардим входящие запросы на сервер терминалов и SQL-сервер»). Эта особенность может быть использована для отладки правил.
Будь внимателен, в OpenBSD 4.7 синтаксис конфига несколько изменился:
pass out on rl1 from 192.168.0.0/24 to any \
nat-to $out_ip
pass in on rl1 proto tcp from any to any \
port 80 rdr-to 192.168.0.100
Cisco
С моей стороны было бы кощунством не рассказать про настройку проброса портов с помощью сетевого оборудования небезызвестной компании Cisco. Благо, здесь все решается одной простой строкой, которая, тем не менее, будет разной для различных типов устройств. Например, проброс портов в Cisco PIX (Private Internet Exchange) или ASA (Adaptive Security Appliance) осуществляется с помощью следующей строки конфигурации:
static (inside,outside) tcp 1.2.3.4 www \
192.168.0.100 www netmask 255.255.255.255
В то же время для оборудования, работающего на операционной системе Cisco IOS, строка будет выглядеть так:
ip nat inside source static tcp 192.168.0.100 80 \
1.2.3.4 80
Обе они не делают ничего кроме проброса порта 80 на сервер 192.168.0.100 для клиента с адресом 1.2.3.4. При этом если необходимо настроить проброс всех портов, достаточно просто опустить номера/ имена портов в строке конфигурации.
Openwrt и DD-WRT
Конечно же, кроме оборудования именитой Cisco на рынке существуют и гораздо менее дорогостоящие решения вроде разного рода домашних роутеров и точек доступа. Большой популярностью среди них пользуются ультра-бюджетные сетевые устройства таких компаний, как D-Link, ASUS, Linksys и других. На многих из них можно установить свободные и более продвинутые прошивки вроде OpenWrt, X-Wrt и DD-wrt, которые отличаются более развитой системой настройки и хорошим комьюнити. Естественно, проброс портов легко выполнить и с их помощью. В DD-Wrt проброс портов осуществляется с помощью локализованного веб-интерфейса. Чтобы настроить проброс по описанной выше схеме, достаточно открыть веб-интерфейс роутера (192.168.1.1), перейти на вкладку «NAT/QoS», далее — вкладка «Перенаправление портов». Теперь в поле «Приложение» пишем любое удобное для нас имя, например, «www», «Порт-источник» — внешний порт роутера, «Протокол» — TCP или UDP, «IP-адрес» — адрес внутреннего сервера, «Порт-приемник» — его порт. Далее выбираем галочку «Включить», жмем кнопку «Добавить », потом — кнопку «Применить».
Это действительно простой путь, который… не сработает для большинства российских провайдеров, предоставляющих как доступ к локальной сети (прямой), так и доступ к сети интернет (через VPN/PPTP). Дело в том, что добавленное таким образом правило будет применено к внешнему физическому интерфейсу, тогда как интерфейс ppp0, используемый для выхода в интернет через VPN/PPTP, останется не при делах. Для решения проблемы можно воспользоваться прямым вмешательством в недра DD-Wrt. Открываем вкладку «Тех.обслуживание», далее — «Команды» и набираем стандартные правила iptables:
iptables -t nat -A PREROUTING -p tcp -i ppp0 \
--dport 80 -j DNAT --to 192.168.0.100:80
Нажимаем «Сохр. брандмауэр» и перезагружаемся. Ненамного труднее выполнить эту операцию с помощью веб-интерфейса прошивок X-Wrt, представляющих собой, по сути, более юзабельный вариант OpenWrt. Жмем на «Network», затем «Firewall», выбираем в меню «New Rule» пункт «Forward» и нажимаем «Add». Записываем в поле «Forward To» IP-адрес внутреннего сервера, в поле «Port» помещаем номер пробрасываемого порта. В выпадающем меню выбираем пункт «Protocol» и нажимаем «Add», в появившемся меню выбираем протокол: TCP или UDP. Если порт, открытый на шлюзе, должен отличаться от порта внутреннего сервера, выбираем в выпадающем меню пункт «Destination Ports», получаем одноименное поле и вводим в него номер порта. Нажимаем кнопку «Save».
Того же эффекта можно достичь, отредактировав конфигурационный файл /etc/config/firewall следующим образом:
forward:proto=tcp dport=80:192.168.0.100:80
Другие подходы
Для осуществления проброса порта совсем необязательно использовать брандмауэры или системные демоны, как, например, этого требуют старые версии FreeBSD. Существует несколько других способов сделать это с помощью специализированного софта или стандартных инструментов ОС (кто знает, возможно, ты используешь Minix в качестве ОС для шлюза :)). Один из таких инструментов — SSH. Далеко не каждый системный администратор в курсе, что проброс порта является стандартной функцией этой программы. Возьмем, к примеру, следующую ситуацию. В локальной сети, закрытой от внешней сети NAT'ом, есть сервер, к которому тебе необходимо иметь доступ. Ситуация усугубляется тем, что ты не имеешь привилегий для настройки файервола на машине-шлюзе. Зато у тебя есть доступ к SSH-серверу, работающему на этом шлюзе. Как это может помочь? На самом деле очень сильно. Ты просто выполняешь следующую команду на удаленной машине (serverip — адрес внутреннего сервера, gateway-ip — адрес шлюза):
$ ssh -L 8080:<server-ip>:80 user@<gateway-ip>
И вуаля, порт 8080 локальной машины становится портом 80 внутреннего сервера локалки. Теперь достаточно набрать в веб-браузере адрес localhost:8080, и ты попадешь туда, куда надо. Твой SSH-клиент создаст туннель с SSH-сервером шлюза, все передаваемые в рамках которого данные будут направлены на порт 80 внутреннего сервера.
Более радикальный способ — установка софта, специально созданного для осуществления проброса портов. Одна из таких программ носит имя rinetd и представляет собой высокопроизводительный сервер, позволяю щий пробрасывать любое количество соединений. Он есть в пакетах для популярных Linux-дистрибутивов и портах BSD-систем.
После его установки достаточно отредактировать файл /etc/rinetd.conf (/usr/local/etc/rinetd.conf), поместив туда строки следующего вида:
1.2.3.4 80 192.168.0.100 80
И (пере)запустить сервер командой:
$ sudo /etc/init.d/rinetd restart
в Ubuntu или:
# /usr/local/etc/rc.d/rinetd start
во FreeBSD. Так же во FreeBSD придется активировать запуск rinetd при
старте:
# echo "rinetd_enable="YES"" >> /etc/rc.conf
После этого весь трафик, пришедший на порт 80 машины 1.2.3.4, будет автоматически перенаправлен на тот же порт машины с IP-адресом 192.168.0.100.
Один из излюбленных способов проброса портов среди UNIX-администраторов заключается в использовании утилиты socket совместно с сетевым супер-сервером inetd. Как и все гениальное, идея в этом случае проста, а реализация очевидна. Открываем файл /etc/inetd.conf (даже если в твоей системе используется более новый xinetd, ты все равно можешь использовать этот файл) и добавляем в него строку следующего вида:
порт1 stream tcp nowait root /usr/local/bin/socket
socket 192.168.0.100 порт2
Здесь порт1 — это прослушиваемый порт на машине-шлюзе, а порт2 — порт назначения на внутренней машине 192.168.0.100. При этом оба они должны быть заданы в форме имени службы (www, ftp и т.д.), если же таковой не имеется (ты выбрал произвольный порт), то ее необходимо добавить в файл /etc/services.
Далее можно перезагрузить inetd командой «kill -HUP» и наслаждаться результатом. Если же его нет, то смотрим в файл /etc/hosts.allow. Доступ к службе должен быть открыт.
Выводы
Несмотря на выбранный для статьи пример с пробросом порта в локальную сеть, у технологии DNAT есть множество других применений, включая создание более удобного способа доступа к удаленной машине, обход правил брандмауэра или просто обман. В любом случае, проброс портов остается очень удобной и легкой в реализации и применении технологией, которая может оказаться полезной в любой момент.
UDP-туннель между двумя NAT
Утилита pwnat (http://samy.pl/pwnat/) позволяет любому количеству клиентов, находящихся за одним NAT-сервером, соединяться с сервером, который стоит за другим NAT, причем никакой проброски портов на серверах не потребуется.
Клиент может подключаться через такой сервер к любым ресурсам, либо только к тем, что ограничены сервером pwnat.
Автоматический проброс портов
Universal Plug and Play (UPnP) — технология, призванная упростить и автоматизировать процесс общения сетевых устройств и приложений между собой. Поддерживается почти любым современным сетевым оборудованием, включает в себя механизм автоматического проброса портов в случае необходимости. Тот же механизм реализован во многих файлообменных программах.