Linux tunnel over nat

Как получить доступ к серверу Linux за NAT через обратный туннель SSH

Оригинал: How to access a Linux server behind NAT via reverse SSH tunnel
Автор: Dan Nanni
Дата публикации: May 4, 2015
Перевод: Н.Ромоданов
Дата перевода: сентябрь 2015 г.

Вы запустили Linux-сервер дома, который находится за маршрутизатором NAT или защищен брандмауэром. Теперь, когда вы находитесь не дома, вам нужен доступ к домашнему серверу через SSH. Как это настроить? Возможным вариантом будет, безусловно, перенаправление на порт SSH. Однако перенаправление портов может оказаться более сложным в случае, если у вас среда с несколькими вложенными NAT. Кроме того, на выбранное решение могут оказывать влияние различные ограничения, устанавливаемые интернет-провайдерами, например, ограничительные брандмауэры провайдеров, которые блокируют перенаправление портов или NAT с трансляцией адресов, что позволяет пользователям одновременно пользоваться одними и теми же адресами IPv4.

Что такое обратное туннелирование SSH?

Одной из альтернатив перенаправлению портов SSH является обратное туннелирование SSH. Концепция реверсного туннелирования SSH сравнительно проста. Для этого вам понадобится еще один хост (так называемый «хост релея»), находящийся за пределами защищенной домашней сети, к которому вы можете подключиться через SSH из либого места независимо от того, где вы находитесь. Вы можете настроить хост релея на отдельном экземпляре виртуального частного сервера VPS, использующего общедоступный адрес IP. После этого все, что вам потребуется сделать, это настроить постоянный туннель SSH туннель от сервера в вашей домашней сети на хост общественного релея. Благодаря этому вы можете подключаться «в обратном направлении» к домашнему сервера с хоста релея (именно поэтому такой туннель называется «обратным» туннелем). Д тех пор, пока хост релея доступен для вас, вы можете подключиться к домашнему серверу из любого места, где бы вы не находились, причем независимо от того, используется ли в вашей домашней сети ограничивающий NAT или брандмауэр.

Настройка в Linux обратного туннелирования SSH

Давайте посмотрим, каким образом можно создавать и использовать обратный туннель SSH. Предположим следующее. Мы будем настраивать обратный туннель SSH от домашнего сервера homeserver к серверу релея relayserver , так что мы можем получать доступ через SSH к homeserver через relayserver с некоторого другого компьютера, который называется клиентским компьютером clientcomputer . Общедоступным адресом сервера релея relayserver является 1.1.1.1.

На сервере homeserver открываем соединение SSH к серверу релея relayserver следующим образом.

Здесь порт 10022 является портом с любым номером, который вы выберите. Просто убедитесь, что на сервере relayserver этот порт не используется другими программами.

Параметр «-R 10022:localhost:22» определяет ревесный туннель. Он перенаправляет трафик с порта 10022 сервера relayserver на порт 22 на сервере homeserver

Благодаря параметру «-fN» SSH уйдет в фоновый режим сразу, как только вы успешно пройдете проверку подлинности на сервере SSH. Этот параметр полезен в случае, если вы не хотите на удаленном сервере SSH выполнять какие-либо команды, а просто хотите, как в нашем случае, использовать перенаправление портов.

После запуска указанной выше команды вы вернетесь обратно к командной строке сервера homeserver .

Войдите на сервер relayserver и убедитесь, что 127.0.0.1:10022 привязан к sshd . Если это так, то это означает, что обратный туннель настроен правильно.

Теперь с любого другого компьютера (например, с клиента clientcomputer ) войдите на сервер relayserver . Затем получите доступ к серверу homeserver следующим образом.

Читайте также:  Windows search taskbar что это

Единственное, на что следует обратить внимание, это то, что логин/пароль, который вы набираете для localhost , должен быть для сервера homeserver , а не для серевера relayserver , поскольку вы через локальную конечную точку туннеля вошли на сервер homeserver . Так что не вводите логин/пароль для сервера relayserver . После успешного входа в систему, вы будете находиться на сервере homeserver .

Прямое подключение к серверу с NAT через обратный туннель SSH

Хотя описанный выше метод позволяет вам получить доступ к серверу homeserver , который находится за NAT, вам протребуется входить дважды: сначала — на сервер relayserver , а затем — на сервер homeserver . Это связано с тем, что конечная точка туннеля SSH на сервере relayserver привязана к адресу loopback (127.0.0.1).

Но на самом деле, есть способ получить доступ к серверу homeserver , который закрыт NAT, с помощью одного входа на сервер relayserver . Для этого вам нужно сделать, чтобы sshd, расположенный на сервере relayserver , мог перенаправлять порт не только с адреса loopback но и с внешнего хоста. Это достигается путем указания параметра GatewayPorts в sshd , работающего на сервере relayserver .

Откройте файл /etc/ssh/sshd_conf на сервере relayserver и добавьте к нему следующее.

В системе на основе Debian:

В системе на основе Red Hat:

Теперь давайте инициализируем обратный туннель SSH из homeserver следующим образом.

Войдите на сервер relayserver и убедитесь с помощью команды netstat в том, что обратный туннель SSH успешно установлен.

В отличие от предыдущего случая, конечной точкой туннеля теперь является 1.1.1.1:10022 (общедоступный адрес IP сервера relayserver ), а не 127.0.0.1:10022. Это означает, что конечная точка туннеля доступна с внешнего хоста.

Теперь для того, чтобы получить доступ к серверу homeserver , защищенному NAT, введите на любом другом компьютере (например, на клиентском компьютере clientcomputer ), следующую команду.

Хотя в приведенной выше команде 1.1.1.1 является общедоступным адресом IP сервера relayserver , homeserver_user должен быть учетной записью на сервере homeserver . Это связано с тем, что реальный хост, на который вы входите, это homeserver , а не relayserver . Последний просто ретранслирует ваш трафик SSH трафик на сервер homeserver .

Настройка в Linux постоянного обратного туннеля SSH

Теперь, когда вы понимаете, как создать обратный туннель SSH, давайте сделаем туннель «постоянным», так что туннель поднимался и работал постоянно (независимо от временной повышенной загрузки сети, тайм-аута SSH, перезагрузки хоста релея, и т.д.). Поскольку, если туннель поднимается не всегда, то у вас не будет надежного подключения к вашему домашнему серверу.

Для создания постоянного туннеля, я собираюсь использовать инструмент, который называется autossh . Как следует из названия, эта программа позволяет автоматически перезапускать сессию SSH в случае, если она по какой-либо причине пропадает. Так что для того, чтобы сохранять активным обратный туннель SSH, можно воспользоваться этой программой.

В качестве первого шага, давайте установим возможность беспарольного входа через SSH с сервера homeserver на сервер relayserver . Таким образом, программа autossh сможет без вмешательства пользователя перезапускать пропавший обратный туннель SSH.

Затем на сервере homeserver , откуда начинается туннель, установите программу autossh .

На сервере homeserver запустите autossh со следующими аргументами с тем, чтобы создать постоянный туннель SSH, действующий в направлении сервера relayserver .

Параметр «-M 10900» указывает порт на сервере relayserver , для которого будет осуществляться мониторинг и который будет использоваться для обмена тестовыми данными при контроле сессии SSH. Этот порт не должен на сервере relayserver использоваться какой-либо другой программой.

Параметр «-fN» перенаправляется в команду ssh , что позволит туннелю SSH работать в фоновом режиме.

Параметр «-o XXXX» сообщает команде ssh следующее:

  • Использовать ключ аутентификации, а не парольную аутентификацию.
  • Автоматически принимать (неизвестные) ключи хоста SSH
  • Каждые 60 секунд обмениваться сообщениями keep-alive.
  • Отправлять до трех сообщений keep-alive без получения каких-либо ответов.
Читайте также:  Windows 10 рабочие столы hdmi

Остальные параметры обратного туннелирования SSH те же самые, что и в предыдущих примерах.

Если вы хотите, чтобы туннель SSH автоматически поднимался при загрузке системы, вы можете в /etc/rc.local добавить указанную выше команду autossh .

Заключение

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

Источник

Прямой VPN-туннель между двумя компьютерами находящимися за NAT провайдеров с использованием UDP hole punching

Введение

Теория

Я давно задумался о решении по организации канала передачи данных непосредственно от узла к узлу, которые находятся за NATом провайдеров, без использования серверов-посредников. Перебрав некоторое количество статей о различных технологиях типа GRE-туннелей, IPsec, UDP Hole Punching, OpenVPN и прочего, я понял, что узлы должны пробивать соединение навстречу друг другу, то есть посылать пакеты на IP и порт удаленного узла. Поставил несколько опытов по организации GRE-туннеля через NAT, передачу сообщения при помощи NetCat навстречу друг другу, иногда это работало, иногда нет, всё зависело от типа используемого провайдером NAT. Не так давно попалась на глаза интересная статья, в которой было описание организации работы OpenVPN соединения между двумя компьютерами (далее узлами). Я прочитал, проверил и заработало, но при условии, что локальный порт узла и внешний порт будут совпадать, то есть мой провайдер будет использовать Cone NAT. Мне же стало интересно организовать туннель между двумя компьютерами при условии, что оба будут находятся за любым типом (Cone или Symmetric) NAT, то есть локальный порт может не совпадать с внешним портом. Задача уперлась в невозможность определения текущего порта внешнего интерфейса без внешней помощи. Если внешний IP-адрес хоть как-то можно узнать (например: curl ifconfig.me), а вот с определением текущего внешнего порта возникла трудность.

Практика

Для решения этой задачи пришлось использовать VPS (S-синий овал), на нем я поднял скрипт который выполнял роль «Соединителя», что-то типа STUN-сервера: при помощи утилиты TCPDump получал UDP-пакет (далее везде используется UDP протокол) на определенный интерфейс и порт, парсил содержимое пакета, определял IP-адрес/порт источника и отвечал утилитой NetCat возвращая текущие параметры (IP-адрес и порт) соединения, а так же параметры (IP-адрес и порт) удаленного узла к которому нужно подключиться, если эти данные были доступны, иначе ждал пока они не появятся. Все это дело сопоставлялось с идентификатором (ID) соединения, так как несколько соединений могли мешать друг другу, при использовании ID все решалось. Также была проблема того, что узел получал свои же старые данные и пытался по ним подключиться и это решилось с помощью хеша Hostname.

На узлах A и B я использовал скрипт и сгенерированный заранее ключ для авторизации VPN-соединения, работало это так: запускался скрипт, случайно выбирался локальный порт в диапазоне от 20000 до 65000 и с этого порта отправлялся пакет на VPS, который содержал в себе ID соединения и хеш hostname, с помощью утилиты NetCat и тут же запускался TCPDump ожидая ответа. В ответ приходил пакет который содержал в себе текущие данные (IP-адрес/порт) этого узла, а при наличие данных удаленного узла, они тоже приходили и начинался обмен приветствиями между узлами. Если же данных удаленного узла не было, то опрос повторялся с периодичностью 30-45 секунд, для поддержания сессии. В момент когда все необходимые данные (IP-адрес и порт текущего узла и удаленного) были на узлах, начинался обмен пакетами, пакет содержал в себе число m=0 и сгенерированное число от 0 до 254 (это число использовалось для генерации внутреннего IP-адреса VPN-соединения). Удаленный узел получив пакет с m=0 отправлял в ответ m=1 и так далее до 10. При получении пакета m=10 инициировалась посылка пачки пакетов с периодичность в 1 секунду с m=13 и запуск OpenVPN, удаленный узел получив m=13 тоже запускал OpenVPN используя локальный порт, IP-адрес и порт удаленного узла, а также сгенерированный внутренний IP вида 10.X.X.<1,2>/30.

Схема прямого VPN-туннеля и передачи данных между узлами, без участия сервера
Внимание: скрипты написаны и проверены на ОС Ubuntu 18.04 и Debian 9

Читайте также:  Windows не удается запустить это устройство код 19 usb

Запускается автоматически строкой в /etc/rc.local

где 13013 — это порт который нужно слушать, /var/log/connector2.log — лог.

Скрипт на узлах: # cat vpn7.sh

Скопировать скрипт в буфер и вставить в тектовый редактор, например:

Сделать скрипт исполняемым:

Для первого запуска сгенерируем ключ авторизации secret.key, на удаленной стороне генерировать не надо, нужно скопировать его:

Запустим скрипт, например так:

Ключ 517vA0051smB4dE сгенерировал на strongpasswordgenerator.com

Запускается автоматически строкой в /etc/rc.local

где ID-соединения — это любая уникальная фраза для вашего соединения, /var/log/vpn7.log — лог соединения, ipsrv=«45.141.103.45» — IP-адрес узла где запущен connector2.sh (первый скрипт).

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

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

Приемущества:

  • простота в настройке и использовании
  • трафик идет напрямую
  • трафик шифруется и защищен от перехвата
  • нет необходимости пробрасывать порты
  • скрипт запускается автоматически

Недостатки:

  • главный недостаток это использования VPS как источника данных для соединения, но я думаю над этим
  • некоторые провайдеры блокируют трафик между другими провайдерами (замечено у сотовых операторов)
  • при использовании с обоих сторон одного провадера может не сработать, зависит от типа NAT
  • при использовании провадером «жесткого» NAT может не сработать

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

Думаю на фоне дефицита белых IPv4 адресов моё решение будет актуально, ровно до тех пор, пока в каждый дом не придет IPv6.

Обновлено 11.12.2019, добавлено:

  • команда активации защиты от подмены адресов, уязвимость CVE-2019-14899
  • команды завершающие зависшие процессы NC, ускоряется процесс установки соединения
  • внутренние IP-адреса генерируются при первом запуске и их составляющие хранятся в vpn.cfg

Другая моя реализация VPN-туннеля, без использования VPS, с использованием STUN и Яндекс.Диска опубликована тут

Источник

Оцените статью