情况:
本地 Windows 计算机运行一个非常简单的 HTTP Web 服务器来监听0.0.0.0:8080
。远程 Windows 计算机有OpenSSH 服务器正在运行,并且我有 ssh 凭据,但我只能假设这些。它可能没有互联网,我之前没有访问权限或重新配置或安装的权限,并且/或者它可能只能通过端口 22 进行通信。我希望远程计算机能够访问我的本地 Web 服务器,并且只能访问它。
计划:
我通过打开反向隧道来调用远程机器ssh myremote -R 8080:localhost:8080
,并希望通过发出 HTTP、GET 请求,使用 powershell 来访问我的本地网络服务器,就像Invoke-WebRequest -Uri "http://localhost:8080"
在我建立的会话中一样。
结果:
Invoke-WebRequest : The underlying connection was closed: The connection was closed unexpectedly.
At line:1 char:1
+ Invoke-WebRequest -Uri "http://localhost:8080"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
如果我改为建立一个到本地端口 22 的隧道ssh myremote -R 8080:localhost:22
,则可以成功地使用内部 ssh 将该隧道返回到我的本地计算机,例如ssh localhost -p 8080
,假设我已预先配置了从远程公钥的访问权限。使用本地网络,远程方也可以直接调用 Web 服务器。这不是我想要做的,但很明显隧道已正确建立。此外,如果远程计算机与本地计算机相同(映射可能是)ssh localhost -R 8081:localhost:8080
,那么调用Invoke-WebRequest -Uri "http://localhost:8081"
具有完全相同的效果。其他方法,例如使用浏览器发送 http 请求具有相同的效果。使用从远程(-L
标志)正向隧道具有相同的效果。使用任何其他监听 TCP 流量的方式,例如System.Net.Sockets.TCPListener
都有相同的效果(流量永远不会到达它)。使用 PuTTY 建立等效隧道具有相同的效果。
单台计算机 powershell 程序复制问题:
$port1 = 8080;
$port2 = 8081;
$Listener = [System.Net.Sockets.TcpListener]$port1;
$Listener.Start();
ssh localhost -R "${port2}:localhost:${port1}" powershell Invoke-Webrequest -Uri "http://localhost:$port2"
$Listener.Stop();
问题:
为什么 SSH 可以成功通过隧道,而我尝试的其他任何方法都不成功?如何通过反向隧道与本地服务器应用程序建立 HTTP 或 TCP 连接?
答案1
Windows Vista 及更新版本默认将环回域解析localhost
为(IPv6),监听应用程序必须预料到这一点。我的所有软件都监听或不支持这两种协议,但::1
情况并非如此。0.0.0.0
127.0.0.1
解决方案#1:
使用并配置监听 IPv4 和 IPv6 套接字的库或应用程序。
解决方案 #2:
使用 IPv4 创建 ssh 隧道,明确添加标志-4
或使用127.0.0.1
而不是localhost
。
解决方案 #3:
将前缀策略应用于网络接口,以优先考虑127.0.0.1
或完全禁用 IPv6 偏好。阅读这个答案有关该解决方案的详细信息。
如果您遇到类似问题,而此方法无法解决问题,请考虑 ssh 隧道入口点和服务器监听的地址范围。如果这些套接字必须可远程访问localhost
,则不要监听::1
或127.0.0.1
。明确指定源 IP 范围,或使用::
、0.0.0.0
或*
软件记录为“任何”源的任何内容。