Skip to content
This repository was archived by the owner on Feb 5, 2023. It is now read-only.

Commit 0675ece

Browse files
author
Suyog Rao
authored
Add support for GeoIPLite2-ASN database (logstash-plugins#120)
* Handle ASN. this means we need to use a new Java driver.
1 parent 8e1613f commit 0675ece

File tree

9 files changed

+114
-16
lines changed

9 files changed

+114
-16
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 4.2.0
2+
- Add support for GeoLite2-ASN database from Maxmind for ASN data.
3+
- Update Java dependencies to 2.9.0 to support the new ASN database.
4+
15
## 4.1.1
26
- Add support for commercial databases from Maxmind.
37
- Add ASN data support via GeoIP2-ISP database.

build.gradle

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import de.undercouch.gradle.tasks.download.Download
2+
13
/*
24
* Licensed to Elasticsearch under one or more contributor
35
* license agreements. See the NOTICE file distributed with
@@ -16,14 +18,13 @@
1618
* specific language governing permissions and limitations
1719
* under the License.
1820
*/
19-
2021
apply plugin: "java"
2122
apply plugin: "distribution"
2223
apply plugin: "idea"
2324

2425
// TODO(sissel): Move this to a file shared by the gemspec.
2526
group "org.logstash.filters"
26-
version "4.1.0"
27+
version "4.2.0"
2728

2829
import java.nio.file.Files
2930
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING
@@ -35,6 +36,7 @@ buildscript {
3536

3637
dependencies {
3738
classpath group: 'org.jruby', name: 'jruby-complete', version: "1.7.26"
39+
classpath 'de.undercouch:gradle-download-task:3.2.0'
3840
}
3941
}
4042

@@ -45,18 +47,18 @@ repositories {
4547
dependencies {
4648
compileOnly group: "org.apache.logging.log4j", name: "log4j-api", version: "2.6.2"
4749
compileOnly group: "org.apache.logging.log4j", name: "log4j-core", version: "2.6.2"
48-
compileOnly group: "com.maxmind.geoip2", name: "geoip2", version: "2.8.0"
49-
compileOnly group: "com.maxmind.db", name: "maxmind-db", version: "1.2.1"
50+
compileOnly group: "com.maxmind.geoip2", name: "geoip2", version: "2.9.0"
51+
compileOnly group: "com.maxmind.db", name: "maxmind-db", version: "1.2.2"
5052

51-
runtime group: "com.maxmind.geoip2", name: "geoip2", version: "2.8.0"
52-
runtime group: "com.maxmind.db", name: "maxmind-db", version: "1.2.1"
53+
runtime group: "com.maxmind.geoip2", name: "geoip2", version: "2.9.0"
54+
runtime group: "com.maxmind.db", name: "maxmind-db", version: "1.2.2"
5355

5456
testCompile group: 'junit', name: 'junit', version: '4.12'
5557
testCompile group: "org.apache.logging.log4j", name: "log4j-api", version: "2.6.2"
5658
testCompile group: "org.apache.logging.log4j", name: "log4j-core", version: "2.6.2"
5759
testCompile group: 'org.jruby', name: 'jruby-complete', version: "1.7.26"
58-
testCompile group: "com.maxmind.geoip2", name: "geoip2", version: "2.8.0"
59-
testCompile group: "com.maxmind.db", name: "maxmind-db", version: "1.2.1"
60+
testCompile group: "com.maxmind.geoip2", name: "geoip2", version: "2.9.0"
61+
testCompile group: "com.maxmind.db", name: "maxmind-db", version: "1.2.2"
6062
testCompile fileTree(dir: logstashCoreGemPath, include: '**/*.jar')
6163
testCompile fileTree(dir: logstashCoreEventGemPath, include: '**/*.jar')
6264

@@ -65,6 +67,10 @@ dependencies {
6567
compileOnly fileTree(dir: logstashCoreEventGemPath, include: '**/*.jar')
6668
}
6769

70+
test {
71+
dependsOn 'downloadASNDatabaseForTest'
72+
}
73+
6874
task rubyBootstrap << {
6975
description "Try bundler"
7076
def jruby = new org.jruby.embed.ScriptingContainer()
@@ -120,4 +126,19 @@ task vendor << {
120126
Files.copy(file("$buildDir/libs/${project.name}-${project.version}.jar").toPath(), projectJarFile.toPath(), REPLACE_EXISTING)
121127
}
122128

129+
String databaseRootResource = 'http://geolite.maxmind.com/download/geoip/database/'
130+
131+
task downloadASNDatabaseForTest(type: Download, overwrite: false) {
132+
src([
133+
databaseRootResource + 'GeoLite2-ASN.tar.gz'
134+
])
135+
dest file("build")
136+
doLast {
137+
copy {
138+
from tarTree('build/GeoLite2-ASN.tar.gz')
139+
into file("build")
140+
}
141+
}
142+
}
143+
123144
vendor.dependsOn(jar, generateGemJarRequiresFile)

ci/run.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#!/bin/bash
2+
current_dir="$(dirname "$0")"
3+
14
bundle install
25
bundle exec rake gradle.properties
36
./gradlew assemble

docs/index.asciidoc

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,23 @@ include::{include_path}/plugin_header.asciidoc[]
2121
==== Description
2222

2323
The GeoIP filter adds information about the geographical location of IP addresses,
24-
based on data from the Maxmind GeoLite2 database. Commercial databases from Maxmind are
25-
also supported in this plugin.
24+
based on data from the Maxmind GeoLite2 databases.
25+
26+
==== Supported Databases
27+
28+
This plugin is bundled with https://dev.maxmind.com/geoip/geoip2/geolite2[GeoLite2] City database out of the box. From Maxmind's description --
29+
"GeoLite2 databases are free IP geolocation databases comparable to, but less accurate than, MaxMind’s
30+
GeoIP2 databases". Please see GeoIP Lite2 license for more details.
31+
32+
https://www.maxmind.com/en/geoip2-databases[Commercial databases] from Maxmind are also supported in this plugin.
33+
34+
If you need to use databases other than the bundled GeoLite2 City, you can download them directly
35+
from Maxmind's website and use the `database` option to specify their location. The GeoLite2 databases
36+
can be downloaded from https://dev.maxmind.com/geoip/geoip2/geolite2[here].
37+
38+
If you would like to get Autonomous System Number(ASN) information, you can use the GeoLite2-ASN database.
39+
40+
==== Details
2641

2742
A `[geoip][location]` field is created if
2843
the GeoIP lookup returns a latitude and longitude. The field is stored in

lib/logstash-filter-geoip_jars.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# AUTOGENERATED BY THE GRADLE SCRIPT. DO NOT EDIT.
22

33
require 'jar_dependencies'
4-
require_jar('com.maxmind.geoip2', 'geoip2', '2.8.0')
5-
require_jar('com.maxmind.db', 'maxmind-db', '1.2.1')
6-
require_jar('org.logstash.filters', 'logstash-filter-geoip', '4.1.0')
4+
require_jar('com.maxmind.geoip2', 'geoip2', '2.9.0')
5+
require_jar('com.maxmind.db', 'maxmind-db', '1.2.2')
6+
require_jar('org.logstash.filters', 'logstash-filter-geoip', '4.2.0')

logstash-filter-geoip.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Gem::Specification.new do |s|
22

33
s.name = 'logstash-filter-geoip'
4-
s.version = '4.1.1'
4+
s.version = '4.2.0'
55
s.licenses = ['Apache License (2.0)']
66
s.summary = "$summary"
77
s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"

spec/filters/geoip_spec.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
require "logstash/filters/geoip"
44

55
CITYDB = ::Dir.glob(::File.expand_path("../../vendor/", ::File.dirname(__FILE__))+"/GeoLite2-City.mmdb").first
6+
# this is downloaded in build dir so we don't accidentally package this database when creating a gem
7+
ASNDB = ::Dir.glob(::File.expand_path("../../build/GeoLite2-ASN_*", ::File.dirname(__FILE__))+"/GeoLite2-ASN.mmdb").first
68

79
describe LogStash::Filters::GeoIP do
810

@@ -266,4 +268,23 @@
266268
end
267269
end
268270

271+
describe "GeoIP2-ASN database" do
272+
config <<-CONFIG
273+
filter {
274+
geoip {
275+
source => "ip"
276+
database => "#{ASNDB}"
277+
}
278+
}
279+
CONFIG
280+
281+
sample("ip" => "8.8.8.8") do
282+
expect(subject.get("geoip")).not_to be_empty
283+
expect(subject.get("geoip")["asn"]).to eq(15169)
284+
expect(subject.get("geoip")["as_org"]).to eq("Google Inc.")
285+
end
286+
287+
288+
end
289+
269290
end

src/main/java/org/logstash/filters/Fields.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ public String fieldName() {
6767
static final EnumSet<Fields> DEFAULT_ISP_FIELDS = EnumSet.of(Fields.IP, Fields.AUTONOMOUS_SYSTEM_NUMBER,
6868
Fields.AUTONOMOUS_SYSTEM_ORGANIZATION, Fields.ISP, Fields.ORGANIZATION);
6969

70+
static final EnumSet<Fields> DEFAULT_ASN_LITE_FIELDS = EnumSet.of(Fields.IP, Fields.AUTONOMOUS_SYSTEM_NUMBER,
71+
Fields.AUTONOMOUS_SYSTEM_ORGANIZATION);
72+
7073
public static Fields parseField(String value) {
7174
try {
7275
return valueOf(value.toUpperCase(Locale.ROOT));

src/main/java/org/logstash/filters/GeoIPFilter.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.maxmind.db.InvalidDatabaseException;
2323
import com.maxmind.geoip2.exception.AddressNotFoundException;
2424
import com.maxmind.geoip2.exception.GeoIp2Exception;
25+
import com.maxmind.geoip2.model.AsnResponse;
2526
import com.maxmind.geoip2.model.CityResponse;
2627
import com.maxmind.geoip2.model.CountryResponse;
2728
import com.maxmind.geoip2.model.IspResponse;
@@ -50,7 +51,7 @@ public class GeoIPFilter {
5051
private static final String CITY_DB_TYPE = "GeoIP2-City";
5152
private static final String COUNTRY_DB_TYPE = "GeoIP2-Country";
5253
private static final String ISP_DB_TYPE = "GeoIP2-ISP";
53-
54+
5455
private final String sourceField;
5556
private final String targetField;
5657
private final Set<Fields> desiredFields;
@@ -83,9 +84,11 @@ private Set<Fields> createDesiredFields(List<String> fields) {
8384
desiredFields = Fields.DEFAULT_COUNTRY_FIELDS;
8485
break;
8586
case ISP_DB_TYPE:
86-
case ASN_LITE_DB_TYPE:
8787
desiredFields = Fields.DEFAULT_ISP_FIELDS;
8888
break;
89+
case ASN_LITE_DB_TYPE:
90+
desiredFields = Fields.DEFAULT_ASN_LITE_FIELDS;
91+
break;
8992
}
9093
} else {
9194
for (String fieldName : fields) {
@@ -126,6 +129,8 @@ public boolean handleEvent(RubyEvent rubyEvent) {
126129
geoData = retrieveCountryGeoData(ipAddress);
127130
break;
128131
case ASN_LITE_DB_TYPE:
132+
geoData = retrieveAsnGeoData(ipAddress);
133+
break;
129134
case ISP_DB_TYPE:
130135
geoData = retrieveIspGeoData(ipAddress);
131136
break;
@@ -351,4 +356,30 @@ private Map<String, Object> retrieveIspGeoData(InetAddress ipAddress) throws Geo
351356

352357
return geoData;
353358
}
359+
360+
private Map<String, Object> retrieveAsnGeoData(InetAddress ipAddress) throws GeoIp2Exception, IOException {
361+
AsnResponse response = databaseReader.asn(ipAddress);
362+
Map<String, Object> geoData = new HashMap<>();
363+
for (Fields desiredField : this.desiredFields) {
364+
switch (desiredField) {
365+
case IP:
366+
geoData.put(Fields.IP.fieldName(), ipAddress.getHostAddress());
367+
break;
368+
case AUTONOMOUS_SYSTEM_NUMBER:
369+
Integer asn = response.getAutonomousSystemNumber();
370+
if (asn != null) {
371+
geoData.put(Fields.AUTONOMOUS_SYSTEM_NUMBER.fieldName(), asn);
372+
}
373+
break;
374+
case AUTONOMOUS_SYSTEM_ORGANIZATION:
375+
String aso = response.getAutonomousSystemOrganization();
376+
if (aso != null) {
377+
geoData.put(Fields.AUTONOMOUS_SYSTEM_ORGANIZATION.fieldName(), aso);
378+
}
379+
break;
380+
}
381+
}
382+
383+
return geoData;
384+
}
354385
}

0 commit comments

Comments
 (0)