File pdns_maxmind.patch of Package pdns.openSUSE_Backports_SLE-15-SP1_Update
From 2923e03ffa0c0dd68b677f88562c0ac0540fdf46 Mon Sep 17 00:00:00 2001
From: Aki Tuomi <cmouse@cmouse.fi>
Date: Sat, 30 Dec 2017 13:24:29 +0200
Subject: [PATCH] geoipbackend: Move GeoIP handling to separate class
Makes it easier to add new interfaces
modules/geoipbackend/Makefile.am | 4 +-
modules/geoipbackend/OBJECTFILES | 2 +-
modules/geoipbackend/geoipbackend.cc | 359 ++-------------------
modules/geoipbackend/geoipbackend.hh | 32 +-
modules/geoipbackend/geoipinterface-dat.cc | 336 +++++++++++++++++++
modules/geoipbackend/geoipinterface.cc | 65 ++++
modules/geoipbackend/geoipinterface.hh | 59 ++++
7 files changed, 501 insertions(+), 356 deletions(-)
create mode 100644 modules/geoipbackend/geoipinterface-dat.cc
create mode 100644 modules/geoipbackend/geoipinterface.cc
create mode 100644 modules/geoipbackend/geoipinterface.hh
From 23c4de63a99b44b6b4573ee6a07d85308b08cb33 Mon Sep 17 00:00:00 2001
From: Aki Tuomi <cmouse@cmouse.fi>
Date: Sat, 30 Dec 2017 17:52:54 +0200
Subject: [PATCH] geoipbackend: Replace GeoIPLookup with GeoIPNetmask
GeoIPLookup is part of GeoIP library, and is not
necessarely available on future interfaces, so
replace it with our own structure for same purpose.
This makes it possible to add indepedent interfaces.
modules/geoipbackend/geoipbackend.cc | 32 ++---
modules/geoipbackend/geoipbackend.hh | 8 +-
modules/geoipbackend/geoipinterface-dat.cc | 138 ++++++++++++++-------
modules/geoipbackend/geoipinterface.hh | 28 ++---
4 files changed, 132 insertions(+), 74 deletions(-)
From 5851b614b2499d0de2f6af2009cdf23c0af38906 Mon Sep 17 00:00:00 2001
From: Aki Tuomi <cmouse@cmouse.fi>
Date: Sat, 30 Dec 2017 13:45:45 +0200
Subject: [PATCH] geoipbackend: Reorder includes
From f4a5db3a8de9b52133c31f4caaafe85a674fc7b1 Mon Sep 17 00:00:00 2001
From: Aki Tuomi <cmouse@cmouse.fi>
Date: Sat, 30 Dec 2017 17:54:28 +0200
Subject: [PATCH] geoipbackend: Add mmdb interface
modules/geoipbackend/Makefile.am | 7 +-
modules/geoipbackend/OBJECTFILES | 2 +-
modules/geoipbackend/OBJECTLIBS | 2 +-
modules/geoipbackend/geoipbackend.hh | 1 -
modules/geoipbackend/geoipinterface-mmdb.cc | 240 ++++++++++++++++++++
modules/geoipbackend/geoipinterface.cc | 4 +-
modules/geoipbackend/geoipinterface.hh | 1 +
7 files changed, 250 insertions(+), 7 deletions(-)
create mode 100644 modules/geoipbackend/geoipinterface-mmdb.cc
From e3808f5e47c23e59409f7ea38977b24fdcfbbf54 Mon Sep 17 00:00:00 2001
From: Aki Tuomi <cmouse@cmouse.fi>
Date: Sat, 30 Dec 2017 21:23:49 +0200
Subject: [PATCH] geoipbackend: Make GeoIP interface optional
modules/geoipbackend/geoipinterface-dat.cc | 9 +++++++++
1 file changed, 9 insertions(+)
Index: pdns-4.1.8/m4/pdns_with_geo.m4
===================================================================
--- pdns-4.1.8.orig/m4/pdns_with_geo.m4
+++ pdns-4.1.8/m4/pdns_with_geo.m4
@@ -1,7 +1,46 @@
AC_DEFUN([PDNS_CHECK_GEOIP], [
- PKG_CHECK_MODULES([GEOIP], [geoip],[],
- AC_MSG_ERROR([Could not find libGeoIP])
+ PKG_CHECK_MODULES([GEOIP], [geoip], AC_DEFINE([HAVE_GEOIP], [1], [Define this if you have GeoIP]), [have_geoip=0])
+ AC_ARG_WITH([maxminddb_incdir],
+ AS_HELP_STRING([--with-maxminddb-includedir],[path to maxminddb include directory @<:@default=auto@:>@]),
+ [with_maxminddb_incdir=$withval],
+ [with_maxminddb_incdir=auto]
)
+ AC_ARG_WITH([maxminddb_libdir],
+ AS_HELP_STRING([--with-maxminddb-libdir],[path to maxminddb library directory @<:@default=auto@:>@]),
+ [with_maxminddb_libdir=$withval],
+ [with_maxminddb_libdir=auto],
+ )
+
+ PKG_CHECK_MODULES([MMDB], [libmaxminddb], [
+ AC_DEFINE([HAVE_MMDB], [1], [Define this if you have Maxmind DB])
+ ], [
+ AS_IF([test "x$with_maxminddb_incdir" = "xauto"], [
+ AC_CHECK_HEADER([maxminddb.h], [have_mmdb=1], [have_mmdb=0])
+ ], [
+ OLD_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -I$with_maxminddb_incdir"
+ AC_CHECK_HEADER([maxminddb.h], [have_mmdb=1], [have_mmdb=0])
+ CFLAGS="$OLD_CFLAGS"
+ ])
+
+ AS_IF([test "$have_mmdb" = "1"], [
+ AS_IF([test "x$with_maxminddb_libdir" = "xauto"], [
+ AC_CHECK_LIB([maxminddb], [MMDB_open], [
+ AC_DEFINE([HAVE_MMDB], [1], [Define this if you have Maxmind DB])
+ MMDB_LIBS="-lmaxminddb"
+ ])
+ ], [
+ OLD_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -L$with_maxminddb_libdir"
+ AC_CHECK_LIB([maxminddb], [MMDB_open], [
+ AC_DEFINE([HAVE_MMDB], [1], [Define this if you have Maxmind DB])
+ MMDB_CFLAGS="-I$with_maxminddb_incdir"
+ MMDB_LIBS="-L$with_maxminddb_libdir -lmaxminddb"
+ ])
+ ])
+ ])
+ ])
+
PKG_CHECK_MODULES([YAML], [yaml-cpp >= 0.5],[],
AC_MSG_ERROR([Could not find yaml-cpp])
)
Index: pdns-4.1.8/modules/geoipbackend/Makefile.am
===================================================================
--- pdns-4.1.8.orig/modules/geoipbackend/Makefile.am
+++ pdns-4.1.8/modules/geoipbackend/Makefile.am
@@ -1,9 +1,12 @@
-AM_CPPFLAGS += $(YAML_CFLAGS) $(GEOIP_CFLAGS)
+AM_CPPFLAGS += $(YAML_CFLAGS) $(GEOIP_CFLAGS) $(MMDB_CFLAGS)
EXTRA_DIST = OBJECTFILES OBJECTLIBS
pkglib_LTLIBRARIES = libgeoipbackend.la
-libgeoipbackend_la_SOURCES = geoipbackend.cc geoipbackend.hh
+libgeoipbackend_la_SOURCES = geoipbackend.cc geoipbackend.hh \
+ geoipinterface.cc geoipinterface.hh \
+ geoipinterface-dat.cc \
+ geoipinterface-mmdb.cc
libgeoipbackend_la_LDFLAGS = -module -avoid-version
-libgeoipbackend_la_LIBADD = $(YAML_LIBS) $(GEOIP_LIBS)
+libgeoipbackend_la_LIBADD = $(YAML_LIBS) $(GEOIP_LIBS) $(MMDB_LIBS)
Index: pdns-4.1.8/modules/geoipbackend/OBJECTFILES
===================================================================
--- pdns-4.1.8.orig/modules/geoipbackend/OBJECTFILES
+++ pdns-4.1.8/modules/geoipbackend/OBJECTFILES
@@ -1 +1 @@
-geoipbackend.lo
+geoipbackend.lo geoipinterface-dat.lo geoipinterface.lo geoipinterface-mmdb.lo
Index: pdns-4.1.8/modules/geoipbackend/geoipbackend.cc
===================================================================
--- pdns-4.1.8.orig/modules/geoipbackend/geoipbackend.cc
+++ pdns-4.1.8/modules/geoipbackend/geoipbackend.cc
@@ -23,11 +23,14 @@
#include "config.h"
#endif
#include "geoipbackend.hh"
+#include "geoipinterface.hh"
#include "pdns/dns_random.hh"
#include <sstream>
#include <regex.h>
#include <glob.h>
#include <boost/algorithm/string/replace.hpp>
+#include <fstream>
+#include <yaml-cpp/yaml.h>
pthread_rwlock_t GeoIPBackend::s_state_lock=PTHREAD_RWLOCK_INITIALIZER;
@@ -53,17 +56,12 @@ struct GeoIPDomain {
static vector<GeoIPDomain> s_domains;
static int s_rc = 0; // refcount
-struct geoip_deleter {
- void operator()(GeoIP* ptr) {
- if (ptr) GeoIP_delete(ptr);
- };
-};
-
-static vector<GeoIPBackend::geoip_file_t> s_geoip_files;
-
static string GeoIP_WEEKDAYS[] = { "mon", "tue", "wed", "thu", "fri", "sat", "sun" };
static string GeoIP_MONTHS[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" };
+static string queryGeoIP(const string &ip, bool v6, GeoIPInterface::GeoIPQueryAttribute attribute, GeoIPNetmask& gl);
+
+
/* So how does it work - we have static records and services. Static records "win".
We also insert empty non terminals for records and services.
@@ -91,38 +89,21 @@ GeoIPBackend::GeoIPBackend(const string&
s_rc++;
}
+static vector<std::unique_ptr<GeoIPInterface> > s_geoip_files;
+
void GeoIPBackend::initialize() {
YAML::Node config;
vector<GeoIPDomain> tmp_domains;
string modeStr = getArg("database-cache");
- int flags;
- if (modeStr == "standard")
- flags = GEOIP_STANDARD;
- else if (modeStr == "memory")
- flags = GEOIP_MEMORY_CACHE;
- else if (modeStr == "index")
- flags = GEOIP_INDEX_CACHE;
-#ifdef HAVE_MMAP
- else if (modeStr == "mmap")
- flags = GEOIP_MMAP_CACHE;
-#endif
- else
- throw PDNSException("Invalid cache mode " + modeStr + " for GeoIP backend");
-
s_geoip_files.clear(); // reset pointers
if (getArg("database-files").empty() == false) {
vector<string> files;
stringtok(files, getArg("database-files"), " ,\t\r\n");
for(auto const& file: files) {
- GeoIP *fptr;
- int mode;
- fptr = GeoIP_open(file.c_str(), flags);
- if (!fptr)
- throw PDNSException("Cannot open GeoIP database " + file);
- mode = GeoIP_database_edition(fptr);
- s_geoip_files.emplace_back(geoip_file_t(mode, unique_ptr<GeoIP,geoip_deleter>(fptr)));
+ const string& fileStr = string("dat:") + file + string(";mode=") + modeStr;
+ s_geoip_files.push_back(GeoIPInterface::makeInterface(fileStr));
}
}
@@ -317,7 +298,7 @@ GeoIPBackend::~GeoIPBackend() {
}
}
-bool GeoIPBackend::lookup_static(const GeoIPDomain &dom, const DNSName &search, const QType &qtype, const DNSName& qdomain, const std::string &ip, GeoIPLookup &gl, bool v6) {
+bool GeoIPBackend::lookup_static(const GeoIPDomain &dom, const DNSName &search, const QType &qtype, const DNSName& qdomain, const std::string &ip, GeoIPNetmask &gl, bool v6) {
const auto& i = dom.records.find(search);
int cumul_probability = 0;
int probability_rnd = 1+(dns_random(1000)); // setting probability=0 means it never is used
@@ -333,7 +314,7 @@ bool GeoIPBackend::lookup_static(const G
}
if (qtype == QType::ANY || rr.qtype == qtype) {
d_result.push_back(rr);
- d_result.back().content = format2str(rr.content, ip, v6, &gl);
+ d_result.back().content = format2str(rr.content, ip, v6, gl);
d_result.back().qname = qdomain;
}
}
@@ -350,7 +331,7 @@ bool GeoIPBackend::lookup_static(const G
void GeoIPBackend::lookup(const QType &qtype, const DNSName& qdomain, DNSPacket *pkt_p, int zoneId) {
ReadLock rl(&s_state_lock);
const GeoIPDomain *dom;
- GeoIPLookup gl;
+ GeoIPNetmask gl;
bool found = false;
if (d_result.size()>0)
@@ -392,10 +373,10 @@ void GeoIPBackend::lookup(const QType &q
gl.netmask = node->first.getBits();
// figure out smallest sensible netmask
if (gl.netmask == 0) {
- GeoIPLookup tmp_gl;
+ GeoIPNetmask tmp_gl;
tmp_gl.netmask = 0;
// get netmask from geoip backend
- if (queryGeoIP(ip, v6, GeoIPQueryAttribute::Name, &tmp_gl) == "unknown") {
+ if (queryGeoIP(ip, v6, GeoIPInterface::Name, tmp_gl) == "unknown") {
if (v6)
gl.netmask = target->second.netmask6;
else
@@ -410,7 +391,7 @@ void GeoIPBackend::lookup(const QType &q
// note that this means the array format won't work with indirect
for(auto it = node->second.begin(); it != node->second.end(); it++) {
- sformat = DNSName(format2str(*it, ip, v6, &gl));
+ sformat = DNSName(format2str(*it, ip, v6, gl));
// see if the record can be found
if (this->lookup_static((*dom), sformat, qtype, qdomain, ip, gl, v6))
@@ -449,293 +430,7 @@ bool GeoIPBackend::get(DNSResourceRecord
return true;
}
-bool GeoIPBackend::queryCountry(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_COUNTRY_EDITION ||
- gi.first == GEOIP_LARGE_COUNTRY_EDITION) {
- int id;
- if ((id = GeoIP_id_by_addr_gl(gi.second.get(), ip.c_str(), gl)) > 0) {
- ret = GeoIP_code3_by_id(id);
- return true;
- }
- } else if (gi.first == GEOIP_REGION_EDITION_REV0 ||
- gi.first == GEOIP_REGION_EDITION_REV1) {
- GeoIPRegion* gir = GeoIP_region_by_addr_gl(gi.second.get(), ip.c_str(), gl);
- if (gir) {
- ret = GeoIP_code3_by_id(GeoIP_id_by_code(gir->country_code));
- return true;
- }
- } else if (gi.first == GEOIP_CITY_EDITION_REV0 ||
- gi.first == GEOIP_CITY_EDITION_REV1) {
- GeoIPRecord *gir = GeoIP_record_by_addr(gi.second.get(), ip.c_str());
- if (gir) {
- ret = gir->country_code3;
- gl->netmask = gir->netmask;
- return true;
- }
- }
- return false;
-}
-
-bool GeoIPBackend::queryCountryV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_COUNTRY_EDITION_V6 ||
- gi.first == GEOIP_LARGE_COUNTRY_EDITION_V6) {
- int id;
- if ((id = GeoIP_id_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl)) > 0) {
- ret = GeoIP_code3_by_id(id);
- return true;
- }
- } else if (gi.first == GEOIP_REGION_EDITION_REV0 ||
- gi.first == GEOIP_REGION_EDITION_REV1) {
- GeoIPRegion* gir = GeoIP_region_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl);
- if (gir) {
- ret = GeoIP_code3_by_id(GeoIP_id_by_code(gir->country_code));
- return true;
- }
- } else if (gi.first == GEOIP_CITY_EDITION_REV0_V6 ||
- gi.first == GEOIP_CITY_EDITION_REV1_V6) {
- GeoIPRecord *gir = GeoIP_record_by_addr_v6(gi.second.get(), ip.c_str());
- if (gir) {
- ret = gir->country_code3;
- gl->netmask = gir->netmask;
- return true;
- }
- }
- return false;
-}
-
-bool GeoIPBackend::queryCountry2(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_COUNTRY_EDITION ||
- gi.first == GEOIP_LARGE_COUNTRY_EDITION) {
- int id;
- if ((id = GeoIP_id_by_addr_gl(gi.second.get(), ip.c_str(), gl)) > 0) {
- ret = GeoIP_code_by_id(id);
- return true;
- }
- } else if (gi.first == GEOIP_REGION_EDITION_REV0 ||
- gi.first == GEOIP_REGION_EDITION_REV1) {
- GeoIPRegion* gir = GeoIP_region_by_addr_gl(gi.second.get(), ip.c_str(), gl);
- if (gir) {
- ret = GeoIP_code_by_id(GeoIP_id_by_code(gir->country_code));
- return true;
- }
- } else if (gi.first == GEOIP_CITY_EDITION_REV0 ||
- gi.first == GEOIP_CITY_EDITION_REV1) {
- GeoIPRecord *gir = GeoIP_record_by_addr(gi.second.get(), ip.c_str());
- if (gir) {
- ret = gir->country_code;
- gl->netmask = gir->netmask;
- return true;
- }
- }
- return false;
-}
-
-bool GeoIPBackend::queryCountry2V6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_COUNTRY_EDITION_V6 ||
- gi.first == GEOIP_LARGE_COUNTRY_EDITION_V6) {
- int id;
- if ((id = GeoIP_id_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl)) > 0) {
- ret = GeoIP_code_by_id(id);
- return true;
- }
- return true;
- } else if (gi.first == GEOIP_REGION_EDITION_REV0 ||
- gi.first == GEOIP_REGION_EDITION_REV1) {
- GeoIPRegion* gir = GeoIP_region_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl);
- if (gir) {
- ret = GeoIP_code_by_id(GeoIP_id_by_code(gir->country_code));
- return true;
- }
- } else if (gi.first == GEOIP_CITY_EDITION_REV0_V6 ||
- gi.first == GEOIP_CITY_EDITION_REV1_V6) {
- GeoIPRecord *gir = GeoIP_record_by_addr_v6(gi.second.get(), ip.c_str());
- if (gir) {
- ret = gir->country_code;
- gl->netmask = gir->netmask;
- return true;
- }
- }
- return false;
-}
-
-bool GeoIPBackend::queryContinent(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_COUNTRY_EDITION ||
- gi.first == GEOIP_LARGE_COUNTRY_EDITION) {
- int id;
- if ((id = GeoIP_id_by_addr_gl(gi.second.get(), ip.c_str(), gl)) > 0) {
- ret = GeoIP_continent_by_id(id);
- return true;
- }
- } else if (gi.first == GEOIP_REGION_EDITION_REV0 ||
- gi.first == GEOIP_REGION_EDITION_REV1) {
- GeoIPRegion* gir = GeoIP_region_by_addr_gl(gi.second.get(), ip.c_str(), gl);
- if (gir) {
- ret = GeoIP_continent_by_id(GeoIP_id_by_code(gir->country_code));
- return true;
- }
- } else if (gi.first == GEOIP_CITY_EDITION_REV0 ||
- gi.first == GEOIP_CITY_EDITION_REV1) {
- GeoIPRecord *gir = GeoIP_record_by_addr(gi.second.get(), ip.c_str());
- if (gir) {
- ret = ret = GeoIP_continent_by_id(GeoIP_id_by_code(gir->country_code));
- gl->netmask = gir->netmask;
- return true;
- }
- }
- return false;
-}
-
-bool GeoIPBackend::queryContinentV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_COUNTRY_EDITION_V6 ||
- gi.first == GEOIP_LARGE_COUNTRY_EDITION_V6) {
- int id;
- if ((id = GeoIP_id_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl)) > 0) {
- ret = GeoIP_continent_by_id(id);
- return true;
- }
- } else if (gi.first == GEOIP_REGION_EDITION_REV0 ||
- gi.first == GEOIP_REGION_EDITION_REV1) {
- GeoIPRegion* gir = GeoIP_region_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl);
- if (gir) {
- ret = GeoIP_continent_by_id(GeoIP_id_by_code(gir->country_code));
- return true;
- }
- } else if (gi.first == GEOIP_CITY_EDITION_REV0_V6 ||
- gi.first == GEOIP_CITY_EDITION_REV1_V6) {
- GeoIPRecord *gir = GeoIP_record_by_addr_v6(gi.second.get(), ip.c_str());
- if (gir) {
- ret = GeoIP_continent_by_id(GeoIP_id_by_code(gir->country_code));
- gl->netmask = gir->netmask;
- return true;
- }
- }
- return false;
-}
-
-bool GeoIPBackend::queryName(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_ISP_EDITION ||
- gi.first == GEOIP_ORG_EDITION) {
- string val = valueOrEmpty<char*,string>(GeoIP_name_by_addr_gl(gi.second.get(), ip.c_str(), gl));
- if (!val.empty()) {
- // reduce space to dash
- ret = boost::replace_all_copy(val, " ", "-");
- return true;
- }
- }
- return false;
-}
-
-bool GeoIPBackend::queryNameV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_ISP_EDITION_V6 ||
- gi.first == GEOIP_ORG_EDITION_V6) {
- string val = valueOrEmpty<char*,string>(GeoIP_name_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl));
- if (!val.empty()) {
- // reduce space to dash
- ret = boost::replace_all_copy(val, " ", "-");
- return true;
- }
- }
- return false;
-}
-
-bool GeoIPBackend::queryASnum(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_ASNUM_EDITION) {
- string val = valueOrEmpty<char*,string>(GeoIP_name_by_addr_gl(gi.second.get(), ip.c_str(), gl));
- if (!val.empty()) {
- vector<string> asnr;
- stringtok(asnr, val);
- if(asnr.size()>0) {
- ret = asnr[0];
- return true;
- }
- }
- }
- return false;
-}
-
-bool GeoIPBackend::queryASnumV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_ASNUM_EDITION_V6) {
- string val = valueOrEmpty<char*,string>(GeoIP_name_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl));
- if (!val.empty()) {
- vector<string> asnr;
- stringtok(asnr, val);
- if(asnr.size()>0) {
- ret = asnr[0];
- return true;
- }
- }
- }
- return false;
-}
-
-bool GeoIPBackend::queryRegion(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_REGION_EDITION_REV0 ||
- gi.first == GEOIP_REGION_EDITION_REV1) {
- GeoIPRegion *gir = GeoIP_region_by_addr_gl(gi.second.get(), ip.c_str(), gl);
- if (gir) {
- ret = valueOrEmpty<char*,string>(gir->region);
- return true;
- }
- } else if (gi.first == GEOIP_CITY_EDITION_REV0 ||
- gi.first == GEOIP_CITY_EDITION_REV1) {
- GeoIPRecord *gir = GeoIP_record_by_addr(gi.second.get(), ip.c_str());
- if (gir) {
- ret = valueOrEmpty<char*,string>(gir->region);
- gl->netmask = gir->netmask;
- return true;
- }
- }
- return false;
-}
-
-bool GeoIPBackend::queryRegionV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_REGION_EDITION_REV0 ||
- gi.first == GEOIP_REGION_EDITION_REV1) {
- GeoIPRegion *gir = GeoIP_region_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl);
- if (gir) {
- ret = valueOrEmpty<char*,string>(gir->region);
- return true;
- }
- } else if (gi.first == GEOIP_CITY_EDITION_REV0_V6 ||
- gi.first == GEOIP_CITY_EDITION_REV1_V6) {
- GeoIPRecord *gir = GeoIP_record_by_addr_v6(gi.second.get(), ip.c_str());
- if (gir) {
- ret = valueOrEmpty<char*,string>(gir->region);
- gl->netmask = gir->netmask;
- return true;
- }
- }
- return false;
-}
-
-bool GeoIPBackend::queryCity(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_CITY_EDITION_REV0 ||
- gi.first == GEOIP_CITY_EDITION_REV1) {
- GeoIPRecord *gir = GeoIP_record_by_addr(gi.second.get(), ip.c_str());
- if (gir) {
- ret = valueOrEmpty<char*,string>(gir->city);
- gl->netmask = gir->netmask;
- return true;
- }
- }
- return false;
-}
-
-bool GeoIPBackend::queryCityV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
- if (gi.first == GEOIP_CITY_EDITION_REV0_V6 ||
- gi.first == GEOIP_CITY_EDITION_REV1_V6) {
- GeoIPRecord *gir = GeoIP_record_by_addr_v6(gi.second.get(), ip.c_str());
- if (gir) {
- ret = valueOrEmpty<char*,string>(gir->city);
- gl->netmask = gir->netmask;
- return true;
- }
- }
- return false;
-}
-
-
-string GeoIPBackend::queryGeoIP(const string &ip, bool v6, GeoIPQueryAttribute attribute, GeoIPLookup* gl) {
+static string queryGeoIP(const string &ip, bool v6, GeoIPInterface::GeoIPQueryAttribute attribute, GeoIPNetmask& gl) {
string ret = "unknown";
for(auto const& gi: s_geoip_files) {
@@ -743,33 +438,33 @@ string GeoIPBackend::queryGeoIP(const st
bool found = false;
switch(attribute) {
- case ASn:
- if (v6) found = queryASnumV6(val, gl, ip, gi);
- else found = queryASnum(val, gl, ip, gi);
+ case GeoIPInterface::ASn:
+ if (v6) found = gi->queryASnumV6(val, gl, ip);
+ else found =gi->queryASnum(val, gl, ip);
break;
- case Name:
- if (v6) found = queryNameV6(val, gl, ip, gi);
- else found = queryName(val, gl, ip, gi);
+ case GeoIPInterface::Name:
+ if (v6) found = gi->queryNameV6(val, gl, ip);
+ else found = gi->queryName(val, gl, ip);
break;
- case Continent:
- if (v6) found = queryContinentV6(val, gl, ip, gi);
- else found = queryContinent(val, gl, ip, gi);
+ case GeoIPInterface::Continent:
+ if (v6) found = gi->queryContinentV6(val, gl, ip);
+ else found = gi->queryContinent(val, gl, ip);
break;
- case Region:
- if (v6) found = queryRegionV6(val, gl, ip, gi);
- else found = queryRegion(val, gl, ip, gi);
+ case GeoIPInterface::Region:
+ if (v6) found = gi->queryRegionV6(val, gl, ip);
+ else found = gi->queryRegion(val, gl, ip);
break;
- case Country:
- if (v6) found = queryCountryV6(val, gl, ip, gi);
- else found = queryCountry(val, gl, ip, gi);
+ case GeoIPInterface::Country:
+ if (v6) found = gi->queryCountryV6(val, gl, ip);
+ else found = gi->queryCountry(val, gl, ip);
break;
- case Country2:
- if (v6) found = queryCountry2V6(val, gl, ip, gi);
- else found = queryCountry2(val, gl, ip, gi);
+ case GeoIPInterface::Country2:
+ if (v6) found = gi->queryCountry2V6(val, gl, ip);
+ else found = gi->queryCountry2(val, gl, ip);
break;
- case City:
- if (v6) found = queryCityV6(val, gl, ip, gi);
- else found = queryCity(val, gl, ip, gi);
+ case GeoIPInterface::City:
+ if (v6) found = gi->queryCityV6(val, gl, ip);
+ else found = gi->queryCity(val, gl, ip);
break;
}
@@ -779,14 +474,14 @@ string GeoIPBackend::queryGeoIP(const st
break;
}
- if (ret == "unknown") gl->netmask = (v6?128:32); // prevent caching
+ if (ret == "unknown") gl.netmask = (v6?128:32); // prevent caching
return ret;
}
-string GeoIPBackend::format2str(string sformat, const string& ip, bool v6, GeoIPLookup* gl) {
+string GeoIPBackend::format2str(string sformat, const string& ip, bool v6, GeoIPNetmask& gl) {
string::size_type cur,last;
time_t t = time((time_t*)NULL);
- GeoIPLookup tmp_gl; // largest wins
+ GeoIPNetmask tmp_gl; // largest wins
struct tm gtm;
gmtime_r(&t, >m);
last=0;
@@ -796,21 +491,21 @@ string GeoIPBackend::format2str(string s
int nrep=3;
tmp_gl.netmask = 0;
if (!sformat.compare(cur,3,"%cn")) {
- rep = queryGeoIP(ip, v6, Continent, &tmp_gl);
+ rep = queryGeoIP(ip, v6, GeoIPInterface::Continent, tmp_gl);
} else if (!sformat.compare(cur,3,"%co")) {
- rep = queryGeoIP(ip, v6, Country, &tmp_gl);
+ rep = queryGeoIP(ip, v6, GeoIPInterface::Country, tmp_gl);
} else if (!sformat.compare(cur,3,"%cc")) {
- rep = queryGeoIP(ip, v6, Country2, &tmp_gl);
+ rep = queryGeoIP(ip, v6, GeoIPInterface::Country2, tmp_gl);
} else if (!sformat.compare(cur,3,"%af")) {
rep = (v6?"v6":"v4");
} else if (!sformat.compare(cur,3,"%as")) {
- rep = queryGeoIP(ip, v6, ASn, &tmp_gl);
+ rep = queryGeoIP(ip, v6, GeoIPInterface::ASn, tmp_gl);
} else if (!sformat.compare(cur,3,"%re")) {
- rep = queryGeoIP(ip, v6, Region, &tmp_gl);
+ rep = queryGeoIP(ip, v6, GeoIPInterface::Region, tmp_gl);
} else if (!sformat.compare(cur,3,"%na")) {
- rep = queryGeoIP(ip, v6, Name, &tmp_gl);
+ rep = queryGeoIP(ip, v6, GeoIPInterface::Name, tmp_gl);
} else if (!sformat.compare(cur,3,"%ci")) {
- rep = queryGeoIP(ip, v6, City, &tmp_gl);
+ rep = queryGeoIP(ip, v6, GeoIPInterface::City, tmp_gl);
} else if (!sformat.compare(cur,3,"%hh")) {
rep = boost::str(boost::format("%02d") % gtm.tm_hour);
tmp_gl.netmask = (v6?128:32);
@@ -842,7 +537,7 @@ string GeoIPBackend::format2str(string s
} else {
last = cur + 1; continue;
}
- if (tmp_gl.netmask > gl->netmask) gl->netmask = tmp_gl.netmask;
+ if (tmp_gl.netmask > gl.netmask) gl.netmask = tmp_gl.netmask;
sformat.replace(cur, nrep, rep);
last = cur + rep.size(); // move to next attribute
}
Index: pdns-4.1.8/modules/geoipbackend/geoipbackend.hh
===================================================================
--- pdns-4.1.8.orig/modules/geoipbackend/geoipbackend.hh
+++ pdns-4.1.8/modules/geoipbackend/geoipbackend.hh
@@ -27,12 +27,7 @@
#include <vector>
#include <map>
#include <string>
-#include <fstream>
-#include <yaml-cpp/yaml.h>
#include <pthread.h>
-
-#include <GeoIP.h>
-#include <GeoIPCity.h>
#include <sys/types.h>
#include <dirent.h>
@@ -41,13 +36,16 @@
#include "pdns/dnsbackend.hh"
#include "pdns/lock.hh"
-struct geoip_deleter;
+class GeoIPInterface;
class GeoIPDomain;
+struct GeoIPNetmask {
+ int netmask;
+};
+
class GeoIPBackend: public DNSBackend {
public:
- typedef pair<int,unique_ptr<GeoIP,geoip_deleter> > geoip_file_t;
GeoIPBackend(const std::string& suffix="");
~GeoIPBackend();
@@ -68,41 +66,16 @@ public:
bool activateDomainKey(const DNSName& name, unsigned int id) override;
bool deactivateDomainKey(const DNSName& name, unsigned int id) override;
- enum GeoIPQueryAttribute {
- ASn,
- City,
- Continent,
- Country,
- Country2,
- Name,
- Region
- };
-
private:
static pthread_rwlock_t s_state_lock;
void initialize();
- void ip2geo(const GeoIPDomain& dom, const string& qname, const string& ip);
- string queryGeoIP(const string &ip, bool v6, GeoIPQueryAttribute attribute, GeoIPLookup* gl);
- bool queryCountry(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- bool queryCountryV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- bool queryCountry2(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- bool queryCountry2V6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- bool queryContinent(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- bool queryContinentV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- bool queryName(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- bool queryNameV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- bool queryASnum(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- bool queryASnumV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- bool queryRegion(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- bool queryRegionV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- bool queryCity(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- bool queryCityV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
- string format2str(string format, const string& ip, bool v6, GeoIPLookup* gl);
- bool d_dnssec;
+ string format2str(string format, const string& ip, bool v6, GeoIPNetmask& gl);
+ bool d_dnssec;
bool hasDNSSECkey(const DNSName& name);
- bool lookup_static(const GeoIPDomain &dom, const DNSName &search, const QType &qtype, const DNSName& qdomain, const std::string &ip, GeoIPLookup &gl, bool v6);
+ bool lookup_static(const GeoIPDomain &dom, const DNSName &search, const QType &qtype, const DNSName& qdomain, const std::string &ip, GeoIPNetmask& gl, bool v6);
vector<DNSResourceRecord> d_result;
+ vector<GeoIPInterface> d_files;
};
#endif /* PDNS_GEOIPBACKEND_HH */
Index: pdns-4.1.8/modules/geoipbackend/geoipinterface-dat.cc
===================================================================
--- /dev/null
+++ pdns-4.1.8/modules/geoipbackend/geoipinterface-dat.cc
@@ -0,0 +1,399 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "geoipbackend.hh"
+#include "geoipinterface.hh"
+#ifdef HAVE_GEOIP
+#include "GeoIPCity.h"
+
+struct geoip_deleter {
+ void operator()(GeoIP* ptr) {
+ if (ptr) GeoIP_delete(ptr);
+ };
+};
+
+class GeoIPInterfaceDAT : public GeoIPInterface {
+public:
+ GeoIPInterfaceDAT(const string &fname, const string &modeStr) {
+ int flags;
+ if (modeStr == "standard")
+ flags = GEOIP_STANDARD;
+ else if (modeStr == "memory")
+ flags = GEOIP_MEMORY_CACHE;
+ else if (modeStr == "index")
+ flags = GEOIP_INDEX_CACHE;
+ #ifdef HAVE_MMAP
+ else if (modeStr == "mmap")
+ flags = GEOIP_MMAP_CACHE;
+ #endif
+ else
+ throw PDNSException("Invalid cache mode " + modeStr + " for GeoIP backend");
+
+ d_gi = std::unique_ptr<GeoIP,geoip_deleter>(GeoIP_open(fname.c_str(), flags));
+ if (d_gi.get() == NULL)
+ throw PDNSException("Cannot open GeoIP database " + fname);
+ d_db_type = GeoIP_database_edition(d_gi.get());
+ }
+
+ bool queryCountry(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ GeoIPLookup tmp_gl = {
+ .netmask = gl.netmask,
+ };
+ if (d_db_type == GEOIP_COUNTRY_EDITION ||
+ d_db_type == GEOIP_LARGE_COUNTRY_EDITION) {
+ ret = GeoIP_code3_by_id(GeoIP_id_by_addr_gl(d_gi.get(), ip.c_str(), &tmp_gl));
+ gl.netmask = tmp_gl.netmask;
+ return true;
+ } else if (d_db_type == GEOIP_REGION_EDITION_REV0 ||
+ d_db_type == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion* gir = GeoIP_region_by_addr_gl(d_gi.get(), ip.c_str(), &tmp_gl);
+ if (gir) {
+ gl.netmask = tmp_gl.netmask;
+ ret = GeoIP_code3_by_id(GeoIP_id_by_code(gir->country_code));
+ return true;
+ }
+ } else if (d_db_type == GEOIP_CITY_EDITION_REV0 ||
+ d_db_type == GEOIP_CITY_EDITION_REV1) {
+ GeoIPRecord *gir = GeoIP_record_by_addr(d_gi.get(), ip.c_str());
+ if (gir) {
+ ret = gir->country_code3;
+ gl.netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool queryCountryV6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ GeoIPLookup tmp_gl = {
+ .netmask = gl.netmask,
+ };
+ if (d_db_type == GEOIP_COUNTRY_EDITION_V6 ||
+ d_db_type == GEOIP_LARGE_COUNTRY_EDITION_V6) {
+ ret = GeoIP_code3_by_id(GeoIP_id_by_addr_v6_gl(d_gi.get(), ip.c_str(), &tmp_gl));
+ gl.netmask = tmp_gl.netmask;
+ return true;
+ } else if (d_db_type == GEOIP_REGION_EDITION_REV0 ||
+ d_db_type == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion* gir = GeoIP_region_by_addr_v6_gl(d_gi.get(), ip.c_str(), &tmp_gl);
+ if (gir) {
+ gl.netmask = tmp_gl.netmask;
+ ret = GeoIP_code3_by_id(GeoIP_id_by_code(gir->country_code));
+ return true;
+ }
+ } else if (d_db_type == GEOIP_CITY_EDITION_REV0_V6 ||
+ d_db_type == GEOIP_CITY_EDITION_REV1_V6) {
+ GeoIPRecord *gir = GeoIP_record_by_addr_v6(d_gi.get(), ip.c_str());
+ if (gir) {
+ ret = gir->country_code3;
+ gl.netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool queryCountry2(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ GeoIPLookup tmp_gl = {
+ .netmask = gl.netmask,
+ };
+ if (d_db_type == GEOIP_COUNTRY_EDITION ||
+ d_db_type == GEOIP_LARGE_COUNTRY_EDITION) {
+ ret = GeoIP_code_by_id(GeoIP_id_by_addr_gl(d_gi.get(), ip.c_str(), &tmp_gl));
+ gl.netmask = tmp_gl.netmask;
+ return true;
+ } else if (d_db_type == GEOIP_REGION_EDITION_REV0 ||
+ d_db_type == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion* gir = GeoIP_region_by_addr_gl(d_gi.get(), ip.c_str(), &tmp_gl);
+ if (gir) {
+ gl.netmask = tmp_gl.netmask;
+ ret = GeoIP_code_by_id(GeoIP_id_by_code(gir->country_code));
+ return true;
+ }
+ } else if (d_db_type == GEOIP_CITY_EDITION_REV0 ||
+ d_db_type == GEOIP_CITY_EDITION_REV1) {
+ GeoIPRecord *gir = GeoIP_record_by_addr(d_gi.get(), ip.c_str());
+ if (gir) {
+ ret = gir->country_code;
+ gl.netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool queryCountry2V6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ GeoIPLookup tmp_gl = {
+ .netmask = gl.netmask,
+ };
+ if (d_db_type == GEOIP_COUNTRY_EDITION_V6 ||
+ d_db_type == GEOIP_LARGE_COUNTRY_EDITION_V6) {
+ ret = GeoIP_code_by_id(GeoIP_id_by_addr_v6_gl(d_gi.get(), ip.c_str(), &tmp_gl));
+ gl.netmask = tmp_gl.netmask;
+ return true;
+ } else if (d_db_type == GEOIP_REGION_EDITION_REV0 ||
+ d_db_type == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion* gir = GeoIP_region_by_addr_v6_gl(d_gi.get(), ip.c_str(), &tmp_gl);
+ if (gir) {
+ gl.netmask = tmp_gl.netmask;
+ ret = GeoIP_code_by_id(GeoIP_id_by_code(gir->country_code));
+ return true;
+ }
+ } else if (d_db_type == GEOIP_CITY_EDITION_REV0_V6 ||
+ d_db_type == GEOIP_CITY_EDITION_REV1_V6) {
+ GeoIPRecord *gir = GeoIP_record_by_addr_v6(d_gi.get(), ip.c_str());
+ if (gir) {
+ ret = gir->country_code;
+ gl.netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool queryContinent(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ GeoIPLookup tmp_gl = {
+ .netmask = gl.netmask,
+ };
+ if (d_db_type == GEOIP_COUNTRY_EDITION ||
+ d_db_type == GEOIP_LARGE_COUNTRY_EDITION) {
+ ret = GeoIP_continent_by_id(GeoIP_id_by_addr_gl(d_gi.get(), ip.c_str(), &tmp_gl));
+ gl.netmask = tmp_gl.netmask;
+ return true;
+ } else if (d_db_type == GEOIP_REGION_EDITION_REV0 ||
+ d_db_type == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion* gir = GeoIP_region_by_addr_gl(d_gi.get(), ip.c_str(), &tmp_gl);
+ if (gir) {
+ gl.netmask = tmp_gl.netmask;
+ ret = GeoIP_continent_by_id(GeoIP_id_by_code(gir->country_code));
+ return true;
+ }
+ } else if (d_db_type == GEOIP_CITY_EDITION_REV0 ||
+ d_db_type == GEOIP_CITY_EDITION_REV1) {
+ GeoIPRecord *gir = GeoIP_record_by_addr(d_gi.get(), ip.c_str());
+ if (gir) {
+ ret = ret = GeoIP_continent_by_id(GeoIP_id_by_code(gir->country_code));
+ gl.netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool queryContinentV6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ GeoIPLookup tmp_gl = {
+ .netmask = gl.netmask,
+ };
+ if (d_db_type == GEOIP_COUNTRY_EDITION_V6 ||
+ d_db_type == GEOIP_LARGE_COUNTRY_EDITION_V6) {
+ ret = GeoIP_continent_by_id(GeoIP_id_by_addr_v6_gl(d_gi.get(), ip.c_str(), &tmp_gl));
+ gl.netmask = tmp_gl.netmask;
+ return true;
+ } else if (d_db_type == GEOIP_REGION_EDITION_REV0 ||
+ d_db_type == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion* gir = GeoIP_region_by_addr_v6_gl(d_gi.get(), ip.c_str(), &tmp_gl);
+ if (gir) {
+ gl.netmask = tmp_gl.netmask;
+ ret = GeoIP_continent_by_id(GeoIP_id_by_code(gir->country_code));
+ return true;
+ }
+ } else if (d_db_type == GEOIP_CITY_EDITION_REV0_V6 ||
+ d_db_type == GEOIP_CITY_EDITION_REV1_V6) {
+ GeoIPRecord *gir = GeoIP_record_by_addr_v6(d_gi.get(), ip.c_str());
+ if (gir) {
+ ret = GeoIP_continent_by_id(GeoIP_id_by_code(gir->country_code));
+ gl.netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool queryName(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ GeoIPLookup tmp_gl = {
+ .netmask = gl.netmask,
+ };
+ if (d_db_type == GEOIP_ISP_EDITION ||
+ d_db_type == GEOIP_ORG_EDITION) {
+ string val = valueOrEmpty<char*,string>(GeoIP_name_by_addr_gl(d_gi.get(), ip.c_str(), &tmp_gl));
+ if (!val.empty()) {
+ gl.netmask = tmp_gl.netmask;
+ // reduce space to dash
+ ret = boost::replace_all_copy(val, " ", "-");
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool queryNameV6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ GeoIPLookup tmp_gl = {
+ .netmask = gl.netmask,
+ };
+ if (d_db_type == GEOIP_ISP_EDITION_V6 ||
+ d_db_type == GEOIP_ORG_EDITION_V6) {
+ string val = valueOrEmpty<char*,string>(GeoIP_name_by_addr_v6_gl(d_gi.get(), ip.c_str(), &tmp_gl));
+ if (!val.empty()) {
+ gl.netmask = tmp_gl.netmask;
+ // reduce space to dash
+ ret = boost::replace_all_copy(val, " ", "-");
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool queryASnum(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ GeoIPLookup tmp_gl = {
+ .netmask = gl.netmask,
+ };
+ if (d_db_type == GEOIP_ASNUM_EDITION) {
+ string val = valueOrEmpty<char*,string>(GeoIP_name_by_addr_gl(d_gi.get(), ip.c_str(), &tmp_gl));
+ if (!val.empty()) {
+ vector<string> asnr;
+ stringtok(asnr, val);
+ if(asnr.size()>0) {
+ gl.netmask = tmp_gl.netmask;
+ ret = asnr[0];
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ bool queryASnumV6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ GeoIPLookup tmp_gl = {
+ .netmask = gl.netmask,
+ };
+ if (d_db_type == GEOIP_ASNUM_EDITION_V6) {
+ string val = valueOrEmpty<char*,string>(GeoIP_name_by_addr_v6_gl(d_gi.get(), ip.c_str(), &tmp_gl));
+ if (!val.empty()) {
+ vector<string> asnr;
+ stringtok(asnr, val);
+ if(asnr.size()>0) {
+ gl.netmask = tmp_gl.netmask;
+ ret = asnr[0];
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ bool queryRegion(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ GeoIPLookup tmp_gl = {
+ .netmask = gl.netmask,
+ };
+ if (d_db_type == GEOIP_REGION_EDITION_REV0 ||
+ d_db_type == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion *gir = GeoIP_region_by_addr_gl(d_gi.get(), ip.c_str(), &tmp_gl);
+ if (gir) {
+ gl.netmask = tmp_gl.netmask;
+ ret = valueOrEmpty<char*,string>(gir->region);
+ return true;
+ }
+ } else if (d_db_type == GEOIP_CITY_EDITION_REV0 ||
+ d_db_type == GEOIP_CITY_EDITION_REV1) {
+ GeoIPRecord *gir = GeoIP_record_by_addr(d_gi.get(), ip.c_str());
+ if (gir) {
+ ret = valueOrEmpty<char*,string>(gir->region);
+ gl.netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool queryRegionV6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ GeoIPLookup tmp_gl = {
+ .netmask = gl.netmask,
+ };
+ if (d_db_type == GEOIP_REGION_EDITION_REV0 ||
+ d_db_type == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion *gir = GeoIP_region_by_addr_v6_gl(d_gi.get(), ip.c_str(), &tmp_gl);
+ if (gir) {
+ gl.netmask = tmp_gl.netmask;
+ ret = valueOrEmpty<char*,string>(gir->region);
+ return true;
+ }
+ } else if (d_db_type == GEOIP_CITY_EDITION_REV0_V6 ||
+ d_db_type == GEOIP_CITY_EDITION_REV1_V6) {
+ GeoIPRecord *gir = GeoIP_record_by_addr_v6(d_gi.get(), ip.c_str());
+ if (gir) {
+ ret = valueOrEmpty<char*,string>(gir->region);
+ gl.netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool queryCity(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ if (d_db_type == GEOIP_CITY_EDITION_REV0 ||
+ d_db_type == GEOIP_CITY_EDITION_REV1) {
+ GeoIPRecord *gir = GeoIP_record_by_addr(d_gi.get(), ip.c_str());
+ if (gir) {
+ ret = valueOrEmpty<char*,string>(gir->city);
+ gl.netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool queryCityV6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ if (d_db_type == GEOIP_CITY_EDITION_REV0_V6 ||
+ d_db_type == GEOIP_CITY_EDITION_REV1_V6) {
+ GeoIPRecord *gir = GeoIP_record_by_addr_v6(d_gi.get(), ip.c_str());
+ if (gir) {
+ ret = valueOrEmpty<char*,string>(gir->city);
+ gl.netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ~GeoIPInterfaceDAT() { }
+private:
+ unsigned int d_db_type;
+ unique_ptr<GeoIP,geoip_deleter> d_gi;
+};
+
+unique_ptr<GeoIPInterface> GeoIPInterface::makeDATInterface(const string &fname, const map<string, string>& opts) {
+ string mode = "standard";
+ const auto &opt = opts.find("mode");
+ if (opt != opts.end())
+ mode = opt->second;
+ return unique_ptr<GeoIPInterface>(new GeoIPInterfaceDAT(fname, mode));
+}
+
+#else
+
+unique_ptr<GeoIPInterface> GeoIPInterface::makeDATInterface(const string &fname, const map<string, string>& opts) {
+ throw PDNSException("libGeoIP support not compiled in");
+}
+
+#endif
Index: pdns-4.1.8/modules/geoipbackend/geoipinterface.cc
===================================================================
--- /dev/null
+++ pdns-4.1.8/modules/geoipbackend/geoipinterface.cc
@@ -0,0 +1,67 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "geoipbackend.hh"
+#include "geoipinterface.hh"
+
+unique_ptr<GeoIPInterface> GeoIPInterface::makeInterface(const string& dbStr) {
+ /* parse dbStr */
+ map<string, string> opts;
+ vector<string> parts1, parts2;
+ string driver;
+ string filename;
+ stringtok(parts1, dbStr, ":");
+
+ if (parts1.size() == 1) {
+ stringtok(parts2, parts1[0], ";");
+ /* try extension */
+ filename = parts2[0];
+ size_t pos = filename.find_last_of(".");
+ if (pos != string::npos)
+ driver = filename.substr(pos+1);
+ else
+ driver = "unknown";
+ } else {
+ driver = parts1[0];
+ stringtok(parts2, parts1[1], ";");
+ filename = parts2[0];
+ }
+
+ if (parts2.size() > 1) {
+ parts2.erase(parts2.begin(), parts2.begin()+1);
+ for(const auto &opt: parts2) {
+ vector<string> kv;
+ stringtok(kv, opt, "=");
+ opts[kv[0]] = kv[1];
+ }
+ }
+
+ if (driver == "dat") {
+ return makeDATInterface(filename, opts);
+ } else if (driver == "mmdb") {
+ return makeMMDBInterface(filename, opts);
+ } else {
+ throw PDNSException(string("Unsupported file type '") + driver + string("' (use type: prefix to force type)"));
+ }
+}
Index: pdns-4.1.8/modules/geoipbackend/geoipinterface.hh
===================================================================
--- /dev/null
+++ pdns-4.1.8/modules/geoipbackend/geoipinterface.hh
@@ -0,0 +1,60 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_GEOIPINTERFACE_HH
+#define PDNS_GEOIPINTERFACE_HH
+
+class GeoIPInterface {
+public:
+ enum GeoIPQueryAttribute {
+ ASn,
+ City,
+ Continent,
+ Country,
+ Country2,
+ Name,
+ Region
+ };
+
+ virtual bool queryCountry(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+ virtual bool queryCountryV6(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+ virtual bool queryCountry2(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+ virtual bool queryCountry2V6(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+ virtual bool queryContinent(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+ virtual bool queryContinentV6(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+ virtual bool queryName(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+ virtual bool queryNameV6(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+ virtual bool queryASnum(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+ virtual bool queryASnumV6(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+ virtual bool queryRegion(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+ virtual bool queryRegionV6(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+ virtual bool queryCity(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+ virtual bool queryCityV6(string &ret, GeoIPNetmask& gl, const string &ip) = 0;
+
+ virtual ~GeoIPInterface() { }
+
+ static unique_ptr<GeoIPInterface> makeInterface(const string& dbStr);
+private:
+ static unique_ptr<GeoIPInterface> makeMMDBInterface(const string &fname, const map<string, string>& opts);
+ static unique_ptr<GeoIPInterface> makeDATInterface(const string& fname, const map<string, string>& opts);
+};
+
+#endif
Index: pdns-4.1.8/modules/geoipbackend/OBJECTLIBS
===================================================================
--- pdns-4.1.8.orig/modules/geoipbackend/OBJECTLIBS
+++ pdns-4.1.8/modules/geoipbackend/OBJECTLIBS
@@ -1 +1 @@
-$(YAML_LIBS) $(GEOIP_LIBS)
+$(YAML_LIBS) $(GEOIP_LIBS) $(MMDB_LIBS)
Index: pdns-4.1.8/modules/geoipbackend/geoipinterface-mmdb.cc
===================================================================
--- /dev/null
+++ pdns-4.1.8/modules/geoipbackend/geoipinterface-mmdb.cc
@@ -0,0 +1,240 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "geoipbackend.hh"
+#include "geoipinterface.hh"
+
+#ifdef HAVE_MMDB
+
+#include "maxminddb.h"
+
+class GeoIPInterfaceMMDB : public GeoIPInterface {
+public:
+ GeoIPInterfaceMMDB(const string &fname, const string &modeStr, const string& language) {
+ int ec;
+ int flags = 0;
+ if (modeStr == "")
+ /* for the benefit of ifdef */
+ ;
+#ifdef HAVE_MMAP
+ else if (modeStr == "mmap")
+ flags |= MMDB_MODE_MMAP;
+#endif
+ else
+ throw PDNSException(string("Unsupported mode ") + modeStr + ("for geoipbackend-mmdb"));
+ memset(&d_s, 0, sizeof(d_s));
+ if ((ec = MMDB_open(fname.c_str(), flags, &d_s)) < 0)
+ throw PDNSException(string("Cannot open ") + fname + string(": ") + string(MMDB_strerror(ec)));
+ d_lang = language;
+ L<<Logger::Debug<<"Opened MMDB database "<<fname<<"(type: "<<d_s.metadata.database_type<<
+ " version: "<<d_s.metadata.binary_format_major_version << "." <<
+ d_s.metadata.binary_format_minor_version << ")" << endl;
+ }
+
+ bool queryCountry(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ MMDB_entry_data_s data;
+ MMDB_lookup_result_s res;
+ if (!mmdbLookup(ip, false, gl, res))
+ return false;
+ if (MMDB_get_value(&res.entry, &data, "country", "iso_code", NULL) != MMDB_SUCCESS || !data.has_data)
+ return false;
+ ret = string(data.utf8_string, data.data_size);
+ return true;
+ };
+
+ bool queryCountryV6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ MMDB_entry_data_s data;
+ MMDB_lookup_result_s res;
+ if (!mmdbLookup(ip, true, gl, res))
+ return false;
+ if (MMDB_get_value(&res.entry, &data, "country", "iso_code", NULL) != MMDB_SUCCESS || !data.has_data)
+ return false;
+ ret = string(data.utf8_string, data.data_size);
+ return true;
+ };
+
+ bool queryCountry2(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ return queryCountry(ret, gl, ip);
+ }
+
+ bool queryCountry2V6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ return queryCountryV6(ret, gl, ip);
+ }
+
+ bool queryContinent(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ MMDB_entry_data_s data;
+ MMDB_lookup_result_s res;
+ if (!mmdbLookup(ip, false, gl, res))
+ return false;
+ if (MMDB_get_value(&res.entry, &data, "continent", "code", NULL) != MMDB_SUCCESS || !data.has_data)
+ return false;
+ ret = string(data.utf8_string, data.data_size);
+ return true;
+ }
+
+ bool queryContinentV6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ MMDB_entry_data_s data;
+ MMDB_lookup_result_s res;
+ if (!mmdbLookup(ip, true, gl, res))
+ return false;
+ if (MMDB_get_value(&res.entry, &data, "continent", "code", NULL) != MMDB_SUCCESS || !data.has_data)
+ return false;
+ ret = string(data.utf8_string, data.data_size);
+ return true;
+ }
+
+ bool queryName(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ MMDB_entry_data_s data;
+ MMDB_lookup_result_s res;
+ if (!mmdbLookup(ip, false, gl, res))
+ return false;
+ if (MMDB_get_value(&res.entry, &data, "autonomous_system_organization", NULL) != MMDB_SUCCESS || !data.has_data)
+ return false;
+ ret = string(data.utf8_string, data.data_size);
+ return true;
+ }
+
+ bool queryNameV6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ MMDB_entry_data_s data;
+ MMDB_lookup_result_s res;
+ if (!mmdbLookup(ip, true, gl, res))
+ return false;
+ if (MMDB_get_value(&res.entry, &data, "autonomous_system_organization", NULL) != MMDB_SUCCESS || !data.has_data)
+ return false;
+ ret = string(data.utf8_string, data.data_size);
+ return true;
+ }
+
+ bool queryASnum(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ MMDB_entry_data_s data;
+ MMDB_lookup_result_s res;
+ if (!mmdbLookup(ip, false, gl, res))
+ return false;
+ if (MMDB_get_value(&res.entry, &data, "autonomous_system_number", NULL) != MMDB_SUCCESS || !data.has_data)
+ return false;
+ ret = std::to_string(data.uint32);
+ return true;
+ }
+
+ bool queryASnumV6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ MMDB_entry_data_s data;
+ MMDB_lookup_result_s res;
+ if (!mmdbLookup(ip, true, gl, res))
+ return false;
+ if (MMDB_get_value(&res.entry, &data, "autonomous_system_number", NULL) != MMDB_SUCCESS || !data.has_data)
+ return false;
+ ret = std::to_string(data.uint32);
+ return true;
+ }
+
+ bool queryRegion(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ MMDB_entry_data_s data;
+ MMDB_lookup_result_s res;
+ if (!mmdbLookup(ip, false, gl, res))
+ return false;
+ if (MMDB_get_value(&res.entry, &data, "subdivisions", "0", "iso_code", NULL) != MMDB_SUCCESS || !data.has_data)
+ return false;
+ ret = string(data.utf8_string, data.data_size);
+ return true;
+ }
+
+ bool queryRegionV6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ MMDB_entry_data_s data;
+ MMDB_lookup_result_s res;
+ if (!mmdbLookup(ip, true, gl, res))
+ return false;
+ if (MMDB_get_value(&res.entry, &data, "subdivisions", "0", "iso_code", NULL) != MMDB_SUCCESS || !data.has_data)
+ return false;
+ ret = string(data.utf8_string, data.data_size);
+ return true;
+ }
+
+ bool queryCity(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ MMDB_entry_data_s data;
+ MMDB_lookup_result_s res;
+ if (!mmdbLookup(ip, false, gl, res))
+ return false;
+ if ((MMDB_get_value(&res.entry, &data, "cities", "0", NULL) != MMDB_SUCCESS || !data.has_data) &&
+ (MMDB_get_value(&res.entry, &data, "city", "names", d_lang.c_str(), NULL) != MMDB_SUCCESS || !data.has_data))
+ return false;
+ ret = string(data.utf8_string, data.data_size);
+ return true;
+ }
+
+ bool queryCityV6(string &ret, GeoIPNetmask& gl, const string &ip) override {
+ MMDB_entry_data_s data;
+ MMDB_lookup_result_s res;
+ if (!mmdbLookup(ip, true, gl, res))
+ return false;
+ if ((MMDB_get_value(&res.entry, &data, "cities", "0", NULL) != MMDB_SUCCESS || !data.has_data) &&
+ (MMDB_get_value(&res.entry, &data, "city", "names", d_lang.c_str(), NULL) != MMDB_SUCCESS || !data.has_data))
+ return false;
+ ret = string(data.utf8_string, data.data_size);
+ return true;
+ }
+
+ ~GeoIPInterfaceMMDB() { MMDB_close(&d_s); };
+private:
+ MMDB_s d_s;
+ string d_lang;
+
+ bool mmdbLookup(const string &ip, bool v6, GeoIPNetmask& gl, MMDB_lookup_result_s& res) {
+ int gai_ec = 0, mmdb_ec = 0;
+ res = MMDB_lookup_string(&d_s, ip.c_str(), &gai_ec, &mmdb_ec);
+
+ if (gai_ec != 0)
+ L<<Logger::Warning<<"MMDB_lookup_string("<<ip<<") failed: "<<gai_strerror(gai_ec)<<endl;
+ else if (mmdb_ec != MMDB_SUCCESS)
+ L<<Logger::Warning<<"MMDB_lookup_string("<<ip<<") failed: "<<MMDB_strerror(mmdb_ec)<<endl;
+ else if (res.found_entry) {
+ gl.netmask = res.netmask;
+ /* If it's a IPv6 database, IPv4 netmasks are reduced from 128, so we need to deduct
+ 96 to get from [96,128] => [0,32] range */
+ if (!v6 && gl.netmask > 32)
+ gl.netmask -= 96;
+ return true;
+ }
+ return false;
+ }
+};
+
+unique_ptr<GeoIPInterface> GeoIPInterface::makeMMDBInterface(const string &fname, const map<string, string>& opts) {
+ string mode = "";
+ string language = "en";
+ const auto &opt_mode = opts.find("mode");
+ if (opt_mode != opts.end())
+ mode = opt_mode->second;
+ const auto &opt_lang = opts.find("language");
+ if (opt_lang != opts.end())
+ language = opt_lang->second;
+ return unique_ptr<GeoIPInterface>(new GeoIPInterfaceMMDB(fname, mode, language));
+}
+
+#else
+
+unique_ptr<GeoIPInterface> GeoIPInterface::makeMMDBInterface(const string &fname, const map<string, string>& opts) {
+ throw PDNSException("libmaxminddb support not compiled in");
+}
+
+#endif