Пробрасываем порты в окнах, никсах и кисках
Евгений Зобнин (j1m@synack.ru)
У этой технологии есть множество названий, это и трансляция порт-адрес, и проброс портов, и перенаправление, и буржуйские порт-форвардинг/порт-маппинг, и сокращенные DNAT/PAT. Но как бы она не называлась, о ее полезности спорить не приходится. Проброс портов просто спасательный круг для тех, кто хочет показать свой сервер из-за высокой и крепкой стены под названием NAT.
Содержание:
Недостаток сетевых адресов стандарта IPv4 оставил свой отпечаток на топологии современных сетей. Белые адреса слишком дороги, чтобы наделять ими всех, кого попало, поэтому простым смертным приходится ютиться в небольших частных подсетях, а в интернет выходить через один общий сервер, на котором настроен NAT. Благодаря такой схеме пользователи целой подсети могут использовать один внешний IP-адрес, а общая инфраструктура интернета продолжает жить, даже несмотря на очевидную нехватку IP-адресов. Но что если речь идет не о клиентах провайдера, сидящих за NAT’ом, а о локальной сети небольшой компании, многие машины которой должны выполнять роль не только клиентов, но и серверов. Например, на одной из машин может находиться web-сервер, а другая обслуживать SMTP- и FTP-клиентов, но выделять каждой из них белый IP-адрес как-то уж слишком расточительно. Вот здесь нам на помощь и приходит DNAT или, по простому, проброс портов. С помощью этой технологии можно сделать так, чтобы входящий на шлюз трафик перенаправлялся к одной из внутренних машин сети на основе порта назначения. Другими словами, проброс портов позволяет выставить во внешний мир сервисы локальных ресурсов и создать иллюзию того, что они находятся на шлюзе.
Эта статья рассказывает о настройке проброса портов в самых разных операционных системах, начиная с Windows и заканчивая ОС, установленными в сетевом оборудовании. В большинстве случаев для реализации проброса портов используются специальные правила брандмауэра, и здесь я должен сделать первое предостережение. Дело в том, что любой брандмауэр выполняет трансляцию сетевых адресов до их фильтрации, поэтому описанные в статье правила должны находиться в начале. Второе: для успешного прохождения оттранслированных пакетов должны быть добавлены правила, разрешающие входящие подключения на целевой порт шлюза, а также правила, разрешающие обмен данными между внутренней целевой машиной и шлюзом.
Начнем, как говорится, с азов. Проще всего проброс портов настроить в операционных системах семейства Windows. Здесь все это делается в «Свойствах NAT»:
-
Заходим в «Администрирование -> Маршрутизация», выбираем локальную машину, далее «IP-маршрутизация -> NAT».
- Включаем NAT для локального интерфейса.
- Переходим к вкладке «Службы и порты», выбираем интересующую нас службу или добавляем свою.
-
В открывшемся окне выбираем протокол, входящий порт (тот, который будет виден извне), адрес машины внутренней сети и ее порт.
В 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 отличается тем, что имеет две независимые реализации механизма NAT (а значит, и технологии проброса портов). Первая носит имя natd и, как можно догадаться из названия, представляет собой демон уровня пользователя, который принимает «сырые» пакеты, выполняет необходимые преобразования адресов и отдает их обратно ядру. Вторую принято называть «kernel nat», то есть механизм NAT, реализованный в ядре FreeBSD. Он позволяет выполнять преобразование адресов и проброс портов, используя правила брандмауэра ipfw.
Ясно, что вторая реализация производительнее и удобнее в использовании, а потому предпочтительнее. Однако «kernel nat» появился во FreeBSD не так давно, поэтому мы рассмотрим оба подхода на тот случай, если в твоем распоряжении оказалась машина, использующая устаревшую версию этой операционной системы.
Итак, метод номер 1: natd, divert и все-все-все. Для активации NAT и проброса портов с помощью демона natd необходимо проделать следующие шаги:
- Включить 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"
- Настроить NAT и проброс портов в /etc/natd.conf:
# vi /etc/natd.conf same_ports yes use_sockets yes # Проброс портов: # протокол адрес-сервера-внутри-сети:порт порт-на-шлюзе redirect_port tcp 192.168.0.100:80 80
-
Чтобы все пакеты, проходящие через внешний интерфейс (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Далее можно добавить правила фильтрации.
Метод номер 2: ядерный 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. Здесь механизм 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 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. При этом, если необходимо настроить проброс всех портов, достаточно просто опустить номера/имена портов в строке конфигурации.
Конечно же, кроме оборудования именитой Cisco, на рынке существуют и гораздо менее дорогостоящие решения, вроде разного рода домашних роутеров и точек доступа. Большой популярностью среди них пользуются ультра-бюджетные сетевые устройства таких компаний, как D-Link, ASUS, Linksys и других. На многие из них можно установить свободные и более продвинутые прошивки вроде OpenWrt, X-Wrt и DD-wrt, которые отличаются более развитой системой настройки и хорошим комьюнити. Естественно, проброс портов легко выполнить и с их помощью.
В DD-Wrt проброс портов осуществляется с помощью локализованного Web-интерфейса. Чтобы настроить проброс по описанной выше схеме, достаточно открыть web-интерфейс роутера (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Далее нажимаем «Сохр. брандмауэр» и перезагружаемся.
Не намного труднее выполнить эту операцию с помощью web-интерфейса прошивок 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-серверу, работающему на этом шлюзе. Как это может помочь? На самом деле очень сильно. Ты просто выполняешь следующую команду на удаленной машине (server-ip — адрес внутреннего сервера, gateway-ip — адрес шлюза):$ ssh -L 8080:<server-ip>:80 user@<gateway-ip>
И вуаля, порт 8080 локальной машины становится портом 80 внутреннего сервера локалки. Теперь достаточно набрать в web-браузере адрес 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 есть множество других применений, включая создание более удобного способа доступа к удаленной машине, обход правил брандмауэра или просто обман. В любом случае проброс портов остается очень удобной и легкой в реализации и применении технологией, которая может оказаться полезной в любой момент.
Автоматический проброс портов
Universal Plug and Play (UPnP) — технология, призванная упростить и автоматизировать процесс общения сетевых устройств и приложений между собой. Поддерживается почти любым современным сетевым оборудованием, включает в себя механизм автоматического проброса портов в случае необходимости. Тот же механизм реализован во многих файлообменных программах.
UDP туннель между двумя NAT
Утилита позволяет любому количеству клиентов, находящихся за одним NAT-сервером, соединяться с сервером, который стоит за другим NAT, причем никакой проброски портов на серверах не потребуется. Клиент может подключаться через такой сервер к любым ресурсам, либо только тем, что ограничены сервером pwnat.
Получаем HighID
Вот так можно обеспечить клиентскому хосту 192.168.0.2 получение HighID на любом eDonkey-сервере:
# vi /etc/pf.conf rdr pass on $ext_if inet proto tcp from any \ to any port 4661 -> 192.168.0.2 rdr pass on $ext_if inet proto tcp from any \ to any port 4662 -> 192.168.0.2 rdr pass on $ext_if inet proto udp from any \ to any port 4665 -> 192.168.0.2 rdr pass on $ext_if inet proto udp from any \ to any port 4672 -> 192.168.0.2Статья опубликована в августовском номере журнала «Xakep» за 2010 год.





