最稳妥的做法是在操作系统层面的防火墙(如 iptables 或 firewalld)上针对 OpenVPN 使用的网络接口或监听端口添加拒绝规则,而不是试图在 OpenVPN 配置文件内部实现 IP 封锁。
先说结论:通过宿主机的防火墙规则在数据包进入 OpenVPN 进程前进行拦截,效率更高且配置解耦。
- 先判断:确认是要封禁连接端口的访问,还是限制已建立隧道后的内网访问。
- 优先做:在操作系统防火墙层面添加 DROP 规则,针对 UDP/TCP 端口或 tun 接口。
- 再验证:使用外部网络测试连接是否被阻断,并检查防火墙日志。
命令速用版
如果你使用的是 iptables 且 OpenVPN 监听默认 UDP 1194 端口,封禁特定源 IP 的命令如下:
iptables -I INPUT -p udp `--dport` 1194 -s 1.2.3.4 -j DROP
如果是针对已经建立连接后的隧道流量(假设隧道接口为 tun0):
iptables -I FORWARD -i tun0 -s 10.8.0.5 -j DROP
注意:执行前请确保你有其他方式访问服务器,避免规则错误导致自己无法连接。
为什么会这样
OpenVPN 本身是一个运行在用户空间的程序,主要负责加密、解密和路由转发。如果在 OpenVPN 配置文件中做限制,数据包通常已经完成了网络层的接收,甚至可能已经消耗了部分解密资源。
操作系统防火墙(如 netfilter/iptables)工作在内核层,可以在数据包到达 OpenVPN 进程之前就将其丢弃。这样做有两个好处:一是性能开销更小,二是规则管理更统一,不需要重启 OpenVPN 服务即可生效。
分步处理
1. 确认监听端口和协议
查看 OpenVPN 配置文件(通常是 /etc/openvpn/server.conf 或类似路径),确认 port 和 proto 设置。默认通常是 UDP 1194。
grep -E "^port|^proto" /etc/openvpn/server.conf
2. 添加防火墙规则
以 iptables 为例,将拒绝规则插入到 INPUT 链的头部(-I 参数),确保它优先于允许规则被执行。
iptables -I INPUT -p udp `--dport` 1194 -s 192.168.1.100 -j DROP
如果你使用的是 firewalld(CentOS 7+/RHEL 8+ 常见):
firewall-cmd `--add-rich-rule`='rule family="ipv4" source address="192.168.1.100" port port="1194" protocol="udp" reject' `--permanent`
firewall-cmd `--reload`
3. 保存规则
iptables 规则默认重启后失效,需要保存。Debian/Ubuntu 可使用 iptables-persistent,CentOS 可使用 service iptables save 或手动备份。
怎么验证是否生效
1. 连接测试
在被封禁的 IP 机器上尝试连接 OpenVPN 服务端,客户端应显示连接超时或握手失败,而不是认证失败。
2. 抓包确认
在服务端使用 tcpdump 观察是否有来自该 IP 的数据包进入。如果防火墙生效,通常看不到入站数据包,或者能看到入站但无回应(取决于 DROP 还是 REJECT)。
tcpdump -i any host 192.168.1.100 and port 1194
3. 日志检查
查看内核日志或防火墙日志,确认是否有丢弃记录。部分配置下需要开启日志记录规则(-j LOG)才能看到。
常见坑
1. 规则顺序错误
防火墙规则是从上到下匹配的。如果在拒绝规则之前已经有一条允许所有(ACCEPT)的规则,拒绝将不会生效。务必使用 -I 插入到链条顶部,或检查现有规则顺序。
2. 把自己锁在外面
如果你正在通过 OpenVPN 连接管理服务器,添加拒绝规则时要小心不要误封自己的当前 IP。建议先设置超时自动清除的规则,或确保有 SSH 等带外管理方式。
3. IPv6 遗漏
如果服务器开启了 IPv6,iptables 只管理 IPv4。需要同时检查 ip6tables 或 nftables,防止攻击者通过 IPv6 绕过限制。
4. 隧道内 IP 与公网 IP 混淆
区分清楚是要封禁“连接 VPN 的公网 IP”还是“分配给客户端的隧道内网 IP”。前者在 INPUT 链控制,后者通常在 FORWARD 链控制。