Поиск по сайту:

Как перенаправить порты через шлюз Linux с помощью Iptables


Введение

NAT, или трансляция сетевых адресов, — это общий термин для искажения пакетов с целью их перенаправления на альтернативный адрес. Обычно это используется, чтобы разрешить трафику выходить за границы сети. Хост, реализующий NAT, обычно имеет доступ к двум или более сетям и настроен на маршрутизацию трафика между ними.

Переадресация портов — это процесс переадресации запросов для определенного порта на другой хост, сеть или порт. Поскольку этот процесс изменяет пункт назначения пакета в пути, он считается типом операции NAT.

В этом руководстве мы покажем, как использовать iptables для переадресации портов на хосты за брандмауэром с использованием методов NAT. Это полезно, если вы настроили частную сеть, но все еще хотите разрешить определенный трафик внутри через назначенный шлюз.

Предпосылки

Чтобы следовать этому руководству, вам понадобятся:

  • Два сервера Ubuntu 20.04 установлены в одном центре обработки данных с включенной частной сетью. На каждой из этих машин вам нужно будет настроить учетную запись пользователя без полномочий root с привилегиями sudo. Вы можете узнать, как это сделать, из нашего руководства по начальной настройке сервера Ubuntu 20.04. Обязательно пропустите шаг 4 этого руководства, так как в этом руководстве мы будем устанавливать и настраивать брандмауэр.
  • На одном из ваших серверов настройте шаблон брандмауэра с помощью iptables, чтобы он мог работать в качестве вашего сервера брандмауэра. Вы можете сделать это, следуя нашему руководству «Как реализовать базовый брандмауэр с Iptables в Ubuntu 20.04». После завершения на вашем сервере брандмауэра должно быть готово следующее:
    • iptables-persistent установлен
    • Набор правил по умолчанию сохранен в /etc/iptables/rules.v4
    • Понимание того, как добавлять или настраивать правила, редактируя файл правил или используя команду iptables

    Сервер, на котором вы настроили шаблон брандмауэра, будет служить брандмауэром и маршрутизатором для вашей частной сети. В демонстрационных целях на втором хосте будет настроен веб-сервер, доступ к которому возможен только через его частный интерфейс. Вы будете настраивать компьютер с брандмауэром для пересылки запросов, полученных через его общедоступный интерфейс, на веб-сервер, к которому он будет обращаться через свой частный интерфейс.

    Сведения о хосте

    Прежде чем начать, вам нужно знать, какие интерфейсы и адреса используются обоими вашими серверами.

    Поиск сведений о вашей сети

    Чтобы получить подробную информацию о ваших собственных системах, начните с поиска сетевых интерфейсов. Вы можете найти интерфейсы на своих машинах и связанные с ними адреса, выполнив следующее:

    1. ip -4 addr show scope global
    Sample Output
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 203.0.113.1/18 brd 45.55.191.255 scope global eth0 valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 10.0.0.1/16 brd 10.132.255.255 scope global eth1 valid_lft forever preferred_lft forever

    Выделенный вывод показывает два интерфейса (eth0 и eth1) и адреса, назначенные каждому (203.0.113.1 и 10.0.0.1 соответственно). Чтобы узнать, какой из этих интерфейсов является вашим публичным интерфейсом, выполните следующую команду:

    1. ip route show | grep default
    Output
    default via 111.111.111.111 dev eth0

    Информация об интерфейсе из этого вывода (eth0 в этом примере) будет интерфейсом, подключенным к вашему шлюзу по умолчанию. Это почти наверняка ваш общедоступный интерфейс.

    Найдите эти значения на каждой из ваших машин и используйте их, чтобы следовать остальной части этого руководства.

    Образцы данных, используемые в этом руководстве

    Чтобы было понятнее, в этом руководстве мы будем использовать следующие пустые назначения адресов и интерфейсов. Пожалуйста, замените свои собственные значения на те, которые перечислены ниже:

    Сетевые данные веб-сервера:

    • Общедоступный IP-адрес: 203.0.113.1
    • Частный IP-адрес: 10.0.0.1
    • Общий интерфейс: eth0
    • Частный интерфейс: eth1

    Сведения о сети брандмауэра:

    • Общедоступный IP-адрес: 203.0.113.2
    • Частный IP-адрес: 10.0.0.2
    • Общий интерфейс: eth0
    • Частный интерфейс: eth1

    Настройка веб-сервера

    Начните подключаться к хосту вашего веб-сервера и войдите в систему под своим пользователем sudo.

    Установка Nginx

    Первый шаг — установить Nginx на хост вашего веб-сервера и заблокировать его, чтобы он прослушивал только свой частный интерфейс. Это гарантирует, что ваш веб-сервер будет доступен только в том случае, если вы правильно настроили переадресацию портов.

    Начните с обновления локального кеша пакетов:

    1. sudo apt update

    Затем используйте apt для загрузки и установки программного обеспечения:

    1. sudo apt install nginx

    Ограничение Nginx частной сетью

    После установки Nginx откройте файл конфигурации блока сервера по умолчанию, чтобы убедиться, что он прослушивает только частный интерфейс. Откройте файл с помощью предпочитаемого вами текстового редактора. Здесь мы будем использовать nano:

    1. sudo nano /etc/nginx/sites-enabled/default

    Внутри найдите директиву listen. Он должен быть указан дважды подряд в верхней части конфигурации:

    server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;
    
        . . .
    }
    

    В первой директиве listen добавьте частный IP-адрес вашего веб-сервера и двоеточие перед 80, чтобы указать Nginx прослушивать только частный интерфейс. В этом руководстве мы демонстрируем только переадресацию IPv4, поэтому вы можете удалить вторую директиву listen, настроенную для IPv6.

    Затем измените директивы listen следующим образом:

    server {
        listen 10.0.0.1:80 default_server;
    
        . . .
    }
    

    Сохраните и закройте файл, когда закончите. Если вы использовали nano, вы можете сделать это, нажав CTRL + X, затем Y и ENTER.

    Теперь проверьте файл на наличие синтаксических ошибок:

    1. sudo nginx -t
    Output
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful

    Если в выводе нет ошибок, перезапустите Nginx, чтобы включить новую конфигурацию:

    1. sudo systemctl restart nginx

    Проверка ограничения сети

    На этом этапе полезно проверить уровень доступа, который у вас есть к вашему веб-серверу.

    С вашего сервера брандмауэра попробуйте получить доступ к вашему веб-серверу из частного интерфейса с помощью следующей команды:

    1. curl --connect-timeout 5 10.0.0.1

    В случае успеха ваш вывод приведет к следующему сообщению:

    Output
    <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> . . .

    Если вы попытаетесь использовать общедоступный интерфейс, вы получите сообщение о невозможности подключения:

    1. curl --connect-timeout 5 203.0.113.1
    Output
    curl: (7) Failed to connect to 203.0.113.1 port 80: Connection refused

    Эти результаты ожидаемы.

    Настройка брандмауэра для переадресации порта 80

    Теперь вы будете работать над реализацией переадресации портов на вашем компьютере с брандмауэром.

    Включение переадресации в ядре

    Первое, что вам нужно сделать, это включить переадресацию трафика на уровне ядра. По умолчанию в большинстве систем переадресация отключена.

    Чтобы включить переадресацию портов только для этого сеанса, выполните следующее:

    1. echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
    Output
    1

    Чтобы включить переадресацию портов на постоянной основе, вам придется отредактировать файл /etc/sysctl.conf. Вы можете сделать это, открыв файл с привилегиями sudo:

    1. sudo nano /etc/sysctl.conf

    Внутри файла найдите и раскомментируйте строку следующего содержания:

    net.ipv4.ip_forward=1
    

    Сохраните и закройте файл, когда закончите.

    Затем примените настройки в этом файле. Сначала выполните следующую команду:

    1. sudo sysctl -p
    Output
    net.ipv4.ip_forward = 1

    Затем выполните ту же команду, но замените флаг -p на --system:

    1. sudo sysctl --system
    Output
    . . . * Applying /usr/lib/sysctl.d/50-pid-max.conf ... kernel.pid_max = 4194304 * Applying /etc/sysctl.d/99-cloudimg-ipv6.conf ... net.ipv6.conf.all.use_tempaddr = 0 net.ipv6.conf.default.use_tempaddr = 0 * Applying /etc/sysctl.d/99-sysctl.conf ... net.ipv4.ip_forward = 1 * Applying /usr/lib/sysctl.d/protect-links.conf ... fs.protected_fifos = 1 fs.protected_hardlinks = 1 fs.protected_regular = 2 fs.protected_symlinks = 1 * Applying /etc/sysctl.conf ... net.ipv4.ip_forward = 1

    Добавление правил переадресации в базовый брандмауэр

    Затем вы настроите свой брандмауэр так, чтобы трафик, поступающий на ваш общедоступный интерфейс (eth0) через порт 80, перенаправлялся на ваш частный интерфейс (eth1).

    В брандмауэре, который вы настроили в предварительном руководстве, цепочка FORWARD по умолчанию настроена на трафик DROP. Вам нужно добавить правила, которые позволят вам перенаправлять соединения на ваш веб-сервер. В целях безопасности вы достаточно жестко заблокируете это, чтобы были разрешены только те соединения, которые вы хотите перенаправить.

    В цепочке FORWARD вы будете принимать новые подключения, предназначенные для порта 80, которые исходят от вашего общедоступного интерфейса и направляются к вашему частному интерфейсу. Новые подключения идентифицируются расширением conntrack и представляются пакетом TCP SYN, как показано ниже:

    1. sudo iptables -A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT

    Это позволит первому пакету, предназначенному для установления соединения, пройти через брандмауэр. Вам также необходимо разрешить любой последующий трафик в обоих направлениях, возникающий в результате этого соединения. Чтобы разрешить трафик ESTABLISHED и RELATED между общедоступным и частным интерфейсами, выполните следующие команды. Сначала для вашего публичного интерфейса:

    1. sudo iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

    Затем для вашего частного интерфейса:

    1. sudo iptables -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

    Дважды проверьте, что ваша политика в цепочке FORWARD установлена на DROP:

    1. sudo iptables -P FORWARD DROP

    На этом этапе вы разрешили определенному трафику между вашими общедоступными и частными интерфейсами проходить через ваш брандмауэр. Однако вы не настроили правила, которые фактически сообщат iptables, как преобразовывать и направлять трафик.

    Правильное добавление правил NAT для прямых пакетов

    Затем вы добавите правила, которые сообщат iptables, как направлять ваш трафик. Вам необходимо выполнить две отдельные операции, чтобы iptables правильно изменил пакеты, чтобы клиенты могли взаимодействовать с веб-сервером.

    Первая операция, называемая DNAT, будет выполняться в цепочке PREROUTING таблицы nat. DNAT — это операция, которая изменяет адрес назначения пакета, чтобы обеспечить его правильную маршрутизацию при прохождении между сетями. Клиенты в общедоступной сети будут подключаться к вашему серверу брандмауэра и не будут знать о топологии вашей частной сети. Поэтому вам необходимо изменить адрес назначения каждого пакета, чтобы, когда он отправляется в вашу частную сеть, он знал, как правильно добраться до вашего веб-сервера.

    Поскольку вы настраиваете только переадресацию портов, а не выполняете NAT для каждого пакета, попадающего на ваш брандмауэр, вам нужно сопоставить порт 80 в своем правиле. Вы будете сопоставлять пакеты, направленные на порт 80, с частным IP-адресом вашего веб-сервера (10.0.0.1 в следующем примере):

    1. sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1

    Этот процесс заботится о половине изображения. Пакет должен быть правильно перенаправлен на ваш веб-сервер. Однако прямо сейчас пакет по-прежнему будет иметь исходный адрес клиента в качестве исходного адреса. Сервер попытается отправить ответ непосредственно на этот адрес, что сделает невозможным установление легитимного TCP-соединения.

    В DigitalOcean пакеты, покидающие дроплет с другим исходным адресом, фактически будут отбрасываться гипервизором, поэтому ваши пакеты на этом этапе даже не попадут на веб-сервер (что будет исправлено путем мгновенного внедрения SNAT). Это мера защиты от спуфинга, применяемая для предотвращения атак, когда большие объемы данных запрашиваются для отправки на компьютер жертвы путем подделки исходного адреса в запросе. Чтобы узнать больше, прочитайте этот ответ в нашем сообществе.

    Чтобы настроить правильную маршрутизацию, вам также необходимо изменить исходный адрес пакета, поскольку он покидает брандмауэр по пути к веб-серверу. Вам необходимо изменить исходный адрес на частный IP-адрес вашего сервера брандмауэра (10.0.0.2 в следующем примере). Затем ответ будет отправлен обратно на брандмауэр, который, как и ожидалось, сможет переслать его обратно клиенту.

    Чтобы включить эту функцию, добавьте правило в цепочку POSTROUTING таблицы nat, которое оценивается непосредственно перед отправкой пакетов в сеть. Вы сопоставите пакеты, предназначенные для вашего веб-сервера, по IP-адресу и порту:

    1. sudo iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 -d 10.0.0.1 -j SNAT --to-source 10.0.0.2

    Как только это правило будет установлено, ваш веб-сервер должен быть доступен, указав в веб-браузере публичный адрес вашего брандмауэра:

    1. curl 203.0.113.2
    Output
    <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> . . .

    Настройка переадресации портов завершена.

    Настройка постоянного набора правил

    Теперь, когда вы настроили переадресацию портов, вы можете сохранить ее в своем постоянном наборе правил.

    Если вы не хотите потерять комментарии из текущего набора правил, используйте команду netfilter-persistent, чтобы использовать службу iptables и сохранить свои правила:

    1. sudo service netfilter-persistent save
    Output
    * Saving netfilter rules... run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save [ OK ]

    Если вы хотите сохранить комментарии в своем файле, откройте его и отредактируйте вручную:

    1. sudo nano /etc/iptables/rules.v4

    Вам потребуется настроить конфигурацию в таблице filter для добавленных правил цепочки FORWARD. Вам также потребуется настроить раздел, который настраивает таблицу nat, чтобы вы могли добавить свои правила PREROUTING и POSTROUTING. Содержимое будет выглядеть следующим образом:

    *filter
    # Allow all outgoing, but drop incoming and forwarding packets by default
    :INPUT DROP [0:0]
    :FORWARD DROP [0:0]
    :OUTPUT ACCEPT [0:0]
    
    # Custom per-protocol chains
    :UDP - [0:0]
    :TCP - [0:0]
    :ICMP - [0:0]
    
    # Acceptable UDP traffic
    
    # Acceptable TCP traffic
    -A TCP -p tcp --dport 22 -j ACCEPT
    
    # Acceptable ICMP traffic
    
    # Boilerplate acceptance policy
    -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    -A INPUT -i lo -j ACCEPT
    
    # Drop invalid packets
    -A INPUT -m conntrack --ctstate INVALID -j DROP
    
    # Pass traffic to protocol-specific chains
    ## Only allow new connections (established and related should already be handled)
    ## For TCP, additionally only allow new SYN packets since that is the only valid
    ## method for establishing a new TCP connection
    -A INPUT -p udp -m conntrack --ctstate NEW -j UDP
    -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
    -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP
    
    # Reject anything that's fallen through to this point
    ## Try to be protocol-specific w/ rejection message
    -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
    -A INPUT -p tcp -j REJECT --reject-with tcp-reset
    -A INPUT -j REJECT --reject-with icmp-proto-unreachable
    
    # Rules to forward port 80 to our web server
    
    # Web server network details:
    
    # * Public IP Address: 203.0.113.1
    # * Private IP Address: 10.0.0.1
    # * Public Interface: eth0
    # * Private Interface: eth1
    # 
    # Firewall network details:
    # 
    # * Public IP Address: 203.0.113.2
    # * Private IP Address: 10.0.0.2
    # * Public Interface: eth0
    # * Private Interface: eth1
    -A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT
    -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    # End of Forward filtering rules
    
    # Commit the changes
    
    COMMIT
    
    *raw
    :PREROUTING ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    COMMIT
    
    *nat
    :PREROUTING ACCEPT [0:0]
    :INPUT ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    :POSTROUTING ACCEPT [0:0]
    
    # Rules to translate requests for port 80 of the public interface
    # so that we can forward correctly to the web server using the
    # private interface.
    
    # Web server network details:
    
    # * Public IP Address: 203.0.113.1
    # * Private IP Address: 10.0.0.1
    # * Public Interface: eth0
    # * Private Interface: eth1
    # 
    # Firewall network details:
    # 
    # * Public IP Address: 203.0.113.2
    # * Private IP Address: 10.0.0.2
    # * Public Interface: eth0
    # * Private Interface: eth1
    -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1
    -A POSTROUTING -d 10.0.0.1 -o eth1 -p tcp --dport 80 -j SNAT --to-source 10.0.0.2
    # End of NAT translations for web server traffic
    COMMIT
    
    *security
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    COMMIT
    
    *mangle
    :PREROUTING ACCEPT [0:0]
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    :POSTROUTING ACCEPT [0:0]
    COMMIT
    

    Сохраните и закройте файл, как только вы добавите содержимое и настроите значения, чтобы они отражали вашу собственную сетевую среду.

    Затем проверьте синтаксис вашего файла правил:

    1. sudo sh -c "iptables-restore -t < /etc/iptables/rules.v4"

    Если ошибок не обнаружено, загрузите набор правил:

    1. sudo service netfilter-persistent reload
    Output
    * Loading netfilter rules... run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables start run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables start [ OK ]

    Теперь проверьте, что ваш веб-сервер по-прежнему доступен через общедоступный IP-адрес вашего брандмауэра:

    1. curl 203.0.113.2

    Это должно работать так же, как и раньше.

    Заключение

    К этому моменту вы уже должны уметь перенаправлять порты на сервере Linux с помощью iptables. Этот процесс включает в себя разрешение переадресации на уровне ядра, настройку доступа, позволяющую пересылать трафик определенного порта между двумя интерфейсами в системе брандмауэра, и настройку правил NAT для правильной маршрутизации пакетов. Это может показаться громоздким процессом, но он также демонстрирует гибкость структуры фильтрации пакетов netfilter и брандмауэра iptables. Это можно использовать для маскировки топологии вашей частной сети, позволяя служебному трафику свободно проходить через ваш брандмауэр шлюза.