hosts.allow 是什么
TCP Wrappers 是上世纪 90 年代的访问控制机制:服务程序接受连接后,通过 libwrap 查询 /etc/hosts.allow 与 /etc/hosts.deny,按「守护进程名 + 客户端来源」决定是否放行。匹配顺序是:先看 hosts.allow,命中即放行;未命中再看 hosts.deny,命中即拒绝;两边都没命中则默认放行(除非启用 paranoid 模式),所以残留的放行规则优先级最高。
为什么会「写了不生效」
libwrap 不是内核能力,也不是防火墙能力,而是服务程序自己编译链接进去的。主流发行版的 OpenSSH 包早已不再链接 libwrap,写在 hosts.allow 里的 sshd 规则对它完全没有作用;仍有个别老服务(某些构建的 vsftpd、xinetd 托管的明文服务)保留了支持。结果就是同一台机器上,一份文件对一部分服务有效、对另一部分无效,只能逐服务实测确认。
基本信息
| 机制 | TCP Wrappers(libwrap) |
|---|---|
| 配置文件 | /etc/hosts.allow 放行、/etc/hosts.deny 拒绝 |
| 规则语法 | daemon[@host]: client_list |
| 生效前提 | 服务二进制链接了 libwrap |
| 现状 | 主流发行版的 OpenSSH 已不再链接 libwrap |
| 现代替代 | sshd_config 的 AllowUsers/AllowGroups + 防火墙默认拒绝 + SELinux |
典型使用场景
- 老系统基线核查:检查项里仍有 hosts.allow,但结论必须靠实测而非读文件
- 系统整改:把老机制的控制意图转写成 sshd 侧限制与防火墙规则
- 异常排查:同网段 A 服务可连、B 服务连不上,先看两者是否都链接了 libwrap
- 服务下线:移除相关旧组件前,先盘清还有哪些服务依赖它
核查现状
核查现状
ls -l /etc/hosts.allow /etc/hosts.deny # 文件是否存在、最后修改时间
grep -Ev '^#|^$' /etc/hosts.allow /etc/hosts.deny # 看实际写下的规则
ldd /usr/sbin/sshd | grep -i wrap # 有输出才说明 sshd 受 hosts.allow 约束
sshd -T | grep -iE 'allowusers|allowgroups|denyusers' # sshd 侧当前生效的控制转写为现代写法
转写为现代写法
# 老写法:来源用 netmask 形式,不是防火墙习惯的 CIDR
# /etc/hosts.allow
# sshd: 192.168.1.0/255.255.255.0
# 现代写法一:限制可登录的账号与来源
# /etc/ssh/sshd_config
AllowGroups ops-admins
AllowUsers deploy@10.20.0.*
# 现代写法二:防火墙限源
firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=192.168.1.0/24 port port=22 protocol=tcp accept'
sshd -t && systemctl reload sshd # 改 sshd 配置先做语法检查再重载老机制与现代做法对照
| 老写法 | 现代等价做法 | 注意事项 |
|---|---|---|
| sshd: 10.0.0.0/255.0.0.0 | 防火墙限源 + sshd 侧账号限制 | 老写法是 netmask,照抄成 CIDR 到防火墙会失效 |
| sshd: ALL | 防火墙默认拒绝策略 | 老机制默认放行,语义与防火墙默认拒绝不同 |
| hosts.deny 里 ALL: ALL | 默认拒绝 + 服务最小化 | 只在服务链接 libwrap 时生效,覆盖面不可靠 |
| telnetd、in.ftpd 等老服务 | 改用 SSH、sftp、scp 隧道 | 明文协议本身就该被淘汰,不必为新机制保留 |
不同发行版对 tcp_wrappers 相关软件包的取舍不同,个别发行版已不再提供。先确认系统里是否还有 libwrap 及其依赖,再判断哪些服务仍然受影响。
最危险的假象是「文件里配了访问控制」:检查若只读文件内容就下结论,实际可能毫无防护。必须从非允许网段实测一次连接来验证,实测不通过就等于没配。
如果确实要保留老机制,规则写成 daemon: client 形式,来源用 netmask;同时仍应在防火墙上做第二道限制,避免单点依赖。