我们在 内网穿透实战 中简单介绍了下我们实现内网穿透的基本原理,在我们的方案中理论上可以支持所有的 tcp/udp 服务,但其中某些服务可能在应用层有服务地址交换,这种服务我们默认是不支持的,比如 ftp 服务,今天我们以ftp 服务为例来说明下我们怎么支持穿透这种类型的服务,在此之前先来了解下我们建立内网穿透将内网服务映射到访问端的过程。

内网穿透服务映射基本原理和过程


假设我们有个内网服务A 需要穿透访问,服务A 为tcp 服务,在ip1/port1 上监听,我们的内网端 mt_proxy_client_inner 和该服务部署在同一个子网,可以直接访问这个服务A,实现穿透访问服务A 的过程如下:
1. 我们在内网端服务穿透列表中配置服务A的信息,包括协议类型 tcp, 服务地址 ip1/port1 
2. 访问端配置中指定连接服务A对应的内网端(访问端可以访问任意的内网端,但每次只能指定访问其中的一个)
3. 访问端直连或者通过服务中转方式实现跟内网端通讯
4. 访问端请求内网端可穿透的服务列表,获取到列表后访问端在自己的机器上为每个服务建立对应的服务监听,此处假定为服务A 建立的服务监听地址为 tcp/ip2/port2
5. 访问端定时向内网端发送跳维持通道,并等待访问端网络中的机器请求内网穿透服务
6. 当访问端网络的用户x请求服务A时会连接监听地址ip2/port2, 假设这个连接为 socket-x, 我们记录下socket-x对应的内网端地址
7. 如果请求的服务是tcp类型的,我们在socket-x 连接完成后需要通知mt_proxy_client_inner 建立同内网服务的tcp连接,我们假设为 socket-y, 建立这个 socket-y连接时需要记录对应的访问端以及访问端的用户地址,如果不是tcp 这一步可以延后操作
8. 当收到访问端用户的请求数据包时,我们找到socket-x中记录的内网端地址,添加一个包头并将内网地址塞入包头中,然后包头连同数据以前发往内网端
9.  内网端收到请求包后从包头中取出内网地址,看下是否有对应这个数据包的socket-y连接,如果没有则重新建立,建立连接时需要记录访问端以及访问端的用户地址。我们将收到的数据包通过socket-y发往内网服务A
10. 反之当收到服务A的数据包时我们可以根据 socket-y 中记录的访问端信息将数据包发往对应的访问端用户
最终的效果如图所示,我们通过 socket-x, socket-y 好像建立了一个访问端用户x和内网端服务A的逻辑通道。

这里的问题是所有的内网穿透服务都需要先在内网端配置,访问端通过这个配置建立对应的服务监听,但 ftp 服务它是有两种连接的,我们的配置建立的只是命令连接(完成ftp登录、退出、切换目录等命令),ftp 的据连接(一般涉及到磁盘io的请求都是通过数据连接完成,比如列出目录文件、下载、上传文件等)是通过命令连接交换信息双方协商的,如下:
主动ftp 模式:ftp 客户端通过 port n 命令告知服务端,客户端在端口 n监听,服务端主动去建立同ftp 客户端的连接,这种模式用的很少,我们暂不处理
被动 ftp 模式:在需要建立数据连接时,ftp 客户端使用 EPRT, PASV或者 EPSV 命令要求同服务端建立数据连接,服务端收到后新起一个监听socket,并在响应EPRT, PASV或者EPSV 的数据包中告知ftp客户端这个新监听socket 的连接地址,然后等待ftp客户端的数据连接请求
我们可以用 tcpdump 命令抓下包看看PASV 命令的请求和响应:

PASV  
227 Entering Passive Mode (192,168,1,119,117,148) \r\n
EPRT, PASV 模式会同时告知数据连接的IP和端口,EPSV 告知端口,关于这些命令我们不做太多说明,总结下我们遇到的问题:
1. ftp 的数据连接地址是在命令连接中完成协商的,我们目前没有办法使用之前的内网穿透方法,提前建立数据连接的内网穿透通道
2. ftp 的 EPRT,PASV 命令同时告知了IP地址,而这个内网端的IP地址 处于我们访问端的用户是没办法访问的 (对应我们上面的穿透图就是用户x 需要直接访问ip2/port2)

针对 EPSV 模式,解决方法有两种:
1. 修改ftp 服务端的配置,让数据连接的端口固定,即修改如下配置:pasv_min_portpasv_max_port,如可以改成: 

        pasv_min_port=40001
        pasv_max_port=40001

这样我们在配置ftp的穿透时,同时加上这个端口的配置即可

2. 针对ftp 服务,在访问端我们同时预先建立一个额外监听socket-z, 然后观察ftp命令连接,修改 EPSV 的响应,将其端口改成我们的 socket-z 监听端口

针对 PASV、EPRT 模式的解决方法:
1. 针对ftp 服务在访问端我们同时预先建立一个额外监听socket-z然后观察ftp命令连接,修改 EPRT,PASV 命令的响应,将其端口改成我们的 socket-z 监听端口,IP 修改成 socket-z 的IP(这个IP从socket-z 的连接中可以获取到)

其实这里还有个问题,当我们的访问端不是同用户部署在一个子网的时候,这个socket-z 的IP ,用户也可能访问不了,比如前面文章: 内网穿透实战 中提到的将访问端部署在云服务器上,socket-z 的地址可能并不是云服务器的外网IP地址,但所幸的是这个地址一般是固定的,我们加个配置即可解决。

总结下针对 ftp 穿透的解决方法:

在建立ftp 服务的穿透映射时,额外建立一个数据连接的socket监听,并修改命令连接中的地址交换信息为我们额外建立的那个socket 监听地址。另外加个IP 地址的配置,视需要将额外socket 监听的IP 改成我们的配置IP(如访问端和用户部署在同一个子网则不需要这个配置)。

本文在本人公众号首发,关注后第一时间查看分享:


本文系本站原创,转载请注明出处:http://xrkmonitor.com/a/89.html