ssh映射端口
本文介绍,在Linux环境下ssh映射端口
操作环境说明
本地主机(客户机环境)
本地主机版本为 Ubuntu 22.04.2 LTS, 原则上只要有ssh命令即可。
root@ubuntu:~# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.2 LTS
Release: 22.04
Codename: jammy
远程主机(服务器环境)
远程主机版本为 Ubuntu 20.04 LTS , 原则上只要系统是Linux都通用且安装ssh即可。
ubuntu@:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04 LTS
Release: 20.04
Codename: focal
服务器之间互通说明(限制条件)
客户机只可以ssh访问服务器,服务器其他端口有网络策略加持无法访问,且可能由于服务器是生产环境,所以无法直接修改防火墙规则。
服务器与客户端方向网络不通,也即服务端无法ping通客户端IP地址。
一句话客户机只能ssh访问服务器,其他端口都不通。且服务器是公网IP,无法访问客户端服务。
背景介绍
由于网络策略限制,客户机只能ssh访问服务器,服务器上的web服务客户端无法直接访问,我们需要临时进行端口映射以达到客户端可以间接访问服务器服务。
另外客户端的服务,服务端也无法访问,可以利用ssh在服务器上访问客户端服务,以达到特殊的需求(比如,在服务器上通过访问客户端某服务拉取某些测试数据)。
客户端,服务器端IP 以及 服务说明
客户机的IP地址为 192.16.xxx.xxx 有一个web服务,端口为 8901, 也即在客户端上 http://localhost:8901 是可以访问的
服务器的IP地址为 172.17.xxx.xxx 有一个web服务,端口为 80, 也即在服务器上 http://localhost 或 http://localhos:80 是可以访问的
要实现的目标
1.在客户端上,通过ssh映射端口,实现客户端访问服务器服务。
客户端终端执行下面命令
# ssh -L 格式为
# ssh -L [本地主机:]本地主机端口:远程网络主机:远程网络主机端口
# 客户机8088端口流量转发到服务器80端口
ssh -L 8088:localhost:80 [email protected]
在另外一个客户端测试是否可以访问
curl http://localhost:8088
<html><head><meta http-equiv='refresh' content='1;url=/login?from=%2F'/><script>window.location.replace('/login?from=%2F');</script></head><body style='background-color:white; color:white;'>
Authentication required
<!--
-->
</body></html>
2.在客户端上,通过ssh映射端口,实现在服务端可以访问客户端的服务。
客户端终端执行下面命令
# ssh -R 格式为
# ssh -R [登录主机:]登录主机端口:本地网络主机:本地网络主机端口
# 将远程主机8088端口流量转发到本地主机端口8091
ssh -R 8088:localhost:8901 [email protected]
在另外一个客户端测试是否可以访问
curl http://localhost:8088
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
3.在客户端上,通过ssh动态端口转发,实现远程代理。
客户端终端执行下面命令
# ssh -D 格式为
# ssh -D [本地主机:]本地主机端口
# 客户机8088端口流量转发到服务器网络
ssh -D 8888 [email protected]
在另外一个客户端测试是否可以访问
curl --socks5-hostname 127.0.0.1:8888 http://localhost
<html><head><meta http-equiv='refresh' content='1;url=/login?from=%2F'/><script>window.location.replace('/login?from=%2F');</script></head><body style='background-color:white; color:white;'>
Authentication required
<!--
-->
</body></html>
#或
curl --socks5-hostname 127.0.0.1:8888 https://www.baidu.com
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');
</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
ssh切换后台执行
ssh -R 8088:localhost:8901 [email protected]
# 上面命令是前端执行,可以用户 -N -f 命令切换为后端进程,如下
ssh -N -f -R 8088:localhost:8901 [email protected]
部分参数解释
要查看ssh命令的参数,可以使用 man ssh 命令
- -f
Requests ssh to go to background just before command execution. This is useful if ssh is going to ask for passwords or passphrases, but the user wants it in the background. This implies -n. The recommended way to start X11 programs at a remote site is with something like ssh -f host xterm.
一句话转到后台执行命令
- -L [bind_address:]port:host:hostport
-L [bind_address:]port:remote_socket
-L local_socket:host:hostport
-L local_socket:remote_socket
Specifies that connections to the given TCP port or Unix socket on the local (client) host are to be forwarded to the given host and port, or Unix socket, on the remote side. This works by allocating a socket to listen to either a TCP port on the local side, optionally bound to the specified bind_address, or to a Unix socket. Whenever a connection is made to the local port or socket, the connection is forwarded over the secure channel, and a connection is made to either host port hostport, or the Unix socket remote_socket, from the remote machine.
Port forwardings can also be specified in the configuration file. Only the superuser can forward privileged ports. IPv6 addresses can be specified by enclosing the address in square brackets.
By default, the local port is bound in accordance with the GatewayPorts setting. However, an explicit bind_address may be used to bind the connection to a specific address. The bind_address of “localhost” indi‐cates that the listening port be bound for local use only, while an empty address or ‘*’ indicates that the port should be available from all interfaces
翻译
指定本地(客户端)主机上连接到给定 TCP 端口或 Unix 套接字的连接将被转发到远程主机上给定的主机和端口,或 Unix 套接字。这通过分配一个套接字来实现,以监听本地端口或套接字上的连接,可选地绑定到指定的 bind_address,或者绑定到 Unix 套接字。每当连接建立到本地端口或套接字时,连接将通过安全通道转发,并且将在远程机器上建立到主机端口 hostport 或 Unix 套接字 remote_socket 的连接。
端口转发也可以在配置文件中指定。只有超级用户可以转发特权端口。IPv6 地址可以通过将地址括在方括号中来指定。
默认情况下,本地端口根据 GatewayPorts 设置绑定。然而,可以使用显式的 bind_address 将连接绑定到特定地址。绑定到“localhost”的 bind_address 表示监听端口仅供本地使用,而空地址或 '*' 表示该端口应该从所有接口可用。
- -R [bind_address:]port:host:hostport
-R [bind_address:]port:local_socket
-R remote_socket:host:hostport
-R remote_socket:local_socket
-R [bind_address:]port
Specifies that connections to the given TCP port or Unix socket on the remote (server) host are to be forwarded to the local side.
This works by allocating a socket to listen to either a TCP port or to a Unix socket on the remote side. Whenever a connection is made to this port or Unix socket, the connection is forwarded over the secure channel, and a connection is made from the local machine to either an explicit destination specified by host port hostport, or local_socket, or, if no explicit destination was specified, ssh will act as a SOCKS 4/5 proxy and forward connections to the destinations requested by the remote SOCKS client.
Port forwardings can also be specified in the configuration file. Privileged ports can be forwarded only when logging in as root on the remote machine. IPv6 addresses can be specified by enclosing the address in square brackets.
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)).
If the port argument is ‘0’, the listen port will be dynamically allocated on the server and reported to the client at run time. When used together with -O forward the allocated port will be printed to the stan‐dard output.
翻译
指定将连接到远程(服务器)主机上给定的 TCP 端口或 Unix 套接字的连接转发到本地侧。
这通过分配一个套接字来实现,以监听远程侧的 TCP 端口或 Unix 套接字。每当建立到该端口或 Unix 套接字的连接时,连接将通过安全通道转发,并且从本地机器到明确由主机端口 hostport 或 local_socket 指定的目标,或者,如果没有明确指定目标,ssh 将充当 SOCKS 4/5 代理并将连接转发到远程 SOCKS 客户端请求的目标。
端口转发也可以在配置文件中指定。只有在远程主机上以 root 身份登录时才能转发特权端口。IPv6 地址可以通过将地址括在方括号中来指定。
默认情况下,服务器上的 TCP 监听套接字将仅绑定到环回接口。这可以通过指定 bind_address 来覆盖。一个空的 bind_address,或地址 ‘*’,表示远程套接字应该在所有接口上监听。只有在服务器的 GatewayPorts 选项启用时,指定远程 bind_address 才会成功(参见 sshd_config(5))。
如果端口参数是 ‘0’,则监听端口将在运行时在服务器上动态分配,并将在客户端报告。当与 -O forward 一起使用时,分配的端口将打印到标准输出。
- -D [bind_address:]port
Specifies a local “dynamic” application-level port forwarding. This works by allocating a socket to listen to port on the local side, optionally bound to the specified bind_address. Whenever a connection is made to this port, the connection is forwarded over the secure channel, and the application protocol is then used to determine where to connect to from the remote machine. Currently the SOCKS4 and SOCKS5 protocols are supported, and ssh will act as a SOCKS server. Only root can forward privileged ports. Dynamic port forwardings can also be specified in the configuration file.
IPv6 addresses can be specified by enclosing the address in square brackets. Only the superuser can forward privileged ports. By default, the local port is bound in accordance with the GatewayPorts setting.
However, an explicit bind_address may be used to bind the connection to a specific address. The bind_address of “localhost” indicates that the listening port be bound for local use only, while an empty address or ‘*’ indicates that the port should be available from all interfaces.
翻译
指定本地的“动态”应用级端口转发。这通过分配一个套接字来实现,在本地一侧监听端口,可选地绑定到指定的 bind_address。每当建立到该端口的连接时,连接将通过安全通道转发,并且应用程序协议将用于确定从远程机器连接到何处。目前支持 SOCKS4 和 SOCKS5 协议,ssh 将充当 SOCKS 服务器。只有超级用户才能转发特权端口。动态端口转发也可以在配置文件中指定。
IPv6 地址可以通过将地址括在方括号中来指定。只有超级用户才能转发特权端口。默认情况下,本地端口根据 GatewayPorts 设置绑定。
然而,可以使用显式的 bind_address 将连接绑定到特定地址。绑定到“localhost”的 bind_address 表示监听端口仅供本地使用,而空地址或 '*' 表示该端口应该从所有接口可用。
- -N
Do not execute a remote command. This is useful for just forwarding ports. Refer to the description of SessionType in ssh_config(5) for details
一句话就是创建连接后不执行任何命令
其他情况说明
如果遇到超时问题,可以尝试在ssh命令中添加 -o ServerAliveInterval=60 -o ServerAliveCountMax=60 选项。
或者修改配置文件
vim /etc/ssh/ssh_config
ServerAliveInterval 60
ServerAliveCountMax 60
# 重启ssh服务使配置生效
systemctl restart sshd