使用 knockd 实现端口敲门:动态开放 Linux 服务
端口敲门原理
端口敲门(Port Knocking)是一种隐蔽的服务访问控制机制。管理员预先定义一组端口序列,外部主机必须按顺序访问这些端口(通常使用 TCP 或 UDP 数据包),才能触发服务器动态修改防火墙规则,短暂开放原本隐藏的服务端口,如 SSH(22)或 HTTPS(443)。未提供正确敲门序列的连接尝试会被防火墙直接丢弃,使得端口扫描无法发现真实服务,从而降低被攻击面。
在 Linux 中,这一功能由 knockd 服务实现,它监听网络接口上的所有数据包,匹配预定义的敲门序列,然后执行用户指定的命令(通常是添加或删除 iptables 规则)。
安装 knockd
apt install knockd
配置文件结构
主配置文件为 /etc/knockd.conf,分为全局选项和若干规则段。每个规则段定义一组敲门序列及对应的动作。以下是一个基础示例,包含开启和关闭 SSH 的两个规则段:
[options]
UseSyslog
Interface = enp0s3
[openSSH]
sequence = 5000,6000,7000
seq_timeout = 25
command = /sbin/iptables -I INPUT 1 -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags = syn
[closeSSH]
sequence = 7000,6000,5000
seq_timeout = 25
command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags = syn
关键参数说明:
- Interface:指定监听的网络接口,默认值为
eth0,现代系统需改为实际接口名,如enp0s3、ens33等。 - sequence:敲门端口序列,客户端必须按顺序向这些端口发送 TCP SYN 包(若未指定协议,默认使用 TCP)。
- seq_timeout:完成整个序列的最大时间(秒),超时则序列失效,需重新开始。
- command:序列匹配成功后执行的命令,
%IP%会被替换为客户端的 IP 地址。 - tcpflags:要求匹配的 TCP 标志,通常使用
syn来匹配初始连接请求。
配置防火墙默认策略:由于动态规则使用 ACCEPT,应确保防火墙默认 INPUT 链为 DROP 或尾部存在拒绝规则,否则规则可能不生效。推荐使用 -I 在链首插入规则,避免被已有规则遮蔽。
iptables -P INPUT DROP
启动与管理服务
systemctl enable knockd
systemctl restart knockd
检查状态:
systemctl status knockd
触发敲门动作
安装 knockd 后自带的 knock 工具是最可靠的敲门方式:
# 开启 SSH 端口
knock 192.168.1.100 5000 6000 7000 -v
# 关闭 SSH 端口
knock 192.168.1.100 7000 6000 5000 -v
# 可指定协议和端口
knock 192.168.1.100 5000:tcp 6000:udp 7000:tcp
其他工具如 nc、nmap 理论上可行,但 nc 表现不稳定,且需注意超时设置,避免总耗时超过 seq_timeout。例如:
nc -z -w 1 192.168.1.100 5000 6000 7000
实际使用中推荐优先使用 knock 命令。
高级配置示例
自动关闭:使用 start_command 与 stop_command
当服务需要临时开放并在一定时间后自动关闭,可使用单个规则段配合 cmd_timeout:
[opencloseSSH]
sequence = 2222:udp,3333:tcp,4444:udp
seq_timeout = 15
tcpflags = syn,ack
start_command = /sbin/iptables -A INPUT -s %IP% -p tcp --syn -j ACCEPT
cmd_timeout = 30
stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --syn -j ACCEPT
成功敲门后执行 start_command,等待 cmd_timeout 秒后自动执行 stop_command 撤销规则。
一次性序列防重放
通过 one_time_sequences 指定一个序列文件,每次成功敲门后,该序列即失效,下次必须使用文件中的下一个序列,有效防止嗅探重放:
[opencloseSMTP]
one_time_sequences = /etc/knockd/smtp_sequences
seq_timeout = 15
tcpflags = fin,!ack
start_command = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 25 -j ACCEPT
cmd_timeout = 5
stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 25 -j ACCEPT
序列文件 /etc/knockd/smtp_sequences 中每行一个序列,格式与 sequence 相同,knockd 会逐行读取并删除已使用的序列。
IPv4 与 IPv6 双栈支持
为 IPv4 和 IPv6 分别定义命令,使用 _6 后缀的指令:
[opencloseHTTPS]
sequence = 12345,54321,24680,13579
seq_timeout = 10
start_command = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 443 -j ACCEPT
start_command_6 = /sbin/ip6tables -A INPUT -s %IP% -p tcp --dport 443 -j ACCEPT
cmd_timeout = 30
stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 443 -j ACCEPT
stop_command_6 = /sbin/ip6tables -D INPUT -s %IP% -p tcp --dport 443 -j ACCEPT
全局选项一览
- UseSyslog:将日志输出到 syslog(通常为
/var/log/messages)。 - LogFile:指定自定义日志文件路径,如
/var/log/knockd.log。 - PidFile:指定 PID 文件位置,默认
/var/run/knockd.pid。 - Interface:监听接口,必配项,默认
eth0在现代系统中已不适用。
合理配置端口敲门,可有效隐藏关键服务,提升服务器的安全防护级别。