This article is a set by step that shows how to allow only network packet from a certain subnet to reach your web server with firewalld.
The subnet taken in this example is the subnet of Cloudflare
firewalld is based on iptable and therefore the same concept such as zone, a service and rule applied also for firewalld.
To filter by subnet, you need to:
This article gives your a detailed step by step on how to do it.
With the same method, you can also filter by country
Each set of ip has a storage format called the type that defines :
You can't change this format once the ip set is created.
The file format for a hash:net type is:
ip
ip[/cidr]
fromaddr-toaddr
Luckily, Cloudflare is providing this files at Cloudflare IPS:
The below commands create two ipset name of the type hash:net named:
Create the set for ipv4 address:
firewall-cmd \
--new-ipset=cloudflare-ipv4 \
--type=hash:net \
--permanent \
--option=family=inet
where:
This command creates the set for Ipv6 address.
firewall-cmd \
--new-ipset=cloudflare-ipv6 \
--type=hash:net \
--permanent \
--option=family=inet6
The command should return:
success
cd /tmp
wget https://www.cloudflare.com/ips-v4
firewall-cmd \
--ipset=cloudflare-ipv4 \
--permanent \
--add-entries-from-file=ips-v4
wget https://www.cloudflare.com/ips-v6
firewall-cmd \
--ipset=cloudflare-ipv6 \
--permanent \
--add-entries-from-file=ips-v6
Reload to load the ipset in memory and therefore make it visible to the ipset command
systemctl reload firewalld
Check that the ipset is not full
ipset -t list cloudflare-ipv4
Name: cloudflare-ipv4
Type: hash:net
Revision: 6
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 1272
References: 0
Number of entries: 14
Their is one line by entry (ie 14)
While with a hash:ip, you're list would be much bigger because the record is not at the net level but at the ip. It creates therefore all IP for each subnet.
You can test your IP with ipset test.
ipset test cloudflare-ipv4 167.114.98.233
167.114.98.233 is NOT in set cloudflare-ipv4.
ipset test cloudflare-ipv4 173.245.48.0
Warning: 173.245.48.0 is in set cloudflare-ipv4.
Adding a rule that drops all packet for the https Firewalld (port 443) if they are not from Cloudflare
firewall-cmd \
--zone=public \
--permanent \
--add-rich-rule='rule family="ipv4" source not ipset="cloudflare-ipv4" service name="https" drop'
firewall-cmd \
--zone=public \
--permanent \
--add-rich-rule='rule family="ipv6" source not ipset="cloudflare-ipv6" service name="https" drop'
firewall-cmd \
--zone=public \
--permanent \
--add-rich-rule='rule family="ipv4" source not ipset="cloudflare-ipv4" service name="http" drop'
firewall-cmd \
--zone=public \
--permanent \
--add-rich-rule='rule family="ipv6" source not ipset="cloudflare-ipv6" service name="http" drop'
When your restart you are making the rules active. If you are locked out because of any manipulation, check this article that will help you recover your system.
Made the rule effective.
systemctl reload firewalld
systemctl stop firewalld
systemctl start firewalld
Check the log;
systemctl status firewalld
# or tail -20 /var/log/firewalld
Check that the rule is still present
firewall-cmd --list-rich-rule
To test that you can't connect, you can use your browser.
Just start it and set its DNS resolution for your website to your server IP.
For instance for chrome, you would start it with the below command that points the name datacadamia.com to the IP 212.186.33.26
chrome.exe --host-resolver-rules="MAP datacadamia.com 212.186.33.26"
Be sure to have no background chrome process running otherwise it will not work
Then if your try to see a page, you should get a Server could not be reached error.