Подробное описание SSH и примеры использования туннелей
Содержание
- 1 Подробное описание SSH и примеры использования туннелей
- 1.1 Зачем нужен SSH?
- 1.2 Как работает SSH-туннелирование
- 1.3 Прямой туннель SSH — обеспечиваем доступ к серверу за NAT
- 1.4 Как проходят сетевые пакеты внутри SSH-туннеля
- 1.5 Обратный SSH-туннель — выставить свои ресурсы в интернет
- 1.6 Двойное туннелирование
- 1.7 Динамический туннель — SSH как Socks-прокси
- 1.8 Как использовать SSH в Microsoft Windows?
- 1.9 В каких случаях использовать SSH-туннели?
После публикации статьи об использовании SSH в Windows, от друзей-сетевиков возникла куча вопросов. Понадобилось подробное описание принципов работы протокола SSH. Понадобилось понимание того, как устроены и работают ssh-туннели. Вплоть до того, что и куда ходит, как заворачивается трафик, как проходят пакеты по сети.
Друзья попросили написать об этом статью. Но поскольку подобные описания уже существуют, то не было смысла переписывать это ещё раз. Была найдена вот эта отличная статья иженера компании «Белтел» — Сергея Герасимова. При перепечатке она подверглась незначительной редактуре для удобства восприятия, и дополнена моими комментариями.
Эта статья, практически рассказывает об SSH на пальцах.
На её основе я решил сделать эту страницу, чтобы в случае чего ссылаться на неё. Наверняка это в будущем понадобится, поскольку на сайте планируются ещё публикации об SSH и возможностях его применения для разных практических задач.
SSH — это магия, друзья!
Зачем нужен SSH?
Каждый системный администратор или сетевой инженер хоть раз в своей практике сталкивался с ситуацией, когда нужно получить доступ из публичной сети Интернет к ресурсам своей рабочей сети, скрытой за NAT и защищённой фаерволом.
Конечно, для решения этой задачи можно настроить шифрованный site-to-site туннель или PPTP.
Или же воспользоваться сторонним приложением для организации удалённого доступа, например TeamViewer. Однако есть более простое решение, на реализацию которого уйдет буквально одна минута. К тому же, это решение не требует никакого стороннего программного обеспечения, кроме включённого по умолчанию в 90% Linux/Unix дистрибутивов пакета OpenSSH.
Прочитав эту статью, вы узнаете, как, кроме реализации обычного удаленного доступа, вы сможете организовать socks-proxy, публиковать сервис, связать между собой несколько находящихся за NAT ресурсов через метод двойного туннелирования и многое другое.
Как работает SSH-туннелирование
SSH туннель или SSH Port Forwarding, как его называет man(1) ssh – это опциональный функционал протокола, который работает поверх всем знакомой обычной SSH сессии. SSH туннель позволяет послать TCP пакет с одной стороны SSH соединения на другую его сторону и произвести трансляцию IP заголовка по заранее определенному правилу в процессе передачи.
Понять, как работает SSH туннель очень просто: если представить его в виде point-to-point соединения. Так же как и в PPP, любой пакет, попавший в один конец соединения,
будет передан и получен на другом конце туннеля. Дальше, в зависимости от адреса получателя заданного в IP заголовке, пакет будет либо обработан принимающей стороной туннеля (если пакет предназначается непосредственно ей), либо смаршрутизирован дальше в сеть (если адресатом является другой узел сети).
Основное отличие SSH туннеля от PPP соединения в том, что в SSH туннель можно завернуть только TCP трафик. (Примечание: есть несколько хаков, как можно передать UDP через TCP-сокет внутри SSH туннеля, но это решение выходит за рамки данной статьи).
Второе отличие состоит в том, что в point-to-point
соединении входящий трафик может быть инициирован с любой стороны, тогда как для SSH туннеля необходимо явно задать «точку входа» для трафика. «Точка входа» – это параметр вида <адрес>:<порт>,
указывающий какой сокет открыть для входа в туннель (с локальной или удалённой стороны SSH сессии).
Кроме точки входа дополнительно нужно указать правило вида
<адрес>:<порт>, по которому должен
быть переписан заголовок (точнее, адрес и порт назначения) TCP пакета в процессе передачи. Точка входа может задаваться с любого конца туннеля. За этот параметр отвечают ключи –L (local) и –R (remote). Под local
и remote подразумеваются стороны туннеля с точки зрения стороны-оригинатора, то есть того хоста, который устанавливает SSH сессию.
Пока выглядит немного запутанно, поэтому давайте разберём на конкретном примере.
Прямой туннель SSH — обеспечиваем доступ к серверу за NAT
Алекс работает системным администратором в маленькой
компании Qwerty Cakes, занимающейся производством яблочных пирогов. Вся сеть компании находится в
одном броадкаст домене 192.168.0.0/24. Для доступа в интернет используется программный маршрутизатор на базе Linux, адрес которого 192.168.0.1 со стороны сети компании и
1.1.1.1 со стороны сети Интернет. На маршрутизаторе поднят и работает демон OpenSSD, который доступен по сокету
1.1.1.1:22. Внутри сети на сервере с адресом 192.168.0.2 установлен внутренний корпоративный портал, на котором до завтрашнего утра Алексу нужно сделать изменения через Web интерфейс. Однако Алекс не хочет задерживаться на работе допоздна, он хочет получить доступ к порталу из дома со своего домашнего компьютера с адресом
2.2.2.2.
Алекс приходит домой и после ужина устанавливает следующее соединение с маршрутизатором компании:
Что произошло? Алекс установил SSH сессию между адресами 2.2.2.2 и 1.1.1.1, при этом открыв локальную «точку входа» в туннель 127.0.0.1:8080
на своем домашнем компьютере:
alex@Alex-PC:~$ sudo lsof -nPi | grep 8080
ssh 3153 alex 4u IPv4 9862 0t0 TCP 27.0.0.1:8080 (LISTEN)
Любой TCP пакет, который попадёт в сокет 127.0.0.1:8080 со стороны компьютера Алекса, будет отправлен по point-to-point соединению внутри сессии SSH, при этом адрес
назначения в TCP заголовке будет перезаписан с 127.0.0.1 на 192.168.0.2, а порт с 8080 на 80.
Теперь Алексу, чтобы попасть на портал своей компании, нужно всего лишь набрать в браузере:
Как проходят сетевые пакеты внутри SSH-туннеля
Давайте детально разберём, что произошло с TCP пакетом в процессе его прохождения по SSH туннелю:
1. TCP пакет с адресом источника 127.0.0.1 и адресом и портом назначения 127.0.0.1:8080 попал в сокет 127.0.0.1:8080, открытый процессом ssh;
2. Процесс ssh получил пакет, в соответствии с правилом трансляции переписал адрес и порт назначения на 192.168.0.2:80 и отправил его внутри SSH сессии удалённой
стороне 1.1.1.1;
3. Процесс sshd на маршрутизаторе 1.1.1.1 получил пакет и, просмотрев адрес назначения, отправил его хосту 192.168.0.2, переписав при этом адрес источника с 127.0.0.1
на адрес собственного интерфейса 192.168.0.1, для того чтобы получатель, который ничего не знает про существование SSH туннеля, вернул пакет роутеру, а не отправил в свой же localhost 127.0.0.1.
alex@Alex-PC:~$ ssh -L
127.0.0.1:8080:192.0.0.2:80 alex@1.1.1.1
В данном примере, если бы портал или любой другой ресурс, к которому Алексу нужно получить доступ, находился на самом роутере (например, по адресу 192.168.0.1:80), то команда выглядела бы следующим образом:
alex@Alex-PC:~$ ssh -L 127.0.0.1:8080:192.0.0.1:80 alex@1.1.1.1
Если сервис доступен по адресу localhost (например, локальный SQL сервер), то и к нему
можно получить доступ:
alex@Alex-PC:~$ ssh -L
127.0.0.1:13306:127.0.0.1:3306 alex@1.1.1.1
Конструкции вида -L 127.0.0.1:80:127.0.0.1:80 могут выглядеть, на первый взгляд, довольно странными. Но в них нет ничего сложного, если помнить, что решение о
маршрутизации пакета принимается на удалённой стороне туннеля. Нужно помнить основное правило: вторая пара
<адрес>:<порт> обрабатывается удалённой стороной туннеля.
Поэтому пакет с адресом назначения 127.0.0.1 в правиле трансляции будет обработан второй стороной SSH сессии, и никак иначе.
Как вы уже, наверное, догадались, точку входа в туннель можно создавать не только на loopback интерфейсе. Если туннель нужно сделать доступным не только для локального хоста, но и для других участников сети, то в качестве адреса сокета можно указать реальный адрес интерфейса.
alex@Alex-PC:~$ ssh -L
10.0.0.5:8080:192.0.0.2:80 alex@1.1.1.1
Компьютер Алекса Alex-PC имеет два сетевых интерфейса с адресами 2.2.2.2 и 10.0.0.5. В процессе установления сессии ssh откроет сокет 10.0.0.5:8080 на компьютере Alex-PC. Теперь Алекс может получить доступ к порталу 192.168.0.2:80 со своего ноутбука с адресом 10.0.0.4 и со всей
своей домашней сети 10.0.0.0/24.
Обратный SSH-туннель — выставить свои ресурсы в интернет
Как я уже говорил, точку входа в туннель можно открывать не только со стороны оригинатора ssh сессии, но и с удалённой стороны, то есть с той, к которой мы устанавливаем ssh сессию. Для этого вместо параметра -L используется параметр -R. Для чего это нужно?
Например, для того, чтобы можно было опубликовать локальный сервис для удалённого доступа.
На ноутбуке Алекса запущен Web сервер apache доступный
по адресу 127.0.0.1 с тестовой копией портала компании. Алексу нужно дать доступ к Web серверу своим
коллегам для проведения тестирования интерфейса. Вообще, для подобных целей Алексу неплохо было бы реализовать более надёжную тестовую песочницу. Но так как наш Алекс не более чем виртуальный персонаж этой статьи, он для
демонстрации работы SSH туннеля устанавливает
сессию между своим ноутбуком и маршрутизатором Linux. А с помощью параметра -R открывает порт 8080 на
внутреннем интерфейсе маршрутизатора с адресом 192.168.0.1, который ссылается на сокет 127.0.0.1:80 его тестового Web сервера.
Как видите, на маршрутизаторе процесс sshd открыл локальный сокет 8080
alex@Router:~$
sudo lsof -nPi | grep 8080
sshd
17233 alex 9u IPv4
95930 0t0 TCP 192.168.0.1:8080 (LISTEN)
Давайте посмотрим, что произойдёт с TCP пакетом, отправленным с компьютера 192.168.0.200 в сторону тестового портала, опубликованного на 192.168.0.1:8080:
1. TCP пакет с адресом источника 192.168.0.200 и адресом и портом назначения 192.168.0.1:8080 попадёт в сокет 192.168.0.1:8080, открытый процессом sshd;
2. Процесс sshd, получив пакет, в соответствии с правилом трансляции перепишет адрес и порт назначения с 192.168.0.1:8080 на 127.0.0.1:80 и отправит его внутри SSH сессии стороне-оригинатору 2.2.2.2;
3. Процесс ssh на ноутбуке Алекса, получив пакет и просмотрев адрес его назначения, перепишет адрес отправителя с 192.168.0.200 на адрес своего loopback, и отправит его в локальный сокет 127.0.0.1:80, открытый процессом apache.
Как видите, правила трансляции очень простые. Хост, который открывает сокет для туннеля, занимается трансляцией адреса и порта назначения согласно правилу трансляции. Хост с противоположной стороны туннеля производит подмену адреса и порта источника согласно своей таблице маршрутизации. Таблица маршрутизации необходима, во-первых, для того чтобы отправить пакет в нужную сторону, а, во вторых, для того чтобы произвести
подмену адреса источника на адрес интерфейса, с которого будет отправлен пакет.
Одно важное замечание, которое я оставил на конец статьи.
Если при открытии точки входа в туннель используется localhost вместо адреса реального интерфейса, то его можно опустить, сократив, таким образом, команду с
alex@Alex-PC:~$ ssh -L 127.0.0.1:8080:192.0.0.1:80 alex@1.1.1.1
до
alex@Alex-PC:~ssh -L
8080:192.0.0.1:80 alex@1.1.1.1
Эта важная особенность синтаксиса пригодится нам в следующем примере.
Двойное туннелирование
Давайте посмотрим на чуть более сложный пример. Пользователю SQL-Tester, находящемуся за NAT, нужно получить доступ к базе данных на SQL сервере, который тоже находится за NAT. SQL-Tester не может установить
соединение напрямую к серверу, так как в NAT серверной сети нет соответствующих трансляций. Однако от обоих хостов можно установить SSH сессию с промежуточным
сервером 3.3.3.3.
С SQL сервера устанавливаем SSH соединение с сервером 3.3.3.3 и открываем на loopback интерфейсе сервера
3.3.3.3 порт 13306, ссылающийся на локальный сервис SQL, запущенный на локальном сокете 127.0.0.1:3306 SQL сервера:
dbuser@SQL-server:~$ ssh -R 13306:127.0.0.1:3306
user1@3.3.3.3
Теперь с клиентского хоста SQL-Tester устанавливаем соединение с 3.3.3.3 и открываем порт 3306 на loopback интерфейсе клиента, который, в свою очередь, ссылается на 127.0.0.1:13306 на сервере
3.3.3.3, который… ссылается на 127.0.0.1:3306 на SQL сервере. Всё просто J
tester@SQL-Tester:~$ ssh -L
3306:127.0.0.1:13306 user2@3.3.3.3
Динамический туннель — SSH как Socks-прокси
В отличие от туннелей с явным указанием правил трансляции, динамический туннель работает совсем по другому принципу. Вместо указания однозначного сопоставления вида адрес:порт для каждого адреса и порта назначения, вы
открываете сокет на локальной стороне SSH сессии, который превращает ваш хост в прокси-сервер, работающий по протоколу SOCKS4/SOCKS5. Давайте разберем
пример:
Создаём сокет динамического туннеля 127.0.0.1:5555 на хосте client внутри сессии SSH к серверу 2.2.2.2
user@client:~$ ssh -D 5555 user@2.2.2.2
Проверяем, что порт открыт
user@client:~$ sudo lsof -nPi | grep 5555
ssh
7284 user 7u
IPv4 0x74fcb9e03a5ef5b1 0t0 TCP 127.0.0.1:5555 (LISTEN)
И прописываем прокси в настройках браузера или любого
другого программного обеспечения, поддерживающего SOCKS прокси.
Теперь весь трафик браузера будет идти через SOCKS прокси внутри шифрованного соединения SSH
между хостами 1.1.1.1 и 2.2.2.2.
Как использовать SSH в Microsoft Windows?
Прочитав статью, вы возможно, решите, что все преимущества SSH туннелей доступны только
пользователям Unix-like систем. Однако это не так. Практически все терминальные клиенты для Windows работающие по протоколу SSH имеют поддержку туннелирования.
С некоторых пор, имеется возможность использовать Windows не только в качестве клиента SSH. Есть возможность установить SSH-сервер на Windows.
В каких случаях использовать SSH-туннели?
Конечно же, для создания постоянных туннелей на боевых серверах нужно использовать специальное программное обеспечение. Но для быстрого решения задачи по пробросу портов, траблшутинга, получения быстрого удалённого доступа да и вообще решения конкретной задачи “здесь и сейчас” зачастую хорошим подспорьем будет использование SSH туннелей.
С их помощью можно выстраивать целые сети, туннели внутри туннелей, комбинировать типы туннелей. Это может позволять быстро получать доступ туда, куда, казалось бы попасть невозможно.
Сомневаюсь что происходит трансляция адресов. Думаю, что все работает сильно проще. А именно ssh устанавливает tcp соединение между двумя компами по каким-то своим портам, затем оно становится сервером в отношении одного из портов (в который надо писать), когда кто-то пишет в этот порт, ssh эту информацию отправляет по tcp соединению на другой комп, и ssh на этом другом компе открывает tcp соединение в с исходящим адресом и пишет в него полученную инфу.
для трансляции нужно добавлять правила трансляции, менять статус ip forwarding и пр. ssh этого не делает (достаточно посмотреть правила iptables во время работы ssh туннеля)
Комментарий на отдельной страницеЧто имеете в виду под «правилами iptables во время работы туннеля»? Для их работы никакие правила не нужны, оно независимо от iptables работает. Да, это не трансляция, это туннелирование. По тексту статьи автор конечно ошибался, называя это трансляцией. Но принципы работы SSH туннелей он описал и проиллюстрировал очень подробно и доступно. Я хотел дать читателям именно это. Поэтому я и поместил статью здесь.
Комментарий на отдельной страницеПро правила — трансляцию без инструмента типа iptables не сделать. Т.е. смотря на определенные этими инструментами правила можно убедиться, что трансляции нет. Действительно статься отличная, но меня она отчасти сбила с толку, т.к. пару недель назад я использовал ее, чтобы разобраться с тем как устроены vpn и пр, и ее содержимое в части трансляции не билось с другими источниками. что ввело меня в легкий ступор на определенном этапе.
Комментарий на отдельной страницеДа, трансляцию и туннелирование нужно различать, тут не поспоришь. SSH-туннели они по устройству ближе к VPN, протоколу PPTP, о чем и говорится в статье.
Комментарий на отдельной страницеВопрос. Я пытался сделать туннель, как описано в статье. Он работает. Но на определенном этапе ssh соединение разрывается и туннель перестает работать. Думаю настройками ssh клиента или демона это можно побороть. Сколько на практике (по времени) может держаться такой туннель?
Комментарий на отдельной страницеВ вашем случае время жизни туннеля зависит от сети, от провайдера, скорей всего. На практике, туннели между разными хостами, тем более через интернет не живут долго. Это связано с настройками сети, полагаю. Что касается самого SSH — то в нем и по умолчанию все выставлено хорошо. Допустим, у меня есть туннель, который завернут внутри самого хоста, через локальную петлю. Так он живет месяцами. Вот, сейчас посмотрел, работает с 31 мая этого года:
Комментарий на отдельной страницеА до мая он тоже жил полгода.
Можете убедиться в этом самостоятельно, завернув у себя какой нибудь туннель внутри хоста.
Так что на практике — только выдумывать костыли, которые будут переподнимать туннель при разрыве. Таких тоже в свое время понаписал достаточно, но иначе как костылями это не назовешь :)
Вот наткнулся на autossh. Тестирую. Команда сама отслеживает и поднимает ssh. Вот здесь хорошо описано http://xmodulo.com/access-linux-server-behind-nat-reverse-ssh-tunnel.html
Комментарий на отдельной страницеИнтересная утилита, спасибо. Кажется, слышал о ней раньше тоже. Но у меня например, туннель много месяцев живет на однм из VPS, не падает вообще.
Комментарий на отдельной страницеОшибок в статье- ужас какой-то! Начиная от простых опечаток, заканчивая матчастью. А вот » TCP пакет с адресом источника 192.168.0.200 и адресом и портом назначения…» — ЭТО ВООБЩЕ ЖЕСТЬ! TCP протокол понятия не имеет ни про какой адрес источника и адрес назначения… равно как и не имеет понятия и сам транспорт SSH туннеля, передающий только TCP пакеты. IP заголовок генерируется на «выходе» туннеля, исходя из ЧЕТКИХ правил указания IP адресов, которые вбиваются при создании туннеля. Статья скорее запутает чем научит.
Комментарий на отдельной страницеДезинформация повсюду))))))
Комментарий на отдельной странице» …при этом адрес назначения в TCP заголовке будет перезаписан с 127.0.0.1 на 192.168.0.2″
Прекрасная статья. Автору спасибо за компиляцию. Для части «обратный туннель»: а как быть, если подключение к ноутбуку Алекса должно происходить не из локальной сети с адреса 192.168.0.200, а из внешней, причем вместо маршрутизатора сервер с белым IP? То есть схема такая: обратный туннель(ноутбук Алекса<—роутер<—провайдер<—внешний сервер)<—компьютер заказчика.
Комментарий на отдельной страницеЗа старания — 5 , а вот за безграмотность в протоколах — жесткий кол. Все как написал Bag71.
Комментарий на отдельной страницеСпасибо. Увы, я не сетевик, поэтому такие штуки я не отследил. Мне понравилось что тут довольно всё подробно именно в практическом плане объяснено, что как и зачем стыкуется. Вероятно статью эту писал тоже не сетевик.
Комментарий на отдельной страницеИмею такие настройки для подключения к удалённому SSH-серверу (не мой, общедоступный)
Server Host : ssh-30-3.sshstores.net
Server Host Cloudflare : ssh-30-3.cdnws.me
Username : бал-бла-бла
Password : 1234567890
SSL/TLS Port : 443,445
Expired : 2022-09-04
Squid Port: 80,3128
Dropbear: 442,143
Port SSH WS Alt: 8880
UDPGW Port : 7313,7300,7390,7385,7376
Каким образом и куда записать эти данные для настройки роутера на Openwrt для поднятия туннеля? В Windows 11 как всё это счастье использовать? Нет же никаких инструкций совершенно! Знаний по этой теме у меня чуть больше, чем «0»…
Комментарий на отдельной странице