Wireshark分析完整的Web请求过程(虚拟机NAT上网)
环境:Win11预览版+VmwarePro16+Ubuntu20.4+Wireshark
本文利用WireShark工具对虚拟机中通过NAT上网的机器进行Web请求的分析
虚拟机NAT上网:
NAT原理:
![](https://img-blog.csdnimg.cn/5bb7297fb35d4d1daf49d30e18e55568.png)
vmware中nat上网的设备主要有:
1)vmnat8:可以理解为一个交换机
2)VMware Network Adapter VMnet8:是虚拟出来的一块网卡,VMnet8仅仅是和Vmnet8虚拟机交换机网络通信的(192.168.128.0/24),并不提供路由功能。禁用掉VMware Network Adapter VMnet8网卡,虚拟机仍然能上网,只是真机与虚拟机之间不能通信。
![](https://img-blog.csdnimg.cn/7e84a175ba054fd797858ef7b65fbb2f.png)
所谓NAT模式就是将虚拟机网卡隐藏在了一个NAT设备之后,在外界看来,只能看到宿主机物理网卡,甚至连NAT设备都看不到,NAT设备默默地转换着虚拟机内部出来的连接的源地址,为了实现的一致和简单,VMWare使用了用户态连接代理的方式来实现NAT设备,因此NAT设备其实就是一个用户态进程,它来执行地址转换,如下图所示:
下图为Windows任务管理器中的进程
![](https://img-blog.csdnimg.cn/e20823b0599e4d2caf41f8915ef3769a.png)
vmnat企图通过一种不对称的方式处理NAT,即对于从Guest OS发出的数据包,通过直接抓取VMNet8的裸IP报文,修改源IP地址后发出,对于进入Guest OS的数据包,由于目标地址是本机,理所当然进入vmnat进程,被创建的socket接收,然后通过socket的方式发入VMNet8这个虚拟网卡。
但是对于TCP而言,上述的方式不适用!因为在反向方向,vmnat会打断序列号(数据进入应用层后会剥离IP头和TCP头,丢失一切协议元信息),这就会打断Guest OS到远端的TCP连接。另外,作为TCP的客户端,不发起connect是无法单独创建socket的,因此,简单的办法就是直接接管整个TCP。
抓包分析:![在这里插入图片描述](https://img-blog.csdnimg.cn/a179c37908c1485ca435d9b3feabfd2c.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2hlbmV5ODIy,size_20,color_FFFFFF,t_70,g_se,x_16)
这是在物理主机上通过对无线网卡抓包获得的原始报文,可以看出:
IP层:
源地址:202.114.200.252(DNS服务器地址)
目的地址:172.27.18.165(本地物理主机地址)
TTL:61
这是在虚拟机内通过对ens33网卡抓包获得的报文(在物理主机上对VMnet8网卡抓包可得同样结果),可以看出:
IP层:
源地址:192.168.232.2(DNS服务器地址)
目的地址:192.168.232.128(本地物理主机地址)
TTL:128
以上两个抓包结果容易看出:在物理主机接收到真正的报文之后,位于物理主机上的NAT进程将其做了一定处理,然后交给虚拟机。
通过观察TTL发现:第一次是61,第二次是128。而TTL在实际转发过程中不可能增大,而且128是TTL的默认值,故推断出NAT将整个IP报文的头部全部替换。
还能得出结论:无论真实物理上的DNS服务器是多少,对于虚拟机来说,其DNS服务器是192.168.232.2(看具体情况)。
Questions:
- 虚拟NAT设备是默认网关吗 ?如何验证 ?是域名服务器吗 ?
是默认网关也是DNS服务器,验证方法:
1)利用route命令查看路由表
2)ip route show 命令查看
3)traceroute+网址 查看访问路径
下文第一节的抓包结果也印证了这一点。
- DNS为什么封装在UDP而不是TCP中 ?
TCP需要连接,三次握手的过程消耗大量时间等资源,而UDP是无连接的,因此效率更高。而且如果DNS查询结果的包丢失,由于存在备用DNS服务器,可以继续查询,从而大大降低了无连接带来的风险。
- 多次对相同域名DNS查询的结果一定相同吗 ?
不一定相同,因为域名和IP不是一一对应的。
事实上:一个IP地址可以对应多个域名,一个域名也可以解析为多个IP地址。一台主机可以托管多个网站,这种情况下这多个网站的IP地址可能就会相同。利用请求的请求头信息将来自不同的域名的请求转发给不同的程序去处理。一个域名解析多个IP地址这种情况一般是针对那种访问量特别大的网站,为了负载均衡,访问者会解析到最合适IP地址。
- 应用层的ping为什么不经过运输层的TCP/UDP而直接利用IP封装 ?
ping工作在应用层,它直接使用网络层的ICMP协议,而没有使用传输层的TCP/UDP协议,我认为是为了节省不必要的开销,如果多经过传输层,在封装处理和网络传输上都会多增加开销,而这种开销是没有必要的。ICMP是为测试网络连通性设计的,根本用不上传输层的流量控制、差错控制等高级手段。
- 为什么VMware的虚拟网卡VMnet8只是虚拟机与物理主机通信的接口,虚拟机并不是依靠其联网,但是在NAT模式下物理主机上却能对其抓包呢 ?
对于大部分的包,NAT对于从Guest OS发出的数据包,通过直接抓取VMNet8的裸IP报文,修改源IP地址后发出,对于进入Guest OS的数据包,由于目标地址是本机,理所当然进入vmnat进程,被创建的socket接收,然后通过socket的方式发入VMNet8这个虚拟网卡。所以VMNet8网卡会经过从物理网卡传来被NAT处理过的包以及虚拟机要发送出去的待处理包(见第一节抓包分析)。
完整的浏览网页的网络过程:
阶段一:DHCP获取本机IP
- 虚拟机开机,Windows下打开Wireshark对“VMware Network Adapter VMnet8”抓包。
生成DHCP请求报文
- 系统生成DHCP请求报文,并将该报文放入目的端口67(DHCP服务器),源端口68(DHCP客户)的UDP报文段中,该UDP报文段又被放入源IP:0.0.0.0目的IP:255.255.255.0的IP数据报中,再将该IP数据报放在目的MAC为FF:FF:FF:FF:FF:FF 源MAC为虚拟网卡的MAC地址的以太网帧中,如图:
![](https://img-blog.csdnimg.cn/4d89cb29789a48a58f1cb2734332ee8c.png)
-
然后用户主机将该帧发送到以太网交换机,以太网交换机转发到所有的出端口(包括路由器端口)。
-
路由器接收到该帧以后,从中逐层取出信息。
-
然后DHCP服务器生成包含分配给本地虚拟主机的IP地址以及DNS服务器的IP地址,默认网关路由器的IP和子网掩码的一个DHCP ACK报文,并逐层将该报文封装进以太网帧中,以太网帧的源MAC是路由器连到归属网络接口时的MAC地址,目的MAC是本地虚拟主机的MAC地址。
-
本地虚拟主机收到DHCP ACK报文,从中提取分配给他的IP地址和DNS服务器的地址。
Questions:
- DHCP ACK的源和目的MAC分别是什么?
对于传输层:UDP的源端口是68表示DHCP客户,目的端口是67表示DHCP服务器。
对于网络层:源IP地址为0.0.0.0,目的IP为广播IP:255.255.255.255
对于链路层:源MAC为本机的MAC:(00:0c:29:26:38:ec)这也是当前主机的唯一标识符,目的MAC为:FF:FF:FF:FF:FF:FF
- 包含DHCP ACK的以太网帧是如何准确发送到客户手中的?
路由器上的DHCP服务器收到请求后,将封装一个ACK报文,所属帧的源MAC为路由器连接到归属网络接口的MAC地址,目的MAC是本地主机的MAC。
该帧发给交换机,由于交换机是自学习的,所以他知道发送给该mac的包该向哪个端口转发。
- 客户收到DHCP ACK后需要做什么 ?
先逐层解析该包,得到DHCP ACK信息,DHCP客户端记录下分配给他的IP和DNS服务器的IP。然后在IP转发表中安装默认网关的地址。
阶段二:DNS获取目的IP
- 打开浏览器,键入URL:(image.baidu.com)。要向该URL发送HTTP请求,需要先知道其IP地址,由于只知道待访问网站的网址而不知道其IP,所以要从DNS服务器获取目的IP地址。
DNS查询报文
- 本地虚拟主机生成DNS查询报文,并逐层封装进以太网帧。然后将该帧发送给网关路由器,但目前只知道网关路由器的IP并不知道其MAC地址,所以还需要进一步的利用ARP来获取网关路由器的MAC地址
ARP查询
- 本地主机生成一个目的IP地址为默认网关IP,目的MAC为广播地址FF:FF:FF:FF:FF:FF 的含有ARP查询报文的以太网帧中。并向交换机发送该帧,交换机将该帧发送给所有连接的设备(其中包含网关路由器)
- 网关路由器收到ARP查询报文,并生成一个ARP回答报文,报文指示其MAC地址 对应IP地址 ,再将该报文封装进以太网帧中并发送回去。
- 本地虚拟主机接收到ARP回答报文并从中读取需要的MAC地址信息
- 本地虚拟主机已经获取到全部的DNS查询所需的信息,所以向DNS服务器发送一条DNS查询报文
DNS流程
- 本地虚拟主机生成的DNS查询报文先发送给交换机,再交付给网关路由器,网关路由器从中提取出IP数据报并查找其目的地址,根据转发表准发给相应的路由器,就这样一步步的抓发到DNS服务器
- DNS服务器收到该查询报文后,从DNS数据库中查询image.baidu.com对应的IP地址,然后将DNS回答报文封装经过以太网发送回本地虚拟主机
- 本地虚拟主机最终获得了待访问的IP地址。
Questions:
- 为什么已经获得网关路由器的IP,还要利用ARP获取其MAC地址 ?
- DNS封装在UDP还是TCP内 ? 为什么 ?
封装在UDP中,因为TCP需要连接,三次握手的过程消耗大量时间等资源,而UDP是无连接的,因此效率更高。而且如果DNS查询结果的包丢失,由于存在备用DNS服务器,可以继续查询,从而大大降低了无连接带来的风险。
- 域名到IP的解析遵循什么样的规则 ?
解析经过:浏览器DNS缓存 -> 本地host配置 -> DNS服务器 -> 上层root server
1、host的解析首先是自上而下的
2、同域名多条记录的时候,首域名记录(域名a这种)的优先级高于非首域名记录(域名b/c这种)
3、同样紧邻ip的 多条同域名记录,优先级遵循第一条,且 非127.0.0.1的优先于127.0.0.1的
4、同域名多条记录且均不紧邻ip的,遵循第一条
5、0.0.0.0 会产生主机记录但ping不通,因此不计入优先级计算范围
阶段三:HTTP获取网页资源
- 经过前两个阶段的准备,本地虚拟主机已经获取到了目的网址的IP,利用这些信息,本地虚拟主机就可以进行TCP的三次握手了。
- 借助于本地虚拟主机的套接字就可以开始浏览网页了,浏览器生成要获取URL的HTTP GET报文并写入套接字最终交付给image.baidu.com
- image.baidu.com的HTTP服务器从TCP套接字读取HTTP GET报文,然后生成响应报文,将其请求的Web内容放入其中,并写入套接字
- HTTP响应报文经过多层转发,最终到达本地虚拟主机,主机上的浏览器从套接字中读取Web网页的 html,并最终将内容显示在屏幕上。
- 抓包分析上述HTTP相关的TCP三次握手和四次挥手。
为什么上述TCP的四次挥手只被捕捉到三次 ?
因为第二次和第三次合并了,FIN报文用在本端没有数据发送给对方时,关闭从本端到对端的连接。但是并不影响从对方到本端的连接,也就是说本端仍然可以接收对方的数据。即发送通道关闭,接收通道正常。如果对方收到本端FIN报文时,对方的接收通道就会关闭。此时,如果对方也没有数据发给本端,那么对方也会发送FIN给本端,用于关闭从对方到本端的连接,这时候就可能出现ACK和FIN合在一起的情况。当然,如果对方仍然有数据发送,那么就等数据发完,再发FIN来关闭连接,这时候就是四次挥手了。
Questions:
- HTTP协议GET和POST的区别 ?
GET 用于获取信息,是无副作用的,是幂等的,且可缓存
POST 用于修改服务器上的数据,有副作用,非幂等,不可缓存
- HTTP无状态有哪些弊端 ? 如何解决 ?
HTTP是一种无状态协议,即服务器不保留与客户交易时的任何状态。
用户登录后,切换到其他界面,进行操作,服务器端是无法判断是哪个用户登录的。 每次进行页面跳转的时候,得重新登录。
解决方法:
1 .Cookie:Cookie 会根据从服务器端发送的响应报文内的一个叫做 Set-Cookie 的首部字段信息,通知客户端保存 Cookie,当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入 Cookie 值后发送出去。也就是 Cookie 是服务器生成的,但是发送给客户端,并且由客户端来保存。每次请求加上 Cookie就行了。服务器端发现客户端发送过来的 Cookie 后,会去检查究竟是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息。
2 .Session:客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,这就是 Session。客户端浏览器再次访问时,只需要从该 Session 中查找该客户的状态就可以了。虽然 Session 保存在服务器,对客户端是透明的,它的正常运行仍然需要客户端浏览器的支持。这是因为 Session 需要使用Cookie 作为识别标志。HTTP协议是无状态的,Session 不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为 JSESSIONID 的 Cookie,它的值为该 Session 的 id(即放在HTTP响应报文头部信息里的Set-Cookie)。Session依据该 Cookie 来识别是否为同一用户。