Перенаправление портов в SSH во FreeBSD



by Brian Hatch
Перевод: Сгибнев Михаил


Введение
Обычно SSH используется для регистрации на удаленном сервере с целью проведения технического обслуживания, чтения почты, управления сервисами и тому подобных задач администрирования. SSH также предоставляет некоторые другие сервисы, такие как копирование файлов (используя scp и sftp) и удаленное выполнение команд (используя ssh с указанием команды после имени хоста при выполнении из командной строки).

Всякий раз используя SSH для соединения одной машины с другой, мы создаем безопасный сеанс связи. Вы можете ознакомиться с другими статьями, связанными с настройкой и эксплуатированием SSH: SSH Host Key Protection, SSH User Identities и SSH and ssh-agent.

SSH также имеет замечательную возможность перенаправления портов, что позволяет нам создать безопасный сеанс связи и затем туннелировать через него произвольные подключения TCP. Туннелирование создается очень легко и не требует знаний программирования, что делает его очень привлекательным. В этой статье мы детально рассмотрим перенаправление портов в SSH, поскольку это - очень полезная, но часто неправильно истолковываемая технология. Перенаправление портов может использоваться в несметном количестве мест. Давайте подкрепим это утверждение примером.
Пример локального перенаправления
Предположим, что на вашей машине имеется почтовый клиент и вы получаете письма с почтового сервера по протоколу POP (Post Office Protocol), порт 110. Вы хотите защитить ваше POP соединение с целью препятствовать перехвату пароля или почты (Некоторые POP серверы поддерживают дополнительные методы авторизации, типа S/Key или обмен запросами).

В обычном случае, клиент создает сессию с портом TCP за номером 110, вводится имя пользователя и пароль и скачиваются письма. Давайте просто попробуем использовать telnet или nc:

xahria@desktop$ nc mailserver 110
+OK SuperDuper POP3 mail server (mailserver.my_isp.net) ready.
USER xahria
+OK
PASS twinnies
+OK User successfully logged on.
LIST
+OK 48 1420253
1 1689
2 1359
3 59905
...
47 3476
48 3925
.
QUIT
+OK SuperDuper POP3 mail server signing off.

xahria@desktop$

Мы можем перенаправить эту TCP-сессию внутрь SSH-сессии используя перенаправление портов. Если мы имеем доступ по SSH к машине, на которой запущен требуемый нам сервис (в нашем случае POP, порт 110), то цель близка и приятна. Также, для наших целей мы можем использовать любой SSH-сервер в сети, из которой доступен целевой почтовый сервер.

Так давайте и рассмотрим ситуацию, в которой мы не имеем доступа к почтовому серверу по SSH, но можем соединиться с помощью защищенного протокола с другим сервером той же сети и создать туннель для нашего сеанса POP.

# first, show that nothing's listening on our local machine on port 9999:
xahria@desktop$ nc localhost 9999
Connection refused.

xahria@desktop$ ssh -L 9999:mailserver:110 shellserver
xahria@shellserver's password: ********

xahria@shellserver$ hostname
shellserver

С другого терминала вашей машины соединитесь с портом 9999 своей же машины(localhost).

xahria@desktop$ nc localhost 9999
+OK SuperDuper POP3 mail server (mailserver.my_isp.net) ready.
USER xahria
+OK
PASS twinnies
...

Прежде чем мы соединились с shellserver по SSH ничто не слушало на порту 9999. Именно технологии туннелирования мы обязаны волшебному появлению на порту 9999 нашей локальной машины приглашения почтового сервера. Давайте подробно разберем предложенный пример:
Вы запустили клиент SSH /usr/bin/ssh из командной строки
Клиент регистрируется на удаленной машине используя один из методов авторизации (пароль или ключ)
SSH клиент занимает определенный вами локальный порт 9999 на кольцевом интерфейсе 127.0.0.1 (loopback)
Открытая же сессия с удаленной машиной вполне пригодна для использования, вы можете архивировать файлы или удалить /etc/shadow...
Когда же вы соединяетесь с локальной машиной 127.0.0.1 на порт 9999, то клиентская программа /usr/bin/ssh принимает соединение.
SSH клиент информирует сервер через шифрованный канал о необходимости создать соединение с mailserver, порт 110
Клиент принимает все данные, посылаемые на порт и посылает их серверу через шифрованный туннель, который расшифровывает их и передает их открытым текстом на mailserver, порт 110
При завершении сеанса любой из точек, туннель также прекращает существование.
Отладка перенаправления
Давайте рассмотрим этот механизм, используя опцию отладки:

xahria@desktop$ ssh -v -L 9999:mailserver:110 shellserver
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Rhosts Authentication disabled, originating port will not be trusted.
debug1: Connecting to shellserver [296.62.257.251] port 22.
debug1: Connection established.
debug1: identity file /home/bri/.ssh/identity type 0
debug1: identity file /home/bri/.ssh/id_rsa type 1
debug1: identity file /home/bri/.ssh/id_dsa type 2
...
debug1: Next authentication method: password
xahria@shellserver's password: ********
debug1: Authentication succeeded (password).
debug1: Connections to local port 9999 forwarded to remote address localhost:110
debug1: Local forwarding listening on 127.0.0.1 port 9999.
debug1: channel 0: new [client-session]
debug1: Entering interactive session.
debug1: channel 0: request pty-req
debug1: channel 0: request shell
xahria@shellserver$

Как вы видите, порт 9999 резервируется для открытия туннеля. В настоящее время мы не соединяемя с этим портом, поэтому туннель не открыт. Вы можете использовать escape-последовательность ~# для просмотра соединений. Эта последовательность работает только после символа перевода каретки, поэтому вам придется сделать так:

xahria@shellserver$ (enter)
xahria@shellserver$ (enter)
xahria@shellserver$ (enter)
xahria@shellserver$ ~#
The following connections are open:
#1 client-session (t4 r0 i0/0 o0/0 fd 5/6)
xahria@shellserver$

Видим, что в системе открыта только одна SSH-сессия, используя именно ее, мы вводим текущие команды unix.

Так, а теперь попробуем выполнить команду telnet localhost 9999 и просмотрим состояние соединений:

xahria@shellserver$ (enter)
xahria@shellserver$ ~#
The following connections are open:
#1 client-session (t4 r0 i0/0 o0/0 fd 5/6)
#2 direct-tcpip: listening port 9999 for mailserver port 110,
connect from 127.0.0.1 port 42789 (t4 r1 i0/0
o0/0 fd 8/8)

И что же мы видим? Таки туннель был создан! Мы можем воспользоваться утилитами netstat или lsof, чтобы увидеть соединение с 127.0.0.1, порт 42789 на 127.0.0.1, порт 9999.
Пример удаленного перенаправления
Перенаправление в SSH, как и известная палка, имеет два конца. Выше был приведен пример локального туннелинга, когда ssh-клиент принимает входящие подключения. Удаленное перенаправление и есть второй конец палки: создание туннеля инициализируется на стороне сервера.

Приведем классический пример использования удаленного перенаправления.Вы весь в работе, а на выходные VPN доступ закрывается на техническое обслуживание. Однако, у вас действительно имеется очень важная работа, но вы предпочитаете делать ее дома, вместо того, что бы торчать в офисе в выходные. И по SSH к вашей рабочей машине никак не пробиться, ибо наличествует фаервол. Значит, перед уходом домой, сделаем пару движений. Ваш ~/.ssh/config должен содержать такие строки:

lainee@work$ tail ~/.ssh/config
Host home-with-tunnel
Hostname 204.225.288.29
RemoteForward 2222:localhost:22
User laineeboo


lainee@work$ ssh home-with-tunnel
laineeboo@204.225.228.29's password: ********

laineeboo@home$ ping -i 5 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=0.1 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=255 time=0.2 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=255 time=0.2 ms
...

Мы утановили в файле конфигурации SSH опцию RemoteForward, она то и позволяет осуществить туннелирование (в случае использования командной строки используйте опцию -R). Для того, чтобы удостовериться, что наше соединение не блокируется системой сетевой защиты, выполним команду ping: Вечером на домашней машине удостоверимся в удачном исходе дела:

laineeboo@home$ last -1
laineeboo pts/18 firewall.my_work.com Tue Nov 23 22:28 still logged in

laineeboo@home$ ps -t pts/18
PID TTY TIME CMD
3794 pts/18 00:00:00 ksh
4027 pts/18 00:00:00 ping -i 5 127.0.0.1

В результате, все соединения на порт 2222 вашей домашней машины будут туннелированы назад через корпоративный фаервол на порт 22 вашей машины на работе. Сделаем же сиё нехитрое действо:

laineboo@home$ ssh -p 2222 lainee@localhost
lainee@localhost's password: ********

lainee@work$

Какая радость и бурный восторг!
Port Forwarding Cheat Sheet
Помнить куда что перенаправляется - довольно непростая задача. Данная таблица должна помочь.

Локальное перенаправление Опции командной строки -L local_listen_port:destination_host:destination_port
Строки в файле конфигурации LocalForward
local_listen_port:destination_host:destination_port
local_listen_port is on SSH client loopback interface
destination_host is contacted from SSH server host
Удаленное перенаправление Опции командной строки -R remote_listen_port:destination_host:destination_port
Строки в файле конфигурации RemoteForward
remote_listen_port:destination_host:destination_port
remote_listen_port is on SSH server loopback interface
destination_host is contacted from SSH client host
Перенаправление может запутать, так как мы привыкли представлять сессию как составляющую четырех вещей: IP адрес источника, порт источника и IP адрес назначения, порт назначения.
Безопасность перенаправления портов
Перенаправление занимает порт на ssh клиенте(локальное перенаправление) или на ssh сервере (удаленное перенаправление). По умолчанию, этот порт будет доступен только на кольцевом интерфейсе 127.0.0.1, это означает, что туннель будет доступен только локальному пользователю.

Если Вы не хотите предоставлять доступ к туннелю кому-либо еще, то оставьте все как есть. В противном случае, используйте один из нижеследующих вариантов:
Command line option Configuration file option
LocalForwards -g GatewayPorts yes
(in ~/.ssh/config or /etc/ssh/ssh_config)
RemoteForwards (none available) GatewayPorts yes
(in /etc/sshd_config)
Другая важная вещь, которую Вы должны помнить - то, что поток данных шифруется только на участке между ssh клиентом b ssh сервером. Если определенный вами destination_host - не localhost, то то часть трафика не будет зашифрована. Рассмотрим пример:

desktop$ ssh -L 8080:www.example.com:80 somemachine

Любое соединение с localhost:8080 будет зашифровано на участке от desktop до somemachine, но пойдет открытым текстом от somemachine до www.example.com. Если это соответствует вашей концепции безопасности, то проблемы нет.

Обновлено: 12.03.2015