ssh建隧道简单介绍:*、本地服务穿透到外网、

这几天研究ssh的隧道技术发现几个比较有趣的用法,跟大家分享一下

先介绍本文通过ssh干的事情吧

1. *;    -- 需要一台能ssh到的墙外vps
2. 本地服务穿透到外网;    -- 需要一台能ssh到的外网vps

完成上面的功能,需要先看看ssh命令能干什么

一、 man ssh

看看ssh命令有哪些选项吧
由于太长,这里只展示本次相关的选项

> man ssh

     -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 speci-
             fied 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 inter-
             faces.

     -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 back-
             ground.  This implies -n.  The recommended way to start X11 programs at a remote site is with something like ssh -f host xterm.

             If the ExitOnForwardFailure configuration option is set to ``yes'', then a client started with -f will wait for all remote port forwards to be successfully established
             before placing itself in the background.

     -L [bind_address:]port:host:hostport
             Specifies that the given port on the local (client) host is to be forwarded to the given host and port on the remote side.  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 a connection is made to host port hostport from the remote machine.  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.

     -N      Do not execute a remote command.  This is useful for just forwarding ports (protocol version 2 only).

     -R [bind_address:]port:host:hostport
             Specifies that the given port on the remote (server) host is to be forwarded to the given host and port on the local side.  This works by allocating a socket to listen
             to port on the remote side, and whenever a connection is made to this port, the connection is forwarded over the secure channel, and a connection is made to host port
             hostport from the local machine.

             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, the listening socket 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 standard output.

上面罗列出了用用到的选项简单介绍一下:

-D [监听地址]监听端口   用于将远程连接的ssh通过本监听本地的端口形成sock4或者sock5服务;(使用**的同学应该不陌生);
-f 让SSH服务运行到后台,做外forward代理的ssh命令运行在后台更省心;
-L ssh将监听本地端口,所有对这个端口的数据操作会穿透到ssh远程地址的对应配置端口;
-N 不执行远程命令,在ssh作为隧道时很有用;
-R ssh将监听远程服务器的某个端口,并将端口的所有数据转发到本地的设置端口;

图解上面配置

-D              将remote能访问的服务都穿透到本地的port上,并提供sock服务;                
                                                 
     ▲ port: sock5                               
     │                                           
┌────┴────────┐                   ┌─────────────┐
│  localhost  │────port: 22──────▶│    remote   │
└─────────────┘                   └─────────────┘

-L              将远程能访问的某个服务host+port穿透到本地,在本地的port上提供对应透传服务;
                                                          
    ▲  bindaddr:port                   ▲ servicehost:port 
    │                                  │                  
┌───┴─────────┐                   ┌────┴────────┐         
│  localhost  │────port: 22──────▶│    remote   │         
└─────────────┘                   └─────────────┘         

-R               将本机能访问的某个服务host+port穿透到remote,在remote机器指定port上提供透传服务;
                                                          
    ▲  servicehost:port                ▲ bindaddr:port    
    │                                  │                  
┌───┴─────────┐                   ┌────┴────────┐         
│  localhost  │────port: 22──────▶│    remote   │         
└─────────────┘                   └─────────────┘         

为了方便起见,假设拥有下面资源

  1. 墙外vps: root@outside_vps
  2. 本机: localhost

二、 通过墙外ECS提供sock5*

命令

ssh -N -f -D 1080 root@outside_vps

输入密码,执行后,本地1080端口被监听,提供sock5服务;使用chrome+SwitchyOmega就能配置*了,效果和*一样。

三、 本地服务穿透到外网80端口

本地起一个服务监听3003端口,这里用nodejs简单实现:

// s.js
require('http').createServer(function (req, res) {
  res.end('xxx');
}).listen(3003);

> node s

ssh 到远程vps,将远程vps的端口监听设置为如下,允许sshd监听处localhost以外的IP:
(在ssh参数中加 -o GatewayPorts=yes 效果一样)

> vim /etc/ssh/sshd_config

# GatewayPorts: no

------ 改成  -----

GatewayPorts: yes

本地启动

ssh -f -N -R outside_vps:80:localhost:3003 root@outside_vps

启动后,在浏览器输入outside_vps,直接能访问到本地3003的服务

tips: 这里能将本地的http服务透传到外网,同样也能将本地22端口透传(慎用次功能,免得密码太弱或者有安全漏洞时让人有机可乘)

四、 服务代理

场景: 当 A 只能访问 B,B 能连接 C ,A需要访问 C 的某个服务,而不能让A访问到C的其他服务。

此时,-L 参数就派上用场了。我们使用B主机通过SSH -L,将 C上面的制定服务代理到 B 的某个端口让A使用,此时 A 只能访问到C被代理的服务,而访问不了C的其它服务;

以将C的mysql服务穿透到B为例:

在B上执行

ssh -N -f -o GatewayPorts=yes -L *:3336:C:3306 root@C

在A*问

mysql -hB -uuser -P3336 -p

输入密码后,跟访问C的端口效果一样!

上面的场景,在网络隔离,B作为出口机时可能会出现,当然,这种代理用Nginx做TCP代理也能轻松实现。

上一篇:generator & co & koa


下一篇:matlab画爱心