Skip to content

Instantly share code, notes, and snippets.

@jasonruyle
Last active February 4, 2024 15:00
Show Gist options
  • Star 51 You must be signed in to star a gist
  • Fork 15 You must be signed in to fork a gist
  • Save jasonruyle/8870296 to your computer and use it in GitHub Desktop.
Save jasonruyle/8870296 to your computer and use it in GitHub Desktop.
UFW to block countries

#Country ban with UFW#

Grab your different country ip addresses and save as Linux IPTables

http://www.ip2location.com/free/visitor-blocker

##Add country## Run the following command

while read line; do sudo ufw deny from $line; done < all.txt

Where the filename is the country.

##Remove country## To remove or revert these rules, keep that list of IPs! Then run a command like so to remove the rules:

while read line; do sudo ufw delete deny from $line; done < all.txt

##Suggestion## What I did was exported each individual country as their own country.txt file. But then realized that I wanted to run this thing one time, so I ran the following command:

cat *.txt >> all.txt

Then you can run your rule against all of the files.

@ntnlabs
Copy link

ntnlabs commented Jan 24, 2019

On the other side, I can do whitelisting with this if I have a service just for one country. I guess I could do this (let's say service is web):

while read line; do ufw allow from $line to any port 80 proto tcp; done < country.txt

or if You have an app for that

while read line; do ufw allow from $line to any app 'Apache Full'; done < country.txt

@prensing
Copy link

Not this is not going to scale well, with 10,000s of lines in the block list. A better solution would involve using ipset, which supports large dictionaries of IP ranges.

@jmcbri
Copy link

jmcbri commented Jun 9, 2020

Just added the CIDR files for the countries I wanted to block: China, Great Britain, and Sweden. Took 20 minutes or so. The size of the files seems unworkable. Didn't see an immediate performance degradation, but it's tens of thousands of lines. Can be the best approach. Maybe Cloudflare free account? Assuming there is such and it will work? Think I read it would, just wanted an on-the-server approach.

@vitor-ao
Copy link

vitor-ao commented Feb 21, 2021

You can use this site and select multiple countries: https://www.countryipblocks.net/acl.php

@poudenes
Copy link

Hi All,

Im try to block some countries because lot requests to login to my mail server and Wordpress sites.
I have 3 countries and created a ACL list. Changed format so I can block them with UFW.

The lines in total are 15.000. How big is the impact when I add them all to my (personal use VPS) with 1CPU, 2GB machine?

@scabilos
Copy link

I'm running the whiel loop right now.
It is very slow, parsing one line pe second.
Given the size of the file, calculation results in 47 hours.
Can I speed this up?

@prensing
Copy link

As I posted earlier, this is not a good solution. Adding 10s of thousands of rules, 1 per IP block, is not scalable. Use ipset (https://ipset.netfilter.org/). You can put all the ranges into a set and then add a single rule into iptables.

@scabilos
Copy link

@poddmo
Copy link

poddmo commented Oct 10, 2023

I have created an IP blocklist solution for UFW: https://github.com/poddmo/ufw-blocklist
It is designed to be very lightweight (runs on a single board computer home internet gateway) and very fast (using ipsets)

@bamdad23
Copy link

As I posted earlier, this is not a good solution. Adding 10s of thousands of rules, 1 per IP block, is not scalable. Use ipset (https://ipset.netfilter.org/). You can put all the ranges into a set and then add a single rule into iptables.

what about this script?

#!/bin/bash

Function to create an ipset and add CIDR ranges from a file

function create_ipset_and_add() {
local ipset_name=$1
local cidr_file=$2
local ipset_type=$3

# Create an ipset if it doesn't exist
sudo ipset create $ipset_name $ipset_type

# Add CIDR ranges from the file to the ipset
while read -r cidr; do
    sudo ipset add $ipset_name $cidr
done < "$cidr_file"

}

Create ipsets for country A and country B for both IPv4 and IPv6

create_ipset_and_add "country_a_cidr" "country_a_cidr.txt" "hash:ip"
create_ipset_and_add "country_b_cidr" "country_b_cidr.txt" "hash:ip"

Allow outgoing traffic to all IPs

sudo ufw default allow outgoing

Allow incoming traffic from country A and country B, block others for both IPv4 and IPv6

sudo ufw deny from any to any
sudo ufw allow from ipset:country_a_cidr
sudo ufw allow from ipset:country_b_cidr

Enable ufw

sudo ufw enable

I'll allow incoming from 2 countries block the rest of world, then allowing all outgoing.

@prensing
Copy link

Yes, that looks sensible. The main point is to use ipset(s) to hold the big list of IPs and do the testing in the firewall rules.

One point, however: you are using an ipset of type "hash:ip". I don't know what you are using for the list of addresses. Most come as a list of IP ranges, so I would guess that "hash:net" would be more appropriate. You also might want to set the size of the table when you create it, but that will only speed up the inital load (I would guess; not an expert on it).

@poddmo
Copy link

poddmo commented Jan 17, 2024

I have a repo with a ufw blocklist solution: (https://github.com/poddmo/ufw-blocklist)
There is also a solution there for multiple blocklists (eg per country, bogans, etc) that tests well for me and I just need to document its use.
In particular, check out the method I use to load list into the ipset. It spawns a subshell into the background so as not to hang the system while the list is loaded.

@timlab55
Copy link

timlab55 commented Jan 26, 2024

@poddmo - Is there anyway of compiling the entire "?.txt" into 1 master.txt file? My target clients that I'm trying to get lives within 25 miles from me in a circle. I'm almost certain they are on "NO" blacklist. But with what I"m doing on a website I would like to know that my database and stuff is protected. I"m running this on Debian 12 on a Raspberry Pi verison 4. I don't know if I will be notify if you respond, but my email address is timlab195@gmail.com.
Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment