Click here to Skip to main content
15,441,149 members
Articles / Programming Languages / Markdown
Project
Posted 20 Sep 2022

Stats

2.8K views
31 downloads
6 bookmarked

IP Geofencing Engine for .NET

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
20 Sep 2022GPL33 min read
A simple and easily extensible IP geo-fencing engine
This project is about the implementation of a simple and extensible IP geofencing engine. It discusses how geofencing rule are declared, and how to configure, run and extend the geofencing engine.

Overview

Geofencing is the use of virtual geographic perimeters to determine the behavior of an application. Provided a specific coordinate (latitude and longitude), a geofencing engine can determine to which virtual geographic area or areas the location belongs, and consequentially take action.

The IP geofencing engine in this project runs based on specific IP addresses. The engine would first translate the IP address into a geographic location, using the free CSV database provided by IP2Location CSV database (included in the project).

The engine then determines which of the configured geographic areas contain the location, and for each match fires the correspondent configured action. Geographic areas can be configured in the engine by importing a file in GeoJSON format. Sample GeoJSON files are included in this project for testing purposes, and are also freely available for the public on the OpenDataSoft website.

Use Case Scenarios

This engine is particularly useful in cases when the IP address is available, but not the coordinate.
These are the typical scenarios in which web applications can use the engine with the IP address of the http requests:

  • Blocking requests from black-listed geographic areas
  • Enabling/disabling features for specific regions
  • Localizing content
  • Finding the availability of products or service nearby the IP location

Anatomy of a Geofencing Rule

A rule is constructed from three elements: name, predicate and action.

  • rule name: short description for the rule

  • predicate: a boolean function that determines if the rule should be applied. The function will receive as input the list of geographic areas that contain the IP address location (normally only one area if the areas do not overlap), plus the IP address and its location info:

    C#
    predicate: (areas, ip, location) => 
    	{ return areas.Any(A => A.Name == "New York"); }
  • action: a routine that will be executed only if the predicate is evaluated as true. Same inputs as the predicate:
    C#
    action: (areas, ip, location) => 
            { Console.WriteLine($"The IP Address: {ip} is in New York State!"); })

In addition to regular rules, default rules can also be specified. Default rules are executed if and only if the IP address location is not contained in any of the geographic areas available. Unlike regular rules, default rules only need the action to be constructed.

Configuring the Geofencing Engine

C#
var engine = new IPGeoFencingEngineBuilder()
	.AddIP2LocationFromCSVFile(@"\\geofencing\data\IP2LOCATION-LITE-DB11.CSV")
	.AddGeographicAreasFromGeoJSONFile(@"\\geofencing\data\demo.geojson")
	.AddRule("New York", 
		predicate: (areas, ip, location) => 
		{ return areas.Any(A => A.Name == "New York"); },	
		action: (areas, ip, location) => 
		{ Console.WriteLine($"The IP Address: {ip} is in New York State!"); })
	.AddRule("Montana",
		predicate: (areas, ip, location) => 
		{ return areas.Any(A => A.Name == "Montana"); },
		action: (areas, ip, location) => 
		{ Console.WriteLine($"The IP Address: {ip} is in Montana!"); })
	.AddRule("Billings",
		predicate: (areas, ip, location) => 
		{ return areas.Any(A => A.Name == "Billings"); },
		action: (areas, ip, location) => 
		{ Console.WriteLine($"The IP Address: {ip} is in Billings, MT"); })
	.AddRule("Montana but not Billings",
		predicate: (areas, ip, location) => 
		{ return areas.Any(A => A.Name == "Montana") && 
		!areas.Any(A => A.Name == "Billings"); },
		action: (areas, ip, location) => 
		{ Console.WriteLine($"The IP Address: 
          {ip} is in Montana but not in Billings!"); })
	.AddRule("New York or Montana",
		predicate: (areas, ip, location) => 
		{ return areas.Any(A => A.Name == "Montana") || 
		areas.Any(A => A.Name == "New York"); },
		action: (areas, ip, location) => 
		{ Console.WriteLine($"The IP Address: 
          {ip} is in New York State or Montana!"); })
	.AddDefaultAction((ip, loc) => 
	Console.WriteLine($"The IP Address: {ip} is outside all the areas provided"))
	.Build();

Running the Engine

C#
engine.Run("98.127.147.57");   //Billings, MT IP Address
//The IP Address: 98.127.147.57 is in Montana!
//The IP Address: 98.127.147.57 is in Billings, MT
//The IP Address: 98.127.147.57 is in New York State or Montana!

engine.Run("172.254.112.210"); //New York, NY IP Address
//The IP Address: 172.254.112.210 is in New York State!
//The IP Address: 172.254.112.210 is in New York State or Montana!

engine.Run("157.240.3.35");    //Seattle, WA IP Address
//The IP Address: 157.240.3.35 is outside all the areas provided

Running the Demo

The solution comes with a simple demo console app that demonstrates the engine configuration and execution. Before you run the demo, make sure to edit the appsettings.json file included in the project and set the correct full path to the data folder in your file system.

Example:

JavaScript
{
  "DataFolder": "D:\\IPGeoFencing\\Data"
}

Extending the Engine

The core services used by the engine that can be easily extended to enrich its functionality:

IIP2LocationProvider

This interface provides the engine with the translation service to obtain the grographic location from the IP address. The project provides out-of-the-box a simple implementation where the Ip2Location CSV data is loaded entirely in memory and the IP translation occurs via Linq queries. More efficient implementations can be added that utilize databases queries/indexes to look up the locations, or leverage the IP2Location API for a lightweight solution, etc.

C#
public interface IIP2LocationProvider
{
	LocationModel? GetLocationFromIP(IPAddress ipAddress);
	LocationModel? GetLocationFromIP(long ipAddress);
}

IGeographicAreasProvider

This interface is used by the engine to determine which geographic areas contain a given coordinate point. The default implementation in the project is loading in memory the full collection of geographic areas (in the shape of polygons or circles) that need to be evaluated. Like the IIP2LocationProvider, more efficient implementations can be added to leverage databases, particularly those supporting geospatial queries (e.g., MongoDB). Moreover, the project currently only supports the GeoJSON file format to import geographic areas, however there are other popular formats that can be integrated: Shapefile (GIS), KML (Google Earth), etc.

C#
public interface IGeographicAreasProvider
{
	IEnumerable<GeographicAreaModel> GetAreasContaining(GeoCoordinate point);
}

Plugging in Your Own Service Implementations

The engine builder already allows developers to plug in their own service implementations:

C#
IIP2LocationProvider myIP2LocationProvider = 
                     new myOwnIP2LocationProviderImplementation();
IGeographicAreasProvider myGeographicAreasProvider = 
                         new myOwnGeographicAreasProviderImplementation();

var engine = new IPGeoFencingEngineBuilder()
    .AddIP2LocationProvider(myIP2LocationProvider)
    .AddGeographicAreasProvider(myGeographicAreasProvider)
.AddRule( ...
This article was originally posted at https://github.com/giovanniscerra/IpGeoFencing

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Technical Lead
United States United States
Technical Director at AFS Technologies, New York, NY

More info about my skills, projects, presentations, etc.:
https://www.linkedin.com/in/giovanniscerra

Comments and Discussions

 
-- There are no messages in this forum --