Cisco Blogs

Block a country with my Cisco Router or Firewall

- February 15, 2012 - 7 Comments


We are often asked by customers about how they can prevent traffic from a certain country (let’s say country X) from entering their network. The motivations for doing this could vary. Sometimes a company does not do business with all countries in the world; therefore, the company doesn’t need to be accessible from all countries. Other times it is an issue of trust and security, where an administrator may not want to allow country X to enter their infrastructure. Finally, there are cases where country X has often been incriminated with malicious activity, so an administrator may want to block country X when there is no need for the organization to interact with this country. In this document I present a methodology on how to write a tool that provides the configuration lines to block country X, using your IOS router or ASA/ASASM firewall.

Available Resources:

First we need to start by finding the allocated address ranges associated with a country. That information is publicly available by the Regional Internet Registries (RIRs). Each RIR has a file with the information of the address blocks it has allocated to various countries. A list of the files is shown below:

The RIR files also contain registered ASN information for BGP, which is outside the interest of this document. The file lines that we are interested in look like the following snippet:


In this example we see that the second column has the country code (US), the third column depicts if the address is IPv4 or IPv6, the third has the address block, and the fourth represents the network mask. Note that the mask for IPv4 is the decimal value of the IPv4 mask, whereas for IPv6 we only have the bits of the IPv6 mask.


In order to be able to build a tool that automates the process of creating an access control list (ACL) for traffic from a specific country, we would first need to be able to download all the address maps from the RIR files and consolidate them into one file. For this example I used a bash script to download the files to a file called addr_all_regs that aggregates the addresses. The script is run daily with a Linux cron job in order to have the latest RIR address allocations. The example script code below downloads the ARIN file and appends it to addr_all_regs.

wget -O addr_tmp
egrep "\|ipv[46]\|" $DIR/addr_tmp >> $DIR/addr_all_regs

After all the addresses are aggregated into a file, it is a matter of extracting the relevant information that we need in order to create the ACL. I chose to use Perl to parse the addr_all_regs file, but other options are available.

The script input options passed to the Perl script are parsed by Perl’s GetOptions. In my example, I chose to pass the IPv4 or IPv6 option in the prot parameter, the source or destination blocking ACL in the d parameter, the country code in the c parameter, the product in the prod parameter, the object or IP address option in the obj parameter, and the help option in the help parameter.

use Getopt::Long;
# Process options.provided as arguments to the script
if ( @ARGV > 0 ) {
    GetOptions('prot:i' => \$protocol,
               'd'      => \$destination,
               'c=s'    => \$country,
               'prod=s' => \$product,
               'obj'    => \$obj,
               'help|h' => \$help);

The input options to the script can vary depending on the needs. An IPv4-only ACL for just one product might use the prot, prod,and obj parameters.

Note that special care should be taken with passing the country code to the script. ISO 3166 provides the mappings of countries to their country codes.

Converting the mask column in the RIR files to real masks that are used in IPv4 ACLs can be tricky. For IPv6 ACLs, the bits of the mask suffice to be used in the ACL. For IPv4 ACLs, I wrote the following Perl code that takes the IPv4 decimal mask and converts it to a wildcard mask for IOS ACLs and to a netmask for ASA ACLs, based on the second function argument. The decv4mask2ipv4mask(x,y) is used in the Perl script that processes the addr_all_regs in order to generate the country ACL.

# Function that converts a decimal number to a mask or a wildcard # mask 
based on the second function argument
sub decv4mask2ipv4mask ($) { 
  # Shift the decimal one bit at a time to find the MSB
  while ($val > 0) {
        $val = $val >> 1;
  # Start from a zero octet IPv4 address
  # For the bits counted above keep shifting adding 1b in the 1st-bit
  while ($tmp > 0) {
  # If the second function argument is 1 then return the wildcard mask
  if ($_[1]) {
     $ip[3]=255-$ip[3]; $ip[2]=255-$ip[2]; $ip[1]=255-$ip[1]; 
  # Else the mask will be returned
  return "$ip[3].$ip[2].$ip[1].$ip[0]";

Algorithm Flowchart:

Now we have all the necessary building blocks in order to create our country-based ACL. We have a file (addr_all_regs) that consolidates all the address-block allocations and we have a function that can convert the masks in the file into Cisco ACL masks. The next step is to parse the file based on the user-supplied input and create a country-based ACL. The image below shows the flowchart of the algorithm I implemented (in Perl) in order to generate the access list.

When parsing the consolidated file for a country, it is important to be able to determine if the country is not present in the address file. If not, then the result should throw a notification to let the user know that this country code did not exist and potentially investigate it.

Also, when generating the ACL it is significant to note the syntactical differences between IOS/IOS-XE, IOS-XR, and ASA ACLs, and the differences between IPv4 and IPv6 ACLs. Even though they are all very similar, there are slight CLI differences between different products. The syntax can be found in the following product configuration guides:


Sometimes, it can be time consuming to write an entire program that does the processing to create the ACL. Thus manual work can often save a lot of time. For that reason, a simple cat addr_all_regs | grep "[country code]\|[ipv4 or ipv6]" for the country and the IPv4 or IPv6 from the addr_all_regs will give the output we desire. Then extracting the columns with addresses and the masks can practically bring us almost to the solution. Converting the address block/netmask pair into an ACL line is trivial using various text editors. So, if writing a whole program to process the addr_all_regs file is not what you want to do, you can also use grep for the information that you require from the file and create the ACL manually by editing the text.

Other alternatives could include downloading and using MaxMind’s GEOLite Location database in order to parse it and extract the information needed.


Even if someone does find it useful to be able to block a country from their network using the above methods, I must say that the methodology presented above is not entirely bulletproof. There are cases where it would not work. One such case would be for addresses that are inaccurately documented. For example, we have seen address blocks from European countries that are listed under country EU instead of the actual country. In that case, these addresses appear to belong to country EU and would not be caught by the ACL that is denying country X.

Another case where the above method would fail is when users use anonymizer services. For example, if a user is located in country X and wants to reach organization Y—which is utilizing an ACL to block country X—the user could still try to use an anonymizer service (there are many available) that practically acts as a proxy. The user would no longer appear to be originating from country X, but instead appear to be originating from the country where the anonymizer is located. That way the ACL blocking country X could be bypassed.


Building a tool that writes country-blocking ACLs involves downloading the country address allocations from various RIRs. After parsing the files and keeping the block allocations, the corresponding IPv4 and IPv6 blocks—with their masks—can be inserted into an ACL that is generated for IPv4 and IPv6 respectively. The ACL can then be used to block traffic or to match it for further processing or investigation. However, attention should be paid to the caveats of the method.

Many might ask “Where is the tool?” that I built. This was a tool built for custom use, it was not built to be provided to customers and is not officially supported. Thus, at this time the tool will not be released. I believe that following the suggestions made in the post, it shouldn’t be too complicated to build your own automated tool that can provide the necessary blocks, in order to write an ACL to match on a specific country.


All comments in this blog are held for moderation. Your comment will not display until it has been approved

In an effort to keep conversations fresh, Cisco Blogs closes comments after 60 days. Please visit the Cisco Blogs hub page for the latest content.


  1. Eng, The RIR files have ipv6 addresses in the format arin|US|ipv6|2001:400::|32|19990803|allocated So, if you consolidate all the RIR files that I talk about in the post in one file and grep for "\|ipv6" you will get all the IPv6 addresses for this country. Using the right country code is important. Regards, Panos

  2. Is there any way to find out the IPv6 addresses block by country?

  3. Hi Zoly, Good point. This tool will not prevent against proxied traffic. I tried to explain it in the "Considerations" section. If we are talking about web traffic that is proxied, then other means like content aware filtering may help. If the concern is spoofed DDoS traffic then measure like Anomaly detection and RTBH could protect against anomalous spoofed packets from Bots. Panos

  4. And what would somebody do about proxy servers? This restrictions has to be at a higher level to be effective I think.

  5. • "... malware that connects using an IP address instead of a domain name will -not- be blocked when you use just domain name lists..." .

  6. Or you can use preprocesed country blocks from, we use them for blocking attacks from China.

  7. Good Post!