nftables and GeoIP

nftables and GeoIP

How to Block IPs from Countries or Continets using NfTables Geoip script


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
               }
 }

Don’t forget to mark ipv6 packets as well.

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
        }
 }

How log droped packets in nftables to external files read my ulogd2 manual.