Home > Uncategorized > .@MaxMind IP to Country offline lookup with #autoUpdate in C#

.@MaxMind IP to Country offline lookup with #autoUpdate in C#

1181834

If you want to determine the country from an IP address, then there are a million and one APIs that you can use, but they tend to have free usage limits, plus there is a performance hit of making a network call every time.

You can donwload a free database from Maxmind that you can use to do the lookup offline, but it ads another complexity – that the fact that IP addresses change ownership, and can map to a different country, if you don’t keep the database updated.

So, not only does this demo determine the Country from an IP address from an offline database, but it also has code to automatically download and update the data every month.

So, if you don’t want to read further, and just jump to the code, here is the repo;

https://github.com/infiniteloopltd/MaxMindDemo

So, the basics first. If you are happy with a rough lookup, then just pull the MaxMind Nuget package as follows

install-package MaxMind.GeoIP2

Then download and unzip the GeoLite2-Country.mmdb file from https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz and place it in your bin folder.

Then all you need is this;

var reader = new DatabaseReader(“GeoLite2-Country.mmdb”);
var response = reader.Country(“8.8.8.8”);
Console.WriteLine(response.Country.IsoCode);

Which should say that IP 8.8.8.8 is in the US (It’s Google)

Now, the next fun part is how to update this mmdb file automatically. We can download the TAR.GZ as follows;

var wc = new WebClient();
var bData = wc.DownloadData(“https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz”);
var zippedStream = new MemoryStream(bData);

Which give’s us a Tar GZ file, Which is a file that is in Tar format (*Uncompressed, but a format where multiple files are stored as one) and Gzipped (Compressed). So, we need to Gzip the file, and copy it into a memory stream –

var gzip = new GZipStream(stream, CompressionMode.Decompress);
var mTar = new MemoryStream();
gzip.CopyTo(mTar);
mTar.Seek(0, SeekOrigin.Begin);

Now, with a TAR stream, we have to separate this into a list of objects that define as follows;

public class TarEntry
{
public string FileName { get; set; }
public byte[] Contents { get; set; }
}

The code to parse the TAR file is as follows;

private static List<TarEntry> ExtractTarEntries(Stream stream)
{
var lTarEntries = new List<TarEntry>();
var buffer = new byte[100];
while (true)
{
stream.Read(buffer, 0, 100);
var name = Encoding.ASCII.GetString(buffer).Trim(‘\0’);
if (String.IsNullOrWhiteSpace(name))
break;
stream.Seek(24, SeekOrigin.Current);
stream.Read(buffer, 0, 12);
var size = Convert.ToInt64(Encoding.ASCII.GetString(buffer, 0, 12).Trim(‘\0’), 8);
stream.Seek(376L, SeekOrigin.Current);
var buf = new byte[size];
stream.Read(buf, 0, buf.Length);
lTarEntries.Add(new TarEntry
{
Contents = buf,
FileName = name
});

var pos = stream.Position;

var offset = 512 – (pos % 512);
if (offset == 512)
offset = 0;

stream.Seek(offset, SeekOrigin.Current);
}
return lTarEntries;
}

finally, the code to check the age is as follows;

var fi = new FileInfo(“GeoLite2-Country.mmdb”);
if (!fi.Exists || (DateTime.Now – fi.LastWriteTime).TotalDays > 30)
{
DownloadGeoliteDB();
}

Advertisements
Categories: Uncategorized
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: