Skip to content

Commit 14d975e

Browse files
committed
Added support for DB-IP Location+ISP (Enterprise) databases, [logstash-plugins#174]
1 parent 099f1fd commit 14d975e

File tree

3 files changed

+176
-7
lines changed

3 files changed

+176
-7
lines changed

CHANGELOG.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
## 7.2.13
2+
- Added support for DB-IP Location+ISP (Enterprise) databases, [#174](https://github.com/logstash-plugins/logstash-filter-geoip/issues/174) and . It is recommended to explicitly configure fields in case of enabled ECS.
3+
14
## 7.2.12
2-
- [DOC] Add `http_proxy` environment variable for GeoIP service endpoint. The feature is included in 8.1.0, and was back-ported to 7.17.2 [#207](https://github.com/logstash-plugins/logstash-filter-geoip/pull/207)
5+
- [DOC] Add `http_proxy` environment variable for GeoIP service endpoint. The feature is included in 8.1.0, and was back-ported to 7.17.2 [#207](https://github.com/logstash-plugins/logstash-filter-geoip/pull/207)
36

47
## 7.2.11
58
- Improved compatibility with the Elastic Common Schema [#206](https://github.com/logstash-plugins/logstash-filter-geoip/pull/206)
6-
- Added support for ECS's composite `region_iso_code` (`US-WA`), which _replaces_ the non-ECS `region_code` (`WA`) as a default field with City databases. To get the stand-alone `region_code` in ECS mode, you must include it in the `fields` directive.
9+
- Added support for ECS's composite `region_iso_code` (`US-WA`), which _replaces_ the non-ECS `region_code` (`WA`) as a default field with City databases. To get the stand-alone `region_code` in ECS mode, you must include it in the `fields` directive.
710
- [DOC] Improve ECS-related documentation
811

912
## 7.2.10
@@ -77,14 +80,14 @@
7780
- Update of GeoLite2 DB [#157](https://github.com/logstash-plugins/logstash-filter-geoip/pull/157)
7881

7982
## 6.0.1
80-
- Fixed deeplink to Elasticsearch Reference
83+
- Fixed deeplink to Elasticsearch Reference
8184
[#151](https://github.com/logstash-plugins/logstash-filter-geoip/pull/151)
8285

8386
## 6.0.0
8487
- Removed obsolete lru_cache_size field
8588

8689
## 5.0.3
87-
- Skip lookup operation if source field contains an empty string
90+
- Skip lookup operation if source field contains an empty string
8891
- Update of the GeoIP2 DB
8992

9093
## 5.0.2
@@ -109,7 +112,7 @@
109112
- Add ASN data support via GeoIP2-ISP database.
110113

111114
## 4.1.0
112-
- Removed from RubyGems.org since it was missing the default GeoIP2 database.
115+
- Removed from RubyGems.org since it was missing the default GeoIP2 database.
113116

114117
## 4.0.6
115118
- Docs: Remove patch classes from the main plugin file

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ enum Fields {
4444
LOCATION("geo.location", "location"),
4545
LATITUDE("geo.location.lat", "latitude"),
4646
LONGITUDE("geo.location.lon", "longitude"),
47-
ORGANIZATION("mmdb.organization", "organization");
47+
ORGANIZATION("mmdb.organization", "organization"),
48+
CONNECTION_TYPE("mmdb.connection_type", "connection_type");
4849

4950
private final String fieldName;
5051
private final String ecsFieldName;

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

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
import com.maxmind.geoip2.exception.GeoIp2Exception;
2525
import com.maxmind.geoip2.model.AsnResponse;
2626
import com.maxmind.geoip2.model.CityResponse;
27+
import com.maxmind.geoip2.model.EnterpriseResponse;
2728
import com.maxmind.geoip2.model.CountryResponse;
2829
import com.maxmind.geoip2.model.DomainResponse;
2930
import com.maxmind.geoip2.model.IspResponse;
31+
import com.maxmind.geoip2.model.ConnectionTypeResponse.ConnectionType;
3032
import com.maxmind.geoip2.record.*;
3133
import org.apache.logging.log4j.LogManager;
3234
import org.apache.logging.log4j.Logger;
@@ -58,6 +60,7 @@ public class GeoIPFilter {
5860
private static final String CITY_SOUTH_AMERICA_DB_TYPE = "GeoIP2-City-South-America";
5961
private static final String COUNTRY_DB_TYPE = "GeoIP2-Country";
6062
private static final String ISP_DB_TYPE = "GeoIP2-ISP";
63+
private static final String DBIP_LOCATION_ISP_TYPE = "DBIP-Location-ISP (compat=Enterprise)";
6164
private static final String DOMAIN_DB_TYPE = "GeoIP2-Domain";
6265

6366
private final String sourceField;
@@ -132,6 +135,11 @@ private Set<Fields> createDesiredFields(List<String> fields, final boolean ecsCo
132135
break;
133136
case DOMAIN_DB_TYPE:
134137
desiredFields = Fields.DEFAULT_DOMAIN_FIELDS;
138+
case DBIP_LOCATION_ISP_TYPE:
139+
desiredFields = Fields.ALL_FIELDS;
140+
break;
141+
default:
142+
throw new IllegalStateException("Unsupported database type '" + databaseReader.getMetadata().getDatabaseType() + "'");
135143
}
136144
} else {
137145
for (String fieldName : fields) {
@@ -189,8 +197,11 @@ public boolean handleEvent(RubyEvent rubyEvent) {
189197
case DOMAIN_DB_TYPE:
190198
geoData = retrieveDomainGeoData(ipAddress);
191199
break;
200+
case DBIP_LOCATION_ISP_TYPE:
201+
geoData = retrieveEnterpriseGeoData(ipAddress);
202+
break;
192203
default:
193-
throw new IllegalStateException("Unsupported database type " + databaseReader.getMetadata().getDatabaseType() + "");
204+
throw new IllegalStateException("Unsupported database type '" + databaseReader.getMetadata().getDatabaseType() + "'");
194205
}
195206
} catch (UnknownHostException e) {
196207
logger.debug("IP Field contained invalid IP address or hostname. exception={}, field={}, event={}", e, sourceField, event);
@@ -352,6 +363,160 @@ private Map<Fields,Object> retrieveCityGeoData(InetAddress ipAddress) throws Geo
352363
return geoData;
353364
}
354365

366+
private Map<Fields,Object> retrieveEnterpriseGeoData(InetAddress ipAddress) throws GeoIp2Exception, IOException {
367+
EnterpriseResponse response = databaseReader.enterprise(ipAddress);
368+
Country country = response.getCountry();
369+
City city = response.getCity();
370+
371+
Location location = response.getLocation();
372+
Continent continent = response.getContinent();
373+
Postal postal = response.getPostal();
374+
Subdivision subdivision = response.getMostSpecificSubdivision();
375+
Traits traits = response.getTraits();
376+
377+
Map<Fields, Object> geoData = new HashMap<>();
378+
379+
// if location is empty, there is no point populating geo data
380+
// and most likely all other fields are empty as well
381+
if (location.getLatitude() == null && location.getLongitude() == null) {
382+
return geoData;
383+
}
384+
385+
for (Fields desiredField : this.desiredFields) {
386+
switch (desiredField) {
387+
case CITY_NAME:
388+
String cityName = city.getName();
389+
if (cityName != null) {
390+
geoData.put(Fields.CITY_NAME, cityName);
391+
}
392+
break;
393+
case CONTINENT_CODE:
394+
String continentCode = continent.getCode();
395+
if (continentCode != null) {
396+
geoData.put(Fields.CONTINENT_CODE, continentCode);
397+
}
398+
break;
399+
case CONTINENT_NAME:
400+
String continentName = continent.getName();
401+
if (continentName != null) {
402+
geoData.put(Fields.CONTINENT_NAME, continentName);
403+
}
404+
break;
405+
case COUNTRY_NAME:
406+
String countryName = country.getName();
407+
if (countryName != null) {
408+
geoData.put(Fields.COUNTRY_NAME, countryName);
409+
}
410+
break;
411+
case COUNTRY_CODE2:
412+
String countryCode2 = country.getIsoCode();
413+
if (countryCode2 != null) {
414+
geoData.put(Fields.COUNTRY_CODE2, countryCode2);
415+
}
416+
break;
417+
case COUNTRY_CODE3:
418+
String countryCode3 = country.getIsoCode();
419+
if (countryCode3 != null) {
420+
geoData.put(Fields.COUNTRY_CODE3, countryCode3);
421+
}
422+
break;
423+
case IP:
424+
geoData.put(Fields.IP, ipAddress.getHostAddress());
425+
break;
426+
case POSTAL_CODE:
427+
String postalCode = postal.getCode();
428+
if (postalCode != null) {
429+
geoData.put(Fields.POSTAL_CODE, postalCode);
430+
}
431+
break;
432+
case DMA_CODE:
433+
Integer dmaCode = location.getMetroCode();
434+
if (dmaCode != null) {
435+
geoData.put(Fields.DMA_CODE, dmaCode);
436+
}
437+
break;
438+
case REGION_NAME:
439+
String subdivisionName = subdivision.getName();
440+
if (subdivisionName != null) {
441+
geoData.put(Fields.REGION_NAME, subdivisionName);
442+
}
443+
break;
444+
case REGION_CODE:
445+
String subdivisionCode = subdivision.getIsoCode();
446+
if (subdivisionCode != null) {
447+
geoData.put(Fields.REGION_CODE, subdivisionCode);
448+
}
449+
break;
450+
case REGION_ISO_CODE:
451+
String countryCodeForRegion = country.getIsoCode();
452+
String regionCode2 = subdivision.getIsoCode();
453+
if (countryCodeForRegion != null && regionCode2 != null) {
454+
geoData.put(Fields.REGION_ISO_CODE, String.format("%s-%s", countryCodeForRegion, regionCode2));
455+
}
456+
break;
457+
case TIMEZONE:
458+
String locationTimeZone = location.getTimeZone();
459+
if (locationTimeZone != null) {
460+
geoData.put(Fields.TIMEZONE, locationTimeZone);
461+
}
462+
break;
463+
case LOCATION:
464+
Double latitude = location.getLatitude();
465+
Double longitude = location.getLongitude();
466+
if (latitude != null && longitude != null) {
467+
Map<String, Object> locationObject = new HashMap<>();
468+
locationObject.put("lat", latitude);
469+
locationObject.put("lon", longitude);
470+
geoData.put(Fields.LOCATION, locationObject);
471+
}
472+
break;
473+
case LATITUDE:
474+
Double lat = location.getLatitude();
475+
if (lat != null) {
476+
geoData.put(Fields.LATITUDE, lat);
477+
}
478+
break;
479+
case LONGITUDE:
480+
Double lon = location.getLongitude();
481+
if (lon != null) {
482+
geoData.put(Fields.LONGITUDE, lon);
483+
}
484+
break;
485+
case AUTONOMOUS_SYSTEM_NUMBER:
486+
Integer asn = traits.getAutonomousSystemNumber();
487+
if (asn != null) {
488+
geoData.put(Fields.AUTONOMOUS_SYSTEM_NUMBER, asn);
489+
}
490+
break;
491+
case AUTONOMOUS_SYSTEM_ORGANIZATION:
492+
String aso = traits.getAutonomousSystemOrganization();
493+
if (aso != null) {
494+
geoData.put(Fields.AUTONOMOUS_SYSTEM_ORGANIZATION, aso);
495+
}
496+
break;
497+
case ISP:
498+
String isp = traits.getIsp();
499+
if (isp != null) {
500+
geoData.put(Fields.ISP, isp);
501+
}
502+
break;
503+
case ORGANIZATION:
504+
String org = traits.getOrganization();
505+
if (org != null) {
506+
geoData.put(Fields.ORGANIZATION, org);
507+
}
508+
break;
509+
case CONNECTION_TYPE:
510+
ConnectionType type = traits.getConnectionType();
511+
if (type != null) {
512+
geoData.put(Fields.CONNECTION_TYPE, type.toString());
513+
}
514+
break;
515+
}
516+
}
517+
return geoData;
518+
}
519+
355520
private Map<Fields,Object> retrieveCountryGeoData(InetAddress ipAddress) throws GeoIp2Exception, IOException {
356521
CountryResponse response = databaseReader.country(ipAddress);
357522
Country country = response.getCountry();

0 commit comments

Comments
 (0)