Вопрос или проблема
Рассмотрим следующую ситуацию:
У меня дома есть роутер (который подключен к интернету), сервер (S) и моя основная машина (M). S доступен из интернета (у него статический IP), и он работает 24/7, в то время как M — нет.
Иногда я хочу сделать какое-то приложение (которое слушает на каком-то порте на M, например, 8888) доступным из внешнего интернета.
Для этого я хотел настроить переадресацию какого-то порта на S (2222) на порт M 8888, чтобы любой, кто обращается к S:2222, чувствовал, что он обращается к M:8888.
Я пытался использовать ssh для переадресации портов, мой лучший способ был следующим:
ssh -L 2222:M:8888 -N M
Но это позволяет мне обращаться к порту 2222 только с сервера, а не с других машин.
Есть ли какой-то способ сделать это правильно? Предпочтительно, я бы хотел, чтобы это была простая команда, которую я бы мог начать и остановить с помощью ^C, когда мне больше не нужна эта переадресация.
Да, это называется GatewayPorts
в SSH. Цитата из ssh_config(5)
:
GatewayPorts
Определяет, разрешено ли удалённым хостам подключаться к локальным
перенаправленным портам. По умолчанию ssh(1) связывает локальные
перенаправления портов с адресом обратной связи. Это предотвращает
подключения других удалённых хостов к перенаправленным портам.
GatewayPorts можно использовать для указания, что ssh должен
связывать локальные перенаправления портов с подстановочным
адресом, таким образом разрешая удалённым хостам подключаться
к перенаправленным портам. Аргумент должен быть "yes" или "no".
По умолчанию — "no".
И вы можете использовать localhost
вместо M
в переадресации, так как вы перенаправляете на ту же машину, к которой вы подключаетесь по SSH — если я правильно понимаю ваш вопрос.
Итак, команда будет такая:
ssh -L 2222:localhost:8888 -N -o GatewayPorts=yes имя-хоста-M
и будет выглядеть так в netstat -nltp
:
tcp 0 0 0.0.0.0:2222 0.0.0.0:* LISTEN 5113/ssh
Теперь любой, имеющий доступ к этой машине на порту 2222 TCP, на самом деле будет общаться с localhost:8888, как это видно на машине M. Обратите внимание, что это не то же самое, что и простая переадресация на порт 8888 M.
Есть другой способ. Вы можете настроить переадресацию порта с S:2222 на W:8888 с помощью iptables. Одна команда:
iptables -t nat -A PREROUTING -p tcp --dport 2222 \
-j DNAT --to-destination 1.2.3.4:8888
где 1.2.3.4 — это IP-адрес M. Это называется NAT (Network Address Translation).
Другие альтернативы: netcat
(традиционный) или socat
На сервере (S):
socat tcp-listen:2222,reuseaddr,fork tcp:M:8888
или
nc -l -p 2222 -c 'nc M 8888'
Подробности смотрите в:
Простой способ создания туннеля от одного локального порта к другому?
Краткий ответ
Оригинальная команда в основном правильная, но не указывает адрес для прослушивания, что приводит к прослушиванию процесса на 127.0.0.1
по умолчанию.
Измените свою команду с ssh -L 2222:M:8888 -N M
на ssh -L S:2222:M:8888 -N M
, и она должна сработать.
Подробный ответ
Проблема, с которой вы столкнулись, вызвана использованием короткой нотации в -L
– “localPort:remoteHost:remotePort”.
Если вы используете её, ssh
слушает на 127.0.0.1
.
Например:
ssh -L 2222:M:8888 -N M
Приведёт к чему-то вроде этого (обратите внимание на адрес, на котором идёт прослушивание):
sudo netstat -nlp | grep 2222
tcp 0 0 127.0.0.1:2222 0.0.0.0:* LISTEN 16208/ssh
Если вы используете полную нотацию (“localAddress:localPort:remoteHost:remotePort”):
ssh -L external-address-of-S:2222:M:8888 -N M
Приведёт к чему-то вроде
sudo netstat -nlp | grep 2222
tcp 0 0 external-address-of-S:2222 0.0.0.0:* LISTEN 16208/ssh
P.S. GatewayPorts
— это более универсальное решение, но оно ведёт себя иначе, если у вашего сервера больше одного IP-адреса. Это решение позволяет выбрать IP, на котором будет идти прослушивание (и позволяет перенаправлять один и тот же порт на разных IP на разные адреса назначения), в то время как GatewayPorts
слушает на всех и перенаправляет их на одно и то же место назначения. Какое лучше подходит для вас, зависит от ваших требований — но оба будут работать для автора вопроса.
P.P.S. Я понимаю, что это очень старый вопрос, но он всё ещё очень актуален сегодня (возможно, даже больше из-за широкого использования облаков) и, как я считаю, ему не хватает простого ответа, который мог бы помочь людям, сталкивающимся с подобной проблемой.
Переадресация порта без демона или постоянного туннеля
У меня возникла аналогичная проблема. В моей ситуации я переношу службу slapd (сервер LDAP). Все клиенты настроены на доступ к серверу LDAP с использованием CNAME (ldap-server.example.com). Правильным способом (и он будет окончательным состоянием) будет исправить/обновить CNAME. Но CNAME управляется другими людьми, и я хотел бы перенаправить входящие ldaps-соединения с старого сервера на новый сервер сейчас.
Я просто выполняю эти три команды на старом сервере, когда сеть в сети активирована:
sysctl net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -p tcp -d 10.0.0.62 --dport 636 -j DNAT --to-destination 10.0.0.35:636
iptables -t nat -A POSTROUTING -o enp3s0 -j MASQUERADE
где 10.0.0.62
— это IP старого сервера, 10.0.0.35
— это IP нового сервера, 636
— это порт, который я перенаправляю (ldaps), и enp3s0
— это (единственный) сетевой интерфейс на старом сервере.
По умолчанию пересылка TCP отключена, отсюда первая строка. Без неё никакие пакеты не перенаправляются вообще.
Вторая строка перенаправляет входящие TCP (ldaps) пакеты на новый сервер.
Третья строка важна: без неё перенаправленные пакеты всё же имеют IP-источник клиента LDAP, соответственно, ответы нового сервера отправляются напрямую клиенту (который не понимает, почему он получает пакеты от машины, к которой он никогда не обращался). С третьей строкой IP-источник перенаправленных пакетов изменяется (на локальный IP, IP старого сервера), и ядро отслеживает это изменение. Таким образом, ответы отправляются на эту (старую серверную) машину, а также перенаправляются клиенту LDAP, корректируя IP-источник/назначение (благодаря маскарадингу ядра).
Таким образом, я получил перенаправление порта на уровне ядра, без необходимости процессов (nc, ssh и т.п.) или демонов (sshd и т.п.)
Ответ или решение
Для решения задачи перенаправления порта с одного устройства на другое в вашей домашней сети можно воспользоваться несколькими методами. Детально рассмотрим каждый вариант.
1. SSH-перенаправление с помощью GatewayPorts
Когда речь идет о перенаправлении портов через SSH, основной проблемой является то, что по умолчанию SSH связывает локальные перенаправления только с loopback-адресом (127.0.0.1
). Чтобы сделать порт доступным извне, необходимо изменить эту настройку. Параметр GatewayPorts
позволяет разрешить подключение удаленных хостов к локально перенаправленным портам.
Команда SSH:
ssh -L 2222:localhost:8888 -N -o GatewayPorts=yes hostname-of-M
Эта команда устанавливает, что сервер S слушает на порту 2222 и перенаправляет трафик на порт 8888 устройства M.
2. Использование iptables для NAT (Перевода сетевых адресов)
Если вашим предпочтением является использование инструментов маршрутизации Linux, вы можете настроить iptables на сервере S для прямого перенаправления портов.
Команды iptables:
sysctl net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -p tcp --dport 2222 -j DNAT --to-destination 1.2.3.4:8888
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Здесь 1.2.3.4
— это IP-адрес устройства M, 2222
— порт на сервере S, который будет перенаправляться, а 8888
— порт на устройстве M. Этот подход позволяет перенаправлять соединения на уровне ядра операционной системы без необходимости запуска каких-либо программ или сервисов.
3. Использование утилит socat и netcat
Эти инструменты предлагают другой подход к перенаправлению портов, устраняя необходимость в постоянных туннелях или дополнительных процессах.
Использование socat:
socat tcp-listen:2222,reuseaddr,fork tcp:M:8888
Использование netcat:
nc -l -p 2222 -c 'nc M 8888'
Заключение: Каждый из методов имеет свои преимущества и недостатки. SSH удобен, если требуется временное и защищенное соединение. Iptables предпочтительнее для более постоянных решений с низкой нагрузкой на систему. Утилиты socat и netcat являются гибким решением с простейшей конфигурацией. Ваш выбор должен основываться на требованиях безопасности, простоте эксплуатации и спецификациях сети.
Если у вас остались вопросы, не стесняйтесь обратиться за дальнейшими разъяснениями.