]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
auth: geoip, compute weight per QType
authorBaptiste Courtois <b.courtois@criteo.com>
Sat, 24 Nov 2018 15:16:11 +0000 (16:16 +0100)
committerBaptiste Courtois <b.courtois@criteo.com>
Fri, 25 Jan 2019 18:45:45 +0000 (19:45 +0100)
As seen in #7051 the former behavior of the geoip backend in mixed
weighted QType cases, was erroneous.
Having per QType weights allows proper static lookup.
It also enables to question with ANY and retrieve one record per QType.

Closes #7051

docs/backends/geoip.rst
modules/geoipbackend/geoipbackend.cc

index 6667988c47f198ad98e6dc9b899e1059b18b25a3..dfadcebc77140f8f6243e5164b925cb5bd7869d4 100644 (file)
@@ -221,7 +221,7 @@ Using the ``weight`` attribute
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 You can use record attributes to define positive and non-zero weight.
-If this is given, only one record is chosen randomly based on the weight.
+If this is given, only one record per type is chosen randomly based on the weight.
 
 Probability is calculated by summing up the weights and dividing each weight with the sum.
 
index 4baabe2fe7c2cf4dc019a5a453c76e1054ecaa82..b3e7480d3f0bebf7e389c37252503f0e3e8113f0 100644 (file)
@@ -261,24 +261,30 @@ void GeoIPBackend::initialize() {
 
     // finally fix weights
     for(auto &item: dom.records) {
-      float weight=0;
-      float sum=0;
+      map<uint16_t, float> weights;
+      map<uint16_t, float> sums;
+      map<uint16_t, GeoIPDNSResourceRecord> lasts;
       bool has_weight=false;
       // first we look for used weight
       for(const auto &rr: item.second) {
-        weight+=rr.weight;
+        weights[rr.qtype.getCode()] += rr.weight;
         if (rr.has_weight) has_weight = true;
       }
       if (has_weight) {
         // put them back as probabilities and values..
         for(auto &rr: item.second) {
-          rr.weight=static_cast<int>((static_cast<float>(rr.weight) / weight)*1000.0);
-          sum += rr.weight;
+          uint16_t rr_type = rr.qtype.getCode();
+          rr.weight=static_cast<int>((static_cast<float>(rr.weight) / weights[rr_type])*1000.0);
+          sums[rr_type] += rr.weight;
           rr.has_weight = has_weight;
+          lasts[rr_type] = rr;
         }
         // remove rounding gap
-        if (sum < 1000)
-          item.second.back().weight += (1000-sum);
+        for(auto &x: lasts) {
+          float sum = sums[x.first];
+          if (sum < 1000)
+            x.second.weight += (1000-sum);
+        }
       }
     }
 
@@ -307,15 +313,15 @@ GeoIPBackend::~GeoIPBackend() {
 
 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;
+  map<uint16_t,int> cumul_probabilities;
   int probability_rnd = 1+(dns_random(1000)); // setting probability=0 means it never is used
 
   if (i != dom.records.end()) { // return static value
     for(const auto& rr : i->second) {
       if (rr.has_weight) {
         gl.netmask = (v6?128:32);
-        int comp = cumul_probability;
-        cumul_probability += rr.weight;
+        int comp = cumul_probabilities[rr.qtype.getCode()];
+        cumul_probabilities[rr.qtype.getCode()] += rr.weight;
         if (rr.weight == 0 || probability_rnd < comp || probability_rnd > (comp + rr.weight))
           continue;
       }