nftables and GeoIP
We'll learn how we can block traffic originated from specific country or continent IPs using GeoIP database and linux nftables . This article describes the configuration for debian linux distros. nftables is the new packet classification framework that intends to replaces the existing {ip,ip6,arp,eb}_tables infrastructure. In a nutshell:
- It is available in Linux kernels >= 3.13
- It comes with a new command line utility nft whose syntax is different to iptables.
- It also comes with a compatibility layer that allows you to run iptables commands over the new nftables kernel framework.
- It provides generic set infrastructure that allows you to construct maps and concatenation. You can use this new feature to arrange your ruleset in multidimensional tree which drastically reduces the number of rules that need to be inspected until you find the final action on the packet.
I assume you have at least basic experience with the nftables configuration.
Clone nftables-geoip GIT repository
We need to clone the nftables-geoip git repository .
Create our working directory:
~] mkdir -p /etc/rc-local
~] cd /etc/rc-local
Install git and wget:
~] apt-get install git wget
Clone nftables-geoip git repository :
~] git clone https://github.com/JMGuisadoG/nftables-geoip
Go to our new cloned directory:
~] ls -alFh
drwxr-xr-x 3 root root 4.0K May 19 14:18 nftables-geoip/
~] cd nftables-geoip/
~] ls -alFh
drwxr-xr-x 8 root root 4.0K May 19 14:18 .git/
-rw-r--r-- 1 root root 18K May 19 14:18 LICENSE
-rw-r--r-- 1 root root 21K May 19 14:18 location.csv
-rwxr-xr-x 1 root root 12K May 19 14:18 nft_geoip.py*
-rw-r--r-- 1 root root 3.2K May 19 14:18 README.md
Generate ipv4 and ipv6 mappings
To generate ipv4 and ipv6 mappings, download geoip data from db-ip.com saving the output in the current folder:
~] ./nft_geoip.py --file-location location.csv --download
Traceback (most recent call last):
File "./nft_geoip.py", line 18, in <module>
import requests
ModuleNotFoundError: No module named 'requests'
nft_geoip.py python script need requests module. You must install it first:
~] apt-get install python3-requests
Run nft_geoip.py script again:
~] ./nft_geoip.py --file-location location.csv --download
Downloading db-ip.com geoip csv file...
Writing country definition files...
Writing nftables maps (geoip-ipv{4,6}.nft)...
Done!
~] ls -alFh
drwxr-xr-x 3 root root 4.0K May 19 14:40 ./
drwxr-xr-x 4 root 1000 4.0K May 19 14:18 ../
-rw-r--r-- 1 root root 17M May 19 14:39 dbip.csv
-rw-r--r-- 1 root root 956 May 19 14:39 geoip-def-africa.nft
-rw-r--r-- 1 root root 8.3K May 19 14:39 geoip-def-all.nft
-rw-r--r-- 1 root root 902 May 19 14:39 geoip-def-americas.nft
-rw-r--r-- 1 root root 15 May 19 14:39 geoip-def-antarctica.nft
-rw-r--r-- 1 root root 808 May 19 14:39 geoip-def-asia.nft
-rw-r--r-- 1 root root 810 May 19 14:39 geoip-def-europe.nft
-rw-r--r-- 1 root root 461 May 19 14:39 geoip-def-oceania.nft
-rw-r--r-- 1 root root 9.5M May 19 14:40 geoip-ipv4.nft
-rw-r--r-- 1 root root 9.2M May 19 14:40 geoip-ipv6.nft
drwxr-xr-x 8 root root 4.0K May 19 14:18 .git/
-rw-r--r-- 1 root root 18K May 19 14:18 LICENSE
-rw-r--r-- 1 root root 21K May 19 14:18 location.csv
-rwxr-xr-x 1 root root 12K May 19 14:18 nft_geoip.py*
-rw-r--r-- 1 root root 3.2K May 19 14:18 README.md
-
geoip-def-all.nft
Containing all definitions. (eg. define $CA = 124 ) the variable name is its It also contains a map between country marks and its corresponding continent mark. -
geoip-def-{continent}.nft
Subset of definitions for countries of a given continent. To be used as marks. -
geoip-ipv4.nft
Containing the map between ipv4 ranges and its geoip data. @geoip4 -
geoip-ipv6.nft
Containing the map between ipv6 ranges and its geoip data. @geoip6
Marking packets to its corresponding country
For marking packets you must know a ISO 3166-1 alpha-2 country code . Here is a wiki webpage for country codes:
https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
example:
meta mark $DE counter accept
Examples
Marking input ipv4 packets and counting Germany traffic
table filter {
include "./geoip-def-all.nft"
include "./geoip-ipv4.nft"
include "./geoip-ipv6.nft"
chain input {
type filter hook input priority 0; policy accept;
meta mark set ip saddr map @geoip4
meta mark set ip6 saddr map @geoip6
meta mark $DE counter
}
}
Marking input packet and block ssh and http(s) traffic from all world without Czech Republic and Germany
#!/usr/sbin/nft -f
table inet ssh {
include "./nftables-geoip/geoip-def-all.nft"
include "./nftables-geoip/geoip-ipv4.nft"
include "./nftables-geoip/geoip-ipv6.nft"
chain ssh {
mark set ip saddr map @geoip4
mark set ip6 saddr map @geoip6
mark { $CZ, $DE } counter log prefix "ssh-accept-cz-or-de " group 3 accept
ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 } counter log prefix "ssh-accept-private " group 3 accept
counter log prefix "ssh-droped " group 3 drop
}
chain input {
type filter hook input priority 350; policy accept;
tcp dport { ssh, http, https } ct state { new } counter goto ssh
}
}