端口敲门是通过预设端口序列触发防火墙临时放行的网络层访问控制机制,knockd监听syn包匹配序列后执行iptables规则增删,实现ssh端口动态开闭,全程不干扰服务且与应用层无关。

端口敲门不是把SSH关掉,而是让它在扫描器眼里“根本不存在”。Knockd 的作用是监听无业务意义的连接请求,按序触发防火墙规则变更——整个过程对 SSH 服务本身零干扰,也不依赖应用层协议。
配置 Knockd 实现双向动态控制
基础开门只是起点,进阶用法必须支持“敲完即开、用完即关”,避免临时规则长期滞留:
- 在 /etc/knockd.conf 中定义两组动作:正向序列(如 7000→8000→9000)执行
iptables -I INPUT 1 -s %IP% -p tcp --dport 22 -j ACCEPT;反向序列(9000→8000→7000)执行iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT - 务必使用 -I INPUT 1 而非 -A INPUT,确保规则插入最前端,优先于默认 DROP 策略
- 设置 seq_timeout = 5–15,太短易误失败,太长增加暴露窗口;cmd_timeout 不建议超过 60 秒
- 启用 tcpflags = syn,只响应 SYN 包,过滤 ACK/RST 干扰,提升抗噪能力
防火墙策略必须前置且严格
Knockd 本身不拦流量,它只改规则。如果底层 iptables 或 ufw 没设好,默认放行就让敲门完全失效:
- 先确认默认策略为 DROP:
sudo iptables -P INPUT DROP;允许 loopback 和已建立连接:sudo iptables -A INPUT -i lo -j ACCEPT、sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT - 显式拒绝 SSH 端口:
sudo iptables -A INPUT -p tcp --dport 22 -j DROP(不是跳过,是明确堵死) - 敲门端口本身无需开放——knockd 直接抓 raw packet,不经过 netfilter 连接跟踪,所以不用在 iptables 里放行 7000/8000/9000
客户端操作要可靠、可集成
手动敲三次再 ssh 容易出错,进阶做法是封装成一键流程:
- 用 knock 命令(需客户端安装 knockd 包):
knock -v server.com 7000 8000 9000 && ssh user@server.com - 无 knock 命令时,用 bash + /dev/tcp 模拟(仅 TCP):
for p in 7000 8000 9000; do timeout 1 bash -c "echo > /dev/tcp/server.com/$p" 2>/dev/null; done - 写入 ~/.ssh/config 实现透明代理:
Host myserver<br> HostName server.com<br> User admin<br> ProxyCommand bash -c 'knock -v %h 7000 8000 9000; exec nc %h %p'
- 加个 alias 自动关门:
alias ssh-out='knock -v server.com 9000 8000 7000'
避坑要点和运维建议
看似简单,但线上部署常因细节翻车:
- 别在云服务器或 NAT 后部署固定 IP 规则——运营商可能做连接复用,导致 %IP% 变成网关地址;建议搭配 StartCommand/StopCommand 或改用 nftables 的 dynamic set
- 启动前检查权限:
getcap /usr/sbin/knockd应返回 cap_net_raw+ep;否则加 systemd capability:CapabilityBoundingSet=CAP_NET_RAW - 日志必须打开:
UseSyslog = On,配合journalctl -u knockd -f实时观察敲门是否命中、哪步失败 - 测试阶段用 nmap -sS -p 22,7000,8000,9000 server.com 验证:未敲门前 22 显示 filtered,敲完立刻变 open,关门后恢复 filtered











