]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
geoipbackend: Add location support
authorAki Tuomi <cmouse@cmouse.fi>
Mon, 1 Jan 2018 15:22:40 +0000 (17:22 +0200)
committerAki Tuomi <cmouse@cmouse.fi>
Wed, 14 Feb 2018 07:15:53 +0000 (09:15 +0200)
modules/geoipbackend/geoipbackend.cc
modules/geoipbackend/geoipinterface-dat.cc
modules/geoipbackend/geoipinterface-mmdb.cc
modules/geoipbackend/geoipinterface.hh

index 724513f3a05845618d32656ce2d0c39a200ad493..856a3335b3a6cff3bf8f44d54f577055fd89b090 100644 (file)
@@ -446,8 +446,24 @@ string queryGeoIP(const string &ip, bool v6, GeoIPInterface::GeoIPQueryAttribute
   return ret;
 }
 
+bool queryGeoLocation(const string &ip, bool v6, GeoIPNetmask& gl, double& lat, double& lon,
+                      boost::optional<int>& alt, boost::optional<int>& prec)
+{
+  for(auto const& gi: s_geoip_files) {
+    string val;
+    if (v6) {
+      if (gi->queryLocationV6(gl, ip, lat, lon, alt, prec))
+        return true;
+     } else if (gi->queryLocation(gl, ip, lat, lon, alt, prec))
+        return true;
+  }
+  return false;
+}
+
 string GeoIPBackend::format2str(string sformat, const string& ip, bool v6, GeoIPNetmask& gl) {
   string::size_type cur,last;
+  boost::optional<int> alt, prec;
+  double lat, lon;
   time_t t = time((time_t*)NULL);
   GeoIPNetmask tmp_gl; // largest wins
   struct tm gtm;
@@ -474,6 +490,48 @@ string GeoIPBackend::format2str(string sformat, const string& ip, bool v6, GeoIP
       rep = queryGeoIP(ip, v6, GeoIPInterface::Name, tmp_gl);
     } else if (!sformat.compare(cur,3,"%ci")) {
       rep = queryGeoIP(ip, v6, GeoIPInterface::City, tmp_gl);
+    } else if (!sformat.compare(cur,4,"%loc")) {
+      char ns, ew;
+      int d1, d2, m1, m2;
+      double s1, s2;
+      if (!queryGeoLocation(ip, v6, gl, lat, lon, alt, prec)) {
+        rep = "";
+      } else {
+        ns = (lat>0) ? 'N' : 'S';
+        ew = (lon>0) ? 'E' : 'W';
+        /* remove sign */
+        lat = fabs(lat);
+        lon = fabs(lon);
+        d1 = static_cast<int>(lat);
+        d2 = static_cast<int>(lon);
+        m1 = static_cast<int>((lat - d1)*60.0);
+        m2 = static_cast<int>((lon - d2)*60.0);
+        s1 = static_cast<double>(lat - d1 - m1/60.0)*3600.0;
+        s2 = static_cast<double>(lon - d2 - m2/60.0)*3600.0;
+        rep = str(boost::format("%d %d %0.3f %c %d %d %0.3f %c") %
+                                d1 % m1 % s1 % ns % d2 % m2 % s2 % ew);
+        if (alt)
+          rep = rep + str(boost::format(" %d.00") % *alt);
+        else
+          rep = rep + string(" 0.00");
+        if (prec)
+          rep = rep + str(boost::format(" %dm") % *prec);
+      }
+      nrep = 4;
+    } else if (!sformat.compare(cur,4,"%lat")) {
+      if (!queryGeoLocation(ip, v6, gl, lat, lon, alt, prec)) {
+        rep = "";
+      } else {
+        rep = str(boost::format("%lf") % lat);
+      }
+      nrep = 4;
+    } else if (!sformat.compare(cur,4,"%lon")) {
+      if (!queryGeoLocation(ip, v6, gl, lat, lon, alt, prec)) {
+        rep = "";
+      } else {
+        rep = str(boost::format("%lf") % lon);
+      }
+      nrep = 4;
     } else if (!sformat.compare(cur,3,"%hh")) {
       rep = boost::str(boost::format("%02d") % gtm.tm_hour);
       tmp_gl.netmask = (v6?128:32);
index c5d2a0414ba5803c3af2aaefa6887313e1c00a9f..a1754781af96b030e7935fdbb0e4e1eab246345c 100644 (file)
@@ -376,6 +376,42 @@ public:
     return false;
   }
 
+  bool queryLocationV6(GeoIPNetmask& gl, const string &ip,
+                       double& latitude, double& longitude,
+                       boost::optional<int>& alt, boost::optional<int>& prec) override {
+    if (d_db_type == GEOIP_REGION_EDITION_REV0 ||
+        d_db_type == GEOIP_REGION_EDITION_REV1 ||
+        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) {
+        latitude = gir->latitude;
+        longitude = gir->longitude;
+        gl.netmask = gir->netmask;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool queryLocation(GeoIPNetmask& gl, const string &ip,
+                     double& latitude, double& longitude,
+                     boost::optional<int>& alt, boost::optional<int>& prec) override {
+    if (d_db_type == GEOIP_REGION_EDITION_REV0 ||
+        d_db_type == GEOIP_REGION_EDITION_REV1 ||
+        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) {
+        latitude = gir->latitude;
+        longitude = gir->longitude;
+        gl.netmask = gir->netmask;
+        return true;
+      }
+    }
+    return false;
+  }
+
   ~GeoIPInterfaceDAT() { }
 private:
   unsigned int d_db_type;
index 488b97f13364c24bb27e362a63542fce9777f06e..1cb48c6e00b25aeba679cce4e9fb558528eb3f33 100644 (file)
@@ -194,6 +194,44 @@ public:
     return true;
   }
 
+  bool queryLocation(GeoIPNetmask& gl, const string &ip,
+                     double& latitude, double& longitude,
+                     boost::optional<int>& alt, boost::optional<int>& prec) 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, "location", "latitude", NULL) != MMDB_SUCCESS || !data.has_data)
+      return false;
+    latitude = data.double_value;
+     if (MMDB_get_value(&res.entry, &data, "location", "longitude", NULL) != MMDB_SUCCESS || !data.has_data)
+      return false;
+    longitude = data.double_value;
+    if (MMDB_get_value(&res.entry, &data, "location", "accuracy_radius", NULL) != MMDB_SUCCESS || !data.has_data)
+      return false;
+    prec = data.uint16;
+    return true;
+  }
+
+  bool queryLocationV6(GeoIPNetmask& gl, const string &ip,
+                       double& latitude, double& longitude,
+                       boost::optional<int>& alt, boost::optional<int>& prec) 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, "location", "latitude", NULL) != MMDB_SUCCESS || !data.has_data)
+      return false;
+    latitude = data.double_value;
+     if (MMDB_get_value(&res.entry, &data, "location", "longitude", NULL) != MMDB_SUCCESS || !data.has_data)
+      return false;
+    longitude = data.double_value;
+    if (MMDB_get_value(&res.entry, &data, "location", "accuracy_radius", NULL) != MMDB_SUCCESS || !data.has_data)
+      return false;
+    prec = data.uint16;
+    return true;
+  }
+
   ~GeoIPInterfaceMMDB() { MMDB_close(&d_s); };
 private:
   MMDB_s d_s;
index 97dd5ee48d1beb74ab9eb0f86cb58ff3b857c55b..87d83bf4fbc19710fd7d3a3c9d76e874fbcf620f 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef PDNS_GEOIPINTERFACE_HH
 #define PDNS_GEOIPINTERFACE_HH
 
+#include "boost/optional.hpp"
+
 class GeoIPInterface {
 public:
   enum GeoIPQueryAttribute {
@@ -48,6 +50,12 @@ public:
   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 bool queryLocation(GeoIPNetmask& gl, const string &ip,
+                             double& latitude, double& longitude,
+                             boost::optional<int>& alt, boost::optional<int>& prec) = 0;
+  virtual bool queryLocationV6(GeoIPNetmask& gl, const string &ip,
+                               double& latitude, double& longitude,
+                               boost::optional<int>& alt, boost::optional<int>& prec) = 0;
 
   virtual ~GeoIPInterface() { }