OFAC, GeoIPs and Blocking Unwanted Network Traffic with Python

2024/12/20

Background

It’s the Holiday season and my employer has some pretty strict an clea rules around changes that can be made during “peak seasons” which, for our product, starts after the US Thanksgiving Holiday and continues until after the 1st of the new year. This has left me with more time than usual to scratch some of the intellectual itches I have accumulated over the past year. This year I decided to work on writing some tools to help automate some of the more tedious, routine tasks that my team is responsible for. This post, however, has nothing at all to do with that work. But it’s important background to know before we dive in to what this post actually is about.

My wife and I purchased a new home in March of 2024. One of the key attractions of the house was that it had a large (~800sq/ft) unfinished and completely open, daylight basement. As I work from home part time, this was very interesting to me as a future home office space. Fast forward to July of this year and we “broke ground” on finishing the basement and turning the concrete and cinder block dungeon I had been working in the last few months in to a proper space in which I could live and work. It’s now about 95% complete and it was time to start re-wiring my home network that included some new (to me) equipment, a Ubiquiti Security Gateway (USG).

I promise I’m Getting to the Point

While setting up the USG I noticed that there was an option to block IP ranges by country of origin. Being the pragmatic engineer that I am, I understand that it’s simply a reality of The Internet that certain GeoIP ranges produce higher volumes of unwanted or malicious traffic and that most of these countries are not countries from which I never expect to see inbound traffic. But I did not want to blindly block every country’s IP range besides the US after all, I do host a small number of service from my home IP address and I don’t know the exact origin of every user of those services. Enter the Office of Foreign Assets Control (OFAC) or, more specifically, OFAC’s Sanctions List Service (SLS).

OFAC and their SLS

For those unfamiliar with OFAC or their SLS, here are some brief excerpts from their website:

The Office of Foreign Assets Control administers and enforces economic sanctions programs primarily against countries and groups of individuals, such as terrorists and narcotics traffickers. These sanctions can be either comprehensive or selective, using the blocking of assets and trade restrictions to accomplish foreign policy and national security goals.

Basically, they’re the organization, within the United States, which enforces the sanctions imposed by executive and legislative branches of government. As part of their efforts in enforcing these sanctions, they provide a service they call the Sanctions List Service (SLS). Again, quoting from their website:

OFAC’s Sanctions List Service (SLS) provides users with easy access to the most up-to-date Sanctions Lists and Sacntions list data ready for immediate download

Effectively, and API for fetching data about current government sanctions.

GeoIPs

The Internet is a big place, on the IPv4 space alone there are 4,294,967,296 unique IP addresses. With the emergence of widespread usage of IPv6, this number has increased to 340 undecillion (yes, that’s apparently an actual number. That’s 340 with 36 zeroes after it or 3.4x1038 for you nerds out there.). That’s a lot of unique devices and a lot of people you probably don’t know.

The Internet is also a (relatively) organized place. Countries are assigned blocks of IP addresses by the Internet Assigned Number Authority (IANA). To save you from having to read it here, if you want to learn more about IANA and GeoIPs, head over to Geo Targetly to learn more, it’s way more than I want to cover here. For our purposes here, you just need to know that IANA assigned blocks of IPs to countries and, to a lesser extent, cities. This information is public and can be found from a number of sources online. One popular source is MAXMIND. They provide a free and paid tier service for downloading up-to-date GeoIP information. They even have official libraries for many of the major programming languages.

Putting the Pieces Together

So, let’s see, I wanted to block IPs from countries that have no business on my network… but I don’t want to blindly block every country, just the ones that we’ll call “adversarial” with respect to my relative geographical location. We should be able to do this by sourcing OFAC’s most recent sanctions list and using that to lookup IP addresses in the MaxMind database, right? Sort of….

Now, I may be wrong but I spent quite a while looking for a way to ask the question:

What IP addresses belong to country X?

The issue stems from the format of the free tier MaxMind GeoLite2-Country database. It is structured with the intention of looking up information by the IP address… which is fine, and is definitely in and of itself useful, but it’s not what we want to do here. After much trial and error, it did not seem like it was going to be possible to efficiently use the GeoIP2 library, with the free tier database, to ask this question.

Fortunately, there is a second Python library available called MaxMindDB. This library is very similar to the official GeoIP2 library except that they’ve implemented an __iter__() method to list out the contents of the entire database file. It’s not ideal, but maybe we can work with this.

Meat and Potatoes

Using the above mentioned MaxMindDB library and it’s __iter__() method, we can construct our own dataset in a format that lets us look up the IP addresses for countries listed in the OFAC SLS list. It’s not quite done yet, but I think it’s “done enough” to officially announce publicly that I’ve written a tool/library to do just this.

The Country IP Lookup project can consume either the MaxMind Database permalink URL (requires a registered MaxMind account) or a locally cached copy of one of the MaxMind Country databases and return the data as follows:

{
  "RU"": ["a.a.a.a","b.b.b.b", "c.c.c.c"],
  "US": ["x.x.x.x", "y.y.y.y", "z.z.z.z"],
  etc...
}

With this data, you can now take the ISO country codes provided by the OFAC SLS and return a list of IPs and IP ranges. Additionally, this library can act as a standalone tool that accepts a country ISO code and returns the IPs and IP ranges as a newline delimited list, useful for incorporation in shell scripts and other non-python utilities:

./lookup.py
  usage: lookup [-h] -c COUNTRY [--config CONFIG_FILE] [-d DB_CACHE]

Conclusion

I was initially very frustrated when I discovered that there didn’t seem to be an existing way to answer my seemingly simple question. But after tackling this problem, I am kind of glad that there wasn’t. It forced me to think outside the box and put some of the skills I’ve obtained over the last years both as a security focused systems administrator and now software developer to work. But I also know that I’m a lifelong learner and that I don’t know everything there is to know about Python or the subjects that I touched on in this post. It’s entirely possible that there actually is a way to produce this same result with the existing libraries and I just couldn’t figure it out. But now I know that I have a way to do it and it’s something I built myself and know how to use, end-to-end. And I know that if there’s ever a time when I want it to work differently, I’m empowered to get my hands dirty again and make it work differently.

As for the practicality of this experiment…. Is this necessary? Probably not. Do I think my home network is going to be the target of some state sponsored cyber attack? I certainly hope not. But was it interesting to learn all this?

You bet.

<< Portable Dev Environments with Devpods