IPtables 根据主机名将动态 IP 列入白名单

IPtables 根据主机名将动态 IP 列入白名单

我想使用 iptables 将对服务器的访问限制为某些 IP,但是:

  • 其中一个 IP 是动态的,是正常的 ISP 家庭连接,它会不时变化。
  • 当 IP 发生变化时,子域名(例如 dynamic.example.org)会使用类似于 dyndns 的服务自动更新。

如果 dynamic.example.org 解析为该 IP,是否可以让 IPtables 允许访问端口?

我目前的想法是设置一个 systemd 单元,定期解析 dynamic.example.org 并相应地调整 iptables。但是,这还需要知道旧 IP 地址(因此将其存储在某处)才能将其从白名单中删除。

是否有更简单的方法可以做到这一点,并且已内置于 iptables 中?

答案1

iptables适用于 IP 地址,而不适用于主机名。您可以使用主机名作为参数,但它们将在输入命令时解析。对每个通过的数据包进行 DNS 查找会太慢。

因此,调整规则是唯一的方法。这可以定期进行,由 systemd 或 cron 等程序控制,或者如果您能够设法在 IP 地址更改时收到通知,那就更好了。

您不必存储旧地址,只需为您的规则创建一个 iptables 链并替换该规则即可。请参阅选项-Riptables要在第一次检查时替换规则,只需添加一条虚拟规则,以便在第一次检查运行时有一条规则可以替换。

INPUT您还可以避免多余的链并替换或中的特定位置的规则FORWARD,但这需要更多的维护工作,因为每当您添加或删除规则时位置编号都会发生变化。

答案2

我这样做的方法是:

  • 每 x 分钟从 crontab 运行一次脚本来更新“ipset”
  • 让 IPtables 使用 ipset

假设此 ipset 中只有 1 个 IP 地址,则以下脚本可以执行:

#!/bin/bash
# Update ipset to let my dynamic IP in
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

set=whitelist
host=myhost.dynamic.example.com

me=$(basename "$0")

ip=$(dig +short $host)

if [ -z "$ip" ]; then
    logger -t "$me" "IP for '$host' not found"
    exit 1
fi

# make sure the set exists
ipset -exist create $set hash:ip

if ipset -q test $set $ip; then
    logger -t "$me" "IP '$ip' already in set '$set'."
else 
    logger -t "$me" "Adding IP '$ip' to set '$set'."
    ipset flush $set
    ipset add $set $ip
fi

crontab每 5 分钟调用一次此脚本:

*/5 * * * * root /usr/local/bin/ipset-update-dyn

在 iptables 中,使用 ipset 的规则如下所示:

-A INPUT -p tcp -m set --match-set whitelist src -m state --state NEW -j ACCEPT

答案3

使用 dig 甚至更简单:

iptables -I INPUT -p tcp -s $(dig +short yourdomain.ddns.net) -m state --state NEW -m tcp -j ACCEPT

解释:

dig+short yourdomain.ddns.net在返回 IPv4 IP 的子进程中启动。此子进程的输出将传递给 iptables 二进制文件,添加一条新规则。

请注意,我们习惯-I将规则添加到所有其他规则的前面,如果要附加,请使用-A

iptables -A INPUT -p tcp -s $(dig +short yourdomain.ddns.net) -m state --state NEW -m tcp -j ACCEPT

更新:

正如 MartinV 所述,如果您继续添加规则,最终可能会产生大量重复规则,并且会达到规则限制容量。

最好的方法是创建一个链来保存您的 DDNS 规则,然后在添加新规则之前刷新自定义链。

如果不存在,则创建一个自定义链,将自定义链 myDDNS 添加到 INPUT 链的前面,以防止被 INPUT 链中的最终一般 REJECT 阻止,并刷新链:

iptables -N myDDNS 2>/dev/null;iptables -I INPUT -j myDDNS;iptables -F myDDNS

如果链存在,则会引发错误,但自定义链不会重复。将错误重定向到 /dev/null 将防止在 STDIN 上抛出错误。

将您的规则添加到您的自定义链中:

iptables -I myDDNS -p tcp -s $(dig +short yourdomain.ddns.net) -m state --state NEW -m tcp -j ACCEPT

只需将所有内容放在一行中,然后每 N 分钟从 cron 调用一次脚本。

iptables -N myDDNS 2>/dev/null;iptables -I INPUT -j myDDNS;iptables -F myDDNS && iptables -I myDDNS -p tcp -s $(dig +short yourdomain.ddns.net) -m state --state NEW -m tcp -j ACCEPT

&&在 (flush) 和规则前置之间添加iptables -F将确保仅当 flush 命令返回 0 时才添加规则

相关内容