Обучение
Life-Hack5) SSH VPN Tunnel
TCP port forwarding — это отличная возможность. Но что если нам нужно больше? Доступ по UDP, доступ к множеству портов и хостов, доступ к динамическим портам? Ответ очевиден — VPN. И всемогущий SSH начиная с версии 4.3 и здесь придет нам на помощь.
Забегая вперед скажу: этот функционал SSH хорошо работает если вам нужно временное решение для каких-то административных задач. Для построения постоянных VPN этот вариант далеко не самый подходящий, т. к. он предполагает TCP-over-TCP, что плохо скажется на скорости соединения.
Еще про TCP forwarding
А вот TCP port forwarding с помощью SSH, если его достаточно, во многих случаях выиграет по производительности у VPN, т. к. при TCP port forwarding передаются только данные приложения, а не исходные пакеты целиком вместе с заголовками, см. ссылку: http://blog.backslasher.net/ssh-openvpn-tunneling.html
Настройка SSH-сервера:
PermitTunnel в настройках sshd по-умолчанию выключен, его нужно включить в /etc/ssh/sshd_config:
PermitTunnel yes
или
PermitTunnel point-to-point
ВАЖНО: для поднятия нового сетевого интерфейса туннеля и на ssh-клиенте, и на ssh-сервере необходимы права суперпользователя. Можно долго спорить о том, насколько это небезопасно, но в большинстве случаев на ssh-сервере достаточно настройки:
PermitRootLogin without-password
Таким образом вы запрещаете вход root по паролю, а разрешаете только другими средствами, например, по ключу RSA, что гораздо безопаснее.
Перезапускаем sshd:
sudo service sshd restart # centos
или
/etc/init.d/ssh restart # (debian/ubuntu)
Туннель поднимается при использовании магического ключа -w:
host1# sudo ssh -w 5:5 root@host2
Где 5:5 — номер интерфейса на локальной машине и на удаленной соответственно. Здесь вас может смутить, что ifconfig не выдаст в списке интерфейса «tun5». Это потому что он в состоянии «down», а вот если вызвать «ifconfig -a» или «ifconfig tun5», то интерфейс будет виден:
host1# ifconfig tun5
tun5 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
POINTOPOINT NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
Назначаем интерфейсам IP-адреса и поднимаем их:
host1# sudo ifconfig tun5 192.168.150.101/24 pointopoint 192.168.150.102
host2# sudo ifconfig tun5 192.168.150.102/24 pointopoint 192.168.150.101
Если есть файрвол, не забываем разрешить соединения с интерфейса tun5:
host1# # сохраняем исходные правила файрвола
host1# sudo iptables-save > /tmp/iptables.rules.orig
host1# sudo iptables -I INPUT 1 -i tun5 -j ACCEPT
host2# # сохраняем исходные правила файрвола
host2# sudo iptables-save > /tmp/iptables.rules.orig
host2# sudo iptables -I INPUT 1 -i tun5 -j ACCEPT
На host1 это делать необязательно, здесь это сделано лишь для того чтобы ping работал в обе стороны.
Наслаждаемся пингом:
host1# ping 192.168.150.102
host2# ping 192.168.150.101
Если рассмотреть более ранний пример с PostgreSQL, то теперь схема будет такая:
А команда для подключения к серверу PostgreSQL будет выглядеть так:
host1# psql -h 192.168.150.102 -U postgres
Ну а далее можно делать какой-либо из этих узлов шлюзом, если нужно обеспечить доступ не к одному узлу, а к сети. Например:
host2# # разрешаем IP forwarding
host2# sudo sysctl -w net.ipv4.ip_forward=1
host2# # разрешаем IP forwarding с host1
host2# sudo iptables -I FORWARD 1 -s 192.168.150.101 -j ACCEPT
host2# # разрешаем IP forwarding на host1
host2# sudo iptables -I FORWARD 1 -d 192.168.150.101 -j ACCEPT
host2# # маскируем IP адрес host1
host2# sudo iptables -t nat -A POSTROUTING -s 192.168.150.101 -j MASQUERADE
host1# # Предположим, у host2 есть доступ к сети 192.168.2.x, куда нам нужно попасть с host1
host1# # Прописываем host2 как шлюз в сеть 192.168.2.x
host1# sudo ip route add 192.168.2.0/24 via 192.168.150.2
host1# # Наслаждаемся доступом в сеть с host1
host1# ping 192.168.2.1
После окончания работы не забываем вернуть net.ipv4.ip_forward и файрвол в исходное состояние.
host1# sudo iptables-restore < /tmp/iptables.rules.orig
host2# sudo iptables-restore < /tmp/iptables.rules.orig
Под спойлером более интересный случай с временным расшариванием Интернета
Допустим, нужно настроить сервер в закрытой сети, где доступ в Интернет запрещен, но тем не менее у вас туда есть лазейка — доступ через один ssh-сервер или цепочку ssh-серверов. Предположим, для настройки сервера вам нужен на нем доступ в Интернет. Тогда проще самостоятельно настроить временный доступ в Интернет на требующем настройки сервере, чем просить это сделать обслуживающий персонал.
Допустим, есть доступ по ssh с вашей рабочей машины host1 на сервер host2, с него — на host3, а уже оттуда — на нужный вам host4. Тогда делаем TCP forwarding для ssh (если с host1 вы сразу можете соединиться с host4, пропустите этот шаг):
host1# ssh -L 2222:localhost:2222 host2
host2# ssh -L 2222:host4:22 host3
Далее, соединяемся с host4 и поднимаем интерфейс tun5:
host1# sudo ssh -p 2222 -w 5:5 root@localhost
host1# # или если host4 доступен сразу: sudo ssh -w 5:5 root@host4
host1# sudo ifconfig tun5 192.168.150.101/24 pointopoint 192.168.150.102
host4# sudo ifconfig tun5 192.168.150.102/24 pointopoint 192.168.150.101
Смотрим таблицу маршрутизации на host4, допустим видим следующее:
host4# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.150.0 0.0.0.0 255.255.255.0 U 0 0 0 tun5
192.168.56.0 0.0.0.0 255.255.255.0 U 1 0 0 eth0
0.0.0.0 192.168.56.254 0.0.0.0 UG 0 0 0 eth0
ВАЖНО! Далее нам скорее всего захочется сделать маршрутом по-умолчанию интерфейс tun5 со шлюзом 192.168.150.101, через который будет доступен Интернет. Поэтому на данном этапе важно точно знать, какие маршруты нужно дописать, чтобы заменить маршрут по-умолчанию. Это важно, поскольку довольно часто маршруты на отдельные сети не прописывают отдельно, а просто задают маршрут по-умолчанию (0.0.0.0/0) со шлюзом, через который и идет весь межсетевой трафик. Более того, вполне вероятно что ваше ssh-соединение с сервером также использует исходный шлюз по-умолчанию.
Для простоты в данном примере предположим, что никаких маршрутов кроме 192.168.56.0/24 серверу для нормального функционирования не нужно и что предыдущий ssh-хост host3 имеет IP-адрес из этой же сети.
Запоминаем и записываем куда-нибудь исходную маршрутную таблицу со шлюзом по-умолчанию:
host4# route -n > routes.orig
Настраиваем наш host1 для работы в качестве шлюза в Интернет для host4:
host1# # разрешаем IP forwarding
host1# sudo sysctl -w net.ipv4.ip_forward=1
host1# # сохраняем исходные правила файрвола
host1# sudo iptables-save > /tmp/iptables.rules.orig
host1# # разрешаем IP forwarding с host4
host1# sudo iptables -I FORWARD 1 -s 192.168.150.102 -j ACCEPT
host1# # разрешаем IP forwarding на host4
host1# sudo iptables -I FORWARD 1 -d 192.168.150.102 -j ACCEPT
host1# # маскируем IP адрес host4
host1# sudo iptables -t nat -A POSTROUTING -s 192.168.150.102 -j MASQUERADE
На всякий случай можно прописать серые сети на шлюз из текущего маршрута по-умолчанию
Если не прописаны:
sudo ip route add 192.168.0.0/16 via 192.168.56.254
sudo ip route add 10.0.0.0/8 via 192.168.56.254
sudo ip route add 172.16.0.0/12 via 192.168.56.254
Изменяем маршрут по-умолчанию на host4 (ОСТОРОЖНО, см. предупреждение выше!):
host4# sudo ip route replace default via 192.168.150.101
host4# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.150.0 0.0.0.0 255.255.255.0 U 0 0 0 tun5
192.168.56.0 0.0.0.0 255.255.255.0 U 1 0 0 eth0
0.0.0.0 192.168.150.101 0.0.0.0 UG 0 0 0 tun5
Если весь Интернет нам не нужен, а только конкретные IP-адреса/маски, то можно маршрут по-умолчанию не менять, а дописать только нужные нам адреса через шлюз на tun5.
Проверяем, что есть Интернет:
host4# ping 8.8.8.8
Отлично. Осталось настроить DNS. Есть множество способов это сделать, проще всего отредактировать файл /etc/resolv.conf и добавить туда строчки:
nameserver 8.8.8.8
nameserver 8.8.4.4
После этого Интернет должен быть полностью доступен:
host4# ping ya.ru
После окончания работы не забываем вернуть все в исходное состояние:
host1# # восстанавливаем правила файрвола на host1
host1# sudo iptables-restore < /tmp/iptables.rules.orig
host1# # не забудьте восстановить также значение net.ipv4.ip_forward
host2# # восстановите маршрут по-умолчанию на host4:
host2# sudo ip route replace default via 192.168.56.254
host2# # и уберите добавленные ранее DNS-сервера из /etc/resolv.conf