/IP2Country

Ip to country mapping

Primary LanguageC#MIT LicenseMIT

Logo IP2Country

Library to map IP addresses (both IPv4 and IPv6) to a country, available as NuGet package. The accuracy depends on the data provider; a lot of providers are supported 'out of the box':

Also available is a caching IIP2CountryResolver in the form of a IP2Country.Caching NuGet package.

This library provides an easy to implement interface (IIP2CountryDataSource) to provide your own data to the IP2CountryResolver. This library only aims for 'country level resolution'; city, ISP etc. information can be returned (when provided) but is not the goal of this library. All data is stored in entities / models derived from IIPRangeCountry which, at the very minimum, must provide a start- and end IP address (IPv4 and/or IPv6, supported completely transparently) and country (usually an ISO 3166-1 alpha-2 country code, but may contain other data depending on the data source).

Usage

In general, you'll want to use one of the above mentioned datasources. You can combine them but it's recommended to use a single one. Install the desired NuGet package (e.g. IP-2-Country.MaxMind) which will also pull in the base package (IP-2-Country) and the generic CSV parser (IP-2-Country.DataSources.CSVFile). Download the datafiles (example code is provided in the DemoApp in this repository) and create an IP2CountryResolver object:

var resolver = new IP2CountryResolver(
    // Country level file, using MaxMind as an example
    new MaxMindGeoLiteFileSource(@"D:\files\GeoLite2-Country-CSV_20190305.zip")
);

And you're done! Now you can resolve IP addresses:

var result = resolver.Resolve("172.217.17.110");
Console.WriteLine("Country: " + result?.Country);

Depending on the datasource some more information may be returned (for example: the IP-2-Country.Registries package returns the Registry, Date, Status and even some Extensions when available). You may need to cast to the returned type in case you need more than the IIPRangeCountry interface provides:

var result = (RegistryIPRangeCountry)resolver.Resolve("172.217.17.110");

The following overloads / convenience-methods are available:

// IIP2CountryResolver
IIPRangeCountry Resolve(string ip);
IIPRangeCountry Resolve(IPAddress ip);

// IIP2CountryBatchResolver
IIPRangeCountry[] Resolve(string[] ips);
IIPRangeCountry[] Resolve(IPAddress[] ips);
IIPRangeCountry[] Resolve(IEnumerable<string> ips);
IIPRangeCountry[] Resolve(IEnumerable<IPAddress> ips);
IDictionary<string, IIPRangeCountry> ResolveAsDictionary(string[] ips);
IDictionary<IPAddress, IIPRangeCountry> ResolveAsDictionary(IPAddress[] ips);
IDictionary<string, IIPRangeCountry> ResolveAsDictionary(IEnumerable<string> ips);
IDictionary<IPAddress, IIPRangeCountry> ResolveAsDictionary(IEnumerable<IPAddress> ips);

To resolve more than one IP address you can use the IP2CountryBatchResolver:

var resolver = new IP2CountryBatchResolver(new IP2CountryResolver(
    new DbIpCSVFileSource(@"D:\files\dbip-country-lite-2019-10.csv.gz")	// Use ANY datasource you want
));

var results = resolve.Resolve(new[] { "172.217.17.110", "172.217.17.111", "172.217.17.112" });

To use caching, use the CachingIP2CountryResolver from the IP2Country.Caching package:

var memcache = new MemoryCache(new MemoryCacheOptions { /* ... */ });
var resolver = new CachingIP2CountryResolver(new IP2CountryResolver(
    new LudostCSVFileSource(@"D:\files\country.db.gz")	// Use ANY datasource you want
	memcache,               // IMemoryCache instance (in this case a MemoryCache)
	TimeSpan.FromHours(1)	// TTL for cached entries
));

var result = resolver.Resolve("172.217.17.110");

And, ofcourse, even the CachingIP2CountryResolver can be used for batch lookups:

var memcache = new MemoryCache(new MemoryCacheOptions { /* ... */ });
var resolver = new IP2CountryBatchResolver(new CachingIP2CountryResolver(new IP2CountryResolver(
    new WebNet77IPv4CSVFileSource(@"D:\files\IpToCountry.csv.gz")	// Use ANY datasource you want
	memcache,		// IMemoryCache instance (in this case a MemoryCache)
	TimeSpan.FromHours(1)	// TTL for cached entries
)));

var results = resolve.Resolve(new[] { "172.217.17.110", "172.217.17.111", "172.217.17.112" });

IIP2CountryBatchResolver and caching

An IP2CountryBatchResolver class is provided to help in resolving many IP's at once. This object takes an IIP2CountryResolver for it's constructor parameter and is nothing more than a simple wrapper implementing the 'batch'-methods.

The IP2Country.Caching package provides a resolver that takes an IMemoryCache to provide a caching mechanism and a TimeSpan to specify how long entries should be cached. Unless you have to resolve a lot of duplicate IP's, the caching probably doesn't add very much value.

Datasources

Besides the provided datasources it's very simple to implement your own datasource; all you need to do is implement a single method (IEnumerable<IIPRangeCountry> Read()) from a single interface (IIP2CountryDataSource). It's up to you whether you want to use a CSV file, binary file, database, Excel file or whatever other method of storage you can imagine. As long as you can provide IP ranges (as start/end pairs) and country data (as string) as an IEnumerable source you're done. This repository has lots of examples of CSV datasources but it's perfectly fine to build and provide your own datasource.

A word on the actual data

The provided datasources are nothing but simple "CSV file readers". It's up to you to download the actual data files (and cache them for later use). The DemoApp contains an example of downloading files into a temp directory and caching them. You can implement your own download/cache mechanism as you see fit for your project. As long as you can provide a datasource that implements the IIP2CountryDataSource interface this library doesn't care about the rest.

More on actual, compatible, databases can be found in the wiki

Accuracy

The accuracy depends entirely on the accuracy of the datasource. This library has no built-in data whatsoever. You may also want to ensure your datasource doesn't provide ranges to the IP2CountryResolver that overlap. It's up to you / the datasource to ensure the data is as accurate as possible (and as up-to-date as possible).

Benchmarks / performance:

On an Intel Xeon E3-1225 v3 CPU it's perfectly possible to achieve over 2,000,000 lookups per second (yes, that is over 2 million on an CPU from 2013!). Obviously results will vary depending on the size of the dataset, the usage, the CPU and other factors.

Note that when an instance of an IP2CountryResolver is created it will load all the data from the datasource into memory. Naturally this is a costly, though one-time, operation. As long as the IP2CountryResolver object is kept alive you can (re)use it to resolve IP addresses. We recommend creating an instance once and keeping it around as long as possible. Create a new instance and swap it out with the old one if there is new data available from the datasource.

Icon

Source: ShareIcon.Net Author: Ayesha Nasir License: Creative Commons (Attribution 3.0 Unported)


Build status NuGet version