文章是本站的原创长文。每篇都保持无脚本、来源可溯,并与本站记录的系统现实一致:一个小型、静态、公网服务如何被构建、加固并保持诚实。
DHCP 只把地址租给你
DHCPv4 的动态分配把地址借给客户端一段租期。续租可以延长期限,到期则允许地址再次分配。DHCP 也支持其他分配策略,所以本文讨论的是有限期的动态租约,不把它说成协议唯一能够提供的配置。租期是使用地址的约定,不是设备对地址的永久所有权,也不是证明设备身份的凭据。 借用而非拥有地址 新初始化的客户端发现服务器、选择一份报价,再请求配置。确认后的租约记录允许使用地址的时间。租约数据库可以追踪分配,但不能保证所有机器都遵守协议:未受管理的静态地址、重叠地址池、服务器状态丢失或非法服务器,仍可能制造冲突。不能因为有集中租约表,就假定服务器永远知道整张网络里所有真实占用情况。 续约让租约保持存活 有限租期内,客户端通常在 T1 向原服务器请求续租;若到 T2 还没收到确认,则广播重绑请求,让其他合适的服务器也有机会回答。默认值分别是租期的一半与八分之七,服务器可以提供其他合法定时值。RFC 2131 建议在固定值附近加入随机变化,以减少客户端同步请求。因此默认比例不是必须原样保留的性能调优命令。 确认后的到期时刻按续租请求发送时间加上获准的新租期计算;后续 T1 和 T2 也应按更新后的租约计算,而不是继续沿最初入网时刻推进。续租通常保留地址,却不能保证设备在重启、换网或策略改变后永远得到同一地址。短租期让离场地址较快回收,也增加续租流量;长租期给客户端更多时间应对服务中断,却让已经离场的设备占用地址池更久。固定身份需求应明确配置分配策略。 过期即可回收 客户端可以主动释放地址,但正确运行不能依赖每台离场设备都发送 RELEASE。租约过期后,客户端必须停止使用地址并重新获取配置;服务器也可以重新分配这个地址。设备回来时可能拿到原地址,也可能获得不同地址,不能把换号写成必然结果。管理端删除绑定不会撤回客户端已经获得的租期,因此不能用盲目清空租约来代替冲突调查,否则可能主动制造重复分配。 坏掉的样子 地址池耗尽时,新发现请求可能收不到报价。NAK 则有特定含义,例如拒绝不适合当前网络的请求地址,不能把它统一解释成“地址池已满”。部分客户端在 DHCP 失败后配置 IPv4 链路本地地址,但这是另一种行为,也不能单凭它推断失败原因。先检查池容量、转发路径与服务器日志,再决定是否扩容或调整重试,避免把网络丢包当成地址不足。 租期过短会增加续租负载,并缩短客户端能够容忍服务器中断的时间。集中开机可能让流量聚集,却不意味着整个网络必然同步续租。应核对服务器实际下发的定时值和客户端重试方式,而不是只看名义租期。给新租约调长时间,也不会追溯性地延长之前已经确认的旧租约,观察窗口需要覆盖这部分过渡。 非法服务器可以给出错误网关或解析器。选择第一个报价只是客户端的一种可能策略,并非协议强制规定。服务器标识选项没有提供密码学认证,攻击者可以伪造;单独记住一个标识,并不能建立信任。交换机 DHCP snooping 等网络控制需要正确配置受信任端口和转发路径,才能限制回答来自哪里,不能用调短或调长定时器代替这个边界。 睡眠和计时处理可能暴露旧配置。设备醒来时若租约已经过期,必须先重新获取配置,不能继续占用地址,也不能假定自己只是进入 T2 重绑阶段。排查要结合租约已经经过的时间和实现日志;墙上时钟同步本身不能证明定时逻辑正确。地址冲突检测和 DECLINE 处理是另外的保障,不能因为租约表看起来正常就省略它们。 快速验证 把代码保存为 dhcp_lease_sim.py,运行 python3 dhcp_lease_sim.py。它只用标准库,通过虚拟时钟和简化的内存服务器检查租期算术与地址归属。单播和广播只是场景标签,没有发送网络报文,也没有实现完整客户端状态机。这里假定请求与确认瞬间完成,T2 取整秒;实际系统应读取服务器给出的值,不能把示例常量当作所有网络的固定设置。 ...