
У меня есть ящик с Windows 11, на котором запущен IIS на 127.0.0.1 на порту 80, который подключен к Интернету через CGNAT. У меня также есть VPS от Linode (поставщик VPS). IP-адрес VPS — 139.162.19.185. Я хочу подключаться к серверам/портам на моем ящике с Windows 11 из любой точки Интернета через мой VPS.
Я выполнил следующую команду, используя командную строку Windows 11 в режиме администратора:
ssh -R 80:localhost:80 [email protected]
Когда я пытаюсь получить доступ к SSH-туннелю на моем VPS, используяhttp://139.162.19.185:80, я получаю отказ в подключении, но когда я пытаюсь получить доступ к своему локальному хосту с помощьюhttp://127.0.0.1, я вижу домашнюю страницу IIS Start.
Я проверил файл /etc/ssh/sshd_config, и GatewayPorts и AllowTcpForwarding включены.
ОБНОВЛЯТЬ:
Это результаты netstat -tlnp
root@localhost:~# netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:80 0.0.0.0:* LISTEN 35027/sshd: root@pt
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 434/sshd: /usr/sbin
tcp6 0 0 ::1:80 :::* LISTEN 35027/sshd: root@pt
tcp6 0 0 :::22 :::* LISTEN 434/sshd: /usr/sbin
root@localhost:~#
Результаты curl следующие:
root@localhost:~# curl http://127.0.0.1:80
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request - Invalid Hostname</h2>
<hr><p>HTTP Error 400. The request hostname is invalid.</p>
</BODY></HTML>
root@localhost:~#
Нужно ли мне редактировать какие-либо файлы конфигурации? Я попробовал отладку, чтобы увидеть, есть ли какие-либо брандмауэры на Linode. Я установил apache2, и он отлично работает на порту 80, поэтому порт 80 не заблокирован.
решение1
То, как вы используете эту -R
опцию, означает, что вы хотите, чтобы удаленная сторона привязывалась только к интерфейсу loopback. Из ssh
страницы руководства:
-R [bind_address:]port:host:hostport
...
By default, TCP listening sockets on the server will be bound to the loopback interface only. This may be overridden by
specifying a bind_address. An empty bind_address, or the address ‘*’, indicates that the remote socket should listen on
all interfaces. Specifying a remote bind_address will only succeed if the server's GatewayPorts option is enabled (see
sshd_config(5)).
Упрощенно это означает:
-R port:host:hostport
будет привязан только к петле-R :port:host:hostport
будет привязан ко всем интерфейсам- как будет
-R *:port:host:hostport
и-R 0.0.0.0:port:host:hostport
Итак, в вашей ситуации подойдет любой из этих вариантов:
ssh -R :80:localhost:80 [email protected]
ssh -R *:80:localhost:80 [email protected]
ssh -R 0.0.0.0:80:localhost:80 [email protected]
*Ниже представлена моя первоначальная попытка объяснить это поведение на основе текста документации — с некоторыми пояснениями.
Вы использовали синтаксис PORT:IP:PORT, в котором не указан bind_address.
Текст specifying a bind_address
в описании выше относится к тому, что :
перед удаленным портом (первый порт в PORT:IP:PORT). В вашем примере нет , :
что означает, что вы не указали bind_address, и согласно странице руководства удаленная сторона будет привязываться только к интерфейсу обратной связи (по умолчанию). Чтобы привязаться ко всем интерфейсам, вам нужно указать bind_address (т. е. добавить :
перед удаленным портом), даже если фактический bind_address — это «пустая строка»! В этом случае подойдет либо «пустая строка», либо *
, но имейте в виду, что :
является обязательным, чтобы не ограничиваться привязкой только к адресу обратной связи!
Обновлять
После комментариев @barlop, похоже, мое объяснение было не совсем понятным, поэтому я попытаюсь прояснить ситуацию здесь шаг за шагом:
- Опция определяется как
-R [bind_address:]port:host:hostport
. - Вся
[bind_address:]
часть необязательна. Если она отсутствует, то опция имеет формат-R port:host:hostport
и применяется поведение по умолчанию, что означаетTCP listening sockets on the server will be bound to the loopback interface only
. - Если
[bind_address:]
часть присутствует, значит у нас есть формат-R bind_address:port:host:hostport
, обратите внимание, что теперь первый:
больше не является необязательным. С этого моментаbind_address
может принимать несколько значений, одно из возможных значений действительнопустая строка! Таким образом, добавление двоеточия к опции означает, чтоbind_address
на этот раз мы указываем a, хотя и пустое (что, согласно описанию, означаетthe remote socket should listen to all interfaces
.
Надеюсь, это немного прояснит ситуацию, в принципе, not specifying a bind_address
это specifying an empty string as bind_address
две разные вещи! "Пустая строка" bind_address считается адресом привязки и относится к использованию :PORT:IP:PORT
синтаксиса без написания чего-либо там для адреса, перед крайним левым двоеточием!.
Вот результат моего тестирования (на другом порту, но эффект тот же):
Посмотрите, как работает SSH-соединение и выполняется netstat -an на удаленной машине.
gepa@localhost:~$ ssh -R :5555:localhost:5555 cloud1 netstat -an | grep :5555
tcp 0 0 0.0.0.0:5555 0.0.0.0:* LISTEN
tcp6 0 0 :::5555 :::* LISTEN
gepa@localhost:~$ ssh -R 5555:localhost:5555 cloud1 netstat -an | grep :5555
tcp 0 0 127.0.0.1:5555 0.0.0.0:* LISTEN
tcp6 0 0 ::1:5555 :::* LISTEN
Обратите внимание, что добавление :
перед первым 5555
заставляет удаленный хост прослушивать все интерфейсы по сравнению с исключением :
.
Кстати, гораздо понятнее не использовать пустую строку bind_address и писать $ ssh -R *:5555:localhost:5555 comp
или0.0.0.0:80:localhost:80
Также причина, по которой синтаксис PORT:IP:PORT привязывается к 127.0.0.1, заключается в соображениях безопасности. Так что если вы хотите, чтобы он привязывался нелокально, лучше сделать это очень ясно, например, с помощью подстановочного знака или указав 0.0.0.0 или указав адрес локальной сети, если подключение осуществляется только из локальной сети.