]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
pdnsutil: add rrset comment management
authorPeter van Dijk <peter.van.dijk@powerdns.com>
Thu, 13 Nov 2025 10:33:16 +0000 (11:33 +0100)
committerPeter van Dijk <peter.van.dijk@powerdns.com>
Mon, 20 Apr 2026 12:45:13 +0000 (14:45 +0200)
Signed-off-by: Peter van Dijk <peter.van.dijk@powerdns.com>
pdns/pdnsutil.cc

index afbe28f3e976536b67c94c522d96d1bd9f31a84c..c3cae5b75da5b16b012d9af58c12d2e77c2e4f12 100644 (file)
@@ -1,5 +1,6 @@
 #include <cerrno>
 #include <csignal>
+#include <cstdlib>
 #include <fcntl.h>
 #include <fstream>
 #include <iomanip>
@@ -86,6 +87,8 @@ static int activateTSIGKey(vector<string>& cmds, std::string_view synopsis);
 static int activateZoneKey(vector<string>& cmds, std::string_view synopsis);
 static int addAutoprimary(vector<string>& cmds, std::string_view synopsis);
 static int addMeta(vector<string>& cmds, std::string_view synopsis);
+static int addComment(vector<string>& cmds, std::string_view synopsis);
+static int listComments(vector<string>& cmds, std::string_view synopsis);
 static int addRecord(vector<string>& cmds, std::string_view synopsis);
 static int addZoneKey(vector<string>& cmds, std::string_view synopsis);
 static int backendCmd(vector<string>& cmds, std::string_view synopsis);
@@ -282,7 +285,13 @@ static const groupCommandDispatcher rrsetCommands{
     "\tCalculate the NSEC3 hash for NAME in ZONE"}},
    {"replace", {true, replaceRRSet,
     R"(ZONE NAME TYPE [TTL] "CONTENT" ["CONTENT"...])",
-    "\tReplace named rrset from ZONE"}}}
+    "\tReplace named rrset from ZONE"}},
+  {"add-comment", {true, addComment,
+    "ZONE NAME TYPE COMMENT [ACCOUNT]",
+    "\tAdd a comment"}},
+   {"list-comments", {true, listComments,
+     "ZONE",
+     "\tList comments for a zone"}}}
 };
 
 // TSIG-KEY / TSIGKEY
@@ -1878,6 +1887,30 @@ static int listZone(const ZoneName &zone) {
   return EXIT_SUCCESS;
 }
 
+static int listComments(const ZoneName &zone) {
+  UtilBackend B; //NOLINT(readability-identifier-length)
+  DomainInfo di; //NOLINT(readability-identifier-length)
+
+  if (! B.getDomainInfo(zone, di)) {
+    cerr << "Zone '" << zone << "' not found!" << endl;
+    return EXIT_FAILURE;
+  }
+  if ((di.backend->getCapabilities() & DNSBackend::CAP_COMMENTS) == 0) {
+    cerr << "Backend for zone '" << zone << "' does not support listing its comments." << endl;
+    return EXIT_FAILURE;
+  }
+
+  Comment comment;
+
+  di.backend->listComments(di.id);
+  while(di.backend->getComment(comment)) {
+    cout<<comment.qname<<"\t"<<comment.qtype<<"\t"<<comment.modified_at<<"\t"<<comment.account<<"\t"<<comment.content<<endl;
+  }
+  return EXIT_SUCCESS;
+}
+
+
+
 // lovingly copied from http://stackoverflow.com/questions/1798511/how-to-avoid-press-enter-with-any-getchar
 static int read1char(){
     int c;
@@ -4343,6 +4376,60 @@ static int changeSecondaryZonePrimary(vector<string>& cmds, const std::string_vi
   }
 }
 
+static int addComment(vector<string>& cmds, const std::string_view synopsis)
+{
+  if(cmds.size() < 4) {
+    return usage(synopsis);
+  }
+
+  UtilBackend B; //NOLINT(readability-identifier-length)
+  DomainInfo di; //NOLINT(readability-identifier-length)
+  ZoneName zone(cmds.at(0));
+  if (!B.getDomainInfo(zone, di)) {
+    cerr << "Zone '" << zone << "' doesn't exist" << endl;
+    return EXIT_FAILURE;
+  }
+
+  Comment comment;
+
+  comment.domain_id = di.id;
+  comment.qname = DNSName(cmds.at(1));
+  comment.qtype = cmds.at(2);
+  comment.content = cmds.at(3);
+  if(cmds.size() > 4) {
+    comment.account = cmds.at(4);
+  }
+  comment.modified_at = time(nullptr);
+
+  if (!comment.qname.isPartOf(zone)) {
+    cerr << "Name \"" << comment.qname.toString() << "\" to add comment to is not part of zone \"" << zone.toString()  << "\"." << endl;
+    return EXIT_FAILURE;
+  }
+
+  di.backend->startTransaction(zone, UnknownDomainID);
+  if (!di.backend->feedComment(comment)) {
+    cerr << "Backend does not support comments" << endl;
+    di.backend->abortTransaction();
+    return EXIT_FAILURE;
+  }
+
+  di.backend->commitTransaction();
+  return EXIT_SUCCESS;
+}
+
+static int listComments(vector<string>& cmds, const std::string_view synopsis)
+{
+  if(cmds.size() != 1) {
+    return usage(synopsis);
+  }
+  if (cmds.at(0) == ".") {
+    cmds.at(0).clear();
+  }
+
+  return listComments(ZoneName(cmds.at(0)));
+}
+
+
 static int addRecord(vector<string>& cmds, const std::string_view synopsis)
 {
   if(cmds.size() < 4) {