суббота, 2 мая 2020 г.

Проброс портов на сервер

Приключилась тут со мной интересная ситуация.
Дано:
  • Домашняя сеть 172.0.0.0/24;
  • Домашний сервер 172.0.0.2, у которого прописан в качестве шлюза по умолчанию адрес маршрутизатора 172.0.0.1 (о нем ниже). К этому серверу осуществляется доступ по ssh;
  • Маршрутизатор mikrotik, через который осуществляется доступ в Интернет. Внутренний адрес маршрутизатора - 172.0.0.1, внешний (WAN) - 77.88.8.8; На маршрутизаторе настроена трансляция сетевых адресов (NAT) типа Masquerading - адреса внутренней сети транслируются во внешний;
  • Зарегистрированное доменное имя homeserver.com, привязанное к 77.88.8.8;
  • Ноутбук, с которого осуществляется подключение к домашнему серверу по доменному имени homeserver.com;
    Задача достаточно простая: иметь возможность подключаться к homeserver.com с ноутбука. Ноутбук при этом может быть как внутри домашней сети, т.е. дома, так и за её пределами - в офисе, в кафе, в дороге или еще где-то.

Для решения задачи доступа из Интернета, я использовал Destination NAT, более известный как "проброс портов". На маршрутизаторе настраивается правило для таблицы NAT в цепочке dst-nat, суть которого можно описать так: если от WAN интерфейса извне пришел пакет на ssh порт 22, то перенаправить этот пакет на домашний сервер на тот же 22ой порт. За счет этого появляется возможность подключаться из Интернета к homeserver.com.

Осталось только решить вопрос доступа из локальной сети. Допустим ноутбук, находясь в локальной сети, будет иметь адрес 172.0.0.3. Это та же самая сеть, в которой находится домашний сервер. К серверу в таком случае без проблем можно обратиться по адресу 172.0.0.2. Но мы хотим обращаться к нему по адресу homeserver.com, а это имя, как мы помним, привязано к адресу 77.88.8.8. Если мы введем команду ssh homeserver.com на ноутбуке, желая подключиться по ssh к серверу, то ответит нам не сервер, а маршрутизатор, т.к. 77.88.8.8 это именно его адрес на порту WAN. Надо как-то сообщить маршрутизатору, чтобы пакеты на 22ой порт, идущие из локальной сети, тоже отправлялись на адрес сервера. Сделать это очень просто: нужно добавить еще одна правило в цепочку dst-nat таблицы NAT, которое в случае поступления пакетов на 22ой порт из интерфейсов LAN сети, будет перенаправлять эти пакеты на сервер. Это правило будет аналогично правилу для WAN, но отличается от него тем, что теперь обрабатываются пакеты, пришедшие из локальной сети. В качестве альтернативы можно не создавать новое правило, а изменить предыдущее, убрав оттуда условие, проверяющее интерфейс, с которого поступил пакет. Тогда все пакеты, пришедшие на маршрутизатор на 22 порт, будут отправлены на сервер.


А теперь интересность: получив такой сетап, подключение к серверу из локальной сети 172.0.0.0/24 работать всё равно не будет. И что еще более интересно, работать подключение начнет, если добавить еще одну локальную сеть, не пересекающуюся с 172.0.0.0/24. Например, добавив на маршрутизатор адрес 10.1.1.1 и переведя ноутбук в сеть 10.1.1.0/24, подключения к серверу будут работать. Как же так получается?

Для этого представим путь, который проходит пакет, запрашивающий соединение по ssh, и идущий из локальной сети 172.0.0.0/24. Ноутбук, имея адрес 172.0.0.3, отправит запрос на подключение к homeserver.com. Перед непосредственно отправкой пакета на запрос соединения произойдет преобразование доменного имени в адрес 77.88.8.8. Именно туда и будет отправлен пакет на 22ой порт. Т.к. адрес 77.88.8.8 находится не в сети 172.0.0.0/24, то ноутбук отправит пакет на шлюз по умолчанию на адрес 172.0.0.1, т.е. на маршрутизатор. Маршрутизатор, получив пакет на 22ой порт, переадресует этот пакет на 22ой порт сервера, т.е. на адрес 172.0.0.2. Сервер, получив запрос на соединение от адреса 172.0.0.3, видит, что запрос пришел от хоста из его собственной сети. И сервер шлет ответ на 172.0.0.3. И вот тут и кроется проблема: 172.0.0.3, наш ноутбук, ожидает ответ не от 172.0.0.2, а от 77.88.8.8. Получив ответ от сервера, ноутбук отбросит его, будто восклицая "дружище 172.0.0.2, я не знаю, кто ты такой, я соединяюсь с 77.88.8.8, а от тебя мне ничего не нужно".

Анимация, демонстрирующая перемещение запроса на соединение от ноутбука к серверу через маршрутизатор.


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

Что же делать в такой ситуации? Добавить еще одно правило трансляции адресов, но теперь уже src-nat. Если пакет приходит на порт 22 из локальной сети и идёт на адрес сервера, то подменить адрес источника на адрес маршрутизатора. В таком случае сервер будет думать, что обращается к нему маршрутизатор, и отвечать будет тоже ему, а маршрутизатор будет возвращать ответ ноутбуку. И всё будет работать.

Комментариев нет:

Отправить комментарий