FTP 是相当古老的传输协议之一,他最主要的功能是在服务器与客户端之间进行文件的传输。 FTP其实是以 TCP封包的模式进行服务器与客户端计算机之间的联机,当联机建立后,使用者可以在客户端端连上 FTP服务器来进行档案的下载与上传。目前在开源操作系统中常用的FTPD套件主要有vsFTPd、ProFTPD、PureFTPd和wuftpd等,而vsFTPd是一款在Linux发行版中最受推崇的FTP服务器程序,特点是小巧轻快,安全易用,vsftpd意思为“very secure FTP daemon(非常安全的FTP进程)。
二、控制通道和数据通道
FTP会话时包含了两个通道,一个叫控制通道,一个叫数据通道,对应端口是21端口和20端口。我们知道22端口是SSH,23端口是telnet,25端口是邮件服务。一般1024以下端口都是服务程序,1024以上端口都是第三方应用程序。
客户端想要获取存放在服务器上的文件时,应先通过一个预定义的端口号21主动与服务器建立连接,服务器收到请求后,通过3次握手,就可在进行FTP命令处理的用户协议解释器(PI)和服务器协议解释器之间建立一条TCP连接。
该连接始终等待用户和服务器之间的通信,并传输用户输入的所有FTP命令和服务器的应答,即FTP传输中的命令连接。
当客户通过交互式用户界面向FTP服务器发出要下载服务器上某一文件的命令时,该命令即被送到用户协议解释器,并由用户协议解释器进行处理。FTP将在服务器端口号20上打开一个数据TCP连接。在数据连接上传送完本次请求需传送的文件之后,它将关闭数据连接,直到再有文件传送请求时再重新打开。
因此,在FTP中,控制连接在整个用户会话期间一直打开着,而数据连接则是一条临时连接,当且仅当执行文件传输过程时才被创建。
三、主动模式和被动模式
FTP链接有两种方式,主动方式和被动方式
1、PORT模式(主动方式)
FTP 客户端首先和FTP Server的TCP 21端口建立连接,通过这个通道发送命令,客户端需要接收数据的时候在这个通道上发送PORT命令。 PORT命令包含了客户端用什么端口(一个大于1024的端口)接收数据。在传送数据的时候,服务器端通过自己的TCP 20端口发送数据。 FTP server必须和客户端建立一个新的连接用来传送数据。
主动过程如下:
A、 S端要开启20、21端口;
B、 C端一个随机端口连接S端21,这个随机范围1024-65536,同时发送命令port+x,指明数据端口C(X)->S(21);
C、 S端收到命令后,将返回一个ACK,S(21)->C(X);
D、 S端将用自己的20端口与C端的X+1端口相连,S(20)->C(X+1);
E、 C给S返回ACT,C(X+1)->S(20).
配置文件:
connect_from_port_20=YES
#主动式连接使用的数据通道
pasv_enable=NO
#支持数据流的被动式连接模式
2、PASV模式(被动方式)
在建立控制通道的时候和PORT模式类似,当客户端通过这个通道发送 PASV命令的时候,FTPserver打开一个位于1024和5000之间的随机端口并且通知客户端在这个端口上传送数据的请求,然后FTP server将通过这个端口进行数据的传送,这个时候FTP server不再需要建立一个新的和客户端之间的连接传送数据。
被动连接过程:
A、
S服务器端要开启21端口和大于1024tcp端口;
B、
C以一个随机端口X与S的21端口相连,这个随机端口范围为1024~65535,并发送命令 PASV. C(X)-> S(21)
C、
S收到命令,返回一个ACK,并在其中指明一个新的高位端口y. S(21) -> C(x)
D、
C发起 x+1端口到S的y的端口的连接.C(x+1) -> S(y)
E、
S返回一个ACK. S(y) ->C(x+1)
被动配置:
connect_from_port_20=NO(默认)
#主动式连接使用的数据通道
pasv_enable=YES
#支持数据流的被动式连接模式
pasv_min_port=1024
pasv_max_port=65536
四、连接方式
ftp支持用户类型1、匿名用户2、本地用户3、虚拟用户。其中匿名用户的用户名是anonymous,密码为空。Vsftpd两种运行模式,1、standlone(xinetd),一次启动,独立运行;2、inetd外部请求才调用。
1、 cmd命令里面输入ftp命令:
ftp 里面命令还有lcd、!dir、put等等,不深究。
2、 IE输入ftp://192.168.1.1
3、 windows资源管理器
在我的电脑上输入ftp://192.168.1.1,即可打开ftp服务器。
4、 第三方软件,如FileZilla
直接在主机输入:192.168.1.1和端口号:21,点击连接即可打开,如下:
五、配置文件
学习一个网络服务,最主要的就是学习它的配置文件。Vsftp的配置文件时vsftpd.conf:
anonymous_enable=YES
write_enable=YES
anon_umask=022
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
listen=YES
ftp_username=nobody
anon_root=/ftproot
anon_max_rate=0
与配置文件相关的目录:
/usr/sbin/vsftpd ---- VSFTPD的主程序(必需)----Y850里:/usr/bin/vsftpd
/etc/rc.d/init.d/vsftpd ---- 启动脚本
/etc/vsftpd.conf ---- 主配置文件(必需)
/etc/pam.d/vsftpd ---- PAM认证文件
/etc/vsftpd.ftpusers ---- 禁止使用VSFTPD的用户列表文件
/etc/vsftpd.user_list ---- 禁止或允许使用VSFTPD的用户列表文件
/etc/userconf ------ 指定用户个人配置文件所在的目录
/var/ftp ---- 匿名用户主目录------------------ Y850里:/ftproot
/var/ftp/pub---- 匿名用户的上传目录---- Y850里:/ftproot/sacard
/var/log/vsftpd.log ------- 日志文件
除vsftpd、vsftpd.conf两个文件外,其他文件的需要具体看主配置文件的配置
vsftpd.conf的具体配置可以网上资料查询,挺多的,不一一介绍了
六、抓包分析
1、三次握手,命令端口建立连接,匿名登录成功
2、三次握手,数据端口建立连接
七、遇到问题
在移植vsftpd过程中遇到较多问题,但最主要的是编译问题,简单描述一下。OpenEmbedded(OE)前面已经介绍过,OE环境中最重要的目录有3个:放工具的bitbake目录、放元数据的目录、和执行构建的build目录。在程序员看来,OpenEmbedded是一些脚本(shell和python脚本)和数据构成的自动构建系统。
脚本实现构建过程,包括下载(fetch)、解包(unpack)、打补丁(patch)、configure(如果使用了autotool)、编译(compile)、安装(install)、打包(package)、staging(以后讨论)、做安装包(package_write_ipk)、构建文件系统等。
刚开始autotool,就遇到严重问题。Vsftp源码直接用的是Makefile,为了和源码移植,刚开始编写了如下文件:
但是遇到不可解问题。
后来放弃autotool方法,直接用源码的Makefile,但是在打包的过程出错。
最终不得已,在core-app_git.bb里加入:
install -m 0755 ${S}/vsftpd/vsftpd.conf -D ${D}${sysconfdir}/
install -m 0755 ${S}/vsftpd/vsftpd -D${D}/usr/bin
其他关于vsftpd问题(记录一下),
我们的GCC路径:
apps_proc/oe-core/build/tmp-eglibc/sysroots/x86_64-linux/usr/bin/armv7a-vfp-neon-oe-linux-gnueabi/arm-oe-linux-gnueabi-gcc
1、 Make编译时出现error: undefined reference to 'cap_get_proc问题
解决:
#elif locate_library /lib/libcap.so.2; then
# echo"/lib/libcap.so.2";
2、 make编译出现error: undefined reference to `crypt'
解决方法:
vim Makefile
LIBS = `./vsf_findlibs.sh`
末尾增加 -lcrypt变成
LIBS = `./vsf_findlibs.sh` -lcrypt
3、用FileZilla连接调试,加入如下代码,创建新的目录。
IMAGE_PREPROCESS_COMMAND+= "mkdir -p ${IMAGE_ROOTFS}/nonexistent;"
IMAGE_PREPROCESS_COMMAND+= "mkdir -p ${USR_IMAGE_ROOTFS}/share/empty;"
IMAGE_PREPROCESS_COMMAND+= "mkdir -p ${IMAGE_ROOTFS}/ftproot/sdcard;"
4、源码权限问题
在postprivparent.c里,重点关注这个函数
minimize_privilege(structvsf_session* p_sess)
vsf_secutil_change_credentials(&user_str, &dir_str, 0, caps,
VSF_SECUTIL_OPTION_CHROOT);
5、当时发现socket错误,用了这么一句话:
snprintf(name,16,"1,%d.%s",error,strerror(retrun));
非常重要的一种调试方法