-
Notifications
You must be signed in to change notification settings - Fork 10
User Guide
Depending on your file system permissions, you will likely have to execute some of the commands below with sudo or similar to avoid permission errors. You can use sudo -s
in a terminal to keep from having to type sudo before every command, then type "exit" to return to your normal user command prompt when you're finished with the setup. Always exercise caution when running with elevated privileges.
See the Notes section near the end of this document for details on the variable and file naming convention used for geolocation sets.
Now that the installation is complete you can move on to setting up your ruleset. One decision you'll need to make is how to load the new IP address ranges after updating the geolocation database each month. There are three basic ways to do this.
-
Reboot the computer (no further setup required).
-
Restart nftables automatically by setting
restart_nftables=yes
in the/etc/geo-nft.conf
configuration file. Be aware that restarting nftables may interrupt established connections between your system and other computers, such as ssh sessions and website connections, as well as resetting rule counters, etc. -
Flush and refill your geolocation sets atomically. This requires some additional setup and testing, but allows servers to continue uninterrupted after a database update.
Both options to restart nftables and flush/refill sets are turned off by default in the /etc/geo-nft.conf
configuration file.
If you're not planning to flush and refill geolocation sets after a database update but would rather restart nftables, then set elements can be defined in your nftables.conf file or your main ruleset. You can include all geolocation set files in the countrysets directory for easier configuration, or just the set files that you need. With this configuration you'll want to set restart_nftables=yes
in /etc/geo-nft.conf
to automatically restart nftables after a database update. This configuration is typically used on workstations and systems that can tolerate the loss of established connections caused by restarting nftables.
After backing up your current nftables.conf file, copy and paste the following code to a new file /etc/nftables.conf
(Ubuntu/Debian) or /etc/sysconfig/nftables.conf
(Fedora/Red Hat):
nftables.conf
#!/usr/bin/nft -f
flush ruleset
# Include all country code set files to make things easier to configure.
# nftables >= v0.9.4 can include all sets with: include "/etc/nftables/geo-nft/countrysets/*"
include "/etc/nftables/geo-nft/include-all.ipv4"
include "/etc/nftables/geo-nft/include-all.ipv6"
table netdev filter {
set geo-netdev4 {
type ipv4_addr
flags interval
# Add IPv4 country code elements for the United States and Great Britain.
elements = { $US.ipv4, $GB.ipv4 }
}
set geo-netdev6 {
type ipv6_addr
flags interval
# Add IPv6 country code elements for the United States, Great Britain and Antarctica.
elements = { $US.ipv6, $GB.ipv6, $AQ.ipv6 }
}
chain ingress {
# Replace <device_name> below with the name of your WAN network interface from "ifconfig".
type filter hook ingress device <device_name> priority 0; policy accept;
# Count IPv4 traffic from the United States and Great Britain.
ip saddr @geo-netdev4 counter
# Count IPv6 traffic from the United States, Great Britain and Antarctica.
ip6 saddr @geo-netdev6 counter
}
}
# Your other ruleset content here...
Note the geolocation "include" lines at the beginning of the file above. This allows you to reference any valid ipv4 or ipv6 country code in your ruleset. Also note that elements for geolocation sets are defined here. Remember to run "ifconfig" in a terminal and replace the <device_name>
in the ingress chain above with the name of your WAN network interface reported by ifconfig, which is typically something like enp16s0f0
or eth0
. You can test the file above by restarting nftables.
systemctl restart nftables
If nftables fails to restart you can check the status of nftables to see what the problem is.
systemctl status nftables
Once the new nftables.conf file is working you can edit your /etc/geo-nft.conf
file to enable nftables to automatically restart after a database update. Open the file in your favorite text editor.
nano /etc/geo-nft.conf
Set the restart_nftables
setting to yes.
restart_nftables=yes
Confirm that enable_refill=no in the configuration file (the default), since that setting is mutually exclusive with the restart_nftables setting. After editing, save the file and exit the text editor.
The last step in testing this configuration is to manually run the geo-nft.sh
script.
sudo /etc/nftables/geo-nft/geo-nft.sh
You can also manually run the script using the soft link that you created in /usr/sbin:
sudo geo-nft
The script output should show that restarting nftables completed successfully. Once this is set up, the geo-nft.sh
script will update the geolocation database each month and restart nftables to use the updated geolocation sets. In the event that your system is turned off during the scheduled monthly database update then the geo-nft.sh
script will run during the next system startup. The setup for this configuration is now complete.
If you are planning to flush and refill geolocation sets after a database update, then set elements should be defined in /etc/nftables/geo-nft/refill-sets.nft
. Geolocation sets are still defined in your nftables.conf
file, but without elements defined. The empty sets will be filled by including the refill-sets.nft
file on the last line of your nftables.conf
file. With this configuration you'll want to set enable_refill=yes in /etc/geo-nft.conf
to automatically flush and refill geolocation sets after a database update. This configuration is typically used on servers that need to maintain established connections that would be interrupted by restarting nftables.
After backing up your current nftables.conf file, copy and paste the following code to a new file /etc/nftables.conf
(Ubuntu/Debian) or /etc/sysconfig/nftables.conf
(Fedora/Red Hat):
nftables.conf
#!/usr/bin/nft -f
flush ruleset
table netdev filter {
set geo-netdev4 {
type ipv4_addr
flags interval
# Leave a reminder here as to where set elements are defined.
# Elements for this set are defined in /etc/nftables/geo-nft/refill-sets.nft
}
set geo-netdev6 {
type ipv6_addr
flags interval
# Leave a reminder here as to where set elements are defined.
# Elements for this set are defined in /etc/nftables/geo-nft/refill-sets.nft
}
chain ingress {
# Replace <device_name> below with the name of your WAN network interface from "ifconfig".
type filter hook ingress device <device_name> priority 0; policy accept;
# Count IPv4 traffic from elements defined in /etc/nftables/geo-nft/refill-sets.nft.
ip saddr @geo-netdev4 counter
# Count IPv6 traffic from elements defined in /etc/nftables/geo-nft/refill-sets.nft.
ip6 saddr @geo-netdev6 counter
}
}
# Your other ruleset content here...
# Include the refill-sets.nft script at the end of your nftables.conf file or
# main ruleset to fill empty geolocation sets at system startup. Uncomment the
# next line after your refill-sets.nft script is tested manually and working.
#include "/etc/nftables/geo-nft/refill-sets.nft"
Note that elements for geolocation sets are not defined in the file above. Also note that there is no geolocation "include" line at the beginning of the file, and the refill-sets.nft
script is included on the last line. This will fill the empty geolocation sets at system startup using the same nftables script that is used for flushing and refilling the sets after a database update. Remember to run "ifconfig" in a terminal and replace the <device_name>
in the ingress chain above with the name of your WAN network interface reported by ifconfig, which is typically something like enp16s0f0
or eth0
. The last line of the nftables.conf file above should remain commented out until your refill-sets.nft script is tested and working per the instructions below.
You can test the nftables.conf
file above by restarting nftables.
systemctl restart nftables
If nftables fails to restart you can check the status of nftables to see what the problem is.
systemctl status nftables
The final step in the flush and refill process is to create and test the refill-sets.nft
script. Create an empty file in the base geolocation directory named refill-sets.nft
.
touch /etc/nftables/geo-nft/refill-sets.nft
Open the new file in your favorite text editor.
nano /etc/nftables/geo-nft/refill-sets.nft
Copy and paste the following code to the file:
refill-sets.nft
#!/usr/bin/nft -f
#=============================================================================================
# /etc/nftables/geo-nft/refill-sets.nft
# An nftables script to atomically flush and update geolocation sets defined in your ruleset.
#
# Example: The table address family is "netdev", supporting both IPv4 and IPv6. The table name
# is "filter", and the sets to flush and update are named "geo-netdev4" and "geo-netdev6".
# Both sets are defined (without elements) in /etc/nftables.conf or your main ruleset.
#
# After modifiying this file, run it manually from a terminal to ensure everything works.
#
# sudo nft -f /etc/nftables/geo-nft/refill-sets.nft
#
# Include country sets to reference in your ruleset.
# To include individual country sets: include "/etc/nftables/geo-nft/countrysets/AQ.ipv6"
# To include only IPv4 country sets: include "/etc/nftables/geo-nft/include-all.ipv4"
# To include only IPv6 country sets: include "/etc/nftables/geo-nft/include-all.ipv6"
# nftables >= v0.9.4 can include all sets with: include "/etc/nftables/geo-nft/countrysets/*"
# To include all IPv4 and IPv6 country sets:
include "/etc/nftables/geo-nft/include-all.ipv4"
include "/etc/nftables/geo-nft/include-all.ipv6"
# Defines Section
# Define a list of ipv4 country codes (in table netdev filter) to refill your "geo-netdev4" set with.
define elements-netdev4 = { $AD.ipv4, $BI.ipv4 }
# Define a list of ipv6 country codes (in table netdev filter) to refill your "geo-netdev6" set with.
define elements-netdev6 = { $AD.ipv6, $BI.ipv6, $AQ.ipv6}
# Define any additional country code lists here.
# Flush your ipv4 set (in table netdev filter) named "geo-netdev4".
flush set netdev filter geo-netdev4
# Fill your ipv4 set (in table netdev filter) named "geo-netdev4" with country codes defined above
# with "$elements-netdev4".
add element netdev filter geo-netdev4 $elements-netdev4
# Flush your ipv6 set (in table netdev filter) named "geo-netdev6".
flush set netdev filter geo-netdev6
# Fill your ipv6 set (in table netdev filter) named "geo-netdev6" with country codes defined above
# with "$elements-netdev6".
add element netdev filter geo-netdev6 $elements-netdev6
# Repeat the "flush" and "add element" commands for any additional sets here.
Add the geolocation set names defined in your ruleset that you want to flush and refill, as well as any other information necessary. After editing, save the file and exit the text editor. You can now test the refill-sets.nft
script manually to ensure that your sets are properly flushed and reloaded.
sudo nft -f /etc/nftables/geo-nft/refill-sets.nft
If the previous command fails then you can check the status of nftables to determine the cause.
systemctl status nftables
Once you have the refill-sets.nft
file working manually you'll need to uncomment the "include" line on the last line of your /etc/nftables.conf
file. This will fill your geolocation sets during system startup with set data defined in the refill-sets.nft
file. Open the /etc/nftables.conf
file in your favorite text editor.
nano /etc/nftables.conf
Uncomment the last "include" line in the file so it looks like this.
include "/etc/nftables/geo-nft/refill-sets.nft"
Save the file and exit the text editor.
The next step is to edit your /etc/geo-nft.conf
file to enable the refill script to run automatically after a database update. Open the file in your favorite text editor.
nano /etc/geo-nft.conf
Set the enable_refill
setting to yes.
enable_refill=yes
Confirm that restart_nftables=no in the configuration file (the default), since that setting is mutually exclusive with the enable_refill setting. After editing, save the file and exit the text editor. The refill-sets.nft
script will now run automatically after a database update. You can test this by manually running the geo-nft.sh
script with:
sudo /etc/nftables/geo-nft/geo-nft.sh
You can also manually run the script using the soft link that you created in /usr/sbin:
sudo geo-nft
The script output should show that the flush and refill operation completed successfully. Once this is set up, the geo-nft.sh
script will update the geolocation database each month and atomically flush and refill geolocation sets without interrupting your server's connections. In the event that your system is turned off during the scheduled monthly database update then the geo-nft.sh
script will run during the next system startup. The setup for this configuration is now complete.
You can also configure systemd to send you an e-mail if the monthly database update fails. Instructions can be found in this guide.
The geo-nft.sh
script builds the country code list from the database itself, instead of using a third party location file that may not be up-to-date. Generating the list directly from the latest geolocation database file ensures that new and expired country codes are accounted for in the address range sets.
The db-ip.com geolocation database contains two non-standard country codes according to their FAQ. The ZZ country code is assigned to invalid address blocks that have by definition, no location and owner such as private or multicast IP addresses. The geo-nft.sh
script will exclude the ZZ country code and won't create any sets associated with this code.
The database also contains a non-standard country code XK, which is used by the European Commission, Switzerland, the Deutsche Bundesbank, SWIFT, and other organizations as a temporary country code for Kosovo. This temporary code has been used for more than a decade, and the database contains approximately 100 IP address ranges representing tens of thousands of valid IPv4 and IPv6 addresses for this code. The geo-nft.sh
script includes the XK country code and will generate sets associated with this code.
The geo-nft.sh
script will automatically generate sets associated with any new country codes that db-ip.com may add to their database in the future.
-
To keep things simple, the file naming convention used for country set files uses the same name for the defined country code variable as the filename itself. For example, the IPv4 set file for the United States is named
US.ipv4
and contains a defined variableUS.ipv4
. When you reference$US.ipv4
in your ruleset you're actually referencing the defined variable name in the file rather than the filename itself. Following the same naming convention, the IPv6 set file for the United States is namedUS.ipv6
and contains a defined variableUS.ipv6
. The variable definition in each geolocation set file contains the IP address ranges for that particular country code and IP protocol. You can open any of the geolocation set files in your favorite text editor and view the data format as well as details such as the number of address range elements in each set. Geolocation sets are located by default in/etc/nftables/geo-nft/countrysets
. -
When you include geolocation set filenames in your
/etc/nftables/geo-nft/refill-sets.nft
file, you can include all of the country code files at once to make it easier to add and remove country codes without having to include each individual country code that you use in your ruleset. Newer versions of nftables starting with v0.9.4 have proper support for include wildcards, so you'll no longer need to include theinclude-all.ipv4
andinclude-all.ipv6
files to load all geolocation sets even though they still work great with newer nftables versions. To include all IPv4 and IPv6 country set files with nftables v0.9.4 and above:include "/etc/nftables/geo-nft/countrysets/*"
To include all IPv4 only country set files with nftables v0.9.4 and above:
include "/etc/nftables/geo-nft/countrysets/*.ipv4"
To include all IPv6 only country set files with nftables v0.9.4 and above:
include "/etc/nftables/geo-nft/countrysets/*.ipv6"
Older versions of nftables <= 0.9.3 can include all geolocation sets with either or both of the following:
include "/etc/nftables/geo-nft/include-all.ipv4" include "/etc/nftables/geo-nft/include-all.ipv6"
If your system has a small amount of memory then you can save memory by only including the individual set files that you need.
Special note
Sometimes when running a script that has more than one include line, nftables will display the following error:
Error: syntax error, unexpected include, expecting newline or semicolon
If you get this error simply add a semicolon to the end of each include line like this:
include "/etc/nftables/geo-nft/countrysets/US.ipv4"; include "/etc/nftables/geo-nft/countrysets/GB.ipv6";
-
Errors detected by the
geo-nft.sh
script will be written to the log file/etc/geo-nft-error.log
. Any future errors will be appended to the end of the error log file, which can be deleted at any time. This logging is in addition to error logging done by the journal. If you experience an error, one or more of the following commands should help you determine the cause:journalctl -u geo-update.service journalctl -xe systemctl status nftables
-
Be aware that some countries may only have IPv4 addresses or IPv6 addresses. The
geo-nft.sh
script will list those country codes on the screen when run manually from a terminal. While creating your geolocation rules it's a good idea to first check the/etc/nftables/geo-nft/countrysets
directory to verify that the IPv4 or IPv6 country code file exists. If you reference an IPv4 or IPv6 country code variable that isn't defined then nftables will alert you. -
Although the examples above define geolocation sets in a netdev table, you can also define sets in ip, ip6, or inet tables to geolocation filter incoming or outgoing packets. Outgoing packets can be rejected instead of dropped to notify the local client or app that the connection is blocked, saving them from having to wait for the connection to time out. A typical outgoing rule to count and reject IPv4 traffic that matches a geolocation set named
geo-inet4
would look like this:ip daddr @geo-inet4 counter reject
Notice that the previous example matches the destination IP address (daddr) for outgoing packets rather than the source IP address (saddr) used to match incoming packets.
-
If you would like to upgrade your version of nftables to something newer than what's available in your distribution's repository, then see the nftables Wiki for good information on building and installing nftables from sources.
-
The following examples will give you an idea of how long it takes the
geo-nft.sh
script to run. The script creates ~500 IPv4 and IPv6 set files from the geolocation database in about 10 seconds on a low power 4 core 2200ge server with SSD storage. The script takes about 80 seconds to do the same task on a Raspberry Pi 4 with SD card storage. A number of variables will affect the run time, such as processor speed, storage speed, and whether you generate IPv4 sets, IPv6 sets, or both. -
While the
geo-nft.sh
script does an extensive amount of error checking, nothing is infallible. If you find a use case that could benefit from better error checking, please use the issue tracker to report the problem.
Geolocation for nftables documentation is licensed under the GNU GPLv2 (or at your option, any later version).
For Geolocation for nftables copyright information see the Copyright Notice.
Photos used to create the header image courtesy of NASA Visible Earth.
All trademarks, logos and copyrights are the property of their respective owners.