服务端辅助脚本会配置一个子网,然后用自选的动态地址池把它填满。这个默认值一直很方便,直到某些地址必须留在分配之外——无论它们是为固定分配预留的,还是为将来的网段保留下来的。关闭自动地址池并自行声明范围,只需要两行,以及一个关于哪些地址不参与分配的有意决定。其余就是运维纪律:盘点、应用、验证、回滚。

这是对正在运行的服务做变更,所以把它当作运维任务:先盘点,再按正常生命周期应用,用新客户端验证,并保留回滚方案。

从你已经有的子网出发

读取当前服务端配置和客户端实际占用的地址。地址池变更只有对照这条基线才有意义,而基线并不总是文件所暗示的那样,因为托管产品或配置生成器可能才是你正在读的文件的拥有者。

grep -nE '^(topology|server|ifconfig-pool|max-clients|client-config-dir)' /etc/openvpn/server/lab.conf
ip -4 addr show tun0

确认生效的拓扑。在子网拓扑下,每个客户端从池中取一个地址;较老的 net30 布局为每个客户端分配一个小块,算法完全不同。如果服务端仍在 net30 上,这一页就是错误的迁移指南,池中的数字也不会是你预期的含义。在从别处照搬地址算法之前,先核对那一行。

写下服务端自身的地址、客户端配置目录中的每一条固定分配,以及任何路由或访问规则所依赖的地址。这些就是必须留在动态范围之外的地址。先把它们写下来,范围才会成为决定而不是猜测。它也让回滚有具体的东西可以恢复。

加入 nopool 并声明范围

辅助关键字接受 nopool,它保留子网配置并关闭自动动态地址池,正如 OpenVPN 2.6 手册所述。随后显式的 ifconfig-pool 行给出你想要的包含两端的范围,其网络掩码与子网一致。两行都属于同一个 server 块,因为脱离子网的池没有意义。两者之间的顺序只影响可读性,因为服务启动时辅助脚本会把这一对展开。

topology subnet
server 10.70.0.0 255.255.255.0 nopool
ifconfig-pool 10.70.0.50 10.70.0.120 255.255.255.0

两端都是包含的,所以这个例子提供七十一个地址。把服务端地址和每一条固定分配留在该范围之外;落在动态范围内的固定分配会产生依赖连接顺序的冲突,而这是最难排查的一类。如果固定分配可能增加,就在保留集合与范围之间留出余量。

范围大小和并发数是两个独立的限制。如果 max-clients 另有规定,一百个地址并不等于一百个并发客户端,而池大于并发上限是正常的,不是浪费。重要的是这两个限制是有意选择的,而不是从默认值继承来的。

让固定分配留在动态范围之外

针对单个客户端的 ifconfig-push 与池分配是不同的机制,必须使用与当前拓扑相符的参数。在子网模式下它是一个地址加网络掩码;因为旧示例里出现过就照搬 net30 的一对地址,是常见的错误。

分配历史只是提示,不是权威。persist 文件记住哪个客户端用过哪个地址,所以重连的客户端往往拿到同一个,但它既不预留、也不释放地址,更不替代固定分配。如果某台设备必须始终持有某个地址,就使用固定分配,而不要依赖 persist 文件。

然后检查依赖地址的路径。推送给客户端的路由、放行某个子网的防火墙规则,或期望特定主机的监控检查,都可能假设的是旧范围。不改读它们就换池,会把故障转移到看似无关的地方。

按生命周期应用,然后验证

按照服务通常接收配置的方式应用变更——要么直接改文件并重启,要么通过会重新生成文件的管理层。对生成文件的手工修改只能撑到下一次生成,再久就不行。记录哪个机制拥有该文件,因为下一位操作者需要知道去哪里做同样的改动。然后重启一次,并在邀请客户端之前读日志。

systemctl restart openvpn-server@lab
journalctl -u openvpn-server@lab -n 30 --no-pager
# on a fresh client
ip -4 addr show tun0

连接一个此前从未连接过的客户端,确认地址落在声明范围之内、保留集合之外。然后确认回程:客户端应当能到达策略允许的范围,而不更多。地址符合计划却没有可用路由,就不是成功的变更。

重新连接一个曾持有旧范围地址的客户端。它应当拿到新范围内的地址,任何与旧地址绑定的会话级状态都应当消失。如果它仍保留旧地址,那就是别的东西在分配,池并不是你以为的拥有者。

回滚范围变更

在变更记录里保留前三行,而不只是上一个文件。恢复它们并重启,分配就回到旧行为,之后重连的客户端会从中拿到地址。

记录里应当有两点提醒。回滚时已经连接的客户端会保留当前地址直到重连,所以回滚并非全舰队即时生效。而如果旧范围与某条固定分配重叠,恢复它也会把冲突恢复回来;正是那处重叠促成了这次变更,它需要的是与回滚不同的修法。

当新客户端拿到范围内的地址、保留地址从不被发放、并且使用这些地址的路由与规则仍按预期工作时,地址池变更才算完成。任何少于这些的情况,都会留给下一个人去发现三者之中哪一条不成立。

相关文章