Подробное описание SSH и примеры использования туннелей Часть 1
Зачем нужен 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.
Теперь Алексу, чтобы попасть на портал своей компании, нужно всего лишь набрать в браузере 127.0.0.1:8080
Как проходят сетевые пакеты внутри SSH-туннеля
Давайте детально разберём, что произошло с TCP пакетом в процессе его прохождения по SSH туннелю:
TCP пакет с адресом источника 127.0.0.1 и адресом и портом назначения 127.0.0.1:8080 попал в сокет 127.0.0.1:8080, открытый процессом ssh;
Процесс ssh получил пакет, в соответствии с правилом трансляции переписал адрес и порт назначения на 192.168.0.2:80 и отправил его внутри SSH сессии удалённой стороне 1.1.1.1;
Процесс 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.