Last active
March 22, 2025 22:47
Firewalld nftables CloudFlare IP Whitelisting
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env sh | |
## Check if script is running as Administrator | |
if [[ $EUID -ne 0 ]]; then | |
echo "This script needs to be run as Administrator!" | |
exit 1 | |
fi | |
# Get CloudFlare IPs from CloudFlare API | |
## Save the response from the CloudFlare IP into a Variable called "response" | |
response=$(curl --request GET --url https://api.cloudflare.com/client/v4/ips) | |
## Get the response Variable and echo it into the ipv4 Variable but just that from the result > ipv4_cidrs[] array | |
ipv4=$(echo $response | jq -r '.result.ipv4_cidrs[]') | |
## Get the response Variable and echo it into the ipv6 Variable but just that from the result > ipv6_cidrs[] array | |
ipv6=$(echo $response | jq -r '.result.ipv6_cidrs[]') | |
## Set the default Firewall Zone to DMZ | |
firewall-cmd --permanent --set-default-zone=dmz | |
## Create a new ipset called "Cloudflarev4". | |
firewall-cmd --permanent --new-ipset=Cloudflarev4 --type=hash:net | |
## Loop trough all CloudFlare IPs | |
echo "$ipv4" | while read ip; do | |
## And add it into the Cloudflarev4 ipset. | |
firewall-cmd --permanent --ipset=Cloudflarev4 --add-entry="$ip" | |
done | |
## Create a new ipset called "Cloudflarev6" !!! KEEP IN MIND THIS IS JUST FOR IPv6 IPs !!! | |
firewall-cmd --permanent --new-ipset=Cloudflarev6 --type=hash:net --option=family=inet6 | |
## Create a new ipset called "webAdd" in case someone wants to add more IP Addresses | |
firewall-cmd --permanent --new-ipset=webAddV4 --type=hash:net | |
firewall-cmd --permanent --new-ipset=webAddV6 --type=hash:net --option=family=inet6 | |
## Loop trough all CloudFlare IPs | |
echo "$ipv6" | while read ip; do | |
## And add it into the Cloudflarev6 ipset. | |
firewall-cmd --permanent --ipset=Cloudflarev6 --add-entry="$ip" | |
done | |
## Add the CloudFlare ipsets to the DMZ Zone | |
firewall-cmd --permanent --zone=dmz --add-source=ipset:Cloudflarev4 | |
firewall-cmd --permanent --zone=dmz --add-source=ipset:Cloudflarev6 | |
firewall-cmd --permanent --zone=dmz --add-source=ipset:webAddV4 | |
firewall-cmd --permanent --zone=dmz --add-source=ipset:webAddV6 | |
## Drop all http and https requests in the dmz zone and also log it. Also with the lowest priority | |
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv4" priority=32767 source address="0.0.0.0/0" service name="http" log prefix="HTTP-/080-DROP: " drop' | |
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv4" priority=32767 source address="0.0.0.0/0" service name="https" log prefix="HTTPS/443-DROP: " drop' | |
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv6" priority=32767 source address="::/0" service name="https" log prefix="HTTPS/443-DROP: " drop' | |
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv6" priority=32767 source address="::/0" service name="http" log prefix="HTTP-/080-DROP: " drop' | |
## Accept all http and https requests in the dmz zone for all whitelisted CloudFlare IP Addresses with the highest Priority | |
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv4" priority=1 source ipset="Cloudflarev4" service name="https" accept' | |
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv6" priority=1 source ipset="Cloudflarev6" service name="https" accept' | |
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv4" priority=1 source ipset="Cloudflarev4" service name="http" accept' | |
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv6" priority=1 source ipset="Cloudflarev6" service name="http" accept' | |
## Additional Space | |
## Everything is broken below this comment | |
## WhiteList more IPs | |
ipv4_regex="^([0-9]{1,3}\.){3}[0-9]{1,3}$" | |
ipv6_regex="^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$" | |
while true; do | |
echo "Do you want to add additional IPs? (j/n)" | |
read yn | |
case $yn in | |
[Yy]* ) | |
echo "Enter the IP you want to add:" | |
read ip | |
if [[ $ip =~ $ipv4_regex ]]; then | |
echo "IPv4 Address added: $ip" | |
# Hier können Sie die Variable für IPv4-Adressen setzen oder aktualisieren. | |
ipv4="$ip" | |
firewall-cmd --permanent --ipset=webAddV4 --add-entry="$ip" | |
elif [[ $ip =~ $ipv6_regex ]]; then | |
echo "IPv6 address added: $ip" | |
# Hier können Sie die Variable für IPv6-Adressen setzen oder aktualisieren. | |
ipv6="$ip" | |
firewall-cmd --permanent --ipset=webAddV6 --add-entry="$ip" | |
else | |
echo "Thats not a Valid IPv4- or IPv6-Adress." | |
fi;; | |
[Nn]* ) break;; | |
* ) echo "Answere with y (yes) or n (no).";; | |
esac | |
done | |
## WhiteList more Ports | |
port_regex="^([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$" | |
while true; do | |
echo "Do you want to whitelist extra ports? (y/n)" | |
read yn | |
case $yn in | |
[Yy]* ) | |
echo "Enter port you want to whitelist:" | |
read input | |
if [[ $input =~ $port_regex ]]; then | |
echo "Port added: $input" | |
port="$input" | |
## Deny it | |
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv4" priority=32767 source address="0.0.0.0/0" service port port="$port" protocol="tcp" log prefix="Add/$port-DROP: " drop' | |
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv6" priority=32767 source address="::/0" port port="$port" protocol="tcp" log prefix="Add/$port-DROP: " drop' | |
## Allow it | |
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv4" priority=1 source ipset="Cloudflarev4" port port="$port" protocol="tcp" accept' | |
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv6" priority=1 source ipset="Cloudflarev6" port port="$port" protocol="tcp" accept' | |
else | |
echo "Invalid Port." | |
fi;; | |
[Nn]* ) break;; | |
* ) echo "Answere with y (yes) or n (no).";; | |
esac | |
done | |
## Restart Firewalld to apply changes | |
firewall-cmd --reload | |
#### | |
# Attribution-NonCommercial-NoDerivatives 4.0 International by Akama Aka and Akami Solutions | |
#### | |
## | |
# Thanks to DarkDeviL for his help on the CloudFlare Discord | |
## | |
### | |
# WARNING THIS FIREWALLD SETUP IS NOT TO 100% TESTED! ALSO USE NFTABLES TO PREVENT ISSUES! | |
# NOTE: MAKE SURE YOU HAVE jq INSTALLED ON YOUR SYSTEM | |
### |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment