前言

在前面一篇文章中 vsftpd 的调试环境的搭建, 我们搭建了一个 vsftpd 的一个调试环境

既然搭建了一个调试环境, 目的就是为了能够调试 vsftpd, 如果 不去调试, 那岂非毫无意义

这里 就拿相对比较简单的登录流程 来进行开刀

呵呵 虽然只是简单的登录流程, 但是 代码的设计还是颇为复杂, 初看的话 也很容易 迷糊

里面对于 多进程的使用, 多进程来组合完成 ftp服务, 多进程之间的数据交互, 着实还是有一些 令人头痛(头秃)的地方的

并且 由于处理业务使用的是 多进程的模式, 调试也非常不方便

以下调试基于 vsftpd 3.0.2, 配置均基于 源码仓库的默认配置

ftp 的登录

master:~ jerry$ ftp
ftp> open 192.168.202.133
Connected to 192.168.202.133.
220 this is greeting
Name (192.168.202.133:jerry): root
331 Please specify the password.
Password:
230 Login successful.

ftp 客户端 & 服务端 tcp 交互

一下为 以上命令 的过程中, 客户端 和 服务端的 协议交互概览信息

其中 192.168.202.1 为 ftp 客户端, 也就是我本机, 192.168.202.133 为服务端, 虚拟机里面的一个 ftp 服务器

10   0.005591    192.168.202.133 192.168.202.1   FTP 88  Response: 220 this is greeting
12  1.224853    192.168.202.1   192.168.202.133 FTP 77  Request: USER root
14  1.225629    192.168.202.133 192.168.202.1   FTP 100 Response: 331 Please specify the password.
16  1.989461    192.168.202.1   192.168.202.133 FTP 77  Request: PASS root
20  2.034438    192.168.202.133 192.168.202.1   FTP 89  Response: 230 Login successful.

vsftpd 服务器的启动

首先我们来看一下 它绑定的端口, 从代码中可以看到 取到的是 21, 可以通过配置 listen_port 来修改这个端口

但是 从下面的 p_sockaddr.u.u_sockaddr_in.sin_port 看到的是 5376, 这两者是什么对应关系 ?

21 = 0x0015
htons(0x0015) = 0x1500 = 5376

服务创建了之后 可以看到 开始在这里不断的接收连接了

open 192.168.202.133

当我们输入了 open 192.168.202.133 之后, 两台机器之间会有如下 协议数据交互

1    0.000000    192.168.202.1   192.168.202.133 TCP 78  54946 → 21 [SYN, ECN, CWR] Seq=0 Win=65535 Len=0 MSS=1460 WS=64 TSval=1002536282 TSecr=0 SACK_PERM=1
2   0.000358    192.168.202.133 192.168.202.1   TCP 74  21 → 54946 [SYN, ACK, ECN] Seq=0 Ack=1 Win=28960 Len=0 MSS=1460 SACK_PERM=1 TSval=11985962 TSecr=1002536282 WS=128
3   0.000428    192.168.202.1   192.168.202.133 TCP 66  54946 → 21 [ACK] Seq=1 Ack=1 Win=131712 Len=0 TSval=1002536282 TSecr=11985962
4   0.004275    192.168.202.133 192.168.202.1   FTP 88  Response: 220-this is greeting
5   0.004342    192.168.202.1   192.168.202.133 TCP 66  54946 → 21 [ACK] Seq=1 Ack=23 Win=131712 Len=0 TSval=1002536286 TSecr=11985963
6   0.004366    192.168.202.133 192.168.202.1   FTP 72  Response: 220
7   0.004380    192.168.202.1   192.168.202.133 TCP 66  54946 → 21 [ACK] Seq=1 Ack=29 Win=131712 Len=0 TSval=1002536286 TSecr=11985963

前三行对应的是 tcp 客户端, 服务端建立请求的三次握手

第 4, 6 行对应的是 ftp 服务器响应个客户端的一个 友好问候提示, 客户端收到 数据之后 提示用户输入密码

第 5, 7 行分别对应的是, 第 4, 6 行的 tcp 确认请求

可以看到我们 open 之后是没有录入端口到信息, 这里使用的是 默认的 21 端口作为 控制端口

当客户端的请求来到服务端, 我们先看一下 请求的相关信息, p_accept_addr 为客户端的相关信息

# 服务器拿到的客户端的端口
14551 = 0x38D7
htons(port) = 0x38D7
port = 0xD738 = 55096# 服务器拿到的 客户端的 ip
30058688 = 0x1CAA8C0
htons(ip) = 0x1CAA8C0
ip = 0xc0a8ca01 = 192.168.202.1

当然也有现成的工具方法来解析 ip 和 端口, 比如如下 156 行的 println3 输出的结果如下

40697 - 192.168.202.1 <- host & port -> 55096

然后再来看看 处理这个 tcp 请求的逻辑

可以看到的是 fork 了一个子进程出来

父进程处理的事情就是 记录了一下客户端的信息, 然后继续 去阻塞接受请求了

子进程的处理是 return 了, 继续走 standalone_main 之后的处理

到此为止 可以再 ide 里面调试的东西 就这些了, 呵呵 因为处理业务的进程是 fork 了一个进程来进行处理

vsf_standalone_main fork 的子线程

调试tips

所以 只能通过一些"输出" 之类的方式来进行调试了

并且 普通的 printf 是不行的, 因为 printf 的数据会被返回给客户端, 导致客户端 数据异常, 我这里采用的方式是 输出到 日志文件

子进程在默认的配合下面 会走 main 后面的 vsf_two_process_start

以下截图省略掉了一部分我们这里不太关心的代码, priv_sock_init 里面初始化了两个 fd, parent_id, child_fd, 用于 之后的父子进程进行通讯

然后 之后父进程进入等待子进程和客户端进行输入用户名, 密码的交互

子进程发送 友好问候信息[提示客户端输入用户名], 也就是 上面的 "220 this is greeting"

vsf_two_process_start fork 的子线程

子进程需要执行的 init_connection 如下, 如果启动 ftp 服务, 需要给客户端 greeting

然后之后 进入与客户端进行交互的 repl

greeting 消息的处理, banner_str 表示的是 banner_file 解析出来的配置信息, 在 main 方法里面配置的

另外可以手动配置 ftpd_banner 作为 banner 返回

默认的 banner 为 (vsFTPd $version)

和客户端交互的 认证相关操作, 这里省略了一些其他的 认证方式, 只留下了我们这里的 用户名 密码 的认证

ftp 客户端拿到了 服务器传递的 greeting 的信息之后, 会提示输入 用户, 也就是接下来的 "Name (192.168.202.133:jerry): root"

这个 greeting 信息对应于上面的 ftp 响应 "Response: 220 this is greeting"

Name (192.168.202.133:jerry): root

客户端提示用户输入用户名, 录入用户名 回车之后, 客户端发送 请求给服务端, 也就是上面的 ftp 请求 "Request: USER root"

处理请求的业务代码大致如下[省略了一部分ssl相关的校验代码], 对于上下文比较重要的就是设置了 user_str 的值, 其他的大部分为数据校验

最后, 如果匿名用户不需要密码 直接走登录流程, 如果需要密码, 返回 ftp 响应 "331 Please specify the password."

Password: ****

客户端拿到了 "331 Please specify the password.", 之后提示用户输入密码

331 Please specify the password.
Password: 

用户录入了密码之后, 客户端发送请求给服务端, 也就是上面的 ftp 请求 "Request: PASS root"

处理请求的业务代码大致如下, 主要是将业务委托给了 vsf_two_process_login, 带上了 session 和 ftp_arg_str[用户输入的密码]

vsf_two_process_login 的处理流程大致如下, 封装了一个命令, 并带上了需要的几个参数, 用户名 密码, use_ssl 等相关参数

和它的父进程进行交互, 它的父进程 也就是 vsf_standalone_main fork 出来的子进程, 如果是登录成功之后, 当前这个进程就已经完成了它的事情了, exit

如果登录失败 继续进入 parse_username_password 的循环流程, 客户端可以再传入密码, 或者其他的方式

对于登录失败的场景, 我们这里的 ftp 客户端的处理方式很简单 你需要重新建立连接

登录的业务处理

那么 登录的逻辑是在哪里处理的呢?

上面 的子进程吧用户录入的用户名密码 等信息交给了父进程, 也就是 vsf_standalone_main fork 的子进程, vsf_two_process_start 中的父进程

复制上面的这张图下来, 可以看到的是 父进程是进入了一个 while(true), 处理的函数是 process_login_req, 呵呵 名字还是 很符合实际意义的

这里面等待的是 子进程发送消息过来, 校验了一下消息, 然后获取参数 等等, 校验用户名密码, 是否有效

如果登录失败 返回标记给 子进程, 如果登录成功 最终调用核心处理函数 common_do_login 走登录之后的流程

具体的用户名密码的校验是基于 PAM认证机制, 有兴趣可以了解了解

common_do_login fork 子进程

然后我们来看看 common_do_login 的相关处理

这里我们可以看到 上面的 和 vsf_two_process_start 类似的处理方式

priv_sock_init 创建了一个 socket pair 来供父子进程交互

子进程走的是 process_post_login, 接受客户端的请求并处理

父进程走的是 vsf_priv_partent_postlogin, 主要是 子进程这边有什么需要进行业务的支撑

process_post_login 的处理就是 和 ftp 客户端登录之后的相关交互了

另外就是 登录成功之后的 ftp 响应 "230 Login successful." 来自于这里

以上 ftp 请求/响应

ftp 请求 "USER root", 格式为 请求命令 + 空格 + 参数.. + \r\n

ftp 响应 "331 Please specify the password.“, 格式为 响应码 + 空格 + 响应内容 + \r\n

其他的请求响应 不多加赘述, 类似的

FileZilla 的一次登录

可以看出的是, 大致的流程是和 命令行的 ftp 客户端的登录流程一致

使用 用户名, 密码 验证之前尝试使用 auth 来进行验证, 但是我服务器不支持 ssl, 因此这段处理 走的是 ”vsf_cmdio_write(p_sess, FTP_LOGINERR,                         "Please login with USER and PASS.");“

最后尝试使用  明文的 用户名, 密码进行的登录

登录之后 客户端自动发起了一些请求用于支撑客户端的展示, 以及业务使用等等, 比如这里的 SYST, PWD, LIST 等等

4    0.004657    192.168.202.133 192.168.202.1   FTP 88  Response: 220-this is greeting
6   0.004733    192.168.202.133 192.168.202.1   FTP 72  Response: 220
8   0.005402    192.168.202.1   192.168.202.133 FTP 76  Request: AUTH TLS
10  0.005663    192.168.202.133 192.168.202.1   FTP 104 Response: 530 Please login with USER and PASS.
12  0.005765    192.168.202.1   192.168.202.133 FTP 76  Request: AUTH SSL
13  0.005838    192.168.202.133 192.168.202.1   FTP 104 Response: 530 Please login with USER and PASS.
15  2.200732    192.168.202.1   192.168.202.133 FTP 77  Request: USER root
16  2.201208    192.168.202.133 192.168.202.1   FTP 100 Response: 331 Please specify the password.
18  2.201349    192.168.202.1   192.168.202.133 FTP 77  Request: PASS root
20  2.257612    192.168.202.133 192.168.202.1   FTP 89  Response: 230 Login successful.
22  2.257870    192.168.202.1   192.168.202.133 FTP 72  Request: SYST
24  2.259606    192.168.202.133 192.168.202.1   FTP 85  Response: 215 UNIX Type: L8
26  2.259859    192.168.202.1   192.168.202.133 FTP 72  Request: FEAT
27  2.260888    192.168.202.133 192.168.202.1   FTP 81  Response: 211-Features:
29  2.261840    192.168.202.133 192.168.202.1   FTP 73  Response:  EPRT
31  2.262123    192.168.202.133 192.168.202.1   FTP 73  Response:  EPSV
33  2.262237    192.168.202.133 192.168.202.1   FTP 73  Response:  MDTM
35  2.262311    192.168.202.133 192.168.202.1   FTP 73  Response:  PASV
37  2.263128    192.168.202.133 192.168.202.1   FTP 80  Response:  REST STREAM
39  2.263194    192.168.202.133 192.168.202.1   FTP 73  Response:  SIZE
41  2.263916    192.168.202.133 192.168.202.1   FTP 73  Response:  TVFS
43  2.264924    192.168.202.133 192.168.202.1   FTP 73  Response:  UTF8
45  2.265039    192.168.202.133 192.168.202.1   FTP 75  Response: 211 End
47  2.265168    192.168.202.1   192.168.202.133 FTP 80  Request: OPTS UTF8 ON
48  2.267011    192.168.202.133 192.168.202.1   FTP 92  Response: 200 Always in UTF8 mode.
50  2.269004    192.168.202.1   192.168.202.133 FTP 71  Request: PWD
51  2.270520    192.168.202.133 192.168.202.1   FTP 79  Response: 257 "/root"
53  2.277446    192.168.202.1   192.168.202.133 FTP 74  Request: TYPE I
54  2.278030    192.168.202.133 192.168.202.1   FTP 97  Response: 200 Switching to Binary mode.
56  2.278217    192.168.202.1   192.168.202.133 FTP 72  Request: PASV
57  2.278825    192.168.202.133 192.168.202.1   FTP 117 Response: 227 Entering Passive Mode (192,168,202,133,70,9).
60  2.281531    192.168.202.1   192.168.202.133 FTP 72  Request: LIST
63  2.283049    192.168.202.133 192.168.202.1   FTP 105 Response: 150 Here comes the directory listing.
69  2.283372    192.168.202.133 192.168.202.1   FTP 90  Response: 226 Directory send OK.
73  2.284575    192.168.202.1   192.168.202.133 FTP 83  Request: MDTM vsftpd.log
74  2.285112    192.168.202.133 192.168.202.1   FTP 86  Response: 213 20201214034847

commons.net-3.6 的客户端的登录

呵呵 和命令行的 ftp 客户端的步骤一致, 丝毫没有多余的交互

513  570.291665  192.168.202.133 192.168.202.1   FTP 88  Response: 220-this is greeting
515 570.291781  192.168.202.133 192.168.202.1   FTP 72  Response: 220
517 570.294873  192.168.202.1   192.168.202.133 FTP 77  Request: USER root
519 570.295090  192.168.202.133 192.168.202.1   FTP 100 Response: 331 Please specify the password.
521 570.295219  192.168.202.1   192.168.202.133 FTP 77  Request: PASS root
525 570.339024  192.168.202.133 192.168.202.1   FTP 89  Response: 230 Login successful.

一次登录经历过的进程

从日志可以看到 fork 了三次, 但是 从程序里面获取到的 进程号 似乎是存在问题的, newPid 不为 0 的是父进程, newPid 为 0 的是 fork 出来的子进程

40697 - 192.168.202.1 <- host & port -> 60628
40697 - 40697 - vsf_standalone_main fork with newPid - 42738
40697 - 40697 - vsf_standalone_main fork with newPid - 0
40697 -  vsf_two_process_start, forked with newPid = 2
40697 -  vsf_two_process_start, forked with newPid = 0
40697 - common_do_login, forked with newPid = 3
40697 - common_do_login, forked with newPid = 0

查看一下相关的进程, 可以看到 40697 是监听 21 端口的主进程, 在 vsf_standalone_main 里面 fork 出来的是 42738

42738 在 vsf_two_process_start 中 fork 出了 xxx[程序里面拿到的是 2], 然后登陆成功之后 exit 掉了, 所以 ps -ef 里面是看不到这个进程的

42738 在 common_do_login 中 fork 出了 42740, 用于和登陆之后的客户端的输入进行交互

root@ubuntu:~# ps -ef | grep ftp
root      40697  40695  0 14:43 pts/21   00:00:00 /root/ClionWorkStations/vsftpd/vsftpd ./vsftpd.conf
nobody    42738  40697  0 20:03 ?        00:00:00 /root/ClionWorkStations/vsftpd/vsftpd ./vsftpd.conf
root      42740  42738  0 20:03 ?        00:00:00 /root/ClionWorkStations/vsftpd/vsftpd ./vsftpd.conf

inspect 一下 vsf_two_process_start fork 出来的 xxx[程序里面拿到的是 2]

从代码中我们可以知道, 这个 2 号进程向客户端返回了 提示信息, 并在等待客户端的输入, 那么我们可以在这里 看到这个进程

ftp 客户端操作为, 等待用户输入用户名, 密码

ftp> open 192.168.202.133
Connected to 192.168.202.133.
220-this is greeting
220
Name (192.168.202.133:jerry): 

此时后台日志信息如下

40697 - 192.168.202.1 <- host & port -> 60713
40697 - 40697 - vsf_standalone_main fork with newPid - 42793
40697 - 40697 - vsf_standalone_main fork with newPid - 0
40697 -  vsf_two_process_start, forked with newPid = 2
40697 -  vsf_two_process_start, forked with newPid = 0

进程信息如下

root@ubuntu:~# ps -ef | grep ftp
root      40697  40695  0 14:43 pts/21   00:00:00 /root/ClionWorkStations/vsftpd/vsftpd ./vsftpd.conf
root      42793  40697  0 20:12 ?        00:00:00 /root/ClionWorkStations/vsftpd/vsftpd ./vsftpd.conf
nobody    42794  42793  0 20:12 ?        00:00:00 /root/ClionWorkStations/vsftpd/vsftpd ./vsftpd.conf

03 vsftpd 登录过程的调试相关推荐

  1. win7系统口令登录过程调试方法图解

    转载自:http://www.jb51.net/os/windows/81155.html Windows7以后Winlogon进程是动态的,有用户登录就会创建一个 Winlogon 进程,因此系统中 ...

  2. Windows7 口令登录过程调试

    Windows7 口令登录过程调试 基本原理     Windows7 以后 Winlogon 进程是动态的,有用户登录就会创建一个 Winlogon 进程,因此系统中完全 可能存在多个登录进程,注销 ...

  3. 【JS 逆向百例】复杂的登录过程,最新微博登录逆向

    文章目录 声明 逆向目标 登录流程 1.预登陆 2.获取加密后的密码 3.获取 token 4.获取加密后的账号 5.发送验证码 6.校验验证码 7.访问 redirect url 8.访问 cros ...

  4. linux ftp 登录慢,linux中vsftpd登录,上传下载文件慢解决办法linux操作系统 -电脑资料...

    vsftpd登录慢主要是nameserver #定义DNS服务器的IP地址没有设置了,这样我们只要设置或更新一下nameserver即可解决了, 在使用vsftpd的过程中,一直以来都有一个问题就是在 ...

  5. .net连接Sql时出现已成功与服务器建立连接,但是在登录过程中发生错误。 (provider: TCP 提供程序, error: 0 - 指定的网络名不再可用。) ...

    已成功与服务器建立连接,但是在登录过程中发生错误. (provider: TCP 提供程序, error: 0 - 指定的网络名不再可用.) 今天早上的程序还好好的,下午休息后打开程序,用户登录后发现 ...

  6. ubuntu14.04.03 vsftpd

    ubuntu14.04.03 vsftpd apt-get install vsftpd /etc/vsftpd.conf配置Example listen=YES anonymous_enable=N ...

  7. 已成功与服务器建立连接,但是在登录过程中发生错误。 (provider: SSL Provider, error: 0 - 接收到的消息异常,或格式不正确。)...

    之前做好的asp.net部署后,发现 访问数据库时: 异常:已捕获: "已成功与服务器建立连接,但是在登录过程中发生错误. (provider: SSL Provider, error: 0 ...

  8. 已成功与服务器建立连接,但是在登录过程中发生错误。 (provider: SSL Provider, error: 0 - 接收到的消息异常,或格式不正确。)

    已成功与服务器建立连接,但是在登录过程中发生错误. (provider: SSL Provider, error: 0 - 接收到的消息异常,或格式不正确.) 参考文章: (1)已成功与服务器建立连接 ...

  9. 域用户的登录过程和GC的关系

    域用户的登录过程和GC的关系 1. 模拟环境 根域为contoso.msft,dc为dc1.contoso.msft,dc2.contoso.msft同时也是GC,所处站点site 1: 子域为chi ...

  10. cas sso单点登录 登录过程和登出过程原理说明

    CAS大体原理我就不说了,网上一大把,不过具体交互流程没说清楚,所以有这篇文章,如果有错误,请多多指教 登录过程 用户第一次访问一个CAS 服务的客户web 应用时(访问URL :http://192 ...

最新文章

  1. 张小龙:我是对AI的未来表示担忧的人之一
  2. 整数转换为罗马数字 Integer to Roman
  3. linux suse最新版本,查看SUSE LINUX版本
  4. gridview的buttonfield获取该行的索引值(实例讲解)
  5. (转)网上常用免费WebServices集合
  6. VTK:图片之ImageCorrelation
  7. 微信小程序srt_微信小程序微商城(八):缓存实现商品购物车功能
  8. 分立元件封装尺寸及PCB板材工艺与设计实例
  9. javaSocket编程TCP
  10. FPGA实现sobel边缘检测并Modelsim仿真,与MATLAB实现效果对比
  11. 学习《华为基本法》(4):组织结构管理原则
  12. 从零开始前端学习[26]:html5的一些常用标签,header,footer,section,aside,figure,figcaption,nav,artical,
  13. 【家庭网络】申请安装移动宽带过程及简单建议
  14. 32位无符号整数快开方函数
  15. Web前端js实现tif文件浏览(含多页tif)
  16. linux磁盘配额步骤,Linux磁盘配额设置及使用
  17. 如何获取网站的HTTPS证书?
  18. libpng warning: iCCP: known incorrect sRGB profile 警告解决
  19. python新浪股票接口_python 爬虫sina股票数据
  20. 《统计学习方法》学习笔记 第二十一章 PageRank算法

热门文章

  1. 太阳能充电板给锂电池充电电路设计
  2. Windows10批处理文件中用regedit导入注册表文件失败的原因和解决办法
  3. SCCM配置PXE启动
  4. 计算机软考你真的了解吗?10G+干货全在这里了
  5. 软件推荐之 QttabBar
  6. wps下一步快捷键_WPS常用快捷键大全(附下载)
  7. xp系统升级到win7系统打印驱动的安装
  8. C语言游戏开发——打飞机游戏1.0
  9. 贼心不死安cuda记录-双显卡笔记本Ubuntu安装cuda9.0
  10. Spring Data JPA实战视频教程