在浏览器里输入 url 之后发生了什么 小林 大概流程:
- 浏览器解析 url
- 浏览器检查缓存, 看是否有这个 url 对应的资源
- dns, 根据域名找 ip
- 有 ip 了, 数据包就要出子网了
- 要出子网要先通过 ARP 找 路由器 的 MAC address
- 数据包发到路由器, 从路由器走出子网, 通过 BGP 在路由器中跳转
- 到达目标子网之后, 再通过 ARP 找到目标主机
- 数据包到目标主机过后, 终于可以建立连接了; 根据 ip port 进行 tcp 握手
- ssl / tls 握手
- 浏览器生成 http 请求, 握完手之后 (连接建立完毕之后), 才会发 application data
- server 处理 http 请求, 在 tcp 连接上发送 http response
- 浏览器收到 http response, 解析返回, 渲染页面, 加载资源; dom tree 啥的
未覆盖:
- 网卡、 switch 之类的
- 数据包长啥样
- 主机收到数据包之后, 网卡、操作系统、内存 之间是怎么交互的
浏览器本身
解析
以 www.example.com 为例子
在浏览器中输入一个 url, 首先浏览器会 解析 这个 URL, 解析什么内容?
- URL 中涉及到的协议
- URL 中的 host 等信息
检查缓存
- 浏览器检查有没有缓存这个 http 请求对应的资源
解析完之后, 如果是个 http 的协议, 那浏览器会 生成 http 请求
应用层
HTTP
http 是个应用层的协议, 一般都基于传输层的 tcp http message 包含:
- 请求头, 请求方法, 目标 url
- 请求长度, 可以接受的数据类型
- 协商缓存相关的请求头
- 其他请求头
- 请求体数据
dns
有了 http 请求过后, 需要通过 DNS 来查询请求 host 中域名对应的 IP 地址 dns 是应用层的协议, 一般都基于 udp
缓存
- 浏览器会先查询自己是否已经对这个 域名的 IP 地址 有缓存了
- 浏览器没有缓存, 那会查询 OS 的缓存
- 都没有缓存的情况会进行 dns 查询
dns 查询
- 客户端会先向 本地的 域名服务器 进行查询
- (本地的域名服务器一般是指自己的 ISP 的服务器, 也可以是客户端自己配置的 google 或 cloudflare 1.1.1.1 啥的)
- 如果 本地域名服务器 存有这个 域名对应的 IP 地址就会直接返回
- 本地的域名服务器如果没有缓存的话, 就会充当一个 resolver 的角色, 对 域名的 IP 地址 进行查询 查询顺序:
- 从 根域名 开始, resolver 向根域名发起查询请求, 根域名服务器返回对应的顶级域名服务器的 域名和 IP 地址
- 顶级域名服务器再返回 权威域名服务器 的地址
- 权威域名服务器能够返回对应域名的 IP 地址
- root → top level → authoritative
- resolver 最后向客户端返回 IP 地址 note:
- 整个查询的过程对于 客户端 来说是 迭代 iterative 的, 但是对于 resolver 来说是 递归 recursive 的
- 一共只有 13 个 root domain name server, 客户端的操作系统里一般都有存这 13 个 server 的地址
传输层
tcp
tcp 是个 面向连接的, 可靠的, 面向数据流 的传输层协议
http 请求的 header 和 payload 被操作系统传到传输层, 在 tcp 这边进行进一步封装成 tcp segment tcp segment 包括:
- source port, destination port
- seq number, ack number
- flag: syn, ack, fin 等 6 个
- window size
- checksum
- http 请求的信息被封装到 payload 里了
三次握手:
- client hello, 发送 syn 请求建立连接
- server hello, 同一条消息里发送 ack 来 acknowledge 收到了 client 的 syn, 同时自己发送一个 syn 来表示建立连接
- client 发送 ack 来 acknowledge 收到了 server 的 syn
ssl / tls
ssl / tls 是介于 传输层 和 应用层 之间的一个协议, 在 osi 里被定义成 会话层 session layer 定义了 client 和 server 之间 协商密钥和认证身份 的方式
在建立 tcp 连接后四次握手
- client 发送 client hello, 包含 tls version, cipher suites, random number
- server 发送 server hello, 包含 tls version, cipher suites, random number 和 ssl certificates
- client 收到 server 的 ssl cert 之后会进行校验, 通过 chain of trust; 同时生成一个 随机的 pre-master key 并且用 server 的 public key 加密 pre-master key
- client 发送 加密后的 pre-master key, change cipher spec 来告诉 server 要开始使用加密, 然后 done
- server 发送 change cipher spec, 同意加密
- server 用自己的密钥解密 pre-master key, 结合两个 random number 来生成 会话密钥
chain of trust
- client 会根据收到的 ssl cert 一层一层地 往上 校验
- client 从网站证书开始, 如果还没信任网站证书, 那就会看是否已经信任了颁发这个网站证书的 中间证书 intermediate cert (中间证书可能有多个)
- 如果还没信任这个中间证书, 那就会往上查找, 看是否已经信任了颁发这个中间证书的 根证书
- 如果不信任根证书, 那整条链就会断掉, 根证书是个 trust anchor
再次连接
- 再次连接的时候, 如果是 tls 1.2 1.3, 那可以实现 1 RTT 甚至 0 RTT 的握手.
网络层
IP
- 如果 destination ip 地址是在同一个子网的话, 可以直接进行 ARP
- 如果 destination ip 地址是在其他子网里的话, 需要路由器进行转发
- 客户端查询 ip 路由表, 查看应该往哪里发这个数据
- 如果路由表里没有相关信息, 会使用默认路由, 也就是这个子网的 gateway
- 如果没有子网的 gateway, 那数据包会被丢弃 从 传输层 传下来的数据被 IP module 封装成 IP packet, IP packet 包含:
- source IP, destination IP
- 传输层的协议类型
- TTL
- checksum
- 其他信息 IP packet 往下传到 data link 层
data link layer
Address Resolution Protocol
- data link layer 的 protocol
- 把 IP 地址 map 成 物理设备的 MAC 地址
缓存
第一步是查看是否有缓存, 有缓存直接用, 没有缓存则发送 ARP 请求
ARP 工作原理
- 客户端在子网中 广播 ARP 请求, 请求中包含 destination IP, source IP, broadcast MAC ff-ff-ff-ff-ff-ff destination MAC, source MAC
- 子网中的设备都在监听广播信息, 如果 receiver 在同一个子网中的话, receiver 会 单播 回应自己的 MAC address
- 如果 receiver 在其他子网中的话, ARP 请求中的 destination IP 会是 default gateway 的 IP, default gateway 会回应自己的 MAC 地址
- 有了目标的 MAC 地址之后, 从网络层传下来的 IP packet 就可以被 封装成 ethernet frame 了
物理层
网卡和 switch
通过网卡和 switch, 数字信号转化成电信号, 在物理链路上传输出去
网络中跳转
broader gateway network
用来实现数据包在网络之间的跳转, 找到 routing 的最佳路线
接收方
接受方和发送方的过程是相反的:
- 接受方子网的路由器收到数据包
- 路由器根据 ip 地址进行 ARP 请求, 找到目标设备的 MAC 地址
- 目标设备收到数据之后, ip module 解析 ip packet, 判断是否为自己的 packet
- 是自己的 packet 的话, 会根据请求头中的 tcp/udp 来判断如何进一步处理数据
- tcp segment 被传到 tcp module, 解析是什么 port
- 根据 port number, tcp segment 操作系统上对应的 进程 所处理
- 应用再把这些 tcp segment 拼凑回 http 信息, 做出相应的响应
- 处理完之后生成 http response
- http response 又经过这一整套, 发送回给客户端
receiver 收到数据包后
- receiver 的底层 ethernet 收到数据包
- 操作系统会根据数据包的包头里的类型决定, 是由 ARP module 处理还是 IP module 处理
- 神奇, ARP 和 IP 都不是同一层的协议
- IP module 根据数据包的包头里的类型决定, 是由 TCP module 处理还是 UDP module 处理
- TCP、UDP module 根据数据包包头的类型决定, 数据包要去到哪个 端口
linux 是怎么处理数据的? (TBC)
- 收到数据, napi 来处理
- 写到 ring buffer,
图 4-2 是网卡接收到信息后,把信息发送给用户态的进程处理的流程图。这个过程可以分为四步来理解:
- 网卡接收到一段数据,通过 DMA 方式写入内存
- NIC 向 CPU 发出硬件中断请求,告诉内核有新的数据过来了
- Linux 内核响应中断,系统切换为内核态,处理 Interrupt Handler,从 RingBuffer 拿出一个 Packet,然后解析数据,找到这个端口对应的是哪个 PID,然后包装成 socket 发送给那个进程
- 系统切换为用户态,用户进程处理内核传递过来的 socket 数据 credit

问题
- dns 查询的时候, 每次的域名服务器返回的是下一级域名服务器的 IP 地址吗?
- 是的, 返回下一级域名服务器的 domain, ip, 和一些其他信息
- chain of trust 是从 根证书 开始从上到下 (像dns一样) 还是从 下到上?
- 从下到上, 如果已经手动信任了网站的证书, 那就不需要再往上走了
- 所以不能随便信任证书哈