]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Merge pull request #4195 from zeha/api-nameservers-or-ns-rrset
authorPeter van Dijk <peter.van.dijk@powerdns.com>
Mon, 21 Aug 2017 13:06:10 +0000 (15:06 +0200)
committerGitHub <noreply@github.com>
Mon, 21 Aug 2017 13:06:10 +0000 (15:06 +0200)
API: prevent duplicate records in single RRset

1  2 
pdns/ws-auth.cc

diff --combined pdns/ws-auth.cc
index 212d417a425d25ba2d2ec4afb871df157a962dc3,0c377d3eeeb105532396fb954568ea3038c2775d..dc567135b5cf54326f622af99c9cf4d723356622
@@@ -950,13 -950,13 +950,13 @@@ static void apiZoneCryptokeys(HttpReque
  
    if (req->method == "GET") {
      apiZoneCryptokeysGET(zonename, inquireKeyId, resp, &dk);
 -  } else if (req->method == "DELETE") {
 +  } else if (req->method == "DELETE" && !::arg().mustDo("api-readonly")) {
      if (inquireKeyId == -1)
        throw HttpBadRequestException();
      apiZoneCryptokeysDELETE(zonename, inquireKeyId, req, resp, &dk);
 -  } else if (req->method == "POST") {
 +  } else if (req->method == "POST" && !::arg().mustDo("api-readonly")) {
      apiZoneCryptokeysPOST(zonename, req, resp, &dk);
 -  } else if (req->method == "PUT") {
 +  } else if (req->method == "PUT" && !::arg().mustDo("api-readonly")) {
      if (inquireKeyId == -1)
        throw HttpBadRequestException();
      apiZoneCryptokeysPUT(zonename, inquireKeyId, req, resp, &dk);
@@@ -991,6 -991,26 +991,26 @@@ static void gatherRecordsFromZone(cons
    }
  }
  
+ /** Throws ApiException if records with duplicate name/type/content are present.
+  *  NOTE: sorts records in-place.
+  */
+ static void checkDuplicateRecords(vector<DNSResourceRecord>& records) {
+   sort(records.begin(), records.end(),
+     [](const DNSResourceRecord& rec_a, const DNSResourceRecord& rec_b) -> bool {
+       return rec_a.qname.toString() > rec_b.qname.toString() || \
+         rec_a.qtype.getCode() > rec_b.qtype.getCode() || \
+         rec_a.content < rec_b.content;
+     }
+   );
+   DNSResourceRecord previous;
+   for(const auto& rec : records) {
+     if (previous.qtype == rec.qtype && previous.qname == rec.qname && previous.content == rec.content) {
+       throw ApiException("Duplicate record in RRset " + rec.qname.toString() + " IN " + rec.qtype.getName() + " with content \"" + rec.content + "\"");
+     }
+     previous = rec;
+   }
+ }
  static void apiServerZones(HttpRequest* req, HttpResponse* resp) {
    UeberBackend B;
    DNSSECKeeper dk(&B);
      auto document = req->json();
      DNSName zonename = apiNameToDNSName(stringFromJson(document, "name"));
      apiCheckNameAllowedCharacters(zonename.toString());
+     zonename.makeUsLowerCase();
  
      bool exists = B.getDomainInfo(zonename, di);
      if(exists)
      }
  
      for(auto& rr : new_records) {
+       rr.qname.makeUsLowerCase();
        if (!rr.qname.isPartOf(zonename) && rr.qname != zonename)
          throw ApiException("RRset "+rr.qname.toString()+" IN "+rr.qtype.getName()+": Name is out of zone");
        apiCheckQNameAllowedCharacters(rr.qname.toString());
        }
      }
  
+     checkDuplicateRecords(new_records);
      // no going back after this
      if(!B.createDomain(zonename))
        throw ApiException("Creating domain '"+zonename.toString()+"' failed");
@@@ -1419,6 -1443,7 +1443,7 @@@ static void patchZone(HttpRequest* req
                rr.content = makeBackendRecordContent(rr.qtype, rr.content);
              }
            }
+           checkDuplicateRecords(new_records);
          }
  
          if (replace_comments) {