Добавляем правило в таблицу nat, благодаря которому внешние запросы будут попадать на нужный сервер в локальной сети:
Если входящий пакет использует порт нужной службы, адрес назначения подменяется на локальный адрес сервера и пакет передаётся в локальную сеть.
Первые проблемы начнутся, когда компьютер из локальной сети обратится к службе по внешнему адресу. Допустим, службой является веб-сервер. Вот что произойдёт:
Чтобы избежать подобной ситуации, добавляем в таблицу nat новое правило:
То есть, если пакет предназначен серверу, то обратный адрес клиента (не важно внешнего или внутреннего) заменяется на внутренний адрес шлюза. Это гарантирует, что ответ от сервера в любом случае придёт обратно на шлюз.
Но, пока что, для нормальной работы этого недостаточно. Если в качестве клиента выступает сам шлюз, то в соответствии с этими правилами, запрос серверу вернётся на сам шлюз. Исправляем это:
Но и это ещё не всё. Пакеты из внешнего мира будут проходить цепочку FORWARD таблицы filter, поэтому в неё надо добавить разрешающее правило. Оно может выглядеть, например, так:
Вот теперь - всё. Получившийся результат можно оформить в виде скрипта, чтобы не делать каждый раз всё вручную.
Кстати.
Если подключение к сети интернет осуществляется, например, через pppoe, то есть интерфейс ppp0, он и должен быть вписан в правила iptables. Потому что в этом случае интерфейс eth0 будет использоваться только для установки связи с pppoe-сервером.
script.sh
#!/bin/bash
EXT_IP="xxx.xxx.xxx.xxx" # Он всё равно чаще всего один и тот же.
INT_IP="xxx.xxx.xxx.xxx" # См. выше.
EXT_IF=eth0 # Внешний и внутренний интерфейсы.
INT_IF=eth1 # Для шлюза они вряд ли изменятся, поэтому можно прописать вручную.
LAN_IP=$1 # Локальный адрес сервера передаём скрипту первым параметром,
SRV_PORT=$2 # а тип сервера, в смысле какой порт (или набор портов) открывать - вторым
# Здесь желательно сделать проверку ввода данных, потому что операции достаточно серьёзные.
iptables -t nat -A PREROUTING --dst $EXT_IP -p tcp --dport $SRV_PORT -j DNAT --to-destination $LAN_IP
iptables -t nat -A POSTROUTING --dst $LAN_IP -p tcp --dport $SRV_PORT -j SNAT --to-source $INT_IP
iptables -t nat -A OUTPUT --dst $EXT_IP -p tcp --dport $SRV_PORT -j DNAT --to-destination $LAN_IP
iptables -I FORWARD 1 -i $EXT_IF -o $INT_IF -d $LAN_IP -p tcp -m tcp --dport $SRV_PORT -j ACCEPT
Теперь, чтобы обеспечить доступ извне к локальному FTP по адресу 192.168.0.56, достаточно набрать в консоли от имени суперпользователя:
Экономия времени и сил налицо.
Перенаправление портов нужно в том случае, если мы хотим «замаскировать» внутреннюю службу, обеспечив к ней доступ извне не по стандартному, а совсем по другому порту. Конечно, можно заставить сам веб-сервер слушать нестандартный порт, но если он используется рядовыми сотрудниками внутри локальной сети, то мы элементарно столкнёмся с человеческим фактором. Сотрудникам будет очень тяжело объяснить, что теперь для доступа к корпоративному сайту надо после его имени вводить набор цифр через двоеточие.
Именно из-за человеческого фактора перенаправление портов используется, в основном, специалистами, для удалённого администрирования.
Пусть $FAKE_PORT - обманный порт на внешнем интерфейсе шлюза, подключившись к которому мы должны попасть на адрес $LAN_IP и порт $SRV_PORT.
Набор правил для iptables будет отличаться несущественно, поэтому приведу сразу пример итогового скрипта для ленивых.
#!/bin/bash
EXT_IP="xxx.xxx.xxx.xxx" # Он всё равно чаще всего один и тот же.
INT_IP="xxx.xxx.xxx.xxx" # См. выше.
EXT_IF=eth0 # Внешний и внутренний интерфейсы.
INT_IF=eth1 # Для шлюза они вряд ли изменятся, поэтому можно прописать вручную.
FAKE_PORT=$1 # Вначале передаём скрипту "неправильный" порт на внешнем интерфейсе,
LAN_IP=$2 # затем - локальный адрес сервера
SRV_PORT=$3 # и в конце - реальный порт для подключения к серверу
# Здесь опять надо сделать проверку ввода данных, потому что операции всё ещё серьёзные.
iptables -t nat -A PREROUTING -d $EXT_IP -p tcp -m tcp --dport $FAKE_PORT -j DNAT --to-destination $LAN_IP:$SRV_PORT
iptables -t nat -A POSTROUTING -d $LAN_IP -p tcp -m tcp --dport $SRV_PORT -j SNAT --to-source $INT_IP
iptables -t nat -A OUTPUT -d $EXT_IP -p tcp -m tcp --dport $SRV_PORT -j DNAT --to-destination $LAN_IP
iptables -I FORWARD 1 -i $EXT_IF -o $INT_IF -d $LAN_IP -p tcp -m tcp --dport $SRV_PORT -j ACCEPT
По сути изменилась только первая строчка, поскольку только она отвечает за первичную обработку входящих пакетов. Дальше всё следует по стандартной процедуре таблиц и цепочек правил.
Изменения в остальных правилах сделаны для наглядности и их сути не меняют.