CIDR 表示法写作 address/prefix,其中 prefix 表示被固定为网络部分的前导比特位数——因此在 10.0.0.0/16 中,前 16 位标识网络,剩余的 16 位可自由分配给主机。
大多数人都是通过吃亏才真正学会这一点的:大概是第三次发现安全组莫名其妙地拦掉了流量,而罪魁祸首竟是前缀写错了一位数字。就这一行内容,基本足以让你不再只是把 10.0.0.0/16 复制粘贴进 Terraform 文件,而是真正读懂它。本文将为你建立心智模型,讲清从前缀推导可用地址范围与主机数量的两步算法,并梳理 Web 或全栈开发者实际会遇到 CIDR 的场景(VPC 规模规划、安全组规则、允许列表以及容器网络),包括那些会悄无声息地破坏连通性的坑。
核心要点
- CIDR 表示法为
address/prefix;prefix 统计的是前导网络位数,而不是地址的总位数。 - 一个 IPv4 地址块的可用主机数为
2^(32 − prefix) − 2:/24提供 254 个,/26提供 62 个,/30提供 2 个,需减去网络地址和广播地址。 0.0.0.0/0(IPv4)和::/0(IPv6)表示所有地址:在 SSH 或数据库端口上作用域为0.0.0.0/0的允许规则,等于把它暴露给整个互联网。- RFC 1918 保留了三个私有地址范围,你在云和容器配置中会频繁见到:
10.0.0.0/8、172.16.0.0/12和192.168.0.0/16。 - 打算做对等连接(peering)或 VPN 互联的两个网络,绝不能使用重叠的 CIDR 地址块,否则通往相同地址的路由会产生歧义。
什么是 CIDR 表示法?
CIDR(Classless Inter-Domain Routing,无类别域间路由)表示法用一个 IP 地址加斜杠和前缀长度来表示一个网络,其中前缀长度是被固定为网络部分的前导比特位数。它取代了僵化的 A/B/C 类地址体系,使地址块可以是任意大小,而不必对齐到 8、16 或 24 位边界。该方案于 1993 年由 RFC 1519 提出,并于 2006 年整合进当前的权威规范 RFC 4632。前缀不是地址的总位数,这是一个常见的误读。在 192.168.129.23/17 中,/17 意味着前 17 位是网络位,剩下 15 位留给主机。
比特模型:网络位与主机位
Discover how at OpenReplay.com.
一个 IPv4 地址是被拆分为四个 8 位八位组(octet)的 32 位数字,而 /n 前缀相当于在这 32 位中划一条线:线左侧的一切是固定的网络部分,右侧的一切是可变的主机部分。把这条线往右移(更大的前缀)就得到更多、更小的网络;往左移则得到更少、更大的网络。
以 10.0.1.0/24 为例。/24 在第三个八位组之后切分,因此前 24 位被锁定,最后 8 位由你支配:
00001010 . 00000000 . 00000001 . 00000000
└──────── network (24 bits) ──────┘ └ host ┘
10 0 1 0–255
这 8 个主机位的取值范围从 00000000 到 11111111:共 256 种组合,即 10.0.1.0 到 10.0.1.255。决定切分位置的唯一因素就是前缀。
一个 CIDR 地址块里有多少台主机?
IPv4 地址块中的可用主机数为 2^(32 − prefix) − 2:/24 提供 254 个,/26 提供 62 个,/30 提供 2 个;被减去的两个地址分别是网络地址(所有主机位为 0)和广播地址(所有主机位为 1),二者都不能分配给主机。先算出地址总数(2^(32 − prefix)),再减去 2。
| 前缀 | 地址总数 | 可用主机数 | 常见使用场景 |
|---|---|---|---|
/16 | 65,536 | 65,534 | 一整个 VPC |
/24 | 256 | 254 | 标准子网 |
/26 | 64 | 62 | 子网内的某一层 |
/30 | 4 | 2 | 点对点链路 |
/31 | 2 | 2 | 点对点(RFC 3021) |
/32 | 1 | 1 | 单主机路由 |
−2 规则有两个在实践中很重要的例外:/31 可提供 2 个可用地址,因为 RFC 3021 取消了点对点链路上的网络地址和广播地址保留;而 /32 是单主机路由,也就是你在防火墙或允许列表规则中指定某一个确切 IP 时使用的形式。
在实际场景中读懂 CIDR 地址块
读取像 10.0.1.0/24 这样的地址块:网络地址是 10.0.1.0,广播地址是 10.0.1.255,可用范围是 10.0.1.1 到 10.0.1.254。方法分四步:(1) 前缀告诉你有多少位是固定的;(2) 把剩余主机位全置为 0 得到网络地址;(3) 全置为 1 得到广播地址;(4) 中间的所有地址均可用。
反向推导——从主机数需求推出前缀——则选择可用地址数刚好满足需求的最小地址块。需要容纳 30 台设备?/27 提供 30 个可用地址;/28 只有 14 个,所以答案是 /27。你可以用 Python 标准库的 ipaddress 模块验证任何地址块,无需安装任何东西:
python3 -c "import ipaddress; n=ipaddress.ip_network('10.0.1.0/24'); print(n.network_address, n.broadcast_address, n.num_addresses)"
# 10.0.1.0 10.0.1.255 256
在把结果写进配置之前,对任意地址块运行一下,核对你手算的答案。
如果你不想切到终端,OpenReplay CIDR 计算器可以在浏览器中完成同样的展开计算。粘贴一个像 10.0.0.0/16 这样的地址块,它会返回网络地址和广播地址、子网掩码与通配符掩码、首个和最后一个可用主机地址,以及地址总数。它同时支持 IPv4 和 IPv6,并使用大整数运算,因此大地址块和 IPv6 范围也能返回精确结果。所有计算都在本地完成,内部地址范围绝不会离开你的机器。
开发者实际会在哪些地方遇到 CIDR
大多数开发者早在接触路由表之前,就已经在云和应用配置中遇到了 CIDR。RFC 1918 保留了三个你会频繁见到的私有地址范围(10.0.0.0/8、172.16.0.0/12 和 192.168.0.0/16),它们都无法在公共互联网上路由,这正是云 VPC 和 Docker 网络从中取址的原因。以下四种模式几乎覆盖了你会接触到的全部场景:
- VPC 与子网规模规划。 你在创建时设定一个地址块,然后从中划分子网。AWS VPC 的 IPv4 地址块必须在
/16到/28之间,且每个子网会保留前四个地址以及最后一个地址(是五个,而非两个),因此在 AWS 上一个/24子网只有 251 个可用地址,而不是 254 个。通用的−2是上限,而非保证值。 - 防火墙与安全组规则。 规则的作用域由 CIDR 界定,例如仅允许来自
10.10.1.0/24的入站 5432 端口流量,从而让数据库层只接受来自 Web 层的 Postgres 流量,拒绝其他一切。 - 应用配置中的允许列表与拒绝列表。 CORS 源、WAF 规则、API 网关来源范围,以及
nginx的allow/deny指令,全都接受 CIDR 地址块。前缀设置得过窄会悄无声息地拦掉合法客户端;这类实现的会话回放常常把故障表现为被阻止或失败的请求,而根源可以追溯到某个写错的前缀。 - CIDR 重叠这个坑。 打算做对等连接或 VPN 互联的两个网络,绝不能使用重叠的 CIDR 地址块,因为一台主机无法拥有两条通往同一地址的无歧义路由。给每个网络分配各自互不重叠的 RFC 1918 范围,比如
10.10.0.0/16和10.20.0.0/16。
有一个值值得记牢:IPv4 中的 0.0.0.0/0(以及 IPv6 中的 ::/0)表示所有地址。它作为默认路由很有用,但作为入站允许规则则是一把「走火的枪」:在 22 或 5432 端口上使用 0.0.0.0/0,等于向整个互联网敞开大门。
IPv6 使用相同的表示法
IPv6 把完全相同的斜杠表示法应用于 128 位地址,/64 是标准的单子网规模,为每个子网内的主机留出 64 位。要把 /64 当作惯例而非法律:它并不是普遍不变的规则,甚至 AWS 也允许 IPv6 子网掩码在 /44 到 /64 之间以 /4 为步长取值。比特切分的逻辑完全一致,只是地址更长了。
把前缀理解为网络位的数量,用 2^(32 − prefix) − 2 计算 IPv4 可用主机数,记住 /31、/32 以及云厂商地址保留这几个例外,并让互联的网络保持不重叠。做到这些,你就能在不借助计算器的情况下规划子网规模或审查防火墙规则。下次某个 CIDR 地址块出现在 pull request 里时,一眼就把它解析出来,并确认那个 /0 是否本该出现在那里。
常见问题
像 255.255.255.0 这样的子网掩码和像 /24 这样的 CIDR 前缀有什么区别?
它们以两种方式表达同一个边界。子网掩码是一个 32 位数值,其中网络位为 1、主机位为 0,所以 255.255.255.0 的二进制形式是 24 个 1 后跟 8 个 0。CIDR 前缀 /24 只是统计了这些前导的 1 位。255.255.255.0 等于 /24,255.255.255.192 等于 /26,255.255.255.252 等于 /30。CIDR 就是同一掩码的简写形式。
一个 /30 提供多少个可用 IP 地址,为什么它常用于点对点链路?
/30 在总共 4 个地址中提供 2 个可用地址,因为按标准的减 2 规则,网络地址和广播地址仍然被保留。两个可用地址正好够点对点链路的两个端点使用,这就是 /30 成为传统选择的原因。后来 RFC 3021 允许 /31 承担同样的用途,在总共 2 个地址中提供 2 个可用地址,取消了网络地址和广播地址的保留,不浪费任何地址。
同一网络中的两个子网可以使用重叠的 CIDR 地址块吗?
如果它们需要互相路由,就不行。在单个路由表内部,重叠会通过最长前缀匹配来解决:目标为 10.0.1.5 的数据包会走 10.0.1.0/24 的路由,而不是更宽的 10.0.0.0/16,所以路径永不含歧义。问题出现在你要连接两个各自独立编址的网络时。两个都使用 10.0.0.0/16 的 VPC 之间的对等连接会失败,因为每一侧都已在本地路由该地址块,无法到达对端。这就是 VPC 对等连接和站点到站点 VPN 要求地址范围不重叠的原因。从一开始就为每个网络分配各自独立的 RFC 1918 地址块。
前缀数字更小意味着网络更大还是更小?
前缀数字更小意味着网络更大。前缀统计的是固定的网络位,因此网络位越少,留给主机的位就越多。/8 有 24 个主机位、超过 1600 万个地址,而 /24 只有 8 个主机位、256 个地址。随着前缀数字每减小一位,地址块规模翻一倍:/23 的地址数是 /24 的两倍,而 /16 的地址数是 /24 的 256 倍。
为什么 AWS 上的 /24 子网只有 251 个可用地址,而不是 254 个?
AWS 每个子网保留五个地址,而不是通用减 2 规则假设的两个。AWS 会预留每个子网 CIDR 地址块的前四个地址以及最后一个地址,用于网络地址、VPC 路由器、DNS、未来用途和广播。因此一个总共 256 个地址的 /24 在 AWS 上只有 251 个可用地址,而在普通网络计算中是 254 个。在紧凑规划子网规模之前,务必先查看你的云服务商的地址保留规则。