nftables-port-policy

Nftables 防火墙端口策略

服务器上搭建了KMS激活服务器,但是由于国外版权保护和DMCA 限制,我需要限制国外ip访问我的服务器1688 端口,网上大部分关于这方面问题的教程采取了ipset + iptables 的解决方案,暂无nftables解决方案,所以写一篇供大家参考。

获取nft_geoip 脚本

来源: https://wiki.nftables.org/wiki-nftables/index.php/GeoIP_matching

1
2
3
# mkdir /opt/script/nft-geoip
# git clone https://github.com/pvxe/nftables-geoip.git /opt/script/nft-geoip
# mkdir -p /etc/nft.d

构建定时更新脚本

1
# sudo vim  /etc/systemd/system/nft-geoip.service
1
2
3
4
5
6
7
8
[Unit]
Description=Nftables GeoIP

[Service]
User=root
Type=oneshot
ExecStart=/usr/bin/python3 /opt/script/nft-geoip/nft_geoip.py --file-location /opt/script/nft-geoip/location.csv -d -o /etc/nft.d/
ExecStartPost= /usr/sbin/nft -f /etc/nftables.conf
1
# sudo vim /etc/systemd/system/nft-geoip.timer
1
2
3
4
5
6
7
8
9
10
[Unit]
Description=Every Friday AM 3:00 renewal of nftables geoip

[Timer]
OnCalendar=Fri *-*-* 03:00:00
RandomizedDelaySec=1h
Persistent=true

[Install]
WantedBy=timers.target

参考配置

nftables 引用geoip区域文件做区域限制
给出我的 inet filter input 示例以供参考:

载入文件较大,需要超过 300M 的可用内存空间!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/usr/sbin/nft -f
# vim:set ts=2 sw=2 et:

# IPv4/IPv6 Simple & Safe firewall ruleset.
# More examples in /usr/share/nftables/ and /usr /share/doc/nftables/examples/.

# A simple firewall

flush ruleset

table inet filter {
include "/etc/nft.d/geoip-def-all.nft"
include "/etc/nft.d/geoip-ipv4.nft"
include "/etc/nft.d/geoip-ipv6.nft"
chain input {
type filter hook input priority 0; policy drop;

# insert geoip map
meta mark set ip saddr map @geoip4
meta mark set ip6 saddr map @geoip6

# established/related connections
ct state established,related accept

# invalid connections
# ct state invalid drop

# loopback interface
iif lo accept

# ICMP & IGMP
ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept
ip protocol icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept
ip protocol igmp accept
ip protocol icmp accept

# SSH (port 22)
# recommend nftables geoip zones limit
meta mark $CN tcp dport ssh log prefix "cn-zones-ssh-accept" counter packets 0 bytes 0 accept

# HTTP (ports 80 & 443)
tcp dport { http, https } accept
# vlmcsd -- Windows Key Management Services
# recommend nftables geoip zones limit
meta mark $CN tcp dport 1688 log prefix "cn-zones-kms-accept" counter packets 0 bytes 0 accept
# count and drop any other traffic
counter packets 0 bytes 0 drop
}
}

效果展示

如图:

错误示例:

网上有大量从apnic获取国内ip地址端的示例:

1
cn_ipv4=$(curl http://ftp.apnic.net/stats/apnic/delegated-apnic-latest | awk -F '|' '/CN/&&/ipv4/ {print $4 "/" 32-log($5)/log(2)}' )  

错误示例: cn_ipv6=$(curl http://ftp.apnic.net/stats/apnic/delegated-apnic-latest | awk -F ‘|’ ‘/CN/&&/ipv6/ {print $4 “/“ 32-log($5)/log(2)}’ )

1
cn_ipv6=$(curl http://ftp.apnic.net/stats/apnic/delegated-apnic-latest | awk -F '|' '/CN/&&/ipv6/ {print $4 "/" $5 }'  

ipv4 子网掩码可通过 32- 分配位数2的对数取余 获取,ipv6 掩码也这么算,明显是错误的,例如会算出这样一个奇怪的掩码:

1
240a:6000::/27.415

可见,大部分都,没有思考ipv4 地址端计算方式,
ipv6 合适的地址段表示:

1
2
3
4
apnic|CN|ipv6|2001:7fa:5::|48|20031106|assigned
转换为:
2001:7fa:5::-2001:7fa:5:ffff:ffff:ffff:ffff:ffff
2001:7fa:5::/48

F & A:

  • 为何不使用iptables + ipset ?

debian 12 自带的防火墙为nft,并且主流发行版新版本后端都采用了nft,这篇文章是学习nft用法。另外nft 可以省略ip6tables 规则的书写,直接使用inet表覆盖了ip和ip6.

  • 这个场景下nft 性能更好?

性能比较见 redhat-benchmarking-nftables
可见iptables如果规则写的好,不要有太多的jump和goto,性能甚至比nftables略胜一筹

  • iptables 如何实现?

可以使用iptables + ipset 实现,你可以google搜索,相信相关blog很多。