dzaczek/nftgeo

GitHub: dzaczek/nftgeo

nftgeo 是一个用于 Debian/Ubuntu 上 nftables 的声明式地理防火墙工具,通过简单的规则文件自动生成并维护按国家/地区/IP 过滤的防火墙策略。

Stars: 1 | Forks: 0

# nftgeo `nftgeo` 是一个用于 Debian 和 Ubuntu 上 `nftables` 的小型声明式地理防火墙。 你只需针对每个端口和方向描述允许哪些国家或地区,该工具就会为你构建并维护 `nftables` 规则: - 通过简单的 `rules.conf` 实现基于方向的允许/拒绝规则:入站、出站, 以及转发(路由器/网关/VPN)流量, - 按国家、地区或字面 IPv4/IPv6 地址或子网进行匹配, - 支持 tcp、udp、sctp、icmp、icmpv6、esp、ah 和 gre,支持单个端口或端口范围, - 有状态:对你自身请求的回复始终被允许, - 在你指定的位置拦截 AbuseIPDB 黑名单,其粒度与其他任何规则的方向/协议/端口设置相同, - 始终允许包含受信任 IP 或主机名的可配置白名单(后者在每次运行时重新解析), - 每条规则均带有计数器,因此 `nft list` 会显示每条规则的数据包/字节总数, - 仅下载你的规则实际使用的国家区域,并具备本地缓存, - 通过 `systemd` timer 每天刷新两次规则, - 在加载前验证 `nftables` 文件并对其进行原子替换。 ## 工作模型 你可以在 `/etc/nftgeo/rules.conf` 中像写句子一样编写规则: ``` # action dir proto port target allow in tcp 22 europe allow in tcp 22 203.0.113.5 allow in icmp - any deny in tcp 22 ru deny in any - abuse allow in all 5060 de allow out udp 53 any allow fwd-in esp - europe deny fwd-in any - abuse ``` 两个简单的保证: - 出现在任何(该方向的)`allow` 规则中的端口默认是**关闭的**: 只有列出的区域能够通过,其他所有人都会被丢弃。 - 你未曾提及的端口/方向将**保持原样**。 在受管端口之上,白名单始终具有最高优先级。AbuseIPDB 黑名单是可选的: 它只会在你编写 `deny ... abuse` 规则的地方被丢弃,因此你可以控制其确切的作用范围(见下文)。 ### 字段 - `action` - `allow` 或 `deny`。`deny` 会丢弃某个区域的数据,但不会对 其他所有人关闭该端口,并且在 `allow` 之前进行评估。 - `dir` - 以下选项之一: - `in` - 入站到此主机(根据源国家匹配), - `out` - 从此主机出站(根据目标国家匹配), - `fwd-in` - 路由/转发的流量,根据源国家匹配, - `fwd-out` - 路由/转发的流量,根据目标国家匹配。 - `proto` - 基于端口的:`tcp`、`udp`、`sctp` 或 `all`(tcp 和 udp)。无端口的: `icmp`(仅限 IPv4)、`icmpv6`(仅限 IPv6)、`esp`、`ah`、`gre` 或 `any` (所有协议和端口)。 - `port` - 单个端口(`22`)或范围(`5060-5070`);对于无端口的协议(包括 `any`),请使用 `-`。 - `target` - 源/目标地址的匹配依据:可以混合使用以逗号分隔的 国家代码(`pl`)、地区名称(`europe`)、字面 IPv4/IPv6 地址 (`203.0.113.5`、`2001:db8::1`)、带掩码的 IPv4/IPv6 (`10.0.0.0/8`、`2001:db8::/32`)、配置文件中名为 `GROUP_` 的列表 (通过其小写名称使用,例如 `office`),或者保留字 `any`(所有地址)和 `abuse`(AbuseIPDB 黑名单,仅限 `deny`)。可混合使用的目标可以组合在一条规则中 (`allow in tcp 80 198.51.100.0/24,de,office`);`any` 和 `abuse` 独立使用。 在 `config` 中以 `GROUP_` 变量的形式定义可重用的地址组; 一个组本身可以混合 IP、子网、国家代码和地区名称: ``` GROUP_OFFICE="203.0.113.5 198.51.100.0/24 2001:db8:1::/48" GROUP_PARTNERS="de fr 192.0.2.0/24" ``` 组不能引用其他组。 生成的每条规则都带有 `counter`,因此 `nft list table inet nftgeo` 会报告每条规则的数据包和字节总数。 `in`/`out` 构建 `input`/`output` 链;`fwd-in`/`fwd-out` 构建 `forward` 链,当主机是路由器、网关或在网络间传递流量的 VPN 节点时使用它们。 ### 回复与“仅作为响应的入站” 每条链首先接受 `established,related` 连接,因此对你发起的请求的 回复始终是被允许的。这意味着,入站流量只有在作为请求的响应时才会被允许, *除非*有 `allow in` 规则为新连接显式开放了端口。要运行一个可能向外发送 并接收响应的客户端,只需编写 `allow out` 规则;返回的数据包会自动流通。 ### 内置区域 `europe`、`north_america`、`caribbean`、`south_america`、`middle_east`、`asia`、 `africa`、`oceania`。覆盖其中任何一个,或者在 `config` 中添加你自己的 `REGION_`。 ## 示例 [`examples/`](examples/) 目录包含可直接适配的 `rules.d` 片段,适用于 常见服务 - SSH、公共 Web 服务器、邮件、Prometheus exporter、 WireGuard 节点、网关、出站控制和全局滥用黑名单。每个 文件都解释了每一行;将你需要的文件复制到 `/etc/nftgeo/rules.d/` 中并 编辑国家/IP。参见 [`examples/README.md`](examples/README.md)。 ## 环境要求 - Debian 或 Ubuntu - `systemd`、`nftables`、`curl` - root 权限 - 如果你想使用 AbuseIPDB 黑名单,则需要 AbuseIPDB API key 如果没有 AbuseIPDB key,脚本仍然可以工作;AbuseIPDB 集合将保持为空。 ## 安装 ``` cd /root/nftgeo sudo ./install.sh ``` 安装程序会: - 安装 `curl`、`nftables` 和 `ca-certificates`, - 将引擎复制到 `/usr/local/sbin/nftgeo-update`,并将操作员 CLI 复制到 `/usr/local/sbin/nftgeo`, - 创建 `/etc/nftgeo/config` 和 `/etc/nftgeo/rules.conf`,以及用于 存放插入文件的空 `rules.d/` 和 `groups.d/` 目录, - 安装 `nftgeo.service` 和 `nftgeo.timer`, - 在开机时启用该服务,并启用每天运行两次的 timer。 ## 配置 所有配置都位于 `/etc/nftgeo` 中: ``` /etc/nftgeo/ config # settings: AbuseIPDB key, WHITELIST, WHITELIST_HOSTS, ZONE_CACHE_HOURS, regions, groups rules.conf # rules (optional if you only use rules.d) rules.d/*.conf # rule fragments, included in sorted filename order groups.d/*.conf # GROUP_*/REGION_* definitions, sourced after config ``` 首先读取 `rules.conf`,然后按照 `LC_ALL=C` 排序的文件名顺序读取每个 `rules.d/*.conf` - 使用数字前缀(`10-ssh.conf`、`20-web.conf`、 `90-default.conf`)使顺序一目了然。同样地,`groups.d/*.conf` 会在 `config` 之后按排序顺序被加载,因此后面的文件可以覆盖 先前文件(或 `config`)设置的变量。 关于文件优先级:在一条链内,引擎始终按固定顺序评估 - `whitelist -> deny -> allow -> deny-by-default` - 无论规则来自 哪个文件(`deny ... abuse` 规则是 `deny` 步骤的一部分)。因此,`deny` 始终 优先于 `allow`,而两条 `allow` 规则永远不会冲突;文件顺序仅影响 在 `nft list` 中规则的查看方式,而不影响过滤决策。 编辑任何文件后,请应用更改: ``` sudo systemctl start nftgeo.service ``` ### AbuseIPDB ``` ABUSEIPDB_API_KEY="your-api-key" ABUSEIPDB_CONFIDENCE_MINIMUM="90" ABUSEIPDB_LIMIT="10000" ABUSEIPDB_DAYS="30" ABUSEIPDB_RETENTION_DAYS="30" ``` - `ABUSEIPDB_API_KEY` - AbuseIPDB API key。 - `ABUSEIPDB_CONFIDENCE_MINIMUM` - 最低滥用置信度分数。 - `ABUSEIPDB_LIMIT` - 最多下载的条目数。 - `ABUSEIPDB_DAYS` - 要考虑的 AbuseIPDB 历史记录天数。 - `ABUSEIPDB_RETENTION_DAYS` - 在最后一次在成功的 API 响应中被看到后, 要在本地保留 AbuseIPDB 地址的天数。 例如,将其设置为 `30` 或 `60`,可以将较旧的下载地址带入 后续的防火墙集合中,并自动丢弃超过该期限的条目。 保留的 AbuseIPDB 状态存储在 `/var/lib/nftgeo/abuseipdb.tsv` 中。 当 AbuseIPDB 下载失败时,`nftgeo` 会使用保留的状态,而不是 加载空的 `abuse` 集合。 黑名单通过 `rules.conf` 中保留的 `abuse` 目标应用, 并且仅当至少有一条规则使用它时才会下载。你可以像对待 任何其他规则一样决定其作用范围: ``` deny in any - abuse # block every protocol/port inbound from abuse IPs deny in tcp 22 abuse # block abuse IPs only on inbound SSH deny in all 1-65535 abuse # block abuse IPs on every tcp+udp port inbound deny out tcp 443 abuse # block outbound HTTPS to abuse IPs ``` `abuse` 仅限 `deny` 且独立使用(它不能与国家或 IP 组合在同一条规则中)。它会在白名单之后被丢弃,因此白名单中的 地址永远不会被它拦截。 #### 额外的黑名单源 `abuse` 集合不限于 AbuseIPDB。将 `ABUSE_FEEDS` 指向任何 纯文本 IP/CIDR 黑名单,它们就会被合并到相同的 `abuse4`/`abuse6` 集合中,因此每条 `deny ... abuse` 规则也会覆盖它们: ``` ABUSE_FEEDS="https://iplists.firehol.org/files/firehol_level1.netset https://www.spamhaus.org/drop/drop.txt" ``` 以空格或换行符分隔的 URL,仅在规则指定 `abuse` 时获取。 注释标记(`#`、`;`)以及地址之后的任何文本都会被剥离,这涵盖了 常见的源格式(FireHOL、Spamhaus DROP、blocklist.de、GreenSnow)。 每个源最后一次正常的副本会被缓存在 `/var/lib/nftgeo/feeds` 下,如果 后续下载失败则会重用该缓存,因此源中断绝不会缩小拦截列表。源在 有无 AbuseIPDB key 的情况下均可工作。 请注意源的质量:保守的列表(FireHOL level1、Spamhaus DROP)很少有 误报,而范围更广的列表(blocklist.de、GreenSnow)会拦截更多内容,但可能 会误伤合法流量。`WHITELIST` 始终优先于 `abuse`,因此请将你 自己的网络保留在那里。 ### 白名单(始终允许的 IP) `WHITELIST` 确保受信任的地址无论如何都能保持连接。白名单 IP 可以访问任何端口,即使它们位于允许的地理区域之外或出现在 AbuseIPDB 黑名单上: ``` WHITELIST="203.0.113.10 198.51.100.0/24 2001:db8::/48" ``` 以空格分隔,支持 IPv4 和 IPv6,支持单个地址或 CIDR 范围。这是 保护你自己的管理员 IP 免遭意外锁定的推荐方法。 `WHITELIST` 仅接受字面地址。要按名称将某项加入白名单 - 通常是动态 DNS 管理端点,例如 WireGuard 设备 - 请改为将其列在 `WHITELIST_HOSTS` 中: ``` WHITELIST_HOSTS="wireguard.example.ch vpn.example.net" WHITELIST_HOSTS_RETENTION_DAYS="7" ``` 每次运行时都会解析每个主机名(通过 `getent`,遵循 `/etc/hosts` 和 `resolv.conf`),并将生成的 IP 合并到白名单中。由于 `systemd` timer 会运行更新,这些名称会被定期重新解析;如果 地址发生更改,下一次成功的查找将替换旧的地址。主机最后一次成功解析的地址会保留在 `/var/lib/nftgeo/whitelist_hosts.tsv` 中,保留时间为 `WHITELIST_HOSTS_RETENTION_DAYS`,因此 短暂的 DNS 故障不会切断你的访问,而停止解析的地址将在该期限后失效。IPv4 映射的 IPv6 结果(`::ffff:...`)将被忽略。 ### 区域 区域是扩展为国家代码列表的宏。以下区域是 内置的,无需配置:`europe`、`north_america`、`caribbean`、 `south_america`、`middle_east`、`asia`、`africa`、`oceania`。 通过在 `config` 中定义 `REGION_` 变量来覆盖 内置区域或添加你自己的区域;在 `rules.conf` 中使用的名称是 `REGION_` 之后的小写部分: ``` REGION_EUROPE="ad al at ... ua va xk" # e.g. a trimmed Europe without ru/by REGION_NORDICS="dk fi is no se" # custom region, usable as "nordics" ``` ### 区域缓存 ``` ZONE_CACHE_HOURS="20" ``` 下载的国家区域在被刷新前会被重用这么多小时。 ## 手动运行 ``` sudo /usr/local/sbin/nftgeo-update ``` 运行过程通过锁(`/var/lib/nftgeo/.lock`)串行化,因此手动运行和 计划运行不能重叠;如果在 `LOCK_WAIT` 秒(默认为 60)内无法获取锁的运行 将在不触及规则集的情况下退出。 ## 操作员 CLI `nftgeo` 命令封装了常见的日常检查: ``` nftgeo check 203.0.113.7 # what does the firewall do to this address? nftgeo status # version, last run, set sizes, drop counters, next run nftgeo validate # check the current config renders/loads, without applying nftgeo plan # show how the rendered ruleset differs from what is loaded nftgeo apply # rebuild and load now (same as the update engine) ``` `nftgeo validate` 和 `nftgeo plan` 允许你在应用之前检查编辑内容: 如果配置无效,`validate` 将以零状态退出,而 `plan` 会打印策略 差异(诸如 abuse/geo 地址之类的集合内容会被省略,因此只会显示你的规则 更改)。两者都需要 root 权限,且均不会触及生效的规则集。 `nftgeo check ` 会报告该地址是否在白名单中、是否在滥用 列表中,或是否在任何地理集合中,打印匹配它的规则,并给出明确的判定 (允许 / 丢弃 / 位置)。`nftgeo status` 是从 生效的表、日志和源缓存中提取的单屏摘要。 ## 状态检查 如果你想要直接使用,以下是 `nftgeo status` 背后的原始命令: ``` nftgeo-update --version # installed version systemctl status nftgeo.timer systemctl list-timers --all nftgeo.timer systemctl status nftgeo.service journalctl -u nftgeo.service -n 100 --no-pager ``` 每次运行都会在 `Loaded` 行中记录其版本,例如 `nftgeo 1.0.0 loaded inet/nftgeo: rules=3 ...`。 带有每条规则计数器的活动规则,以及缓存的数据: ``` nft list table inet nftgeo nft list chain inet nftgeo input # or output / forward ls /var/lib/nftgeo/zones ls /var/lib/nftgeo/abuseipdb.tsv ``` 每次运行还会将其加载的集合持久化存储在 `/var/lib/nftgeo` 下 (`whitelist4.set`、`whitelist6.set`、`abuse4.set`、`abuse6.set`),以及保留的 `abuseipdb.tsv`。 ## 规则是如何构建的 对于上面的 `rules.conf` 示例,生成的链如下所示 (为简洁起见,省略了 IPv6 行): ``` chain input { type filter hook input priority -100; policy accept; ct state established,related counter accept # replies always allowed ip saddr @whitelist4 counter accept # whitelist wins first tcp dport 22 ip saddr @g_ru4 counter drop # explicit deny ip saddr @abuse4 counter drop # deny in any - abuse tcp dport 22 ip saddr @g_europe4 counter accept # geo allow (source) meta l4proto icmp counter accept # icmp "any" tcp dport 22 counter drop # deny-by-default } chain forward { type filter hook forward priority -100; policy accept; ct state established,related counter accept ip saddr @whitelist4 counter accept ip daddr @whitelist4 counter accept # both sides for routed traffic ip saddr @abuse4 counter drop # deny fwd-in any - abuse meta l4proto esp ip saddr @g_europe4 counter accept # geo allow (source) meta l4proto esp counter drop # deny-by-default } ``` `allow in all 5060 de` 和 `allow out udp 53 any` 规则添加了其余内容(一个 udp output 链和 5060 的 tcp+udp 条目);为了简洁起见,上面省略了它们。 请注意每条规则的 `counter`,以及默认拒绝(deny-by-default)为每个协议 和端口发出一条规则(因此重叠的单个端口和范围永远不会发生冲突)。 系统只会生成你实际使用方向的链。该表会进行原子替换: 生成的文件会在一次 `nft -f` 加载中重新创建该表,因此不存在 规则缺失的时刻。链策略为 `accept`,因此仅受你管理的端口会受到影响;其他一切保持原样。 该工具具备故障安全机制:如果 `allow` 规则中使用的国家解析后没有 地址(其区域无法下载且没有缓存副本),更新将 中止并保留之前的规则集,而不是冒险用空的 allow 集合关闭端口。仅在 `deny` 规则中使用的国家将被跳过 - 空的 deny 集合不会丢弃任何内容 - 因此一个无法解析的代码不能冻结 整个更新。 ## 访问安全 在对用于 SSH 的端口进行地理围栏之前,请确保你当前的 IP 位于 允许的地理范围内,或者将其添加到 `WHITELIST` 中。如果你可以通过 VPS 提供商的紧急控制台进行访问,请将其保留为恢复计划。 推荐的 SSH 配置: ``` PubkeyAuthentication yes PasswordAuthentication no KbdInteractiveAuthentication no AuthenticationMethods publickey ``` ## 更新计划 timer 会在以下时间运行更新: - 系统启动 2 分钟后, - 每天 2 次(03:00 和 15:00), - 最多 30 分钟的随机延迟。 上游 `ipdeny.com` 的国家区域每天重新生成一次,因此 比每天更频繁的刷新不会返回更新的数据。每天两次的计划 缩短了过期时间窗口(以便在 IP 分配在国家之间迁移时 能更快被获取),这意味着单次运行失败不会导致你落后 整整一天。`ZONE_CACHE_HOURS` 设置可防止第二次日常运行 重新下载第一次运行已经获取的内容。要更改频率,请编辑 `/etc/systemd/system/nftgeo.timer` 中的 `OnCalendar=` 并运行 `systemctl daemon-reload`。 ## 卸载 ``` cd /root/nftgeo sudo ./uninstall.sh ``` 移除生效的 `nftables` 表、systemd 单元、脚本以及 `/etc/nftables.d/nftgeo.nft`。保留 `/etc/nftgeo` 和 `/var/lib/nftgeo` 不变。 ## 版本控制 版本发布遵循[语义化版本控制](https://semver.org/)并标记为 `vMAJOR.MINOR.PATCH`。`nftgeo-update --version` 会报告已安装的版本,并且 每次运行都会将其记录在日志中。请参阅 [CHANGELOG.md](CHANGELOG.md) 了解版本之间的 更改。 ## 数据源 - AbuseIPDB 黑名单 API:`https://api.abuseipdb.com/api/v2/blacklist` - 国家 IP 前缀:`https://www.ipdeny.com` ## 注意事项 `nftgeo` 仅触及 `rules.conf` 中列出的端口。它不会为 整个系统设置默认的 `DROP` 策略,也不会关闭其他端口。
标签:Cutter, Debian, nftables, 地理封锁, 网络防火墙, 运维工具