主题
可追溯性:DET44 存在的全部理由
上一篇讲了 DET44 放弃了多少能力:没有静态映射、没有 twice-NAT、没有负载均衡、 没有高可用,端口配额还是死的。
它用这些换来一件事。这一篇讲这件事为什么值。
运营商的合规压力
运营商会收到这样的请求:
2026 年 3 月 12 日 14:23,公网地址 203.0.113.100 的 3995 端口, 对应的是哪个用户?
来源可能是执法机关、版权投诉、或者被攻击方的溯源要求。必须能回答。
传统 NAT 只有一条路:记日志。每建立一条会话就记一行,内容包括时间、 内网地址端口、外网地址端口。
text
一个中等规模的城域网
────────────────────────────────────────────
5 万用户 × 人均 100 条并发会话 = 500 万条活跃会话
会话平均寿命按 60 秒算 → 每秒新建约 8 万条
每条日志按 100 字节算:
每秒 8 MB
每天 690 GB
留存 6 个月(常见合规要求) ≈ 124 TB而且这 124 TB 不能是冷存储 —— 收到查询请求时要能在合理时间内检索出来。 存储、索引、备份、审计,全都是钱。
DET44 的答案:不用记
映射是算出来的,所以不需要记录。只要知道当时的映射配置,一条命令就能回答。
亲自试一次
bash
./labctl reset base
./labctl apply base 09
# 让 h1 出去几次
ssh chenzhong@192.168.49.182 \
'docker exec clab-natbase-h1 nc -w 2 203.0.113.11 9000'text
[s1 tcp/9000] 我看到你的地址是 203.0.113.100:3995现在假装你是运营商,只知道"203.0.113.100 的 3995 端口":
bash
./labctl vppctl base det44 reverse 203.0.113.100:3995text
10.10.0.11完了。没有查日志,没有检索,没有存储成本。
自检会把整条链路验一遍
bash
./labctl verify base 09text
── 4) 可追溯性:拿公网端口反推内网主机 ──────────
203.0.113.100:3995 → 10.10.0.11
203.0.113.100:3881 → 10.10.0.11
203.0.113.100:3813 → 10.10.0.11
203.0.113.100:4127 → 10.10.0.12
203.0.113.100:4295 → 10.10.0.12
✓ 每个端口都能准确反推回内网主机两个方向的查询
bash
# 正向:这个用户占用了哪些公网端口?
vppctl det44 forward 10.10.0.11text
203.0.113.100:<3796-4047>bash
# 反向:这个公网端口是谁在用?
vppctl det44 reverse 203.0.113.100:3995text
10.10.0.11正向查询在另一类场景里有用:用户投诉自己被封了。 拿到用户的内网地址,算出他占用的公网端口区间,就能去对方的封禁列表里比对。
最重要的一个坑:反查结果依赖当时的配置
改了映射配置,历史反查会静默给出错误答案
这是 DET44 用于合规场景时最危险的地方。
同一个端口 203.0.113.100:3995,在不同映射配置下的反查结果:
text
映射配置 det44 reverse 203.0.113.100:3995
────────────────────────────────── ────────────────────────────────
in 10.10.0.0/24 out 203.0.113.100/32 → 10.10.0.11
in 10.10.0.0/24 out 203.0.113.96/28 → 10.10.0.64 ← 完全不同!
(映射被删除) → no match改了共享比之后,同一个查询返回了另一台主机。它不报错,不警告, 就是给你一个看起来很正常的错误答案。
如果你在 3 月配的是 /32,5 月改成了 /28,然后 6 月收到一个关于 3 月的查询 —— 按当前配置查出来的是 10.10.0.64,而真正的用户是 10.10.0.11。 你会把无辜的人交出去。
所以必须记什么
DET44 免掉的是会话日志,不是配置变更记录。你仍然需要:
text
必须留存 可以不留存
──────────────────────────────── ──────────────────────
每次 det44 add / del 的时间和内容 每条会话的建立和关闭
内网地址与真实用户的对应关系 (这才是 TB 级的那部分)
(谁在用 10.10.0.11,从什么时候开始)第二条同样关键。det44 reverse 只能告诉你内网地址, 从内网地址到"张三这个账号"还需要另一套映射 —— DHCP 租约、 PPPoE 会话记录、或者静态分配表。这部分 DET44 帮不上忙。
一个可行的做法
把映射配置纳入配置管理(Git / Ansible),每次变更自动打时间戳归档。 查询时先按时间找到当时的配置,再据此计算 —— 而不是拿当前配置去算历史。
更保险的是:尽量不改共享比。规划时留足余量, 让映射配置在整个留存周期内保持不变。
会话表仍然可以查
虽然不需要日志,实时排障时还是要看活跃会话:
bash
./labctl vppctl base show det44 sessionstext
NAT44 deterministic sessions:
in 10.10.0.11:55001 out 203.0.113.100:3861 external host 203.0.113.11:9001
state: udp-active expire: 632一行里有完整的四元信息:内网端、公网端、外部主机、状态和剩余时间。
手工关闭会话
bash
det44 close session in <内网地址>:<端口> <外部地址>:<端口>
det44 close session out <公网地址>:<端口> <外部地址>:<端口>close session out 在 26.06 上不工作
实测对着一条明确存在的会话:
text
in 10.10.0.11:55002 out 203.0.113.100:3862 external host 203.0.113.11:9001
state: udp-activebash
vppctl det44 close session out 203.0.113.100:3862 203.0.113.11:9001text
no match而同一条会话用 in 的写法就能正常关闭:
bash
vppctl det44 close session in 10.10.0.11:55002 203.0.113.11:9001(会话数从 1 变成 0)
所以在 26.06 上只用 close session in。 如果手上只有公网侧的信息,先用 det44 reverse 反查出内网地址, 再用 in 的写法关闭。
IPFIX 日志
DET44 免掉了必须记日志的压力,但 VPP 仍然提供了 IPFIX 导出,用于需要更细粒度审计的场景:
bash
vppctl nat ipfix logging enable
vppctl nat ipfix logging enable domain 1 src-port 4739
vppctl nat ipfix logging disable没有对应的 show 命令
命令执行返回成功,但 VPP 没有提供 show nat ipfix 之类的命令来确认状态。 要验证是否真的在导出,只能在收集器那一侧看有没有数据进来。
日志级别可以调:
bash
vppctl nat set logging level 3用 DET44 还开 IPFIX 看似矛盾,其实有合理场景: DET44 保证了"端口→内网地址"可算,但如果你还想知道 这个用户当时在访问哪个外部目的地,那还是得记录。 只是记录量比传统 NAT 小得多 —— 不需要记映射关系,只记访问行为。
什么时候该选 DET44
text
✓ 适合 ✗ 不适合
────────────────────────────────── ──────────────────────────────
运营商 CGN,有明确的溯源合规要求 企业出口(需要端口转发发布服务)
用户数巨大,日志存储成本无法接受 用户并发差异大(有人几条有人上千条)
用户行为可预测,能算准端口配额 需要高可用(DET44 没有)
能接受"用完就断",不需要弹性借用 需要 twice-NAT / 负载均衡 / VRF最大的业务风险是配额刚性
再强调一次上一篇的要点:DET44 的端口配额用完就断,不能借。
共享比 256 时每台主机只有 252 个端口。一个用户打开几个现代网页 (每个页面几十条连接)就可能到顶,之后所有新连接直接失败 —— 而隔壁用户的 252 个端口可能一个都没用。
上线前必须用真实流量画像估算峰值并发,并留 1.5~2 倍余量。 这个账算错了,故障表现是"部分用户间歇性打不开网页", 而且监控上看不出任何异常 —— 没有池耗尽,没有会话表满, 每个用户都在自己的配额内正常工作,只是有些人的配额不够用。
小结
| 解决什么 | 用算法替代日志,实现零存储成本的溯源 |
| 正向查询 | det44 forward <内网地址> → 公网地址和端口区间 |
| 反向查询 | det44 reverse <公网地址>:<端口> → 内网地址 |
| 省掉的存储 | 会话日志(TB 级) |
| 仍必须留存 | 映射配置的变更历史 + 内网地址到真实用户的对应关系 |
| 最危险的坑 | 改了映射配置后,历史反查静默返回错误答案 |
| 26.06 的 bug | close session out 对存在的会话返回 no match,只用 in |
| 最大业务风险 | 端口配额刚性,超标即失败且监控无异常 |
第 4 章到此结束。CGN 的核心矛盾其实是一句话:
text
弹性(nat44 的地址池) ←→ 可追溯(det44 的算法)
想要弹性,就得记日志买存储
想要省存储,就得接受配额刚性接下来第 5 章进入 IPv6 过渡:nat64 让纯 IPv6 客户端访问 IPv4 服务, 以及 nat66。那需要一个新的实验底座 —— 内网是 IPv6-only 的。