183 lines
6.1 KiB
Markdown
183 lines
6.1 KiB
Markdown
|
|
---
|
|||
|
|
tags: [计算机网络, CIDR, 子网划分, IP计算]
|
|||
|
|
create time: 2026-05-18 00:00
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# CIDR 与子网划分
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
CIDR(Classless Inter-Domain Routing,无类别域间路由)是现代 IP 寻址的核心机制。它摒弃了 A/B/C 类地址的固定边界,允许任意长度的前缀——让网络管理员可以按需精确分配 IP 空间。
|
|||
|
|
|
|||
|
|
> [!QUESTION] 为什么需要子网划分?
|
|||
|
|
> 想象一个有 5000 台主机的公司,如果全放在 /12 大网络里:每秒数千个 ARP 广播、巨大的 MAC 表、单点故障影响面极大。子网划分将大问题拆小,既缩小了广播域,又加强了安全性隔离。
|
|||
|
|
|
|||
|
|
## CIDR 表示法
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
192.168.1.0/24 ← /24 表示前 24 位是网络号
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
即 `192.168.1.0` + 子网掩码 `255.255.255.0`
|
|||
|
|
|
|||
|
|
### 常见子网对照表
|
|||
|
|
|
|||
|
|
| CIDR | 子网掩码 | 主机数 ( usable) | 典型用途 |
|
|||
|
|
|------|---------|-----------------|---------|
|
|||
|
|
| /30 | 255.255.255.252 | 2 | 点对点链路 |
|
|||
|
|
| /29 | 255.255.255.248 | 6 | 小型办公室 |
|
|||
|
|
| /28 | 255.255.255.240 | 14 | VLAN 极小 |
|
|||
|
|
| /27 | 255.255.255.224 | 30 | 小组 VLAN |
|
|||
|
|
| /26 | 255.255.255.192 | 62 | 小型部门 |
|
|||
|
|
| /25 | 255.255.255.128 | 126 | 中型部门 |
|
|||
|
|
| /24 | 255.255.255.0 | 254 | **最常用**,标准办公室 VLAN |
|
|||
|
|
| /23 | 255.255.255.254 | 510 | 大型部门 |
|
|||
|
|
| /22 | 255.255.255.252 | 1022 | 数据中心租户 |
|
|||
|
|
| /21 | 255.255.255.248 | 2046 | 大规模部署 |
|
|||
|
|
| /16 | 255.255.255.0 | 65534 | 大型企业内网 |
|
|||
|
|
|
|||
|
|
> [!tip] 快速计算可用主机数
|
|||
|
|
> $N_{usable} = 2^h - 2$,其中 $h$ 是主机位数量($h = 32 - \text{prefix}$)
|
|||
|
|
> - `-2` 因为网络地址和广播地址不可用
|
|||
|
|
> - 对于 /31(点对点链路),RFC 3021 允许使用 2 个地址(无网络/广播位)
|
|||
|
|
|
|||
|
|
## 子网划分的核心算法
|
|||
|
|
|
|||
|
|
### 示例:从 /24 划分为 4 个子网
|
|||
|
|
|
|||
|
|
原始:`192.168.1.0/24`(254 台主机)
|
|||
|
|
目标:分成 4 个子网 → 需借 2 位主机位 → `/26`
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
原始 /24 的网络位:
|
|||
|
|
192.168.1.0 = 11000000.10101000.00000001.00000000
|
|||
|
|
|
|||
|
|
借 2 位给子网:
|
|||
|
|
192.168.1.XX = XX 是子网位(00, 01, 10, 11)
|
|||
|
|
|
|||
|
|
四个子网:
|
|||
|
|
Subnet 0: 192.168.1.0/26 — 范围: .0 ~ .63 — 可用: .1 ~ .62 — Bcast: .63
|
|||
|
|
Subnet 1: 192.168.1.64/26 — 范围: .64 ~ .127 — 可用: .65 ~ .126 — Bcast: .127
|
|||
|
|
Subnet 2: 192.168.1.128/26 — 范围: .128~.191 — 可用: .129~.190 — Bcast: .191
|
|||
|
|
Subnet 3: 192.168.1.192/26 — 范围: .192~.255 — 可用: .193~.254 — Bcast: .255
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart LR
|
|||
|
|
S0["192.168.1.0/26<br/>.1-.62"] -->|"PCs / Servers"| SW0[Switch-A]
|
|||
|
|
S1["192.168.1.64/26<br/>.65-.126"] -->|"IP Phones"| SW1[Switch-B]
|
|||
|
|
S2["192.168.1.128/26<br/>.129-.190"] -->|"Guest WiFi"| AP1[AP-C]
|
|||
|
|
S3["192.168.1.192/26<br/>.193-.254"] -->|"IoT Devices"| GW1[Gateway .1]
|
|||
|
|
|
|||
|
|
style S0 fill:#DDA0DD,color:#000
|
|||
|
|
style S1 fill:#FFD700,color:#000
|
|||
|
|
style S2 fill:#98FB98,color:#000
|
|||
|
|
style S3 fill:#B0C4DE,color:#000
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### VLSM(可变长子网掩码)
|
|||
|
|
|
|||
|
|
不同子网可以用不同长度的掩码——这就是**可变长子掩码**。
|
|||
|
|
|
|||
|
|
场景:公司有 4 个部门,需要不同规模:
|
|||
|
|
- 研发部:200 台 → 需要至少 202 → /24(254 台)
|
|||
|
|
- 市场部:50 台 → 需要至少 52 → /26(62 台)
|
|||
|
|
- 行政部:10 台 → 需要至少 12 → /28(14 台)
|
|||
|
|
- 互联链:2 台 → 需要 2 → /30(2 台)
|
|||
|
|
|
|||
|
|
总计借用:32 - 24 = 8 位主机位
|
|||
|
|
- 研发 /24: 借回 0 位子网位 → 用掉 1 个大块
|
|||
|
|
- 剩余给其他 3 个 /26, /28, /30...
|
|||
|
|
|
|||
|
|
## 实用计算工具
|
|||
|
|
|
|||
|
|
### Linux ipcalc
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
$ ipcalc 192.168.10.50/26
|
|||
|
|
Network: 192.168.10.0/26
|
|||
|
|
Netmask: 255.255.255.192 = 26
|
|||
|
|
Wildcard: 0.0.0.63
|
|||
|
|
Broadcast: 192.168.10.63
|
|||
|
|
HostMin: 192.168.10.1
|
|||
|
|
HostMax: 192.168.10.62
|
|||
|
|
Hosts/Net: 62
|
|||
|
|
|
|||
|
|
# Python 中内置 ipaddress 模块
|
|||
|
|
$ python3 -c "import ipaddress; print(list(ipaddress.ip_network('192.168.10.0/26').hosts()))"
|
|||
|
|
[IPv4Address('192.168.10.1'), ..., IPv4Address('192.168.10.62')]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 快速手算方法
|
|||
|
|
|
|||
|
|
| 步骤 | 操作 |
|
|||
|
|
|------|------|
|
|||
|
|
| 1 | 将最后一个 octet 转换为二进制 |
|
|||
|
|
| 2 | 前 prefix%32 位为网络位,其余为主机位 |
|
|||
|
|
| 3 | 网络地址 = 全置 0;广播地址 = 全置 1 |
|
|||
|
|
| 4 | 可用范围 = 网络地址+1 ~ 广播地址-1 |
|
|||
|
|
|
|||
|
|
## 私有地址空间(RFC 1918)
|
|||
|
|
|
|||
|
|
以下地址段在公网不可路由,专供内部网络使用:
|
|||
|
|
|
|||
|
|
| 地址段 | 数量 | 默认掩码 | 适用场景 |
|
|||
|
|
|--------|------|---------|---------|
|
|||
|
|
| `10.0.0.0 – 10.255.255.255` | 16,777,216 | /8 | 大型企业、运营商 |
|
|||
|
|
| `172.16.0.0 – 172.31.255.255` | 1,048,576 | /12 | 中型企业 |
|
|||
|
|
| `192.168.0.0 – 192.168.255.255` | 65,536 | /16 | 家庭/小型办公室 |
|
|||
|
|
|
|||
|
|
> [!tip] 如何选择私有地址段?
|
|||
|
|
> - 单机房、<1000 台主机 → `192.168.0.0/16` 够用
|
|||
|
|
> - 多机房、分布式 → `10.0.0.0/8` 留有余量
|
|||
|
|
> - Docker 默认使用 `172.17.0.0/16`
|
|||
|
|
|
|||
|
|
## 超网聚合(Supernetting / CIDR Aggregation)
|
|||
|
|
|
|||
|
|
将多个连续的小网合并为一个更大的网:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
原始: 192.168.1.0/24, 192.168.2.0/24, 192.168.3.0/24
|
|||
|
|
= 11000000.10101000.00000001.0/24
|
|||
|
|
+ 11000000.10101000.00000010.0/24
|
|||
|
|
+ 11000000.10101000.00000011.0/24
|
|||
|
|
|
|||
|
|
共同前缀: 11000000.10101000.000000XX → /22
|
|||
|
|
|
|||
|
|
聚合后: 192.168.0.0/22 包含 1024 个 IP
|
|||
|
|
(注意:实际只用了其中两个 /24 块,浪费了中间两个)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
路由聚合减少了全球 BGP 路由表的大小。没有 CIDR 聚合,BGP 路由表会膨胀到百万级别。
|
|||
|
|
|
|||
|
|
## Go 中的子网判断
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
import "net"
|
|||
|
|
|
|||
|
|
ip := net.ParseIP("192.168.1.50")
|
|||
|
|
_, cidr, _ := net.ParseCIDR("192.168.1.0/26")
|
|||
|
|
|
|||
|
|
if cidr.Contains(ip) {
|
|||
|
|
fmt.Println("IP 在子网范围内 ✅")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 遍历所有可用 IP
|
|||
|
|
for ip := cidr.IP.Mask(cidr.Mask); cidr.Contains(ip); inc(ip) {
|
|||
|
|
if ip.Equal(cidr.IP) || ip.Equal(lastIP) {
|
|||
|
|
continue // 跳过网络地址和广播地址
|
|||
|
|
}
|
|||
|
|
// 处理每个可用 IP
|
|||
|
|
}
|
|||
|
|
func inc(ip net.IP) { for i := len(ip) - 1; i >= 0; i-- {
|
|||
|
|
ip[i]++
|
|||
|
|
if ip[i] > 0 { break }
|
|||
|
|
}}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 关联笔记
|
|||
|
|
|
|||
|
|
- [[hhs/NETWORK/IPv4首部与分段重组]] — IP 地址在 IPv4 包中的位置
|
|||
|
|
- [[hhs/NETWORK/IPv6地址与扩展头部]] — IPv6 同样使用 CIDR 表示法
|
|||
|
|
- [[hhs/NETWORK/NAT原理与应用]] — NAT 通常映射到私有地址空间
|