Tuesday, October 13, 2020

Finding Distance between Source IPs



In this post we will review to find distance between two source IPs. This can be used in case, for example, we know that a certain user, which was sending HTTP requests to our site from one IP, and now the requests arrive from a new IP, so we want to understand how far had the user traveled.


Given a source IP, we will use a Geo IP database to find the estimated location of the source IP. Then we will use a sphere distance function to calculate the points. Let's review the steps to perform this.


Download a Geo IP Database


There are several companies providing a Geo location database. A Geo location database provides a list of IPs subnets, and for each network subnet the following details can be included:
  • Country
  • City
  • Longitude
  • Latitude
  • ISP
  • ASN
  • Accuracy radius
We will use MaxMind's GeoIP location database. MaxMind provides the following GeoIP databases types:

  1. GeoIP - a full and accurate database, with a max accuracy, and weekly updates. This database can be purchased at a price of ~100$ per month, and includes support from the MaxMind's team.
  2. GeoLite2 - a light version of the GeoIP, which can be downloaded for free. It is less accurate, includes less frequent updates, and does not include support from MaxMind's team.
The good thing about this, is that both GeoIP and GeoLite2 are using the same format, so we can start with the GeoLite2 database, implement our code, and then, if we move to production, and need more accurate results, we can switch to the GeoIP database.

Notice that each database type include the Country version and the City version. The country version only provides the country name per network subnet, and is less relevant for us. We will use the City version.


Find the Location of a Source IP


Now that we have downloaded the GeoIP database, we can use the GO library maxminddb-golang to get details per a source IP. An example of such code is listed below.


package main

import (
"fmt"
"github.com/oschwald/maxminddb-golang"
"math"
"net"
)

type location struct {
Latitude float32 `maxminddb:"latitude"`
Longitude float32 `maxminddb:"longitude"`
}

type record struct {
Location location `maxminddb:"location"`
}

func main() {
db, err := maxminddb.Open("/geoip.mmdb")
if err != nil {
panic(err)
}

ip := "8.8.8.8"
netIp := net.ParseIP(ip)
var r record
err = db.Lookup(netIp, &r)
if err != nil {
panic(err)
}

fmt.Print(r)
}



Find the Distance between Two Locations


Now that we have the location for a source IP, specified by latitude and longitude, we can find the distance between the points. We will use a circle distance function. The distance implementation is below. It returns the distance in KiloMeters units.


func hsin(theta float64) float64 {
return math.Pow(math.Sin(theta/2), 2)
}

func (l *location) distance(other *location) float64 {
la1 := float64(l.Latitude) * math.Pi / 180
lo1 := float64(l.Longitude) * math.Pi / 180
la2 := float64(other.Latitude) * math.Pi / 180
lo2 := float64(other.Longitude) * math.Pi / 180

h := hsin(la2-la1) + math.Cos(la1)*math.Cos(la2)*hsin(lo2-lo1)

r := 6371.0 // Earth radius in KM
return 2 * r * math.Asin(math.Sqrt(h))
}


A nice representation of a distance function can be shown in Google Maps, finding the distance between the Google DNS server IP 8.8.8.8, and Tel-Aviv:











No comments:

Post a Comment