Add new functions for calculating geographic distance

Added a new BIF haversine_distance that computes distance between two
geographic locations.

Added a new Bro script function haversine_distance_ip that does the same
but takes two IP addresses instead of latitude/longitude.  This function
requires that Bro be built with libgeoip.
This commit is contained in:
Daniel Thayer 2016-06-07 12:55:50 -05:00
parent 58dea28504
commit 91496543ad
5 changed files with 93 additions and 0 deletions

View file

@ -12,6 +12,7 @@
@load base/utils/directions-and-hosts @load base/utils/directions-and-hosts
@load base/utils/exec @load base/utils/exec
@load base/utils/files @load base/utils/files
@load base/utils/geoip-distance
@load base/utils/numbers @load base/utils/numbers
@load base/utils/paths @load base/utils/paths
@load base/utils/patterns @load base/utils/patterns

View file

@ -0,0 +1,26 @@
##! Functions to calculate distance between two locations, based on GeoIP data.
## Returns the distance between two IP addresses using the haversine formula,
## based on GeoIP database locations. Requires Bro to be built with libgeoip.
##
## a1: First IP address.
##
## a2: Second IP address.
##
## Returns: The distance between *a1* and *a2* in miles, or -1.0 if GeoIP data
## is not available for either of the IP addresses.
##
## .. bro:see:: haversine_distance lookup_location
function haversine_distance_ip(a1: addr, a2: addr): double
{
local loc1 = lookup_location(a1);
local loc2 = lookup_location(a2);
local miles: double;
if (loc1?$latitude && loc1?$longitude && loc2?$latitude && loc2?$longitude)
miles = haversine_distance(loc1$latitude, loc1$longitude, loc2$latitude, loc2$longitude);
else
miles = -1.0;
return miles;
}

View file

@ -3787,6 +3787,35 @@ function lookup_asn%(a: addr%) : count
return new Val(0, TYPE_COUNT); return new Val(0, TYPE_COUNT);
%} %}
## Calculates distance between two geographic locations using the haversine
## formula. Latitudes and longitudes must be given in degrees, where southern
## hemispere latitudes are negative and western hemisphere longitudes are
## negative.
##
## lat1: Latitude (in degrees) of location 1.
##
## long1: Longitude (in degrees) of location 1.
##
## lat2: Latitude (in degrees) of location 2.
##
## long2: Longitude (in degrees) of location 2.
##
## Returns: Distance in miles.
##
## .. bro:see:: haversine_distance_ip
function haversine_distance%(lat1: double, long1: double, lat2: double, long2: double%): double
%{
const double PI = 3.14159;
const double RADIUS = 3958.8; // Earth's radius in miles.
double s1 = sin((lat2 - lat1) * PI/360);
double s2 = sin((long2 - long1) * PI/360);
double a = s1 * s1 + cos(lat1 * PI/180) * cos(lat2 * PI/180) * s2 * s2;
double distance = 2 * RADIUS * asin(sqrt(a));
return new Val(distance, TYPE_DOUBLE);
%}
## Converts UNIX file permissions given by a mode to an ASCII string. ## Converts UNIX file permissions given by a mode to an ASCII string.
## ##
## mode: The permissions (an octal number like 0644 converted to decimal). ## mode: The permissions (an octal number like 0644 converted to decimal).

View file

@ -0,0 +1,7 @@
5.8481e+03
5.8481e+03
1.9193e-02
1.5136e-02
9.2419e-01
1.2437e+04
1.2437e+04

View file

@ -0,0 +1,30 @@
#
# @TEST-EXEC: bro -b %INPUT >out
# @TEST-EXEC: btest-diff out
function test(la1: double, lo1: double, la2: double, lo2: double)
{
print fmt("%.4e", haversine_distance(la1, lo1, la2, lo2));
}
event bro_init()
{
# Test two arbitrary locations.
test(37.866798, -122.253601, 48.25, 11.65);
# Swap the order of locations to verify the distance doesn't change.
test(48.25, 11.65, 37.866798, -122.253601);
# Distance of one second of latitude (crossing the equator).
test(.0001388889, 0, -.0001388889, 0);
# Distance of one second of longitude (crossing the prime meridian).
test(38, 0.000138999, 38, -0.000138999);
# Distance of one minute of longitude (test extreme longitude values).
test(38, 180, 38, -179.98333);
# Two locations on opposite ends of the Earth.
test(45, -90, -45, 90);
# Same, but verify that extreme latitude values work.
test(90, 0, -90, 0);
}