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



От редактора AnswIT:

После публикации  статьи об использовании 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.
Gerasimov_SSH.jpg

Алекс приходит домой и после ужина устанавливает следующее соединение   с маршрутизатором компании:

Gerasimov_SSH1.jpg

Что произошло? Алекс установил 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.

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

Gerasimov_SSH2.jpg

Как проходят сетевые пакеты внутри 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

Gerasimov_SSH3.jpg

В данном примере, если бы портал или любой другой ресурс, к   которому Алексу нужно получить доступ, находился на самом роутере (например, по адресу 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
Gerasimov_SSH4.jpg

Если сервис доступен по адресу localhost (например, локальный SQL сервер), то и к нему
можно получить доступ:

alex@Alex-PC:~$ ssh -L
127.0.0.1:13306:127.0.0.1:3306 alex@1.1.1.1

Gerasimov_SSH5.jpg

Конструкции вида -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

Gerasimov_SSH6.jpg

Компьютер Алекса 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 сервера.

Gerasimov_SSH7.jpg

Как видите, на маршрутизаторе процесс 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.

Gerasimov_SSH8.jpg

Как видите, правила трансляции очень простые. Хост, который   открывает сокет для туннеля, занимается трансляцией адреса и порта назначения   согласно правилу трансляции.  Хост с   противоположной стороны туннеля производит подмену адреса и порта источника   согласно своей таблице маршрутизации. Таблица маршрутизации необходима, во-первых,   для того чтобы отправить пакет в нужную сторону, а, во вторых, для того чтобы произвести
подмену адреса источника на адрес интерфейса, с которого будет отправлен пакет.
Одно важное замечание, которое я оставил на конец статьи.
Если при открытии точки входа в туннель используется 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.

Gerasimov_SSH9.jpg

С 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
Gerasimov_SSH10.jpg

Проверяем, что порт открыт

user@client:~$ sudo lsof -nPi | grep 5555

ssh
7284       user    7u
IPv4 0x74fcb9e03a5ef5b1      0t0    TCP 127.0.0.1:5555 (LISTEN)

И прописываем прокси в настройках браузера или любого
другого программного обеспечения, поддерживающего SOCKS прокси.
Gerasimov_SSH11.jpg

Теперь весь трафик браузера будет идти через SOCKS прокси внутри   шифрованного соединения SSH
между хостами 1.1.1.1 и 2.2.2.2.

Как использовать SSH в Microsoft Windows?

 

Прочитав статью, вы возможно, решите, что все преимущества SSH туннелей доступны только
пользователям Unix-like систем. Однако это не так. Практически все терминальные клиенты для Windows работающие по протоколу SSH имеют поддержку туннелирования.

Gerasimov_SSH12.jpg

putty

Gerasimov_SSH13.jpg

SecureCRT

 С некоторых пор, имеется возможность использовать Windows не только в качестве клиента SSH. Есть возможность установить SSH-сервер на Windows.

В каких случаях использовать SSH-туннели?

Конечно же, для создания постоянных туннелей на боевых серверах   нужно использовать специальное программное обеспечение. Но для быстрого решения   задачи по пробросу портов, траблшутинга, получения быстрого удалённого доступа да и вообще решения конкретной задачи “здесь и сейчас” зачастую хорошим   подспорьем будет использование SSH туннелей.

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

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

  1. leonid :

    Ответить

    • drmotor :

  2. leonid :

    Ответить

    • drmotor :

  3. leonid :

    Ответить

    • drmotor :

Сохраните для друзей или чтобы прочесть в другой раз:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>