Recently, our Infrastructure team received a task that involved restricting access to a service only from certain countries. To make things even harder, this had to be done on Cisco IOS devices with relatively low performance. We will review in this article how we were able to solve this.
Thinking about the problem at hand, the following issues were obvious:
- We must get the list of IP addresses for each country.
- The number of IP networks is most likely higher than the number of ACL supported by the platform.
- ACL are extremely CPU intensive.
- The setup must be automated.
The solution to our problem came from a combination of technologies.
Solving the First Challenge
The first issue – obtaining the network address block – was probably the easiest to deal with. We have discarded the use of Geo IP from the start (not reliable enough), so other places to look for full global table were BGP or RIRs (Regional Internet Registry) databases. Since we don’t have country information in BGP, the only possible option was to create a script and obtain the network classes in the desired format directly from RIRs database available at ftp://ftp.arin.net/pub/stat/[RIRCODE]/delegated-[rircode]-latests/.
The Trade Off
Solutions to the second and to the third challenges came from the remotely triggered black hole scenario based on source. The chosen solution allowed us to save CPU power, mainly because routers are optimized for routing and not for ACLs, but the trade off was to use more of the router’s RAM (around 200Mb).
Basically, we created a Linux virtual machine with Quagga installed. Then, we connected it via BGP to the Cisco router, exported the list of network addresses to black list and set next hop to null interface.
This, combined with uRPF allowed the router WAN interface to drop packets coming from IP addresses in the network list exported.
Why did we choose the blacklist approach instead of whitelist? The reason was simple, in case something went wrong with the setup, we would still had access to the service. But this depends strictly on the scenario.
There Is Even More!
But with this setup a new problem appeared: how to limit the restriction to a certain service. Luckily, the solution came from VRFs (Virtual Routing and Forwarding). VRFs allow multiple routing tables inside a router.
So, in the end, we ended up with a solution that can be just as easily used to block DDoS attacks, as same principles apply. A script creates config file for Quagga/bgpd machine, networks are exported marked with a predefined community for blocking and other set of networks (including /32) IP addresses are marked with another community, so that we could whitelist specific IP addresses from the blocked countries. Based on the two communities on the router, we can either set next-hop to an IP address pointing to null interface, or to default route that allows access.
We think that this was a pretty easy and straightforward solution, but if you have a better idea do not hesitate to share it!