Редирект порта с помощью ipfw + natd или ipfw + natd redirect_port [2010]
Поводом для написание этой статьи стало обращение знакомого с вопросом о пробросе порта внутрь локалки.
Я понимаю, что тема вроде как «избитая», так же я ответил и знакомцу: «Гугл тебе в помощь, там все найдешь.»
Через некоторое время он постучался снова, снова с просьбой помочь, что у него не получается. Ну что ж, полез смотреть…..
Вот тут то и выяснился один нюанс, что ему нужно не просто пробросить порт, т.к. default gateway у железки смотрит не на сервер, с которого он пытается пробросить порт.
Дабы не объяснять потом одно и тоже очередному знакомому решил накатать сей пост, копипаст рулит ! ))))
Для простоты будем считать, что у железки default gateway вообще отсутствует. Почему ?
Причин может быть множество, начиная от «так склалось» заканчивая тем что нет полного доступа ни к серверу (который является шлюзом для железки) ни к самой железке
Узнав, что посути ему нужна просто времянка для доступа на оборудование, без реальника на нем, извне, а раз времянка, то natd для этого вполне подойдет.
Реальник сервера: 8.8.8.8 (да да, ну люблю я гугл ))
Внутренний адрес железки: 10.0.2.18
Пробрасываем на железку порт 80 через порт 8080 на сервере (т.к. порт 80 на сервере уже занят apache`ом)
Сервер с FreeBSD 7.2
Внешний интерфейс: em0
Внутренний интерфейс: em1
Для полноты «картины» в статье сначала рассмотрим обычный вариант, а именно схему:
Интернет <==> (<– default GW) [8.8.8.8] Сервер с реальником [10.0.2.2]<===> (<– default GW) [10.0.2.18] Железка с внутренним адресом (default gateway смотрит на сервер)
Так уж повелось, что для natd я никогда не юзал конфиг, а так же не заворачиваю весь трафик с внешнего интерфейса в NAT.
Почему ? Потому что на интерфейсе может быть далеко не один реальный адрес, так зачем туда пхать весь траф ? Фря тем и хороша, что задача одна, а способов её решения множество.
Вот и в этом случае обойдемся без конфига, тем более, напомню, это времянка.
Откройте мануал (man natd), как же без него
-redirect_port proto targetIP:targetPORT[-targetPORT] [aliasIP:]aliasPORT[-aliasPORT] [remoteIP[:remotePORT[-remotePORT]]]
……………..
The natd utility provides a Network Address Translation facility for use with divert(4) sockets under FreeBSD.
……………..
-port | -p port Read from and write to divert(4) port port
По умолчанию natd «слушает» сокет 8668, если он у вас вдруг уже занят, то в примере я буду запускать на 8670. Итак запустим сам natd:
Теперь надо завернуть, только нужный нам трафик, в divert socket, для этого добавим правила ipfw:
ipfw add 700 divert 8670 tcp from any to 8.8.8.8 8080 ipfw add 710 divert 8670 tcp from 10.0.2.18 80 to any
Будьте внимательными с номерами правил, не забывайте о том, что ipfw идет по номерам сверху вниз и ищет более точное совпадение и если выше этих правил будут стоять правила с лучшим совпадением, то трафик до этих правил не дойдет.
Не лишним будет добавить разрешающие правила, например если у вас firewall закрытого типа:
ipfw add 720 allow tcp from any to 10.0.2.18 80 ipfw add 730 allow tcp from 10.0.2.18 80 to any
Ну собственно на этом все.
Теперь можно убедиться что все работает зайдя браузером по линку: http://8.8.8.8:8080 и глянув вtcpdump на внутреннем интерфейсе:
tcpdump -ni em1 host 10.0.2.18
Где должны быть видны запросы извне и ответы от 10.0.2.18.
Если у вас возникнут проблемы, то траблшутинг начните с просмотра tcpdump, добавлением ключа -vк запуску natd, добавив слово log в добавленные правила ipfw.
Эти действия помогут вам разобраться и найти причину проблемы.
Но вернемся к первоначальному вопросу. Теперь схема выглядит так:
Интернет <==> (<– default GW) [8.8.8.8] Сервер с реальником [10.0.2.2/24]<===> [10.0.2.18/24] Железка с внутренним адресом
и вариант описанный выше уже не работает. Почему ?
Ответ на этот вопрос можно сразу узреть в выводе tcpdump`а, это то чего мой знакомый не сделал, потому и не смог понять почему не работает.
Считаем что мы извне обращаемся с адреса 1.1.1.1 и в tcpdump`е будет примерно следущее:
10:20:49.689619 IP 1.1.1.1.52583 > 10.0.2.18.80: S 426822729:426822729(0) win 65535 10:20:49.694417 IP 1.1.1.1.52583 > 10.0.2.18.80: . ack 1 win 260 10:20:49.694750 IP 1.1.1.1.52583 > 10.0.2.18.80: P 1:241(240) ack 1 win 260
Т.е. запросы извне к железке мы видим, но ни одного ответа от неё нет. Почему ? А вы ещё не забыли, что у 10.0.2.18 нет default gateway ? Вот потому и не отвечает, т.к. не знает куда ответить.
Что с этим делать ? Да как обычно Решать проблему.
Для этого нам понадобится ещё один natd. Что он будет делать ? А он будет подменять SRC адрес «вопрощающего» (1.1.1.1) на свой внутренний адрес (10.0.2.2). Таким образом мы решим проблему того что на железке нет default gateway, т.к. отвечать она уже будет в свою подсеть.
Запустим второй процесс natd:
natd -s -m -a 10.0.2.2 -p 8671
Снова завернем трафик, добавим правила ipfw к уже добавленным выше:
ipfw add 705 divert 8671 tcp from any to 10.0.2.18 dst-port 80 ipfw add 706 divert 8671 tcp from 10.0.2.18 80 to 10.0.2.2
Как и в предыдущем случае обращаем внимание на номера правил ipfw.
Снова идем по линку http://8.8.8.8:8080 и смотрим в tcpdump, видим там уже другую картину:
10:43:48.573232 IP 10.0.2.2.53368 > 10.0.2.18.80: . ack 1 win 260 10:43:48.573577 IP 10.0.2.2.53368 > 10.0.2.18.80: P 1:241(240) ack 1 win 260 10:43:48.573967 IP 10.0.2.18.80 > 10.0.2.2.53368: . ack 241 win 32647 10:43:48.606660 IP 10.0.2.18.80 > 10.0.2.2.53368: P 1:92(91) ack 241 win 32647 10:43:48.656346 IP 10.0.2.18.80 > 10.0.2.2.53368: FP 92:457(365) ack 241 win 32647 10:43:48.660740 IP 10.0.2.2.53368 > 10.0.2.18.80: . ack 458 win 258 10:43:50.656411 IP 10.0.2.18.80 > 10.0.2.2.53368: R 1003605212:1003605212(0) win 0
Видим что SRC адрес изменился с 1.1.1.1 на 10.0.2.2, что нам и надо было и сразу же пошли ответы на запросы, что означает что линк открылся и в нем отобразился веб-интерфейс железки с внутренним адресом 10.0.2.18.