请求www.baidu.com到底发生了什么

同一局域网主机互联

假设主机A和主机B在同一局域网,A的ip: 192.168.1.12, B的ip: 192.168.1.13, A想要和B之间进行数据传输要经历怎么样的过程呢?

根据OSI 7层网络模型,主机A发送的数据包要从上到下经过各层并在各层添加上对应的协议头等信息,对于接收方B来说,它接收到的数据包从下往上依次传递,根据每一层的协议进行解包,直到在应用层取到A发给它的数据。先抛开传输层以及以上的协议层,我们看看网络层封装的数据包的核心字段有哪些:

ini 复制代码
src ip = 192.168.1.12
src mac = A mac 地址

dest ip = 192.168.1.13
dest mac = B mac 地址

主机A自然知道自己的ip和mac地址,想要通信的B的ip也是知道的,但是A怎么知道B的mac地址呢?这就需要ARP协议了。

  1. A先检查自己的arp缓存中是否有B的dest ip和dest mac的映射关系,有就直接用
  2. 本地arp缓存没有,A会发送一个ARP请求包,交换机会把arp请求包广播到网络中,询问拥有特定IP地址的设备的MAC地址。
  3. 收到的广播包的设备比较dest ip 是否等于本机ip, 不等于就丢弃,等于就回复一个ARP响应,包含自己的MAC地址,同时B会把src ip和src mac写入到自己的arp缓存
  4. A收到arp响应包会把dest ip和dest mac写到自己的本地arp缓存中

arp -a 可以显示本机的所有arp缓存内容

当主机A知道要发往的dest ip的mac地址之后,数据包又是怎么直接发到对应主机的呢?这就需要利用到交换机的"学习"能力了,交换机会存储mac和端口的映射关系,从而决定dest mac应该从哪个端口转发,而端口的另一端连着的就是目标主机。

当从某个端口收到数据包时,交换机会查看该数据包的源MAC地址,并将此源MAC地址与接收此数据包的端口之间的映射关系存储在一张表中,这张表叫做 MAC 地址表或转发数据库 (FDB)。 以后,每当有新的数据包需要被转发时,交换机都会查看数据包的目标MAC地址,并在MAC地址表中寻找与之匹配的条目,将数据包发送到对应的端口。 如果交换机在MAC地址表中找不到匹配的条目(即不知道数据包应该被发送到哪个端口),那么它会执行广播操作 ------ 将数据包发送到所有其他端口。这样,正确的设备就可以接收到数据包。同时,这个设备如果回复了数据包,交换机就可以从回复的数据包中学习到新的MAC地址与端口的映射关系。

不同局域网主机互联

主机C的ip是192.168.2.13,主机A又是怎么和C进行通信的呢?主机A和主机C通信前,会检查目标ip是否和A在同一网段,在同一网段就按照上面阐述的同一局域网主机互联的方式进行通信,不在同一网段A又是怎么和主机B通信的呢?

既然不在同一网段了,A肯定无法直接和C进行通信,需要借助"第三方"来帮忙,那么A怎么寻找可以帮忙的"第三方"呢?这就需要用到路由表了,具体可以通过route -n查看本机路由表。

route -n 命令是在 Linux 系统中显示或修改 IP 路由表的命令,-n 参数表示数字形式显示,不进行域名解析。其返回结果通常如下:

sql 复制代码
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.1     0.0.0.0         UG    0      0        0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U     1      0        0 eth0

下面是每一列的含义:

  • Destination:目标网络或者主机。

  • Gateway:数据包发送到目标地址需要经过的路由器地址,如果是0.0.0.0则表示这是一个直连的网络,不需要通过其他路由器转发。

  • Genmask:即网络掩码,用来划分子网。

  • Flags:标记位,主要有以下几种:

    • U (route is up)
    • H (target is a host)
    • G (use gateway)
    • R (reinstate route for dynamic routing)
    • D (dynamically installed by daemon or redirect)
    • M (modified from routing daemon or redirect)
    • A (installed by addrconf)
    • C (cache entry)
    • ! (reject route)
  • Metric:权重值,用于在存在多条路径到达相同目标时确定最优路径。

  • Ref:路由项引用计数。

  • Use:这个路由项被使用的次数。

  • Iface:输出接口名称。

有了路由表之后,会拿着dest ip 和 路由表的网络掩码做与操作来确定dest ip所在网段,用这个网段和路由表的Destination对比,找出最匹配的路由项。

如果有多条路由项都与目标IP匹配,那么主机通常会选择最具体(即网络掩码最长)的那条,因为它表示的网络范围最小,也最接近目标IP所在的真实网络。

找到匹配的路由项后,主机就知道了应该通过哪个网络接口(Iface)和(如果有的话)哪个网关(Gateway)来发送数据包。

主机A知道要发往的网关ip之后,会先从本地arp缓存中查询网关的mac地址,没有就发arp广播获取,有就直接用,最终A发出去的数据包长这样:

ini 复制代码
src ip = 192.168.1.12
src mac = A mac 地址

dest ip = 192.168.2.13
dest mac = 网关 mac 地址

那么问题来了,网关收到这个报文怎么知道这是发给自己的还是需要自己帮忙转发的呢?会按照如下的规则进行判断:

arduino 复制代码
if dest mac == 自己 mac {
   if dest ip == 自己 ip {
       // 就是发给自己的包
   } else {
       // 需要帮忙转发,查询路由表继续寻找下一跳的地址
   }
} else {
    // 丢弃
}

网关进行转发时要重新封包,并根据其路由表将接收到的数据包从一个网络接口转发到另一个网络接口。在这个过程中,数据包的源IP和目标IP一般保持不变。然而,在某些特殊的设置或配置(例如NAT,网络地址转换)下,网关可能会改变传入数据包的源或目标IP地址。一个常见的例子是家用路由器,它们通常会使用NAT将私有(内部)网络地址转换为公共(外部)网络地址,以允许多台设备分享单一的公共IP地址进行Internet访问。

再来看请求百度到底发生了什么

当我们在浏览数输入www.baidu.com, 首先经过DNS解析得到百度的ip地址,可以通过nslookup进行查看:

yaml 复制代码
~/Desktop$ nslookup www.baidu.com
Server:         192.168.43.1
Address:        192.168.43.1#53

Non-authoritative answer:
www.baidu.com   canonical name = www.a.shifen.com.
Name:   www.a.shifen.com
Address: 36.155.132.31
Name:   www.a.shifen.com
Address: 36.155.132.55
Name:   www.a.shifen.com
Address: 2409:8c20:6:1135:0:ff:b027:210c
Name:   www.a.shifen.com
Address: 2409:8c20:6:1d55:0:ff:b09c:7d77

我们得到百度的ip是36.155.132.31,本机发现和自己不在一个网段,会通过route -n查看路由表,寻找转发的网关,找到网关ip并利用arp得到网关的mac地址,此时本机发出去的报文是这样的:

ini 复制代码
src ip = 192.168.1.12
src mac = 本机 mac
dest ip = 36.155.132.31
dest mac = 网关mac

这里的网关一般就是路由器,路由器从LAN口收到报文后,根据路由表查询下一跳的地址,在这个过程中dest ip一直保持不变,但是src ip在不断变化:

markdown 复制代码
------------我的机器----------
src ip = 192.168.1.12
-----------------------------

------------路由器------------
然后 src ip = 192.168.1.1  (LAN口)
然后 src ip = 223.104.150.14  (WAN口)
-----------------------------

通过路由器可以在内网中划分不同的网段,不同网段接到不同LAN口: LAN1、LAN2....., 不同LAN的ip不一样,比如192.168.1.1 和 192.168.2.1,这就表示划分了两个网段,如果192.168.1.3要发包给192.168.2.3话,路由器收到需要转发的包时,会把src ip设置成LAN1的ip 也就是192.168.1.1

数据包被送到公网之前经过一次NAPT:不仅具备SNAT改变IP地址的能力,也改变传输层(如TCP或UDP)的端口号

当然了,路由器会记录下SNAT转换前和转换后的对应关系,这个对应关系用于之后收到百度给它回包时寻找到一开始发送请求的机器。

下面是路由器的NAT转换表, 注意每个由NAPT处理的连接必须有一个唯一的公共端口号,也就是说内部源的端口可以一样,但是外部源的端口必须不同。

makefile 复制代码
内部源 IP:端口        外部源 IP:端口
192.168.1.12:5678   X.X.X.X:12345
192.168.1.13:5678   X.X.X.X:23456

假设路由器收到百度的响应包长下面这样:

ini 复制代码
src ip = 36.155.132.31:80  (百度公网网关路由器WAN口ip和端口)
src mac = 百度公网网关路由器mac
dest ip = 223.104.150.14:5678  (路由器的WAN口ip和端口)
dest mac = 路由器的mac

路由器会进行下面的判断:

java 复制代码
if dest mac = 自己mac {
   if dest ip == 自己ip {
      // 包就是要发给我的? 但我只是个路由器,只工作在OSI的前三层,你这个包是最终是要应用层处理的,所以我不能真正解析这个包,只能根据NAT表继续转发
      if NAT转换表 包含 dest ip {
          // dest ip 223.104.150.14:5678 对应 192.168.1.12:5678
          // 转发
      }
   }
} else {
   // 丢弃
}

接收到百度的响应数据包后,我们的机器将开始处理这些数据,依照OSI七层网络模型进行解析。首先,从物理层开始,经过数据链路层、网络层、传输层,一直上升到会话层、表示层,最终到达应用层。在应用层,根据HTTP协议,解析并处理来自百度的响应报文。

响应报文包含HTML代码,浏览器将解析这个HTML代码,并渲染出图形用户界面。这就是我们通常在浏览器中看到的网页内容。

值得注意的是,以上述述的处理过程并没有考虑iptables的影响。实际上,当引入iptables进行网络流量控制时,情况会变得更加复杂。iptables可以基于各种规则来决定是否允许数据包通过,或者应该如何处理数据包。这可能会影响到数据包是否能够成功地从源头传递到目标,以及它们如何被处理。

相关推荐
GZ_TOGOGO8 小时前
【2024最新】华为HCIE认证考试流程
大数据·人工智能·网络协议·网络安全·华为
三金121388 小时前
SpringIoC容器的初识
网络·网络协议·rpc
SizeTheMoment10 小时前
初识HTTP协议
网络·网络协议·http
程序员-珍14 小时前
虚拟机ip突然看不了了
linux·网络·网络协议·tcp/ip·centos
魏大橙15 小时前
linux RCE本地/公网测试
网络·网络协议·udp
鄃鳕16 小时前
HTTP【网络】
网络·网络协议·http
秋夫人20 小时前
http cache-control
网络·网络协议·http
limengshi1383921 天前
通信工程学习:什么是RIP路由信息协议
网络·网络协议·学习·智能路由器·信息与通信
GodK7771 天前
HTTPS 的加密流程
网络协议·http·https
limengshi1383921 天前
通信工程学习:什么是TFTP简单文件传输协议
网络·网络协议·学习·信息与通信