Skip to content

网络协议

计算机网络模型是一个多层次结构的协议堆栈,自底向上分为:

  • 物理层
  • 链路层
  • 网络层
  • 传输层
  • 应用层

该分层由 Linux 的协议栈来实现。

链路层

以太网、局域网

以太网是一种计算机局域网技术,规定了包括物理层的连线、电子信号和介质访问层协议的内容。

以太网往往就代表了物理网络拓扑结构,只有以太网联通,上层的 IP 网络层才能联通。但是在局域网中的设备,即使没有实现 IP 层协议,设备之间依然可以通过以太网协议进行通信。

以太网中的元素,主要由以太网接口、以太网链路、以太网设备组成:一个以太网接口就是一个以太网线的接口或者插孔,一个以太网接口有一个 MAC 地址用于标识接口的地址,一个设备可以有多个以太网接口意味着它有多个向外界链接的以太网链路,这些链路可能位于不同的局域网中视具体的网络拓扑结构而定。

交换机是一个具有多个接口的以太网设备,它可以根据自身维护的 MAC 表和 MAC 地址转发数据包-以太帧,它是二层数据包的交通枢纽或者中转站。交换机可以设置转发规则,决定某个接口进入的流量是否可以从某个接口流出。在以太网中,设备有两种角色:数据的收发者和数据的中转者。两台设备之间进行收发消息,可能需要第三者、第四者的协助转运,交换机扮演的就是中转者的角色。

以太网中的设备基于 MAC 地址和以太帧进行流量转发,以太帧可以携带额外的数据,这些数据往往是为上层应用提供载货空间。以太帧的最小长度为 64 字节,最大长度为 1518 字节(不包含前导码和帧开始定界符)。

MAC 表

MAC 表是交换机的核心数据结构,它记录了 MAC 地址与端口的映射关系。交换机通过自学习机制建立 MAC 表:当从某个端口接收到数据帧时,交换机会记录源 MAC 地址与该端口的映射关系。MAC 表项有老化时间,通常为几分钟,过期的表项会被删除以保持表的准确性。

现代交换机使用硬件(ASIC)实现 MAC 表的查找和转发,使得转发延迟可以低至微秒级。在虚拟化环境中,Linux 网桥同样维护类似的 FDB 表来实现软件交换机的功能。

二层隧道

由于 Linux 提供了 TAP 虚拟以太网卡的功能,二层隧道技术应运而生。它可以解决跨网段的二层网络联通、虚拟化场景下的二层网络联通、数据加密等需求。

其中的一个典型应用就是 VPN 软件:VPN 软件在客户端机器中添加一个 TAP 设备,读取 TAP 设备中的数据模拟数据发送,将数据进行加密,使用机器上的真实网络接口接入互联网向远程的 VPN 服务器发送加密后的流量,VPN 服务器解密流量,在远程机器上生成网桥并配置二层转发,VPN 服务器将解密的数据进行二层转发由此直接勾连客户端进入远程服务器所在的以太局域网中,这种效果相当于客户端和远程局域网有网线直连一样。

另一个重要的二层隧道技术是 VXLAN,它通过在三层网络之上构建二层 Overlay 网络来解决数据中心 VLAN 数量限制的问题。VXLAN 使用 UDP 封装以太帧,将 24 位的 VNI 作为网络标识,理论上可以支持 1600 万个独立网络。

网络层

网络层用于定义网络协议,协议是计算机之间通信的规则,只有遵循特定的规则才能让其他机器理解自己,就像人们在生活中要遵守为人处世的礼仪和规范。

IPv4-广域网、跨网络通信、互联网

我们无法将世界上所有的机器都直接连接在同一个顶层网络之中。网络可以分为大小规模的网络,网络之间可以相互嵌套,层级需要进行划分。当涉及网络之间的嵌套时,数据需要在不同的网络中进行跨网段传递,如何让数据在纷繁的网络中正确找到目标-寻址成为了一个重要的问题。

子网掩码

一个地址并不能代表一台机器,因为机器还需要知道一个子网掩码,用于确认谁是自己的家人居住在同一个子网中。另外,通过子网机器可以确认一个网关地址和一个广播地址。处于同一个子网中的主机意味着彼此之间可以直接通信,它们往往通过物理线路直接相连。当机器需要访问子网外部的主机时,机器将向网关发送自己的请求,由网关代为访问外界,并将结果返回给子网中的机器。

网关是子网中的门户,它同时位于多个网络中,并在两个网络间的机器需要进行通信的时候充当代理人进行数据的转发。转发基于三层规则,依据 NAT 表进行。

IPv6

IPv6 的长度为 128 位,由 8 组 16 进制数组成:

2001:db8:abcd:0000:0000:0000:0000:0001/128

连续出现的"0000"组可以被省略为"::",一个 IPv6 地址中只允许出现一个"::":

2001:db8:abcd:0000:0000:0000:0000:0001/128 -> 2001:db8:abcd::0001/128

IPv6 一般的掩码是 64 位,这意味着前 64 位是网络地址,后 64 位为主机地址。IPv6 地址的接口标识符通常使用 EUI-64 格式生成,即将 MAC 地址中间插入 FFFE 并翻转 U/L 位。

IPv6 兼容 IPv4

掩码为 96 位的"/96"IPv6 网络可以向 IPv4 提供兼容,如果一个网段的掩码为 96,这往往意味着这是一个兼容网络,该网络的路由器可以将 IPv6 和 IPv4 的地址进行转换并达成跨协议通信。IPv6 定义了多种过渡技术:双栈技术、隧道技术(如 6to4、ISATAP、Teredo)、翻译技术(如 NAT64)。

ICMP

ICMP(Internet Control Message Protocol)是 IP 协议的补充,用于在 IP 主机和路由器之间传递控制消息和错误报告。常见的 ICMP 消息类型包括:回显请求和回显应答,用于 ping 工具;目标不可达,当路由器或主机无法交付数据包时发送;超时,当 TTL 变为 0 时发送。

ICMPv6 是 IPv6 的组成部分,除了提供类似 ICMPv4 的功能外,还承担了 ARP(地址解析)和自动配置的功能。ICMPv6 的邻居发现协议(NDP)取代了 ARP、RARP、ICMP 路由发现和 ICMP 重定向等功能。

BGP

BGP(Border Gateway Protocol)是互联网的核心路由协议,用于在自治系统(AS)之间交换路由信息。BGP 是一种路径矢量协议,它不仅通告目标网络的可达性,还包含到达该网络的 AS 路径,从而可以避免路由环路。BGP 使用 TCP 端口 179 建立连接,通过 UPDATE 消息交换路由信息。

BGP 有两种类型:eBGP(外部 BGP)用于不同 AS 之间的路由交换,iBGP(内部 BGP)用于同一 AS 内部的路由器同步路由信息。BGP 的路由选择基于多个属性:AS_PATH(路径长度越短越优先)、LOCAL_PREF(本地优先级,值越大越优先)、MED(多出口鉴别器)。

传输层

传输层为应用进程提供端到端的通信服务,它负责将数据从源进程传输到目的进程。传输层通过端口号来区分不同的应用进程,端口号是一个 16 位的无符号整数。传输层提供两种不同的服务:面向连接的可靠传输(TCP)和无连接的不可靠传输(UDP)。

TCP

TCP 是一种面向连接的协议,通信双方在传输数据前需要先建立连接。TCP 使用三次握手建立连接:客户端发送 SYN 包进入 SYN_SENT 状态,服务器收到 SYN 后回复 SYN-ACK 包进入 SYN_RCVD 状态,客户端收到 SYN-ACK 后回复 ACK 包进入 ESTABLISHED 状态。

TCP 连接的终止使用四次挥手:主动关闭方发送 FIN 包,被动关闭方收到 FIN 后发送 ACK 包,被动关闭方发送 FIN 包,主动关闭方收到 FIN 后发送 ACK 包进入 TIME_WAIT 状态,等待 2MSL 后完全关闭。

TCP 使用序列号和确认号来实现可靠的数据传输。每个字节都有一个序列号,接收方对收到的数据进行累积确认。如果某个报文段丢失,接收方会重复确认前面的序列号,发送方收到三个重复 ACK 后会触发快速重传。

TCP 的流量控制使用滑动窗口机制,接收方在 TCP 头部中的窗口字段通告自己当前的接收窗口大小。TCP 的拥塞控制包括四个核心算法:慢启动、拥塞避免、快重传、快恢复。现代 TCP 还实现了更先进的拥塞控制算法,如 CUBIC(默认用于 Linux)、BBR(基于带宽和 RTT 的拥塞控制)等。

UDP

UDP(User Datagram Protocol)是一种简单而无连接的传输层协议,它只提供了基本的数据复用和分用功能(通过端口号),而不保证数据的可靠交付。UDP 头部只有 8 个字节,包括源端口、目的端口、长度和校验和字段,相比 TCP 的 20 字节头部开销更小。

UDP 的无连接特性意味着发送数据前不需要建立连接,每个数据包独立路由,可能沿不同路径到达,可能乱序或丢失。UDP 不提供流量控制和拥塞控制,发送方可以以任意速率发送数据。UDP 适用于可以容忍数据丢失的实时应用(如视频会议、在线游戏),以及简单的请求-响应应用(如 DNS 查询)。

应用层

应用层协议为特定的应用提供服务,这些协议通常运行在传输层协议(TCP 或 UDP)之上。应用层协议定义了消息的格式、消息的语义以及通信的时序规则。

DNS

DNS(Domain Name System)是互联网的域名系统,它将人类可读的域名转换为机器可用的 IP 地址。DNS 采用分层分布式数据库架构,由根域名服务器、顶级域名服务器、权威域名服务器和本地域名服务器组成。DNS 使用 UDP 端口 53 进行常规查询,当响应超过 512 字节时使用 TCP 进行区域传输。

DNS 查询有多种类型:A 记录(域名到 IPv4 地址的映射)、AAAA 记录(域名到 IPv6 地址的映射)、CNAME 记录(域名别名)、MX 记录(邮件服务器)、NS 记录(权威域名服务器)。DNS 支持递归查询(由 DNS 服务器代为查询)和迭代查询(由客户端自行查询)。

HTTP

HTTP 也称超文本传输协议,从 web browser 诞生,但却不止用于 web browser,由于其简单而直观的协议机制,如今已经广泛用于各类网络通信中。

HTTP 的特点:

  1. 基于纯文本的明文传输
    • HTTP 就是一段按照规则书写的文本,在发送之前将文本数据按照特定的编码集对内容进行编码
    • HTTP 的头 header必须是 ASCII 编码
    • 体 body可以是自定义的编码,当 body 的编码是其他编码的时候需要在 'Content-Type' 头字段中声明编码和数据类型
  2. 一问一答的请求-响应模式
    • HTTP 双方一般默认采用的是一问一答的交流方式
    • 服务端不会主动发送消息
    • 只有客户端主动发送一个 HTTP 的逻辑请求 Request
    • 服务端对请求进行解析、处理,然后响应一个 HTTP 响应 Response
  3. 协议头+协议体的分包方式 一个请求或者响应的消息包,必须要包含如下的格式,请求头和请求体采用的是不同的编码方式,两种编码方式混合在一起使用:
    <请求行>
    <请求头:键值对>
    <请求头:键值对>
    <请求头:键值对>
    <请求头:键值对>
    <空行>
    <请求体>

HTTP/2 引入了二进制帧层、多路复用、头部压缩(HPACK)、服务器推送等特性,解决了 HTTP/1.1 的队头阻塞问题。HTTP/3 基于 QUIC 协议(使用 UDP)解决了 TCP 层面的队头阻塞问题。

SSL/TLS

SSL(Secure Sockets Layer)及其继任者 TLS(Transport Layer Security)是保障网络通信安全的核心协议。它们位于传输层和应用层之间,为应用层协议(如 HTTP、SMTP、POP3、IMAP)提供数据加密、身份验证和数据完整性保护。TLS 1.3 是当前最新版本,相比之前的版本有显著的安全性和性能改进。

TLS 握手过程分为几个阶段:首先客户端发送 ClientHello 消息,包含支持的加密套件和随机数;服务器回复 ServerHello 消息,选择加密套件并发送证书和随机数;双方使用交换的随机数和预主密钥计算会话密钥;客户端发送 Finished 消息验证握手过程,服务器也发送 Finished 消息完成握手。TLS 1.3 将握手过程简化为 1-RTT,并支持 0-RTT 快速恢复。

TLS 支持多种密码套件,包括密钥交换算法(如 RSA、ECDHE)、身份验证算法(如 RSA、ECDSA)、对称加密算法(如 AES-GCM、ChaCha20-Poly1305)和消息认证算法(如 HMAC)。前向保密是现代 TLS 的重要特性,即使服务器的长期私钥泄露,过去的会话密钥仍然安全。

SSH

SSH(Secure Shell)是一种用于远程登录和安全通信的加密协议,主要用于在不安全的网络(如互联网)上安全地管理远程服务器。它的核心作用是提供加密的远程访问,防止密码和数据在传输过程中被窃听或篡改。SSH 使用 TCP 端口 22,支持多种认证方式包括密码认证、公钥认证、主机认证、键盘交互认证等。

SSH 协议分为三层:传输层协议提供服务器认证、数据加密和数据完整性保护;用户认证协议验证客户端身份;连接协议将加密通道复用为多个逻辑通道,支持交互式会话、端口转发、文件传输(SFTP、SCP)等功能。

SSH 端口转发

SSH 转发基于两个目的:代理和加密。当客户端无法直接连接服务端的时候,转发和代理服务就显得重要;当你使用的应用层协议没有自带的加密机制时,可以使用 SSH 进行套壳从而达到加密效果。

本地转发将本地机器 A 的端口 p1 映射为远程服务端 C 的某个端口 p2,用于让本地的应用通过访问本地端口 p1 从而连接远程 C 的端口 p2 上的服务,并且获得加密效果。此时,我们需要引入一个 SSH 中介服务器 B,A 通过 SSH 与 B 建立连接,让 B 代为访问 C,然后将 C 的端口映射到 A 的本地。命令格式为:

ssh -L <主机A端口p1>:<主机C>:<主机C端口p2> <主机B的username>@<主机B的hostname>

远程转发将远程机器的端口映射到本地机器的端口,适用于远程机器无法主动建立 SSH 连接的场景。命令格式为:

ssh -R <远程端口>:<本地目标>:<本地端口> <远程主机>

动态转发将 SSH 服务器配置为 SOCKS 代理,客户端通过 SOCKS 协议指定目标地址和端口,SSH 服务器代为建立连接并转发数据。命令格式为:

ssh -D <本地端口> <SSH服务器>

动态转发本质上是在本地创建一个 SOCKS 代理服务器,当应用程序通过这个代理发送请求时,SSH 客户端会将请求通过 SSH 加密通道发送到 SSH 服务器,由 SSH 服务器代为连接目标服务器并将数据返回。这种方式适用于需要访问多个远程服务器的场景,不需要为每个服务配置单独的转发规则。