确认目标服务是否受tcp_wrapper控制需先用ldd检查二进制是否链接libwrap.so,无输出则规则无效;规则格式须严格,空格、冒号、换行均影响解析;用tcpdmatch验证匹配逻辑;拒绝日志依赖syslog配置及libwrap调用;规则匹配按文件内自上而下首处生效。

确认目标服务是否真的受 tcp_wrapper 控制
很多问题根本没开始就结束了:你改了 /etc/hosts.allow 和 /etc/hosts.deny,但连接照样通——因为服务压根没调用 libwrap.so。
必须用 ldd 实际检查二进制文件:
ldd $(which sshd) | grep libwrap ldd $(which vsftpd) | grep libwrap
如果无输出,说明该服务不支持 tcp_wrapper,写任何规则都无效。常见例外:
- 新版
sshd(OpenSSH ≥ 6.7)默认仍链接libwrap.so,但某些发行版(如 Alpine 或精简镜像)会编译时禁用 -
nginx、redis、postgresql等几乎从不链接libwrap,别白费劲 - systemd socket-activated 服务(如
sshd.socket)可能绕过 wrapper 检查,优先用sshd.service直接启动方式验证
写对规则格式,空格和冒号是致命的
规则不是“能看懂就行”,tcpd 解析器严格按 POSIX 文本格式处理,一个中文冒号、末尾缺换行、多余空格都会导致整行被忽略。
正确写法示例(以允许特定网段访问 sshd):
sshd:192.168.10.0/24 sshd:192.168.10.*
这些写法**全部错误**:
-
sshd : 192.168.10.0/24(冒号前后有空格) -
sshd:192.168.10.0/24(末尾是全角空格或不可见 Unicode 字符) -
sshd:192.168.10.0/24(文件最后一行没换行符 → 整行被内核忽略) -
ssh:192.168.10.0/24(服务名错,必须是二进制名sshd,不是协议名或包名)
用 tcpdmatch 提前验证匹配逻辑
别靠盲试。改完配置后,用 tcpdmatch 模拟判断过程,它不发包、不连端口,只做纯规则解析:
tcpdmatch sshd 192.168.10.5 tcpdmatch vsftpd 203.208.60.1
输出类似 access granted 或 access denied,直接告诉你规则是否生效、走的是 hosts.allow 还是 hosts.deny。若提示 no such process,说明 tcp_wrappers 包未安装(CentOS/RHEL 需 yum install tcp_wrappers,Debian/Ubuntu 是 tcpd 包)。
注意:tcpdmatch 不校验 DNS 反查或 PARANOID 类 ACL,仅做字符串/掩码匹配,够用但不覆盖全部行为。
拒绝连接时看不到日志?先查 syslog 目标和 libwrap 调用路径
tcp_wrapper 拒绝连接时默认写入 /var/log/messages 或 /var/log/secure,但前提是:
- syslog 配置中,
auth或authpriv设施(facility)没被过滤(检查/etc/rsyslog.conf中是否有auth.* /dev/console这类丢弃规则) - 服务确实调用了
libwrap.so,且在拒绝时触发了syslog()调用(有些静态链接或裁剪版会跳过) - 你测试时用的是新连接(已有 SSH 会话不受影响),且客户端 IP 真的匹配了
hosts.deny中某条规则
临时加一条强日志规则调试:
ALL: ALL : twist /bin/echo "tcpd blocked %a from %h" >> /tmp/tcpd.log 2>&1
这条会强制记录所有被拒 IP 和主机名(%a、%h),比依赖 syslog 更可靠。部署前务必删掉,否则影响性能。
最常被忽略的一点:规则顺序只看文件内**第一处匹配**,不是最长前缀、也不是最精确,而是从上到下逐行扫描,遇到第一个匹配就终止。所以把宽泛规则(如 ALL: ALL)放在文件末尾,否则上面的精细规则永远没机会执行。


















