设为首页 | 网站公告 | 网站地图 | 联系我们 加入收藏
| 网站首页 | 技巧文摘 | 电脑书库 | 媒体教程 | P2P资源区 | 在线留言 | 学习资源社区 |
会员登录
 
热门电脑教程
推荐电脑教程
您现在的位置: 计算机应用技巧资讯站 > 技巧文摘 > 网络应用 > 网站建设 > 其他 > 文章正文
FTP会话浅析
来源:转载  阅读次数:  更新日期:2007-3-27
首先简单介绍一下FTP协议。FTP可以算是比较古老的协议,在早期互联网低带宽低稳定性条件下,对大尺寸文件进行可靠传输的要求促使这个协议诞生。现行的FTP官方协议规范是RFC959,1985年10月公布,后有三次补充。正因为要求可靠传输,所以FTP使用可靠的有连接的TCP协议并使用客户端/服务器结构。

IETF官方主页 http://www.ietf.org
RFC索引 http://www.ietf.org/iesg/1rfc_index.txt
RFC959 http://www.ietf.org/rfc/rfc0959.txt

CHAP 1.

  先来看一个普通的FTP会话。以常见的下载工具FlashGet为例,我们分析一下登录日志,以便导出FTP会话通常的工作流程。为节省篇幅,省略了一些不重要的信息。

  我们要下载的是服务器ftp://220.189.192.22:27321上 /The.City.of.Violence.DVDRip.XviD-PosTX/Sample/目录下的postx-jjackpae.sample.avi这个文件,红色部分是客户端发往服务器的指令,蓝色部分是服务器的返回信息,灰色部分是注释。本地IP地址 222.92.3.6

QUOTE:

Sat Sep 16 19:50:40 2006 正在连接 220.189.192.22 [IP=220.189.192.22:27321] //这是个非默认端口,一般默认是21
Sat Sep 16 19:50:41 2006 Socket已连接 ,等待欢迎信息
Sat Sep 16 19:50:41 2006 220-DIVX FTP
Sat Sep 16 19:50:41 2006 USER usrname //提交帐户名
Sat Sep 16 19:50:42 2006 331 User name okay, need password.
Sat Sep 16 19:50:42 2006 PASS ************ //提交密码
Sat Sep 16 19:50:42 2006 230 User logged in, proceed.
Sat Sep 16 19:50:42 2006 成功登录
Sat Sep 16 19:50:42 2006 REST 100 //RESTart命令测试断点续传
Sat Sep 16 19:50:42 2006 350 Restarting at 100. Send STORE or RETRIEVE.
Sat Sep 16 19:50:42 2006 该站点支持断点续传.
Sat Sep 16 19:50:42 2006 REST 0 //再次REST命令将文件块起始位置复位
Sat Sep 16 19:50:42 2006 350 Restarting at 0. Send STORE or RETRIEVE.
Sat Sep 16 19:50:42 2006 TYPE A //设置文件传输类型,一般文本文件用ASCII码传输,即TYPE A,图像或程序文件用二进制即TYPE I
Sat Sep 16 19:50:42 2006 200 Type set to A.
Sat Sep 16 19:50:42 2006 PASV //设置传输模式为被动模式 PASsiVe
Sat Sep 16 19:50:43 2006 227 Entering Passive Mode (220,189,192,22,4,113)
Sat Sep 16 19:50:43 2006 LIST /The.City.of.Violence.DVDRip.XviD-PosTX/Sample/postx-jjackpae.sample.avi //列目录
Sat Sep 16 19:50:43 2006 -rw-rw-rw-   1 user     group    12892160 Sep 15 14:57 postx-jjackpae.sample.avi
Sat Sep 16 19:50:43 2006 150 Opening ASCII mode data connection for /bin/ls.
Sat Sep 16 19:50:44 2006 226 Transfer complete.
Sat Sep 16 19:50:44 2006 开始接受数据!
Sat Sep 16 19:50:44 2006 TYPE I //设置文件传输类型为二进制
Sat Sep 16 19:50:44 2006 200 Type set to I.
Sat Sep 16 19:50:44 2006 PASV //设置传输模式为被动模式
Sat Sep 16 19:50:44 2006 227 Entering Passive Mode (220,189,192,22,4,115)
Sat Sep 16 19:50:44 2006 RETR /The.City.of.Violence.DVDRip.XviD-PosTX/Sample/postx-jjackpae.sample.avi //RETRieve 获取文件,开始传输
Sat Sep 16 19:50:45 2006 150 Opening BINARY mode data connection for postx-jjackpae.sample.avi (12892160 Bytes).


  在下载的同时我们进入命令行,输入netstat -n,显示当前TCP连接状态如下:

QUOTE:

C:\Documents and Settings\sk>netstat -n

Active Connections

 Proto  Local Address          Foreign Address        State
 TCP    222.92.3.6:1376     220.189.192.22:27321   ESTABLISHED
(TCP    222.92.3.6:1377     220.189.192.22:1137    ESTABLISHED) //这个连接因为存在时间很短,并不可见,只是作为完整性的补充
 TCP    222.92.3.6:1378     220.189.192.22:1139    ESTABLISHED


  可以看到,当前有两个TCP连接。这两个连接恰好就是FTP会话的两种连接。

  TCP    222.92.3.6:1376     220.189.192.22:27321   ESTABLISHED --这是个控制连接,客户端发往服务器的所有指令包括用户名密码都走这个连接。
  TCP    222.92.3.6:1378     220.189.192.22:1139    ESTABLISHED --这是个数据连接,从服务器上下载的文件或上传给服务器的文件走这个连接(这个例子是单线程下载,如果是多线程,就会有多个控制连接和数据连接,它们总是成对出现)。其实在这之前还存在一个数据连接,是列目录时服务器返回信息的通道,只不过因为所需时间很短,这个TCP连接很快就完成使命而关闭了,所以没有捕捉到这个状态,我用带括号的补充。

  这里顺便讲一下,类似“TCP    222.92.3.6:1376     220.189.192.22:27321”这种表示方法可以唯一标识一个网络进程,一个互联网地址加上端口称为一个socket,俗称套接字。上面例子中客户端发出PASV指令后,服务器返回的“227 Entering Passive Mode (220,189,192,22,4,115)”就指示了一个socket,括号中逗号分隔的前四组数字是IP地址220.189.192.22,后面的4乘上256,加上最后的115,等于1139,就是服务器监听的数据端口1139,这个信息告诉客户端:“我已经打开了端口1139,你可以发起连接了”。

  另外,关于被动(PASV)和主动(PORT)两种传输模式,可以这样理解:这两种模式都是针对服务器端而言,服务器打开监听端口,客户端发起数据连接,对服务器而言是被动的连接,称为PASV模式;客户端打开监听端口,服务器发起数据连接,对服务器而言是主动的,称为PORT模式,一般FTP程序实现中都把服务器监听的控制连接端口减1,作为自己PORT模式时发起连接的数据端口(像上面例子中,如果使用PORT模式,会看到服务器使用27321-1=27320这个端口与客户端建立数据连接)。被动或主动在双方都具备公众网地址的时候其实是无所谓的,但如果有一方或双方都是私有地址,需要经过NAT转换的时候,就需要考虑了,因为这牵涉到TCP连接究竟由谁发起的问题,NAT带来的复杂性就在这里。这个问题留待后续的小节叙述。

  好了,到这里我们可以做个归纳。类似本节例子这样的一个普通FTP会话,可以用如下的流程描述:

  1.客户端随机选取一个未用端口(一般>1024),向服务器监听的控制端口发起连接请求,经过TCP三次握手建立控制连接,提交帐户名密码登录。
  2.客户端发送指令设置文件传输类型和传输模式,服务器返回响应。如果是PASV模式,服务器监听一数据端口,客户端向这个端口发起数据连接(同样经过TCP三次握手,下同);如果是PORT模式,客户端监听一数据端口,服务器发起数据连接。
  3.服务器与客户端在已建立的数据连接上进行信息交互(列目录,上传或下载文件等)。

  本节的例子用图表表示如下(省略TCP连接的关闭):

QUOTE:

TCP 222.92.3.6:1376 ---Syn---> 220.189.192.22:27321
TCP 222.92.3.6:1376 <-Ack Syn- 220.189.192.22:27321
TCP 222.92.3.6:1376 ---Ack---> 220.189.192.22:27321 //TCP三次握手,Syn是TCP同步请求,Ack是确认,两者都存在于TCP报头中

TCP 222.92.3.6:1376 <--login-> 220.189.192.22:27321 //登录交互过程
TCP 222.92.3.6:1376 <--REST--> 220.189.192.22:27321 //测试断点续传
TCP 222.92.3.6:1376 <--TYPE--> 220.189.192.22:27321 //设置文件传输类型为ASCII
TCP 222.92.3.6:1376 ---PASV--> 220.189.192.22:27321 //设置传输模式为被动
TCP 222.92.3.6:1376 <-socket-- 220.189.192.22:27321 //服务器返回监听的数据端口 (220,189,192,22,4,113)=220.189.192.22:1137

TCP 222.92.3.6:1377 ---Syn---> 220.189.192.22:1137
TCP 222.92.3.6:1377 <-Ack Syn- 220.189.192.22:1137
TCP 222.92.3.6:1377 ---Ack---> 220.189.192.22:1137  //TCP三次握手,客户端发起请求,建立数据连接

TCP 222.92.3.6:1376 ---LIST--> 220.189.192.22:27321 //客户端发送列目录指令
TCP 222.92.3.6:1377 <--data--- 220.189.192.22:1137  //服务器返回目录信息

TCP 222.92.3.6:1376 <--TYPE--> 220.189.192.22:27321 //设置文件传输类型为BINARY
TCP 222.92.3.6:1376 ---PASV--> 220.189.192.22:27321 //设置传输模式为被动
TCP 222.92.3.6:1376 <-socket-- 220.189.192.22:27321 //服务器返回监听的数据端口 (220,189,192,22,4,115)=220.189.192.22:1139

TCP 222.92.3.6:1378 ---Syn---> 220.189.192.22:1139
TCP 222.92.3.6:1378 <-Ack Syn- 220.189.192.22:1139
TCP 222.92.3.6:1378 ---Ack---> 220.189.192.22:1139  //TCP三次握手,客户端发起请求,建立数据连接

TCP 222.92.3.6:1376 ---RETR--> 220.189.192.22:27321 //客户端发送获取文件指令
TCP 222.92.3.6:1378 <--data--- 220.189.192.22:1139  //服务器传送文件至客户端


  值得一提的是,TCP采用确认应答和超时重传机制来保证传输可靠性,一般来讲每发送一个数据包都要求对方返回确认或捎带确认,但为了描述的易读性,上图中的箭头指向只表示数据包的主要流向,不代表实际情况。另外,这一节没有讲TCP连接的关闭,因为跟后面碰到的问题关系不大,所以就省略了。



CHAP 2.

  首先感谢楼内各位的鼓励,让我有动力继续写下去。

  这一节咱们聊聊FXP。对于上一节的例子可能有同学看了会问,你这个例子是客户端从服务器下载文件,那么上传跟下载总有区别吧,工作流程也一样么?其实,在服务器和客户端看来,下载跟上传没有本质区别,因为TCP是一个全双工的协议,在一条TCP连接上可以同时发送和接收数据。下载和上传,在客户端看来是RETR和STOR指令的不同,在服务器看来只是读和写的文件操作不同,而最重要的是,两者都是依靠数据连接进行传输。说起这个全双工,实际上早期的TCP是被设计成单工的协议,这一点在TCP早期的周知端口分配上得到体现,http://www.iana.org/assignments/port-numbers--这个页面是互联网地址指派机构IANA的TCP周知端口分配表,仔细观察那些早期被分配的比较低的端口,你会发现一个有趣的现象--它们都是奇数,对应的偶数端口都被保留了,因为那时候一个网络进程必须使用成对的TCP连接,一个发送,一个接收。

  咳,好像扯的有点远了,咱们回到正题。先引用RFC959中关于FXP的一张原理图,有个大致概念,然后我们再分析一个FXP的log实例,导出FXP的基本流程,在引入NAT之前,还是设定客户端和两个服务器都具有公众网地址。



  原理图也很简单,两个控制连接,一个数据连接。“User-PI”是客户端协议解释器。

  下面是以常用的FXP工具FlashFXP为例,提取的一个FXP日志摘要。左窗口是文件源服务器,右窗口是文件目的服务器,文件从左窗口传至右窗口。红色部分是客户端发往服务器的指令,蓝色部分是服务器的返回信息,灰色部分是注释。本地IP地址 222.92.3.6

QUOTE:

[22:08:29] [左] 正在连接到 ftp://220.189.192.22:27321 -> IP=220.189.192.22 PORT=27321 //连接文件源服务器
[22:08:29] [左] 已连接到 ftp://220.189.192.22:27321
[22:08:29] [左] 220-DIVX FTP
[22:08:29] [左] USER usrname //提交帐户名
[22:08:30] [左] 331 User name okay, need password.
[22:08:30] [左] PASS (隐藏) //提交密码
[22:08:30] [左] 230 User logged in, proceed.
[22:08:30] [左] SYST //查询服务器系统类型
[22:08:30] [左] 215 UNIX Type: L8
[22:08:30] [左] FEAT //查询服务器支持的指令集特性
[22:08:30] [左] 211-Extension supported
[22:08:30] [左] CLNT
[22:08:30] [左] MDTM
[22:08:30] [左] MDTM YYYYMMDDHHMMSS[+-TZ];filename
[22:08:30] [左] SIZE
[22:08:30] [左] SITE PSWD;EXEC;SET;INDEX;ZONE;CHMOD;MSG
[22:08:30] [左] REST STREAM
[22:08:30] [左] XCRC filename;start;end
[22:08:30] [左] MODE Z
[22:08:30] [左] MLST Type*;Size*;Create;Modify*;Win32.ea*;
[22:08:30] [左] 211 End
[22:08:30] [左] CLNT FlashFXP 3.3.7.1129 //提交客户端版本
[22:08:31] [左] 200 Noted.
[22:08:31] [左] PWD //提示当前目录
[22:08:31] [左] 257 "/" is current directory.
[22:08:31] [右] 正在连接到 ftp://221.6.158.121:22 -> IP=221.6.158.121 PORT=22 //连接文件目的服务器
[22:08:31] [右] 已连接到 ftp://221.6.158.121:22
[22:08:31] [右] 220-Serv-U FTP Server v5.0 for WinSock ready...
[22:08:31] [右] USER upusr //提交帐户名
[22:08:31] [右] 331 User name okay, need password.
[22:08:31] [右] PASS (隐藏) //提交密码
[22:08:31] [右] 230 User logged in, proceed.
[22:08:31] [右] SYST //查询服务器系统类型
[22:08:32] [右] 215 UNIX Type: L8
[22:08:32] [右] FEAT //查询服务器支持的指令集特性
[22:08:32] [右] 211-Extension supported
[22:08:32] [右] CLNT
[22:08:32] [右] MDTM
[22:08:32] [右] MDTM YYYYMMDDHHMMSS[+-TZ];filename
[22:08:32] [右] SIZE
[22:08:32] [右] SITE PSWD;EXEC;SET;INDEX;ZONE;CHMOD;MSG
[22:08:32] [右] REST STREAM
[22:08:32] [右] XCRC filename;start;end
[22:08:32] [右] 211 End
[22:08:32] [右] CLNT FlashFXP 3.3.7.1129 //提交客户端版本
[22:08:32] [右] 200 Noted.
[22:08:32] [右] CWD /=---Req---=/test //切换目录
[22:08:32] [右] 250 Directory changed to /=---Req---=/test
[22:08:32] [右] PWD //提示当前目录
[22:08:33] [右] 257 "/=---Req---=/test" is current directory.
[22:08:33] [右] TYPE A //设置文件传输类型为ASCII
[22:08:33] [右] 200 Type set to A.
[22:08:33] [右] PASV //设置传输模式为被动-PASsiVe
[22:08:33] [右] 227 Entering Passive Mode (221,6,158,121,5,59)
[22:08:33] [右] 正在打开数据连接 IP: 221.6.158.121 端口: 1339
[22:08:33] [右] LIST -al //列目录
[22:08:33] [右] 150 Opening ASCII mode data connection for /bin/ls.
[22:08:33] [右] 226 Transfer complete.
[22:08:33] [右] 列表完成: 113 字节 于 0.83 秒 (0.1 KB/秒)
[22:08:33] [左] CWD /Forbidden.Siren.2006.DVDRip.XviD.AC3.iNT-MoMo/Sample //切换目录
[22:08:34] [左] 250 Directory changed to /Forbidden.Siren.2006.DVDRip.XviD.AC3.iNT-MoMo/Sample
[22:08:34] [左] PWD //提示当前目录
[22:08:34] [左] 257 "/Forbidden.Siren.2006.DVDRip.XviD.AC3.iNT-MoMo/Sample" is current directory.
[22:08:34] [左] TYPE A //设置文件传输类型为ASCII
[22:08:34] [左] 200 Type set to A.
[22:08:34] [左] MODE Z //启用压缩传输(适合文本)-Zip
[22:08:34] [左] 200 MODE Z ok.
[22:08:34] [左] PASV //设置传输模式为被动-PASsiVe
[22:08:34] [左] 227 Entering Passive Mode (220,189,192,22,7,179)
[22:08:34] [左] 正在打开数据连接 IP: 220.189.192.22 端口: 1971
[22:08:35] [左] LIST -al //列目录
[22:08:35] [左] 150 Opening ASCII mode data connection for /bin/ls.
[22:08:35] [左] 226 Transfer complete.
[22:08:35] [左] 列表完成: 186 字节 于 1.34 秒 (0.1 KB/秒)
[22:08:35] [左] TYPE I //设置文件传输类型为BINARY
[22:08:35] [左] 200 Type set to I.
[22:08:35] [右] TYPE I //设置文件传输类型为BINARY
[22:08:36] [右] 200 Type set to I.
[22:08:36] [左] MODE S //启用流传输-Stream
[22:08:36] [左] 200 MODE S ok.
[22:08:36] [左] PASV //设置传输模式为被动-PASsiVe
[22:08:36] [左] 227 Entering Passive Mode (220,189,192,22,7,185)
[22:08:36] [右] PORT 220,189,192,22,7,185 //设置传输模式为主动-PORT
[22:08:36] [右] 200 PORT Command successful.
[22:08:36] [右] STOR momo-fs-sample.avi //存储文件-STORe
[22:08:36] [右] 150 Opening BINARY mode data connection for momo-fs-sample.avi.
[22:08:36] [左] RETR momo-fs-sample.avi //获取文件-RETRieve
[22:08:37] [左] 150 Opening BINARY mode data connection for momo-fs-sample.avi (15564800 Bytes).


  在传输的同时跟上一节一样,我们进入命令行,输入netstat -n,显示当前TCP连接如下:

QUOTE:

C:\Documents and Settings\sk>netstat -n

Active Connections

 Proto  Local Address          Foreign Address        State
 TCP    222.92.3.6:1478        220.189.192.22:27321   ESTABLISHED
 TCP    222.92.3.6:1479        221.6.158.121:22       ESTABLISHED
(TCP    222.92.3.6:1480        221.6.158.121:1339     ESTABLISHED)
(TCP    222.92.3.6:1481        220.189.192.22:1971    ESTABLISHED) //这里同样有两个列目录时的TCP连接,存在时间很短


  如果在左窗口服务器上作netstat显示,会看到这样两个连接:

QUOTE:

Active Connections

 Proto  Local Address          Foreign Address        State
 TCP    220.189.192.22:27321   222.92.3.6:1478        ESTABLISHED
(TCP    220.189.192.22:1971    222.92.3.6:1481        ESTABLISHED) //客户端列目录返回信息通道
 TCP    220.189.192.22:1977    221.6.158.121:21     ESTABLISHED


  而右窗口服务器netstat显示如下:

QUOTE:

Active Connections

 Proto  Local Address          Foreign Address        State
 TCP    221.6.158.121:22       222.92.3.6:1479        ESTABLISHED
(TCP    221.6.158.121:1339     222.92.3.6:1480        ESTABLISHED) //客户端列目录返回信息通道
 TCP    221.6.158.121:21     220.189.192.22:1977    ESTABLISHED


  很明显,客户端这时只须维护两个控制连接,而控制连接对客户端带宽的占用微乎其微;数据连接存在于两服务器之间,而两服务器之间带宽一般都很高,可以进行高速的传输。我们分析两服务器的任意一边,都会发现它的控制连接和数据连接的对端地址不一样,如果要禁止FXP,阻止跟控制连接对端不同的地址进行数据连接即可。

  好了,我们做个归纳,FXP的基本流程如下:
  1.客户端分别与两服务器建立控制连接,提交帐户密码登录。
  2.如果客户端需要列目录,则分别设置文件传输类型和传输模式,两服务器返回响应。客户端在两条数据连接上分别获取两边的目录列表。
  3.客户端设置文件传输类型,然后向一边发送PASV指令,获得监听端口,以PORT指令告知另一边,两边建立数据连接,进行高速的信息交互。(FlashFXP一个贴心之处就是能自动换边,如果一边不支持PASV就换另一边,省去手动设置的麻烦。)

  本节例子用图表表示流程如下(省略TCP连接的关闭):

QUOTE:

TCP  222.92.3.6:1478 ----Syn----> 220.189.192.22:27321
TCP  222.92.3.6:1478 <--Ack Syn-- 220.189.192.22:27321
TCP  222.92.3.6:1478 ----Ack----> 220.189.192.22:27321 //TCP三次握手,与左边服务器建立控制连接

TCP  222.92.3.6:1478 <--Login-> 220.189.192.22:27321 //登录左边服务器
TCP  222.92.3.6:1478 <--SYST--> 220.189.192.22:27321 //查询左边服务器系统类型
TCP  222.92.3.6:1478 <--FEAT--> 220.189.192.22:27321 //查询左边服务器支持指令集特性
TCP  222.92.3.6:1478 <--CLNT--> 220.189.192.22:27321 //提交客户端版本
TCP  222.92.3.6:1478 <--PWD---> 220.189.192.22:27321 //提示当前目录

TCP  222.92.3.6:1479 ----Syn----> 221.6.158.121:22
TCP  222.92.3.6:1479 <--Ack Syn-- 221.6.158.121:22
TCP  222.92.3.6:1479 ----Ack----> 221.6.158.121:22 //TCP三次握手,与右边服务器建立控制连接

TCP  222.92.3.6:1479 <--Login-> 221.6.158.121:22 //登录右边服务器
TCP  222.92.3.6:1479 <--SYST--> 221.6.158.121:22 //查询右边服务器系统类型
TCP  222.92.3.6:1479 <--FEAT--> 221.6.158.121:22 //查询右边服务器支持指令集特性
TCP  222.92.3.6:1479 <--CLNT--> 221.6.158.121:22 //提交客户端版本
TCP  222.92.3.6:1479 <--CWD---> 221.6.158.121:22 //切换目录
TCP  222.92.3.6:1479 <--PWD---> 221.6.158.121:22 //提示当前目录
TCP  222.92.3.6:1479 <--TYPE--> 221.6.158.121:22 //设置文件传输类型为ASCII
TCP  222.92.3.6:1479 ---PASV--> 221.6.158.121:22 //设置传输模式为被动
TCP  222.92.3.6:1479 <-socket-- 221.6.158.121:22 //右边服务器返回监听端口1339

TCP  222.92.3.6:1480 ----Syn----> 221.6.158.121:1339
TCP  222.92.3.6:1480 <--Ack Syn-- 221.6.158.121:1339
TCP  222.92.3.6:1480 ----Ack----> 221.6.158.121:1339 //TCP三次握手,与右边服务器建立数据连接

TCP  222.92.3.6:1479 --LIST--> 221.6.158.121:22 //向右边服务器发出列目录指令
TCP  222.92.3.6:1480 <--data-- 221.6.158.121:1339 //右边服务器返回目录信息

TCP  222.92.3.6:1478 <--CWD---> 220.189.192.22:27321 //切换左边服务器目录
TCP  222.92.3.6:1478 <--PWD---> 220.189.192.22:27321 //提示当前目录
TCP  222.92.3.6:1478 <--TYPE--> 220.189.192.22:27321 //设置文件传输类型为ASCII
TCP  222.92.3.6:1478 <--MODE--> 220.189.192.22:27321 //启用压缩传输
TCP  222.92.3.6:1478 ---PASV--> 220.189.192.22:27321 //设置传输模式为被动
TCP  222.92.3.6:1478 <-socket-- 220.189.192.22:27321 //左边服务器返回监听端口1971

TCP  222.92.3.6:1481 ----Syn----> 220.189.192.22:1971
TCP  222.92.3.6:1481 <--Ack Syn-- 220.189.192.22:1971
TCP  222.92.3.6:1481 ----Ack----> 220.189.192.22:1971 //TCP三次握手,与左边服务器建立数据连接

TCP  222.92.3.6:1478 --LIST--> 220.189.192.22:27321 //向左边服务器发出列目录指令
TCP  222.92.3.6:1481 <--data-- 220.189.192.22:1971 //左边服务器返回目录信息

TCP  222.92.3.6:1478 <--TYPE--> 220.189.192.22:27321 //设置文件传输类型为BINARY(左)
TCP  222.92.3.6:1479 <--TYPE--> 221.6.158.121:22 //设置文件传输类型为BINARY(右)
TCP  222.92.3.6:1478 <--MODE--> 220.189.192.22:27321 //启用流传输(左)
TCP  222.92.3.6:1478 ---PASV--> 220.189.192.22:27321 //设置传输模式为被动(左)
TCP  222.92.3.6:1478 <-socket-- 220.189.192.22:27321 //左边服务器返回监听端口1977
TCP  222.92.3.6:1479 ---PORT--> 221.6.158.121:22 //设置传输模式为主动(右)

TCP  221.6.158.121:21 ----Syn----> 220.189.192.22:1977
TCP  221.6.158.121:21 <--Ack Syn-- 220.189.192.22:1977
TCP  221.6.158.121:21 ----Ack----> 220.189.192.22:1977 //TCP三次握手,右边服务器发起连接,与左边服务器建立数据连接

TCP  222.92.3.6:1479 ---STOR--> 221.6.158.121:22 //存储文件(右)
TCP  222.92.3.6:1478 ---RETR--> 220.189.192.22:27321 //获取文件(左)
TCP  221.6.158.121:21 <-data- 220.189.192.22:1977 //左边服务器将文件传输至右边服务器




CHAP 3.

  这一节我们引入NAT(Network Address Translation),来看看FTP经过网络地址转换以后的会话是个什么样,以及需要注意哪些问题。

  NAT最初是作为缓解IPv4地址短缺而提出的一个解决方案(最新的规范应该是RFC3022 http://www.ietf.org/rfc/rfc3022.txt),但是由于它额外提供的对外隐蔽内部网络结构的特性,如今已被普遍应用。

  NAT大致可分两类:
  1.Basic NAT-基本NAT。这类NAT又可分为静态和动态两种。内部网络的数据包在路由至外部网络之前,IP首部中的私有地址将被一对一地转换成合法地址,然后转发出去。静态和动态不同之处在于,静态转换的一对一转换是固定的,而动态转换是从NAT合法地址池中随机选取未用的地址作一对一转换。
  2.NAPT(Network Address Port Translation)-网络地址端口转换。这种转换经常是用一个合法地址来转换所有的内部地址,为了区分不同内部主机发起的连接会话,NAPT需要在IP的上层协议中再寻找一种可作鉴别的标志,对于TCP或UDP,NAPT选择Port,对于ICMP,NAPT选择query ID作为鉴别标志并进行转换。这是现在用的最多的一种NAT,也是这一节将要讨论的NAT形式。

  一个未经特殊配置的NAPT具有这样的特性:允许从内部到外部的主动连接,而从外部到内部的主动连接(我们称其为不请自来的连接)则被禁止。前两个小节我们讨论过,FTP如何使用TCP建立控制连接和数据连接,以及数据连接的两种模式--PASV和PORT。结合NAPT的特性,我们可以发现,在NAPT环境下,TCP三次握手的第一次Syn同步请求是个关键。下面就详细的描述这三次握手是怎样通过NAPT的:

  假设客户端处于内网,主机IP地址172.30.2.3/24,NAPT设备内部接口IP地址172.30.2.1/24,外部接口IP地址222.92.3.6,服务器具有公众网IP地址220.189.192.22。
  1.客户端随机选取端口1366向服务器控制端口27321发起控制连接同步请求(即TCP首部Syn标志位置1),生成的IP报文经本机TCP/IP协议栈检查发现,目的地址不在本地网络,于是将它投递给默认网关,也就是NAPT设备的内部接口(此处省略ARP及MAC层的一些操作,下同,有兴趣的可以参考相关资料),NAPT设备收到此IP报文以后,首先递交给路由引擎,路由引擎发现此报文目的地址位于外部网络一侧,决定将此报文从外部接口转发出去,在转发之前报文被递交给NAT引擎,NAT引擎将IP首部的源地址172.30.2.3修改为222.92.3.6,TCP首部的源端口1366修改为1103(一般也是随机选取),同时在NAT转换表中添加类似这样一条记录“TCP - 172.30.2.3:1366 - 222.92.3.6:1103 - 220.189.192.22:27321”,最后,将此IP报文从NAPT外部接口转发出去,经过互联网的一系列路由最终到达服务器。第一次握手结束。至此,客户端和服务器之间的一条双向通道实际上已经建立,但三次握手还未完结,我们接着往下看。
  2.服务器收到客户端的Syn同步请求后,将返回一个Ack确认和反方向Syn同步请求(TCP首部Ack和Syn标志位同时置1),生成的IP报文经本机TCP/IP协议栈检查发现目的地址222.92.3.6不在本地网络(服务器收到的Syn同步请求来自222.92.3.6:1103,是经过NAPT修改的),于是也投递给本地网关,经过互联网一系列路由到达NAPT的外部接口,然后先递交给NAT引擎,NAT引擎发现报文符合记录“TCP - 172.30.2.3:1366 - 222.92.3.6:1103 - 220.189.192.22:27321”的转换条件,于是将报文IP首部的目的地址222.92.3.6修改为172.30.2.3,TCP首部的目的端口1103修改为1366,并交给路由引擎,路由引擎判断此报文的目的地址位于内部网络,于是将此报文从内部接口转发给客户端,第二次握手结束。
  3.第三次握手Ack确认过程与第一次握手Syn请求类似,不再赘述。到这一步为止,TCP连接才真正建立,双方可以畅通的进行数据交互,直到这个TCP连接关闭,NAPT中的那条转换记录也随之删除。

  上面的过程虽然是用控制连接举例,但数据连接其实也一样,都要经过TCP三次握手。一旦连接建立,对客户端和服务器来说,两者之间的数据交互就是透明的,好像NAPT不存在一样。用图来表示这个三次握手过程如下:

  SS代表Source Socket,源地址和端口;DS代表Destination Socket,目的地址和端口;圆角方框代表IP报文



  如果此时客户端向服务器发送PORT指令,要求服务器向客户端发起数据连接,一般情况下我们会发现服务器发出的Syn同步请求报文在其本地网关处即被丢弃,为什么呢?前两节我们说过,PORT指令是在控制连接上送往服务器的,而客户端生成的PORT指令中包含的是本机的IP地址和监听端口,例如“172.30.2.3:1370”,服务器收到这个报文以后,试图向客户端发起数据连接,生成的Syn同步请求报文的目的地址和端口就是“172.30.2.3:1370”,这样的目的地址在互联网上是不能被路由的,所以一般在其本地网关处就被丢弃了。那么有没有例外的情况呢,有两种可能的例外:
  第一种情况,NAPT设备支持FTP的PORT模式。NAPT会检查控制连接上出去的所有FTP报文,一旦发现报文内容中有PORT指令,便自动生成一条端口转发记录(俗称端口映射),类似这样“TCP 222.92.3.6:1211 -> 172.30.2.3:1370”,然后将PORT指令中的172.30.2.3:1370修改为222.92.3.6:1211转发给服务器,这样服务器生成的Syn同步请求报文目的地址和端口就是222.92.3.6:1211,能顺利的到达NAPT并被转发给客户端。如果你的NAT设备恰好支持这样的特殊实现,是十分幸运的一件事,但不幸的是,多数这样的实现只支持控制端口为21的FTP服务器,本节的服务器控制端口是27321,还是行不通。
  第二种情况,NAPT设备上手动作端口转发,并在客户端软件上作相应配置。以FlashFXP为例,修改参数配置里的数据连接设置,例如下图,限制一个本地端口范围(如果线程比较多范围就设大一些),在“强制活动模式使用此IP”处填入NAPT的外部接口地址,然后在NAT设备上作端口映射,注意要和刚才限制的本地端口范围一一对应。这样客户端发出的PORT指令所带的地址就是合法的NAPT外部接口地址,服务器可以顺利的和客户端建立数据连接了。



  好了,说到这里,相信大家对NAPT环境下的PASV和PORT模式应该有了更深的认识,其实说白了就一句话,具有公众网地址的主机可以被动的接受连接,而具有私有地址的主机要想被动的接受连接必须要在NAT上作端口映射。

  我们以一个FXP会话结束这一小节,考虑一种最不利的情况--FXP的三方都处于内网,如下图所示:



  图中的服务器A位于NAPT A后面,私有地址10.254.5.8,管理员已经在NAPT A上做了控制端口27321->21的转发(考虑一下为什么要做控制端口的转发)以及数据端口1200-1219的转发,并在服务端软件上作了相应配置,这意味着服务器A可以支持PASV模式的数据连接(如下二图。以常用的服务端软件Serv-U为例,与上文FlashFXP设置内网PORT模式类似,我们也可以设置内网服务端支持PASV模式)。服务器B位于NAPT B后面,私有地址192.168.2.55,管理员比较懒,只在NAPT B上做了控制端口22->21的转发,这意味着服务器B只能支持PORT模式的数据连接(可以考虑一下服务器A和B为什么会有这样的不同)。客户端C位于NAPT C后面,考虑到客户端软件列目录的需要以及服务器B只支持PORT模式,我们在NAPT C上做了数据端口1370-1379的转发,并在客户端软件上作相应配置(如上文第二种情况所述);如果NAPT C能支持FTP的PORT模式作自动端口转发并且服务器B的控制端口(外部)是21的话,那就省事多了。





  下面就是五个TCP连接建立过程的图表表示(FXP流程可参考CHAP 2.):

加入收藏】【告诉好友】【打印此文】【关闭窗口
上一篇教程  
下一篇教程  
 
网友评论:(评论内容只代表网友观点,与本站立场无关!)
 姓 名:
 评 分: 1分 2分 3分 4分 5分
 内 容:
计算机应用技巧资讯站 版权所有 粤ICP备05000897号  
Copyright © 2006 www.00083.com Inc. All rights reserved.
软件技术交流群:5895132 硬件技术交流群:19441759 QQ书籍交流群#1:15823216 QQ书籍交流群#2:18211070