脚本生成仅允许cloudflare访问80 443端口的iptables规则

本文最后更新于:2022年11月4日 下午

Cloudflare是一家提供网站安全管理、性能优化等相关技术的跨国科技企业,Cloudflare可以帮助受保护站点抵御包括分布式拒绝服务攻击(DDoS, Distributed Denial of Service)在内的大多数网络攻击,确保该网站长期在线,阻止网络攻击、垃圾邮件等,同时提升网站的性能、访问速度以改善访客体验。Cloudflare提供用户免费使用,是防御DDos的最佳解决方案之一。

本文讲了如何用脚本设置防火墙 80 443 端口仅对Cloudflare CDN的IP开放。

如果不懂iptables或者ip6tables的话最好别用,免得失联

说在前面

  • 服务器。作者使用的是Ubuntu 20.04,关闭ufw
  • 服务器已经配置iptables 【ip6tables可选】
  • 实在失联了作者不负责
  • 作者的服务器具有ipv4和ipv6,所以服务器已经配置iptables 和 ip6tables都是同步讲解,如果你只有其中一个,可以自行更改处理。
  1. 项目仓库地址
    https://github.com/tech-fever/cloudflare_ips_only_iptables

  2. 原理
    新建 iptables 链 CLOUDFLARE 并插入引用到 INPUT 的80 443 端口,对Cloudflare的ip采用的数据包控制方式是 RETURN,丢弃其他网络数据包。就是说如果Cloudflare的IP访问80 443,会先从CLOUDFLARE中匹配,匹配到以后就会返回INPUT链,所以需要之前INPUT链中就有对80 443端口的放行规则,如果之前没有,可以加入iptables -A INPUT -p tcp -m multiport --dports http,https -j ACCEPT,或者把所有的 RETURN 改成 ACCEPT 。如果非Cloudflare的IP访问80和443,在CLOUDFLARE中会匹配到最后两条规则,被记录并丢弃。

  3. ip来源
    脚本使用的所有ip来自Cloudflare官方给的api:

  1. 日志
    日志文件保存在 /var/log/messages ,高版本默认没有这个文件,因为 /etc/rsyslog.d/50-default.conf 将其注释掉了,想看日志的话可以谷歌一下解决办法。
    被DROP掉的连接会被记录,以下面两行开头:
    对于ipv4: IPTABLES_CLOUDFLARE_ONLY_BANNED:
    对于ipv6: IP6TABLES_CLOUDFLARE_ONLY_BANNED:

参考文章

  1. 官方 Allow Cloudflare IP addresses
  2. 论坛帖子 《小鸡iptables只允许cloudflareip

预处理【必须】

如果重启服务器,所有的规则都丢失了。所以要保存规则,使其持久化。安装iptables-persistent包:

1
apt install iptables-persistent

为了防止你改出问题,先保存当前的iptables规则:

1
2
3
4
#保存规则
# mkdir -p /etc/iptables/
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6

查看规则编号。

1
2
3
4
# for ipv4
iptables -nvL --line-numbers
# for ipv6
ip6tables -nvL --line-numbers
在运行脚本之前先手动试试是否可行,如果出现问题可以随时reboot或强制断电重启,只要没有规则持久化(存入/etc/iptables/rules.v4 和 rules.v6 ),重启就会返回之前状态。

iptables新建链【必须】

只有ipv4的话直接跳到后面两节(不过这里有命令的详细解释)

创建一个链,命名为 CLOUDFLARE

1
2
iptables -N CLOUDFLARE
ip6tables -N CLOUDFLARE

让INPUT引用(下面两种选一种
插入引用:

1
2
3
# 适合于已经有其他iptables规则,默认让CLOUDFLARE插入到第一行,优先其他规则生效
iptables -I INPUT -p tcp -m multiport --dports http,https -j CLOUDFLARE
ip6tables -I INPUT -p tcp -m multiport --dports http,https -j CLOUDFLARE

附加引用:

1
2
3
# CLOUDFLARE,附加到最后一条,优先级最低
iptables -A INPUT -p tcp -m multiport --dports http,https -j CLOUDFLARE
ip6tables -A INPUT -p tcp -m multiport --dports http,https -j CLOUDFLARE

命令行添加IP

然后把CF的IP加进链里

1
2
3
4
5
6
7
for ip in `curl https://www.cloudflare.com/ips-v4`; do
iptables -A CLOUDFLARE -s $ip -j RETURN;
done

for ip in `curl https://www.cloudflare.com/ips-v6`; do
ip6tables -A CLOUDFLARE -s $ip -j RETURN;
done

不允许其他

1
2
3
4
5
6
# 记录并丢弃网络数据包
iptables -A CLOUDFLARE -j LOG --log-prefix "IPTABLES_CLOUDFLARE_ONLY_BANNED: "
ip6tables -A CLOUDFLARE -j LOG --log-prefix "IP6TABLES_CLOUDFLARE_ONLY_BANNED: "

iptables -A CLOUDFLARE -j DROP
ip6tables -A CLOUDFLARE -j DROP

如果你只有ipv4

如果你只有ipv4但上面的你看不懂不会改,可以直接执行这里。

1
2
3
4
5
6
7
iptables -N CLOUDFLARE
iptables -I INPUT -p tcp -m multiport --dports http,https -j CLOUDFLARE
for ip in `curl https://www.cloudflare.com/ips-v4`; do
iptables -A CLOUDFLARE -s $ip -j RETURN;
done
iptables -A CLOUDFLARE -j LOG --log-prefix "IPTABLES_CLOUDFLARE_ONLY_BANNED: "
iptables -A CLOUDFLARE -j DROP

iptables持久化一定要做,不然重启就没了
比如ubuntu可以安装iptables-persistent,规则保存在(默认)/etc/iptables/rules.v4
centos不知道,好像自带吧,执行service iptables save

1
2
sudo apt install iptables-persistent
iptables-save > /etc/iptables/rules.v4

脚本时间

创建规则脚本

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
# !/bin/bash
#
# Configure your iptables to allow IPs from Cloudflare only.
# For users whose HTTP server is directly exposed to the host 80/443.

iptables -N CLOUDFLARE
ip6tables -N CLOUDFLARE

# 可以换成 -A
iptables -I INPUT -p tcp -m multiport --dports http,https -j CLOUDFLARE
ip6tables -I INPUT -p tcp -m multiport --dports http,https -j CLOUDFLARE

for ip in `curl https://www.cloudflare.com/ips-v4`; do
iptables -A CLOUDFLARE -s $ip -j RETURN;
done

for ip in `curl https://www.cloudflare.com/ips-v6`; do
ip6tables -A CLOUDFLARE -s $ip -j RETURN;
done

iptables -A CLOUDFLARE -j LOG --log-prefix "IPTABLES_CLOUDFLARE_ONLY_BANNED: "
ip6tables -A CLOUDFLARE -j LOG --log-prefix "IP6TABLES_CLOUDFLARE_ONLY_BANNED: "

iptables -A CLOUDFLARE -j DROP
ip6tables -A CLOUDFLARE -j DROP

更新脚本

这里带ipv4和ipv6:

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
#!/bin/bash

#先删掉"不允许所有",避免在下面命令执行期间GG
iptables -D CLOUDFLARE -j DROP
ip6tables -D CLOUDFLARE -j DROP

#清除规则(旧的CF IP)
iptables -F CLOUDFLARE
ip6tables -F CLOUDFLARE
#添加CF IP,下面可以对curl的结果做一次判断,可以避免网络问题可能出现的问题,自己写
for ip in `curl https://www.cloudflare.com/ips-v4`; do
iptables -A CLOUDFLARE -s $ip -j RETURN;
done

for ip in `curl https://www.cloudflare.com/ips-v6`; do
ip6tables -A CLOUDFLARE -s $ip -j RETURN;
done

# 自己判断是否要保存,个人觉得可以手动执行脚本,之后看要不要保存
#mkdir -p /etc/iptables/
# iptables-save > /etc/iptables/rules.v4
# ip6tables-save > /etc/iptables/rules.v6

# 记录并禁用其他IP
iptables -A CLOUDFLARE -j LOG --log-prefix "IPTABLES_CLOUDFLARE_ONLY_BANNED: "
ip6tables -A CLOUDFLARE -j LOG --log-prefix "IP6TABLES_CLOUDFLARE_ONLY_BANNED: "

iptables -A CLOUDFLARE -j DROP
ip6tables -A CLOUDFLARE -j DROP

清除规则脚本【包售后】

1
2
3
4
5
6
7
8
9
10
11
iptables  -F CLOUDFLARE
ip6tables -F CLOUDFLARE
iptables -D INPUT -p tcp -m multiport --dports http,https -j CLOUDFLARE
ip6tables -D INPUT -p tcp -m multiport --dports http,https -j CLOUDFLARE
iptables -X CLOUDFLARE
ip6tables -X CLOUDFLARE
# 删除保存的规则并存入最新的(自己判断要不要去掉注释)
#> /etc/iptables/rules.v4
#> /etc/iptables/rules.v6
# iptables-save > /etc/iptables/rules.v4
# ip6tables-save > /etc/iptables/rules.v6

测试【重要】

先看看网页能不能用域名正常访问。
使用下面命令:

1
curl -k -v 你的IP

出现类似下面报错:

1
2
3
4
5
6
root@host2:~# curl -k -v `curl -4 ip.sb`
* Trying 你的IP:80...
* connect to 你的IP port 80 failed: Connection timed out
* Failed to connect to 你的IP port 80: Connection timed out
* Closing connection 0
curl: (28) Failed to connect to 你的IP port 80: Connection timed out

说明成功!

附录

持久化

1
2
3
4
#保存规则
# mkdir -p /etc/iptables/
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6
1
2
3
#引用规则
iptables-restore < /etc/iptables/rules.v4
ip6tables-restore < /etc/iptables/rules.v6

iptables和ip6tables仅开放22 80 443 端口和ping

前提是安装iptables-persistent

1
apt install -y iptables-persistent
直接修改/etc/iptables/rules.v4 v6 文件的时候如果不保留别的规则,会导致别的规则丢失!比如docker的和ufw的和fail2ban的。有时候可以通过重启解决。

iptables白名单 22 80 443 端口和允许ping

编辑/etc/iptables/rules.v4

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
*filter

# Allow all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT

# Accept all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow all outbound traffic - you can modify this to only allow certain traffic
-A OUTPUT -j ACCEPT

# Allow HTTP and HTTPS connections from anywhere (the normal ports for websites and SSL).
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

# Allow SSH connections
# The -dport number should be the same port number you set in sshd_config
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT

# Allow ping
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

# Log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

# Reject all other inbound - default deny unless explicitly allowed policy
-A INPUT -j REJECT
-A FORWARD -j REJECT

COMMIT

持久化

1
iptables-restore < /etc/iptables/rules.v4

ip6tables白名单 22 80 443 端口和允许ping

编辑/etc/iptables/rules.v6

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
*filter

# Allow all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d ::1/128 -j REJECT

# Accept all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow all outbound traffic - you can modify this to only allow certain traffic
-A OUTPUT -j ACCEPT

# Allow HTTP and HTTPS connections from anywhere (the normal ports for websites and SSL).
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

# Allow SSH connections
# The -dport number should be the same port number you set in sshd_config
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT

# Allow ping
-A INPUT -p icmpv6 -j ACCEPT

# Log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

# Reject all other inbound - default deny unless explicitly allowed policy
-A INPUT -j REJECT
-A FORWARD -j REJECT

COMMIT

持久化

1
ip6tables-restore < /etc/iptables/rules.v6

其他运维规则脚本

仅允许cloudflare ip访问nginx的规则的生成脚本
使用脚本编写Nginx规则恢复CloudFlare原始访问者 IP

其他参考(还没看,做个记录):
https://github.com/drvy/ufw-cloudflare
https://github.com/kingcc/cloudflare-ips-only


脚本生成仅允许cloudflare访问80 443端口的iptables规则
https://pawswrite.xyz/posts/10938.html
作者
Rainbow
发布于
2022年6月28日
许可协议