From: Aki Tuomi Date: Sat, 30 Dec 2017 11:24:29 +0000 (+0200) Subject: geoipbackend: Move GeoIP handling to separate class X-Git-Tag: dnsdist-1.3.0~85^2~20 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2923e03ffa0c0dd68b677f88562c0ac0540fdf46;p=pdns geoipbackend: Move GeoIP handling to separate class Makes it easier to add new interfaces --- diff --git a/modules/geoipbackend/Makefile.am b/modules/geoipbackend/Makefile.am index b0d0ee924..7aad6f6f6 100644 --- a/modules/geoipbackend/Makefile.am +++ b/modules/geoipbackend/Makefile.am @@ -4,6 +4,8 @@ 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 libgeoipbackend_la_LDFLAGS = -module -avoid-version libgeoipbackend_la_LIBADD = $(YAML_LIBS) $(GEOIP_LIBS) diff --git a/modules/geoipbackend/OBJECTFILES b/modules/geoipbackend/OBJECTFILES index 7173c166c..b2245db98 100644 --- a/modules/geoipbackend/OBJECTFILES +++ b/modules/geoipbackend/OBJECTFILES @@ -1 +1 @@ -geoipbackend.lo +geoipbackend.lo geoipinterface-dat.lo geoipinterface.lo diff --git a/modules/geoipbackend/geoipbackend.cc b/modules/geoipbackend/geoipbackend.cc index e767836d2..6ed40cd62 100644 --- a/modules/geoipbackend/geoipbackend.cc +++ b/modules/geoipbackend/geoipbackend.cc @@ -23,6 +23,7 @@ #include "config.h" #endif #include "geoipbackend.hh" +#include "geoipinterface.hh" #include "pdns/dns_random.hh" #include #include @@ -49,14 +50,6 @@ public: static vector s_domains; static int s_rc = 0; // refcount -struct geoip_deleter { - void operator()(GeoIP* ptr) { - if (ptr) GeoIP_delete(ptr); - }; -}; - -static vector 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" }; @@ -87,38 +80,21 @@ GeoIPBackend::GeoIPBackend(const string& suffix) { s_rc++; } +static vector > s_geoip_files; + void GeoIPBackend::initialize() { YAML::Node config; vector 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 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(fptr))); + const string& fileStr = string("dat:") + file + string(";mode=") + modeStr; + s_geoip_files.push_back(GeoIPInterface::makeInterface(fileStr)); } } @@ -420,274 +396,7 @@ bool GeoIPBackend::get(DNSResourceRecord &r) { 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) { - ret = GeoIP_code3_by_id(GeoIP_id_by_addr_gl(gi.second.get(), ip.c_str(), gl)); - 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) { - ret = GeoIP_code3_by_id(GeoIP_id_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl)); - 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) { - ret = GeoIP_code_by_id(GeoIP_id_by_addr_gl(gi.second.get(), ip.c_str(), gl)); - 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) { - ret = GeoIP_code_by_id(GeoIP_id_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl)); - 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) { - ret = GeoIP_continent_by_id(GeoIP_id_by_addr_gl(gi.second.get(), ip.c_str(), gl)); - 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) { - ret = GeoIP_continent_by_id(GeoIP_id_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl)); - 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(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(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(GeoIP_name_by_addr_gl(gi.second.get(), ip.c_str(), gl)); - if (!val.empty()) { - vector 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(GeoIP_name_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl)); - if (!val.empty()) { - vector 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(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(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(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(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(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(gir->city); - gl->netmask = gir->netmask; - return true; - } - } - return false; -} - - -string GeoIPBackend::queryGeoIP(const string &ip, bool v6, GeoIPQueryAttribute attribute, GeoIPLookup* gl) { +string queryGeoIP(const string &ip, bool v6, GeoIPInterface::GeoIPQueryAttribute attribute, GeoIPLookup* gl) { string ret = "unknown"; for(auto const& gi: s_geoip_files) { @@ -695,33 +404,33 @@ string GeoIPBackend::queryGeoIP(const string &ip, bool v6, GeoIPQueryAttribute a 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; } @@ -748,21 +457,21 @@ string GeoIPBackend::format2str(string sformat, const string& ip, bool v6, GeoIP 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); diff --git a/modules/geoipbackend/geoipbackend.hh b/modules/geoipbackend/geoipbackend.hh index 6f0c67898..9ebe3b5f5 100644 --- a/modules/geoipbackend/geoipbackend.hh +++ b/modules/geoipbackend/geoipbackend.hh @@ -41,13 +41,12 @@ #include "pdns/dnsbackend.hh" #include "pdns/lock.hh" -struct geoip_deleter; +class GeoIPInterface; class GeoIPDomain; class GeoIPBackend: public DNSBackend { public: - typedef pair > geoip_file_t; GeoIPBackend(const std::string& suffix=""); ~GeoIPBackend(); @@ -68,41 +67,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; + 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); vector d_result; + vector d_files; }; #endif /* PDNS_GEOIPBACKEND_HH */ diff --git a/modules/geoipbackend/geoipinterface-dat.cc b/modules/geoipbackend/geoipinterface-dat.cc new file mode 100644 index 000000000..8ced5c72a --- /dev/null +++ b/modules/geoipbackend/geoipinterface-dat.cc @@ -0,0 +1,336 @@ +/* + * 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" +#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_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, GeoIPLookup* gl, const string &ip) override { + 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(), gl)); + 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(), gl); + if (gir) { + 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, GeoIPLookup* gl, const string &ip) override { + 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(), gl)); + 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(), gl); + if (gir) { + 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, GeoIPLookup* gl, const string &ip) override { + 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(), gl)); + 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(), gl); + if (gir) { + 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, GeoIPLookup* gl, const string &ip) override { + 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(), gl)); + 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(), gl); + if (gir) { + 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, GeoIPLookup* gl, const string &ip) override { + 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(), gl)); + 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(), gl); + if (gir) { + 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, GeoIPLookup* gl, const string &ip) override { + 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(), gl)); + 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(), gl); + if (gir) { + 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, GeoIPLookup* gl, const string &ip) override { + if (d_db_type == GEOIP_ISP_EDITION || + d_db_type == GEOIP_ORG_EDITION) { + string val = valueOrEmpty(GeoIP_name_by_addr_gl(d_gi.get(), ip.c_str(), gl)); + if (!val.empty()) { + // reduce space to dash + ret = boost::replace_all_copy(val, " ", "-"); + return true; + } + } + return false; + } + + bool queryNameV6(string &ret, GeoIPLookup* gl, const string &ip) override { + if (d_db_type == GEOIP_ISP_EDITION_V6 || + d_db_type == GEOIP_ORG_EDITION_V6) { + string val = valueOrEmpty(GeoIP_name_by_addr_v6_gl(d_gi.get(), ip.c_str(), gl)); + if (!val.empty()) { + // reduce space to dash + ret = boost::replace_all_copy(val, " ", "-"); + return true; + } + } + return false; + } + + bool queryASnum(string &ret, GeoIPLookup* gl, const string &ip) override { + if (d_db_type == GEOIP_ASNUM_EDITION) { + string val = valueOrEmpty(GeoIP_name_by_addr_gl(d_gi.get(), ip.c_str(), gl)); + if (!val.empty()) { + vector asnr; + stringtok(asnr, val); + if(asnr.size()>0) { + ret = asnr[0]; + return true; + } + } + } + return false; + } + + bool queryASnumV6(string &ret, GeoIPLookup* gl, const string &ip) override { + if (d_db_type == GEOIP_ASNUM_EDITION_V6) { + string val = valueOrEmpty(GeoIP_name_by_addr_v6_gl(d_gi.get(), ip.c_str(), gl)); + if (!val.empty()) { + vector asnr; + stringtok(asnr, val); + if(asnr.size()>0) { + ret = asnr[0]; + return true; + } + } + } + return false; + } + + bool queryRegion(string &ret, GeoIPLookup* gl, const string &ip) override { + 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(), gl); + if (gir) { + ret = valueOrEmpty(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(gir->region); + gl->netmask = gir->netmask; + return true; + } + } + return false; + } + + bool queryRegionV6(string &ret, GeoIPLookup* gl, const string &ip) override { + 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(), gl); + if (gir) { + ret = valueOrEmpty(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(gir->region); + gl->netmask = gir->netmask; + return true; + } + } + return false; + } + + bool queryCity(string &ret, GeoIPLookup* 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(gir->city); + gl->netmask = gir->netmask; + return true; + } + } + return false; + } + + bool queryCityV6(string &ret, GeoIPLookup* 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(gir->city); + gl->netmask = gir->netmask; + return true; + } + } + return false; + } + + ~GeoIPInterfaceDAT() { } +private: + unsigned int d_db_type; + unique_ptr d_gi; +}; + +unique_ptr GeoIPInterface::makeDATInterface(const string &fname, const map& opts) { + string mode = "standard"; + const auto &opt = opts.find("mode"); + if (opt != opts.end()) + mode = opt->second; + return unique_ptr(new GeoIPInterfaceDAT(fname, mode)); +} diff --git a/modules/geoipbackend/geoipinterface.cc b/modules/geoipbackend/geoipinterface.cc new file mode 100644 index 000000000..31c6eac3e --- /dev/null +++ b/modules/geoipbackend/geoipinterface.cc @@ -0,0 +1,65 @@ +/* + * 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::makeInterface(const string& dbStr) { + /* parse dbStr */ + map opts; + vector 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 = driver.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 kv; + stringtok(kv, opt, "="); + opts[kv[0]] = kv[1]; + } + } + + if (driver == "dat") { + return makeDATInterface(filename, opts); + } else { + throw PDNSException(string("Unsupported file type '") + driver + string("' (use type: prefix to force type)")); + } +} diff --git a/modules/geoipbackend/geoipinterface.hh b/modules/geoipbackend/geoipinterface.hh new file mode 100644 index 000000000..c307ad697 --- /dev/null +++ b/modules/geoipbackend/geoipinterface.hh @@ -0,0 +1,59 @@ +/* + * 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, GeoIPLookup* gl, const string &ip) = 0; + virtual bool queryCountryV6(string &ret, GeoIPLookup* gl, const string &ip) = 0; + virtual bool queryCountry2(string &ret, GeoIPLookup* gl, const string &ip) = 0; + virtual bool queryCountry2V6(string &ret, GeoIPLookup* gl, const string &ip) = 0; + virtual bool queryContinent(string &ret, GeoIPLookup* gl, const string &ip) = 0; + virtual bool queryContinentV6(string &ret, GeoIPLookup* gl, const string &ip) = 0; + virtual bool queryName(string &ret, GeoIPLookup* gl, const string &ip) = 0; + virtual bool queryNameV6(string &ret, GeoIPLookup* gl, const string &ip) = 0; + virtual bool queryASnum(string &ret, GeoIPLookup* gl, const string &ip) = 0; + virtual bool queryASnumV6(string &ret, GeoIPLookup* gl, const string &ip) = 0; + virtual bool queryRegion(string &ret, GeoIPLookup* gl, const string &ip) = 0; + virtual bool queryRegionV6(string &ret, GeoIPLookup* gl, const string &ip) = 0; + virtual bool queryCity(string &ret, GeoIPLookup* gl, const string &ip) = 0; + virtual bool queryCityV6(string &ret, GeoIPLookup* gl, const string &ip) = 0; + + virtual ~GeoIPInterface() { } + + static unique_ptr makeInterface(const string& dbStr); +private: + static unique_ptr makeDATInterface(const string& fname, const map& opts); +}; + +#endif