From: Miod Vallat Date: Wed, 15 Jan 2025 07:48:17 +0000 (+0100) Subject: Split main() into one routine per command. X-Git-Tag: dnsdist-2.0.0-alpha1~167^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b5340281496e9d00206d6c1179cbd86575d52a97;p=thirdparty%2Fpdns.git Split main() into one routine per command. This unfortunately removes the "hash-password" easter egg. --- diff --git a/pdns/pdnsutil.cc b/pdns/pdnsutil.cc index 866a442d53..205fdc7f46 100644 --- a/pdns/pdnsutil.cc +++ b/pdns/pdnsutil.cc @@ -1545,52 +1545,6 @@ static int createZone(const DNSName &zone, const DNSName& nsname) { return EXIT_SUCCESS; } -static int createSecondaryZone(const vector& cmds) -{ - UeberBackend B; - DomainInfo di; - DNSName zone(cmds.at(1)); - if (B.getDomainInfo(zone, di)) { - cerr << "Zone '" << zone << "' exists already" << endl; - return EXIT_FAILURE; - } - vector primaries; - for (unsigned i=2; i < cmds.size(); i++) { - primaries.emplace_back(cmds.at(i), 53); - } - cerr << "Creating secondary zone '" << zone << "', with primaries '" << comboAddressVecToString(primaries) << "'" << endl; - B.createDomain(zone, DomainInfo::Secondary, primaries, ""); - if(!B.getDomainInfo(zone, di)) { - cerr << "Zone '" << zone << "' was not created!" << endl; - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} - -static int changeSecondaryZonePrimary(const vector& cmds) -{ - UeberBackend B; - DomainInfo di; - DNSName zone(cmds.at(1)); - if (!B.getDomainInfo(zone, di)) { - cerr << "Zone '" << zone << "' doesn't exist" << endl; - return EXIT_FAILURE; - } - vector primaries; - for (unsigned i=2; i < cmds.size(); i++) { - primaries.emplace_back(cmds.at(i), 53); - } - cerr << "Updating secondary zone '" << zone << "', primaries to '" << comboAddressVecToString(primaries) << "'" << endl; - try { - di.backend->setPrimaries(zone, primaries); - return EXIT_SUCCESS; - } - catch (PDNSException& e) { - cerr << "Setting primary for zone '" << zone << "' failed: " << e.reason << endl; - return EXIT_FAILURE; - } -} - // add-record ZONE name type [ttl] "content" ["content"] static int addOrReplaceRecord(bool addOrReplace, const vector& cmds) { DNSResourceRecord rr; @@ -2515,1794 +2469,2271 @@ static int addOrSetMeta(const DNSName& zone, const string& kind, const vector& cmds, DNSSECKeeper& dk) //NOLINT(readability-identifier-length) +// Command handlers + +static int lmdbGetBackendVersion([[maybe_unused]] vector& cmds) { - if(cmds.size() < 3 ) { - cerr << "Syntax: pdnsutil add-zone-key ZONE [zsk|ksk] [BITS] [active|inactive] [rsasha1|rsasha1-nsec3-sha1|rsasha256|rsasha512|ecdsa256|ecdsa384"; -#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO_ED25519) - cerr << "|ed25519"; -#endif -#if defined(HAVE_LIBCRYPTO_ED448) - cerr << "|ed448"; -#endif - cerr << "]"<& cmds) +{ + if(cmds.size() != 2) { + cerr << "Syntax: pdnsutil test-algorithm algonum"<(cmds.at(1)))) + return 0; + return 1; +} - UeberBackend B("default"); //NOLINT(readability-identifier-length) - DomainInfo di; //NOLINT(readability-identifier-length) +static int ipEncrypt(vector& cmds) +{ + if (cmds.size() < 3 || (cmds.size() == 4 && cmds.at(3) != "key")) { + cerr<<"Syntax: pdnsutil [ipencrypt|ipdecrypt] IP passphrase [key]"<& cmds) +{ + if (testAlgorithms()) return 0; + return 1; +} + +static int listAlgorithms(vector& cmds) +{ + if ((cmds.size() == 2 && cmds.at(1) != "with-backend") || cmds.size() > 2) { + cerr<<"Syntax: pdnsutil list-algorithms [with-backend]"< 0) { - algorithm = tmp_algo; - } - else if (pdns_iequals(cmds.at(n), "active")) { - active=true; - } - else if (pdns_iequals(cmds.at(n), "inactive") || pdns_iequals(cmds.at(n), "passive")) { // 'passive' eventually needs to be removed - active=false; - } - else if (pdns_iequals(cmds.at(n), "published")) { - published = true; - } - else if (pdns_iequals(cmds.at(n), "unpublished")) { - published = false; + cout<<"DNSKEY algorithms supported by this installation of PowerDNS:"<& cmds) +{ +#ifdef HAVE_SQLITE3 + if(cmds.size() != 2) { + cerr << "Syntax: pdnsutil create-bind-db FNAME"< statements; + stringtok(statements, sqlCreate, ";"); + for(const string& statement : statements) { + db.execute(statement); } - else if (pdns::checked_stoi(cmds.at(n)) != 0) { - pdns::checked_stoi_into(bits, cmds.at(n)); + } + catch(SSqlException& se) { + throw PDNSException("Error creating database in BIND backend: "+se.txtReason()); + } + return 0; +#else + cerr<<"bind-dnssec-db requires building PowerDNS with SQLite3"<& cmds) +{ + if (cmds.size() < 3) { + cerr<<"Usage: raw-lua-from-content TYPE CONTENT"<serialize(DNSName(), true))<& cmds) +{ + uint64_t workFactor = CredentialsHolder::s_defaultWorkFactor; + if (cmds.size() > 1) { + try { + pdns::checked_stoi_into(workFactor, cmds.at(1)); } - else { - cerr << "Unknown algorithm, key flag or size '" << cmds.at(n) << "'" << endl; - return EXIT_FAILURE; + catch (const std::exception& e) { + cerr<<"Unable to parse the supplied work factor: "<& cmds) +{ + if(cmds.size() < 3) { + cerr<<"Syntax: pdnsutil zonemd-verify-file ZONE FILENAME"<& cmds) +{ + if(cmds.size() != 2) { + cerr << "Syntax: pdnsutil test-schema ZONE"<& cmds) +{ + if(cmds.size() < 2) { + cerr << "Syntax: pdnsutil rectify-zone ZONE [ZONE..]"<& cmds) +{ + bool quiet = (cmds.size() >= 2 && cmds.at(1) == "quiet"); + DNSSECKeeper dk; + if (!rectifyAllZones(dk, quiet)) { return 1; - } else { - try { - dk.getKeyById(zone, id); - cout<& cmds) { - po::options_description desc("Allowed options"); - desc.add_options() - ("help,h", "produce help message") - ("version", "show version") - ("verbose,v", "be verbose") - ("force", "force an action") - ("config-name", po::value()->default_value(""), "virtual configuration name") - ("config-dir", po::value()->default_value(SYSCONFDIR), "location of pdns.conf") - ("no-colors", "do not use colors in output") - ("commands", po::value >()); + if(cmds.size() != 2) { + cerr << "Syntax: pdnsutil check-zone ZONE"<& cmds) +{ + dbBench(cmds.size() > 1 ? cmds.at(1) : ""); + return 0; +} - vector cmds; +static int checkAllZones(vector& cmds) +{ + bool exitOnError = ((cmds.size() >= 2 ? cmds.at(1) : "") == "exit-on-error"); + DNSSECKeeper dk; + return checkAllZones(dk, exitOnError); +} - if(g_vm.count("commands")) - cmds = g_vm["commands"].as >(); +static int listAllZones(vector& cmds) +{ + if (cmds.size() > 2) { + cerr << "Syntax: pdnsutil list-all-zones [primary|secondary|native|producer|consumer]" << endl; + return 0; + } + if (cmds.size() == 2) + return listAllZones(cmds.at(1)); + return listAllZones(); +} - g_verbose = g_vm.count("verbose"); +static int listMemberZones(vector& cmds) +{ + if (cmds.size() != 2) { + cerr << "Syntax: pdnsutil list-member-zones CATALOG" << endl; + return 0; + } + return listMemberZones(cmds.at(1)); +} - if (g_vm.count("version")) { - cout<<"pdnsutil "<& cmds) +{ + cerr << "Did you mean check-zone?"<& cmds) +{ + cerr << "Did you mean check-all-zones?"<& cmds) +{ + if(cmds.size() < 2) { + cerr << "Syntax: pdnsutil test-speed numcores [signing-server]"< 3) ? cmds.at(3) : "", pdns::checked_stoi(cmds.at(2))); + return 0; +} - if (cmds.empty() || g_vm.count("help") || cmds.at(0) == "help") { - cout << "Usage: \npdnsutil [options] [params ..]\n" - << endl; - cout << "Commands:" << endl; - cout << "activate-tsig-key ZONE NAME {primary|secondary|producer|consumer}" << endl; - cout << " Enable TSIG authenticated AXFR using the key NAME for ZONE" << endl; - cout << "activate-zone-key ZONE KEY-ID Activate the key with key id KEY-ID in ZONE" << endl; - cout << "add-record ZONE NAME TYPE [ttl] content" << endl; - cout << " [content..] Add one or more records to ZONE" << endl; - cout << "add-autoprimary IP NAMESERVER [account]" << endl; - cout << " Add a new autoprimary " << endl; - cout << "remove-autoprimary IP NAMESERVER Remove an autoprimary" << endl; - cout << "list-autoprimaries List all autoprimaries" << endl; - cout << "add-zone-key ZONE {zsk|ksk} [BITS] [active|inactive] [published|unpublished]" << endl; - cout << " [rsasha1|rsasha1-nsec3-sha1|rsasha256|rsasha512|ecdsa256|ecdsa384"; -#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO_ED25519) - cout << "|ed25519"; -#endif -#if defined(HAVE_LIBCRYPTO_ED448) - cout << "|ed448"; -#endif - cout << "]" << endl; - cout << " Add a ZSK or KSK to zone and specify algo&bits" << endl; - cout << "backend-cmd BACKEND CMD [CMD..] Perform one or more backend commands" << endl; - cout << "backend-lookup BACKEND NAME [[TYPE] CLIENT-IP-SUBNET]" << endl; - cout << " Perform a backend lookup of NAME, TYPE and CLIENT-IP-SUBNET" << endl; - cout << "b2b-migrate OLD NEW Move all data from one backend to another" << endl; - cout << "bench-db [filename] Bench database backend with queries, one zone per line" << endl; - cout << "check-zone ZONE Check a zone for correctness" << endl; - cout << "check-all-zones [exit-on-error] Check all zones for correctness. Set exit-on-error to exit immediately" << endl; - cout << " after finding an error in a zone." << endl; - cout << "clear-zone ZONE Clear all records of a zone, but keep everything else" << endl; - cout << "create-bind-db FNAME Create DNSSEC db for BIND backend (bind-dnssec-db)" << endl; - cout << "create-secondary-zone ZONE primary-ip [primary-ip..]" << endl; - cout << " Create secondary zone ZONE with primary IP address primary-ip" << endl; - cout << "change-secondary-zone-primary ZONE primary-ip [primary-ip..]" << endl; - cout << " Change secondary zone ZONE primary IP address to primary-ip" << endl; - cout << "create-zone ZONE [nsname] Create empty zone ZONE" << endl; - cout << "deactivate-tsig-key ZONE NAME {primary|secondary}" << endl; - cout << " Disable TSIG authenticated AXFR using the key NAME for ZONE" << endl; - cout << "deactivate-zone-key ZONE KEY-ID Deactivate the key with key id KEY-ID in ZONE" << endl; - cout << "delete-rrset ZONE NAME TYPE Delete named RRSET from zone" << endl; - cout << "delete-tsig-key NAME Delete TSIG key (warning! will not unmap key!)" << endl; - cout << "delete-zone ZONE Delete the zone" << endl; - cout << "disable-dnssec ZONE Deactivate all keys and unset PRESIGNED in ZONE" << endl; - cout << "edit-zone ZONE Edit zone contents using $EDITOR" << endl; - cout << "export-zone-dnskey ZONE KEY-ID Export to stdout the public DNSKEY described" << endl; - cout << "export-zone-ds ZONE Export to stdout all KSK DS records for ZONE" << endl; - cout << "export-zone-key ZONE KEY-ID Export to stdout the private key described" << endl; - cout << "export-zone-key-pem ZONE KEY-ID Export to stdout in PEM the private key described" << endl; - cout << "generate-tsig-key NAME ALGORITHM Generate new TSIG key" << endl; - cout << "generate-zone-key {zsk|ksk} [ALGORITHM] [BITS]" << endl; - cout << " Generate a ZSK or KSK to stdout with specified ALGORITHM and BITS" << endl; - cout << "get-meta ZONE [KIND ...] Get zone metadata. If no KIND given, lists all known" << endl; - cout << "hash-password [WORK FACTOR] Ask for a plaintext password or api key and output a hashed and salted version" << endl; - cout << "hash-zone-record ZONE RNAME Calculate the NSEC3 hash for RNAME in ZONE" << endl; -#ifdef HAVE_P11KIT1 - cout << "hsm assign ZONE ALGORITHM {ksk|zsk} MODULE SLOT PIN LABEL" << endl << - " Assign a hardware signing module to a ZONE" << endl; - cout << "hsm create-key ZONE KEY-ID [BITS] Create a key using hardware signing module for ZONE (use assign first)" << endl; - cout << " BITS defaults to 2048" << endl; -#endif - cout << "increase-serial ZONE Increases the SOA-serial by 1. Uses SOA-EDIT" << endl; - cout << "import-tsig-key NAME ALGORITHM KEY Import TSIG key" << endl; - cout << "import-zone-key ZONE FILE Import from a file a private key, ZSK or KSK" << endl; - cout << " [active|inactive] [ksk|zsk] [published|unpublished] Defaults to KSK, active and published" << endl; - cout << "import-zone-key-pem ZONE FILE Import a private key from a PEM file" << endl; - cout << " ALGORITHM {ksk|zsk}" << endl; - cout << "ipdecrypt IP passphrase/key [key] Decrypt IP address using passphrase or base64 key" << endl; - cout << "ipencrypt IP passphrase/key [key] Encrypt IP address using passphrase or base64 key" << endl; - cout << "load-zone ZONE FILE Load ZONE from FILE, possibly creating zone or atomically" << endl; - cout << " replacing contents" << endl; - cout << "list-algorithms [with-backend] List all DNSSEC algorithms supported, optionally also listing the crypto library used" << endl; - cout << "list-keys [ZONE] List DNSSEC keys for ZONE. When ZONE is unset, display all keys for all active zones" << endl; - cout << " --verbose or -v will also include the keys for disabled or empty zones" << endl; - cout << "list-zone ZONE List zone contents" << endl; - cout << "list-all-zones [primary|secondary|native|producer|consumer]" << endl; - cout << " List all active zone names. --verbose or -v will also include disabled or empty zones" << endl; - cout << "list-member-zones CATALOG List all members of catalog zone CATALOG" << endl; - - cout << "list-tsig-keys List all TSIG keys" << endl; - cout << "publish-zone-key ZONE KEY-ID Publish the zone key with key id KEY-ID in ZONE" << endl; - cout << "rectify-zone ZONE [ZONE ..] Fix up DNSSEC fields (order, auth)" << endl; - cout << "rectify-all-zones [quiet] Rectify all zones. Optionally quiet output with errors only" << endl; - cout << "remove-zone-key ZONE KEY-ID Remove key with KEY-ID from ZONE" << endl; - cout << "replace-rrset ZONE NAME TYPE [ttl] Replace named RRSET from zone" << endl; - cout << " content [content..]" << endl; - cout << "secure-all-zones [increase-serial] Secure all zones without keys" << endl; - cout << "secure-zone ZONE [ZONE ..] Add DNSSEC to zone ZONE" << endl; - cout << "set-kind ZONE KIND Change the kind of ZONE to KIND (primary, secondary, native, producer, consumer)" << endl; - cout << "set-options-json ZONE JSON Change the options of ZONE to JSON" << endl; - cout << "set-option ZONE Set or remove an option for ZONE Providing an empty value removes an option" << endl; - cout << " [producer|consumer]" << endl; - cout << " [coo|unique|group] VALUE" << endl; - cout << " [VALUE ...]" << endl; - cout << "set-catalog ZONE CATALOG Change the catalog of ZONE to CATALOG. Setting CATALOG to an empty "" removes ZONE from the catalog it is in" << endl; - cout << "set-account ZONE ACCOUNT Change the account (owner) of ZONE to ACCOUNT" << endl; - cout << "set-nsec3 ZONE ['PARAMS' [narrow]] Enable NSEC3 with PARAMS. Optionally narrow" << endl; - cout << "set-presigned ZONE Use presigned RRSIGs from storage" << endl; - cout << "set-publish-cdnskey ZONE [delete] Enable sending CDNSKEY responses for ZONE. Add 'delete' to publish a CDNSKEY with a" << endl; - cout << " DNSSEC delete algorithm" << endl; - cout << "set-publish-cds ZONE [DIGESTALGOS] Enable sending CDS responses for ZONE, using DIGESTALGOS as signature algorithms" << endl; - cout << " DIGESTALGOS should be a comma separated list of numbers, it is '2' by default" << endl; - cout << "add-meta ZONE KIND VALUE Add zone metadata, this adds to the existing KIND" << endl; - cout << " [VALUE ...]" << endl; - cout << "set-meta ZONE KIND [VALUE] [VALUE] Set zone metadata, optionally providing a value. *No* value clears meta" << endl; - cout << " Note - this will replace all metadata records of KIND!" << endl; - cout << "show-zone ZONE Show DNSSEC (public) key details about a zone" << endl; - cout << "unpublish-zone-key ZONE KEY-ID Unpublish the zone key with key id KEY-ID in ZONE" << endl; - cout << "unset-nsec3 ZONE Switch back to NSEC" << endl; - cout << "unset-presigned ZONE No longer use presigned RRSIGs" << endl; - cout << "unset-publish-cdnskey ZONE Disable sending CDNSKEY responses for ZONE" << endl; - cout << "unset-publish-cds ZONE Disable sending CDS responses for ZONE" << endl; - cout << "test-schema ZONE Test DB schema - will create ZONE" << endl; - cout << "raw-lua-from-content TYPE CONTENT Display record contents in a form suitable for dnsdist's `SpoofRawAction`" << endl; - cout << "zonemd-verify-file ZONE FILE Validate ZONEMD for ZONE" << endl; - cout << "lmdb-get-backend-version Get schema version supported by backend" << endl; - cout << desc << endl; - +static int verifyCrypto(vector& cmds) +{ + if(cmds.size() != 2) { + cerr << "Syntax: pdnsutil verify-crypto FILE"<()); - - if (cmds.at(0) == "lmdb-get-backend-version") { - cout << "5" << endl; // FIXME this should reuse the constant from lmdbbackend but that is currently a #define in a .cc +static int showZone(vector& cmds) +{ + if(cmds.size() != 2) { + cerr << "Syntax: pdnsutil show-zone ZONE"<(cmds.at(1)))) - return 0; + DNSSECKeeper dk; + if (!showZone(dk, DNSName(cmds.at(1)))) return 1; - } + return 0; +} - if (cmds.at(0) == "ipencrypt" || cmds.at(0) == "ipdecrypt") { - if (cmds.size() < 3 || (cmds.size() == 4 && cmds.at(3) != "key")) { - cerr<<"Syntax: pdnsutil [ipencrypt|ipdecrypt] IP passphrase [key]"<& cmds) +{ + if(cmds.size() != 2) { + cerr << "Syntax: pdnsutil export-zone-ds ZONE"< 2) { - cerr<<"Syntax: pdnsutil list-algorithms [with-backend]"<& cmds) +{ + if(cmds.size() != 2) { + cerr << "Syntax: pdnsutil disable-dnssec ZONE"< statements; - stringtok(statements, sqlCreate, ";"); - for(const string& statement : statements) { - db.execute(statement); - } - } - catch(SSqlException& se) { - throw PDNSException("Error creating database in BIND backend: "+se.txtReason()); - } - return 0; -#else - cerr<<"bind-dnssec-db requires building PowerDNS with SQLite3"<serialize(DNSName(), true))<& cmds) +{ + if(cmds.size() != 3) { + cerr << "Syntax: pdnsutil activate-zone-key ZONE KEY-ID"< 1) { - try { - pdns::checked_stoi_into(workFactor, cmds.at(1)); - } - catch (const std::exception& e) { - cerr<<"Unable to parse the supplied work factor: "<= 2 && cmds.at(1) == "quiet"); - if (!rectifyAllZones(dk, quiet)) { - return 1; - } - } - else if (cmds.at(0) == "check-zone") { - if(cmds.size() != 2) { - cerr << "Syntax: pdnsutil check-zone ZONE"< 1 ? cmds.at(1) : ""); + if (!dk.activateKey(zone, id)) { + cerr<<"Activation of key failed"<= 2 ? cmds.at(1) : "") == "exit-on-error"); - return checkAllZones(dk, exitOnError); + return 0; +} + +static int deactivateZoneKey(vector& cmds) +{ + if(cmds.size() != 3) { + cerr << "Syntax: pdnsutil deactivate-zone-key ZONE KEY-ID"< 2) { - cerr << "Syntax: pdnsutil list-all-zones [primary|secondary|native|producer|consumer]" << endl; - return 0; - } - if (cmds.size() == 2) - return listAllZones(cmds.at(1)); - return listAllZones(); + DNSName zone(cmds.at(1)); + auto id = pdns::checked_stoi(cmds.at(2)); + if(!id) + { + cerr<<"Invalid KEY-ID"<& cmds) +{ + if(cmds.size() != 3) { + cerr << "Syntax: pdnsutil publish-zone-key ZONE KEY-ID"< 3) ? cmds.at(3) : "", pdns::checked_stoi(cmds.at(2))); + if (!dk.publishKey(zone, id)) { + cerr<<"Publishing of key failed"<& cmds) +{ + if(cmds.size() != 3) { + cerr << "Syntax: pdnsutil unpublish-zone-key ZONE KEY-ID"<& cmds) +{ + if(cmds.size() < 3 ) { + cerr << "Syntax: pdnsutil add-zone-key ZONE [zsk|ksk] [BITS] [active|inactive] [rsasha1|rsasha1-nsec3-sha1|rsasha256|rsasha512|ecdsa256|ecdsa384"; +#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO_ED25519) + cerr << "|ed25519"; +#endif +#if defined(HAVE_LIBCRYPTO_ED448) + cerr << "|ed448"; +#endif + cerr << "]"<(cmds.at(2)); - if(!id) - { - cerr<<"Invalid KEY-ID"< 0) { + algorithm = tmp_algo; } - return 0; - } - else if (cmds.at(0) == "publish-zone-key") { - if(cmds.size() != 3) { - cerr << "Syntax: pdnsutil publish-zone-key ZONE KEY-ID"<(cmds.at(n)) != 0) { + pdns::checked_stoi_into(bits, cmds.at(n)); } - DNSName zone(cmds.at(1)); - unsigned int id = atoi(cmds.at(2).c_str()); // if you make this pdns::checked_stoi, the error gets worse - if(!id) - { - cerr << "Invalid KEY-ID '" << cmds.at(2) << "'" << endl; - return 1; + else { + cerr << "Unknown algorithm, key flag or size '" << cmds.at(n) << "'" << endl; + return EXIT_FAILURE; } + } + int64_t id{-1}; //NOLINT(readability-identifier-length) + if (!dk.addKey(zone, keyOrZone, algorithm, id, bits, active, published)) { + cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<& cmds) +{ + if(cmds.size() < 3) { + cerr<<"Syntax: pdnsutil remove-zone-key ZONE KEY-ID"<(cmds.at(2)); - if (!dk.removeKey(zone, id)) { - cerr<<"Cannot remove key " << id << " from " << zone <(cmds.at(2)); + if (!dk.removeKey(zone, id)) { + cerr<<"Cannot remove key " << id << " from " << zone <& cmds) +{ + if(cmds.size() != 2) { + cerr<<"Syntax: pdnsutil delete-zone ZONE"<& cmds) +{ + if(cmds.size() != 2 && cmds.size()!=3 ) { + cerr<<"Syntax: pdnsutil create-zone ZONE [nsname]"< 2 ? DNSName(cmds.at(2)) : DNSName()); + return createZone(DNSName(cmds.at(1)), cmds.size() > 2 ? DNSName(cmds.at(2)) : DNSName()); +} + +static int createSecondaryZone(vector& cmds) +{ + if(cmds.size() < 3 ) { + cerr << "Syntax: pdnsutil create-secondary-zone ZONE primary-ip [primary-ip..]" << endl; + return 0; } - else if (cmds.at(0) == "create-secondary-zone") { - if(cmds.size() < 3 ) { - cerr << "Syntax: pdnsutil create-secondary-zone ZONE primary-ip [primary-ip..]" << endl; - return 0; - } - return createSecondaryZone(cmds); + UeberBackend B; + DomainInfo di; + DNSName zone(cmds.at(1)); + if (B.getDomainInfo(zone, di)) { + cerr << "Zone '" << zone << "' exists already" << endl; + return EXIT_FAILURE; } - else if (cmds.at(0) == "change-secondary-zone-primary") { - if(cmds.size() < 3 ) { - cerr << "Syntax: pdnsutil change-secondary-zone-primary ZONE primary-ip [primary-ip..]" << endl; - return 0; - } - return changeSecondaryZonePrimary(cmds); + vector primaries; + for (unsigned i=2; i < cmds.size(); i++) { + primaries.emplace_back(cmds.at(i), 53); } - else if (cmds.at(0) == "add-record") { - if(cmds.size() < 5) { - cerr< 3 ? cmds.at(3) : "")); + return EXIT_SUCCESS; +} + +static int changeSecondaryZonePrimary(vector& cmds) +{ + if(cmds.size() < 3 ) { + cerr << "Syntax: pdnsutil change-secondary-zone-primary ZONE primary-ip [primary-ip..]" << endl; + return 0; } - else if (cmds.at(0) == "remove-autoprimary") { - if(cmds.size() < 3) { - cerr << "Syntax: pdnsutil remove-autoprimary IP NAMESERVER" << endl; - return 0; - } - exit(removeAutoPrimary(cmds.at(1), cmds.at(2))); + UeberBackend B; + DomainInfo di; + DNSName zone(cmds.at(1)); + if (!B.getDomainInfo(zone, di)) { + cerr << "Zone '" << zone << "' doesn't exist" << endl; + return EXIT_FAILURE; } - else if (cmds.at(0) == "list-autoprimaries") { - exit(listAutoPrimaries()); + vector primaries; + for (unsigned i=2; i < cmds.size(); i++) { + primaries.emplace_back(cmds.at(i), 53); } - else if (cmds.at(0) == "replace-rrset") { - if(cmds.size() < 5) { - cerr<setPrimaries(zone, primaries); + return EXIT_SUCCESS; } - else if (cmds.at(0) == "delete-rrset") { - if(cmds.size() != 4) { - cerr<<"Syntax: pdnsutil delete-rrset ZONE name type"<& cmds) +{ + if(cmds.size() < 5) { + cerr<& cmds) +{ + if(cmds.size() < 3) { + cerr << "Syntax: pdnsutil add-autoprimary IP NAMESERVER [account]" << endl; + return 0; } - else if (cmds.at(0) == "clear-zone") { - if(cmds.size() != 2) { - cerr<<"Syntax: pdnsutil clear-zone ZONE"< 3 ? cmds.at(3) : ""); +} - return clearZone(DNSName(cmds.at(1))); +static int removeAutoprimary(vector& cmds) +{ + if(cmds.size() < 3) { + cerr << "Syntax: pdnsutil remove-autoprimary IP NAMESERVER" << endl; + return 0; } - else if (cmds.at(0) == "list-keys") { - if(cmds.size() > 2) { - cerr<<"Syntax: pdnsutil list-keys [ZONE]"<& cmds) +{ + return listAutoPrimaries(); +} + +static int replaceRRSet(vector& cmds) +{ + if(cmds.size() < 5) { + cerr<& cmds) +{ + if(cmds.size() != 4) { + cerr<<"Syntax: pdnsutil delete-rrset ZONE name type"< mustRectify; - unsigned int zoneErrors=0; - for(unsigned int n = 1; n < cmds.size(); ++n) { - DNSName zone(cmds.at(n)); - dk.startTransaction(zone, -1); - if(secureZone(dk, zone)) { - mustRectify.push_back(zone); - } else { - zoneErrors++; - } - dk.commitTransaction(); - } + return deleteRRSet(cmds.at(1), cmds.at(2), cmds.at(3)); +} + +static int listZone(vector& cmds) +{ + if(cmds.size() != 2) { + cerr<<"Syntax: pdnsutil list-zone ZONE"<& cmds) +{ + if(cmds.size() != 2) { + cerr<<"Syntax: pdnsutil edit-zone ZONE"<= 2 && !pdns_iequals(cmds.at(1), "increase-serial")) { - cerr << "Syntax: pdnsutil secure-all-zones [increase-serial]"< domainInfo; - B.getAllDomains(&domainInfo, false, false); - - unsigned int zonesSecured=0, zoneErrors=0; - for(const DomainInfo& di : domainInfo) { - if(!dk.isSecuredZone(di.zone)) { - cout<<"Securing "<& cmds) +{ + if(cmds.size() != 2) { + cerr<<"Syntax: pdnsutil clear-zone ZONE"<& cmds) +{ + if(cmds.size() > 2) { + cerr<<"Syntax: pdnsutil list-keys [ZONE]"<& cmds) +{ + if(cmds.size() < 3) { + cerr<<"Syntax: pdnsutil load-zone ZONE FILENAME [ZONE FILENAME] .."<& cmds) +{ + if(cmds.size() < 2) { + cerr << "Syntax: pdnsutil secure-zone ZONE"< 5 && (cmds.at(3) != "group"))) { - cerr << "Syntax: pdnsutil set-option ZONE [producer|consumer] [coo|unique|group] VALUE [VALUE ...]1" << endl; - return EXIT_FAILURE; + DNSSECKeeper dk; + vector mustRectify; + unsigned int zoneErrors=0; + for(unsigned int n = 1; n < cmds.size(); ++n) { + DNSName zone(cmds.at(n)); + dk.startTransaction(zone, -1); + if(secureZone(dk, zone)) { + mustRectify.push_back(zone); + } else { + zoneErrors++; } + dk.commitTransaction(); + } - if ((cmds.at(2) != "producer" && cmds.at(2) != "consumer") || (cmds.at(3) != "coo" && cmds.at(3) != "unique" && cmds.at(3) != "group")) { - cerr << "Syntax: pdnsutil set-option ZONE [producer|consumer] [coo|unique|group] VALUE [VALUE ...]" << endl; - return EXIT_FAILURE; - } + for(const auto& zone : mustRectify) + rectifyZone(dk, zone); + + if (zoneErrors) { + return 1; + } + return 0; +} + +static int secureAllZones(vector& cmds) +{ + if (cmds.size() >= 2 && !pdns_iequals(cmds.at(1), "increase-serial")) { + cerr << "Syntax: pdnsutil secure-all-zones [increase-serial]"< values; - for (unsigned int n = 4; n < cmds.size(); ++n) { - if (!cmds.at(n).empty()) { - values.insert(cmds.at(n)); + vector domainInfo; + B.getAllDomains(&domainInfo, false, false); + + unsigned int zonesSecured=0, zoneErrors=0; + for(const DomainInfo& di : domainInfo) { + if(!dk.isSecuredZone(di.zone)) { + cout<<"Securing "<& cmds) +{ + if(cmds.size() != 3) { + cerr<<"Syntax: pdnsutil set-kind ZONE KIND"<& cmds) +{ + if (cmds.size() != 3) { + cerr << "Syntax: pdnsutil set-options ZONE VALUE" << endl; + return EXIT_FAILURE; } - else if (cmds.at(0) == "set-nsec3") { - if(cmds.size() < 2) { - cerr<<"Syntax: pdnsutil set-nsec3 ZONE 'params' [narrow]"< 2 ? cmds.at(2) : "1 0 0 -"; - bool narrow = cmds.size() > 3 && cmds.at(3) == "narrow"; - NSEC3PARAMRecordContent ns3pr(nsec3params); - DNSName zone(cmds.at(1)); - if (zone.wirelength() > 222) { - cerr<<"Cannot enable NSEC3 for " << zone << " as it is too long (" << zone.wirelength() << " bytes, maximum is 222 bytes)"<& cmds) +{ + if (cmds.size() < 5 || (cmds.size() > 5 && (cmds.at(3) != "group"))) { + cerr << "Syntax: pdnsutil set-option ZONE [producer|consumer] [coo|unique|group] VALUE [VALUE ...]1" << endl; + return EXIT_FAILURE; } - else if (cmds.at(0) == "set-presigned") { - if(cmds.size() < 2) { - cerr<<"Syntax: pdnsutil set-presigned ZONE"< values; + for (unsigned int n = 4; n < cmds.size(); ++n) { + if (!cmds.at(n).empty()) { + values.insert(cmds.at(n)); } - return 0; } - else if (cmds.at(0) == "set-publish-cds") { - if(cmds.size() < 2) { - cerr<<"Syntax: pdnsutil set-publish-cds ZONE [DIGESTALGOS]"<& cmds) +{ + if (cmds.size() != 3) { + cerr << "Syntax: pdnsutil set-catalog ZONE CATALOG" << endl; return 0; } - else if (cmds.at(0) == "unset-publish-cdnskey") { - if(cmds.size() < 2) { - cerr<<"Syntax: pdnsutil unset-publish-cdnskey ZONE"<& cmds) +{ + if(cmds.size() != 3) { + cerr<<"Syntax: pdnsutil set-account ZONE ACCOUNT"<& cmds) +{ + if(cmds.size() < 2) { + cerr<<"Syntax: pdnsutil set-nsec3 ZONE 'params' [narrow]"< 2 ? cmds.at(2) : "1 0 0 -"; + bool narrow = cmds.size() > 3 && cmds.at(3) == "narrow"; + NSEC3PARAMRecordContent ns3pr(nsec3params); - cout< 222) { + cerr<<"Cannot enable NSEC3 for " << zone << " as it is too long (" << zone.wirelength() << " bytes, maximum is 222 bytes)"<& cmds) +{ + if(cmds.size() < 2) { + cerr<<"Syntax: pdnsutil set-presigned ZONE"<(cmds.at(2)); - DNSSECPrivateKey dpk = dk.getKeyById(DNSName(zone), id); - cout << dpk.getKey()->convertToISC() << endl; + DNSSECKeeper dk; + if (!dk.setPresigned(DNSName(cmds.at(1)))) { + cerr << "Could not set presigned for " << cmds.at(1) << " (is DNSSEC enabled in your backend?)" << endl; + return 1; } - else if (cmds.at(0) == "export-zone-key-pem") { - if (cmds.size() < 3) { - cerr << "Syntax: pdnsutil export-zone-key-pem ZONE KEY-ID" << endl; - return 1; - } + return 0; +} - string zone = cmds.at(1); - auto id = pdns::checked_stoi(cmds.at(2)); - DNSSECPrivateKey dpk = dk.getKeyById(DNSName(zone), id); - dpk.getKey()->convertToPEMFile(*stdout); +static int setPublishCDNSKey(vector& cmds) +{ + if (cmds.size() < 2 || (cmds.size() == 3 && cmds.at(2) != "delete")) { + cerr<<"Syntax: pdnsutil set-publish-cdnskey ZONE [delete]"<(cmds.at(3)); + return 0; +} - errno = 0; - pdns::UniqueFilePtr filePtr{std::fopen(filename.c_str(), "r")}; - if (filePtr == nullptr) { - auto errMsg = pdns::getMessageFromErrno(errno); - throw runtime_error("Failed to open PEM file `" + filename + "`: " + errMsg); - } +static int setPublishCDs(vector& cmds) +{ + if(cmds.size() < 2) { + cerr<<"Syntax: pdnsutil set-publish-cds ZONE [DIGESTALGOS]"< key{DNSCryptoKeyEngine::makeFromPEMFile(drc, algorithm, *filePtr, filename)}; - if (!key) { - cerr << "Could not convert key from PEM to internal format" << endl; - return 1; - } + // If DIGESTALGOS is unset + if(cmds.size() == 2) + cmds.push_back("2"); - DNSSECPrivateKey dpk; + DNSSECKeeper dk; + if (!dk.setPublishCDS(DNSName(cmds.at(1)), cmds.at(2))) { + cerr << "Could not set publishing for CDS records for " << cmds.at(1) << endl; + return 1; + } + return 0; +} - uint8_t algo = 0; - pdns::checked_stoi_into(algo, cmds.at(3)); - if (algo == DNSSECKeeper::RSASHA1NSEC3SHA1) { - algo = DNSSECKeeper::RSASHA1; - } +static int unsetPresigned(vector& cmds) +{ + if(cmds.size() < 2) { + cerr<<"Syntax: pdnsutil unset-presigned ZONE"<& cmds) +{ + if(cmds.size() < 2) { + cerr<<"Syntax: pdnsutil unset-publish-cdnskey ZONE"< 4) { - if (pdns_iequals(cmds.at(4), "ZSK")) { - flags = 256; - } - else if (pdns_iequals(cmds.at(4), "KSK")) { - flags = 257; - } - else { - cerr << "Unknown key flag '" << cmds.at(4) << "'" << endl; - return 1; - } - } - else { - flags = 257; // ksk - } - dpk.setKey(key, flags, algo); +static int unsetPublishCDs(vector& cmds) +{ + if(cmds.size() < 2) { + cerr<<"Syntax: pdnsutil unset-publish-cds ZONE"<& cmds) +{ + if(cmds.size() < 3) { + cerr<<"Syntax: pdnsutil hash-zone-record ZONE RNAME"<& cmds) +{ + if(cmds.size() < 2) { + cerr<<"Syntax: pdnsutil unset-nsec3 ZONE"< key(DNSCryptoKeyEngine::makeFromISCFile(drc, fname.c_str())); - - uint16_t flags = 257; - bool active=true; - bool published=true; - - for(unsigned int n = 3; n < cmds.size(); ++n) { - if (pdns_iequals(cmds.at(n), "ZSK")) - flags = 256; - else if (pdns_iequals(cmds.at(n), "KSK")) - flags = 257; - else if (pdns_iequals(cmds.at(n), "active")) - active = true; - else if (pdns_iequals(cmds.at(n), "passive") || pdns_iequals(cmds.at(n), "inactive")) // passive eventually needs to be removed - active = false; - else if (pdns_iequals(cmds.at(n), "published")) - published = true; - else if (pdns_iequals(cmds.at(n), "unpublished")) - published = false; - else { - cerr << "Unknown key flag '" << cmds.at(n) << "'" << endl; - return 1; - } - } + DNSSECKeeper dk; + if (!dk.unsetNSEC3PARAM(DNSName(cmds.at(1)))) { + cerr << "Cannot unset NSEC3 param for " << cmds.at(1) << endl; + return 1; + } + cerr<<"Done, please rectify your zone if your backend needs it (or reload it if you are using the bindbackend)"<getAlgorithm(); - if (algo == DNSSECKeeper::RSASHA1NSEC3SHA1) { - algo = DNSSECKeeper::RSASHA1; - } - dpk.setKey(key, flags, algo); + return 0; +} - int64_t id{-1}; - if (!dk.addKey(DNSName(zone), dpk, id, active, published)) { - cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<& cmds) +{ + if (cmds.size() < 3) { + cerr << "Syntax: pdnsutil export-zone-key ZONE KEY-ID" << endl; + return 1; } - else if (cmds.at(0) == "export-zone-dnskey") { - if(cmds.size() < 3) { - cerr<<"Syntax: pdnsutil export-zone-dnskey ZONE KEY-ID"<(cmds.at(2)); - DNSSECPrivateKey dpk=dk.getKeyById(zone, id); - cout << zone<<" IN DNSKEY "<(cmds.at(2)); + DNSSECPrivateKey dpk = dk.getKeyById(DNSName(zone), id); + cout << dpk.getKey()->convertToISC() << endl; + return 0; +} + +static int exportZoneKeyPEM(vector& cmds) +{ + if (cmds.size() < 3) { + cerr << "Syntax: pdnsutil export-zone-key-pem ZONE KEY-ID" << endl; + return 1; } - else if (cmds.at(0) == "generate-zone-key") { - if(cmds.size() < 2 ) { - cerr << "Syntax: pdnsutil generate-zone-key zsk|ksk [rsasha1|rsasha1-nsec3-sha1|rsasha256|rsasha512|ecdsa256|ecdsa384"; -#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO_ED25519) - cerr << "|ed25519"; -#endif -#if defined(HAVE_LIBCRYPTO_ED448) - cerr << "|ed448"; -#endif - cerr << "] [bits]"< 0) { - algorithm = tmp_algo; - } - else if (pdns::checked_stoi(cmds.at(n)) != 0) - pdns::checked_stoi_into(bits, cmds.at(n)); - else { - cerr << "Unknown algorithm, key flag or size '" << cmds.at(n) << "'" << endl; - return 0; - } - } - cerr<<"Generating a " << (keyOrZone ? "KSK" : "ZSK")<<" with algorithm = "< dpk(DNSCryptoKeyEngine::make(algorithm)); - if(!bits) { - if(algorithm <= 10) - bits = keyOrZone ? 2048 : 1024; - else { - if(algorithm == DNSSECKeeper::ECCGOST || algorithm == DNSSECKeeper::ECDSA256 || algorithm == DNSSECKeeper::ED25519) - bits = 256; - else if(algorithm == DNSSECKeeper::ECDSA384) - bits = 384; - else if(algorithm == DNSSECKeeper::ED448) - bits = 456; - else { - throw runtime_error("Can not guess key size for algorithm "+std::to_string(algorithm)); - } - } - } - dpk->create(bits); - DNSSECPrivateKey dspk; - dspk.setKey(dpk, keyOrZone ? 257 : 256, algorithm); + DNSSECKeeper dk; + string zone = cmds.at(1); + auto id = pdns::checked_stoi(cmds.at(2)); + DNSSECPrivateKey dpk = dk.getKeyById(DNSName(zone), id); + dpk.getKey()->convertToPEMFile(*stdout); + return 0; +} - // print key to stdout - cout << "Flags: " << dspk.getFlags() << endl << - dspk.getKey()->convertToISC() << endl; +static int increaseSerial(vector& cmds) +{ + if (cmds.size() < 2) { + cerr << "Syntax: pdnsutil increase-serial ZONE" << endl; + return 1; } - else if (cmds.at(0) == "generate-tsig-key") { - string usage = "Syntax: " + cmds.at(0) + " name (hmac-md5|hmac-sha1|hmac-sha224|hmac-sha256|hmac-sha384|hmac-sha512)"; - if (cmds.size() < 3) { - cerr << usage << endl; - return 0; - } - DNSName name(cmds.at(1)); - DNSName algo(cmds.at(2)); - string key; - try { - key = makeTSIGKey(algo); - } catch(const PDNSException& e) { - cerr << "Could not create new TSIG key " << name << " " << algo << ": "<< e.reason << endl; - return 1; - } + DNSSECKeeper dk; + return increaseSerial(DNSName(cmds.at(1)), dk); +} - UeberBackend B("default"); - if (B.setTSIGKey(name, DNSName(algo), key)) { // you are feeling bored, put up DNSName(algo) up earlier - cout << "Create new TSIG key " << name << " " << algo << " " << key << endl; - } else { - cerr << "Failure storing new TSIG key " << name << " " << algo << " " << key << endl; - return 1; - } - return 0; +static int importZoneKeyPEM(vector& cmds) +{ + if (cmds.size() < 4) { + cerr << "Syntax: pdnsutil import-zone-key-pem ZONE FILE ALGORITHM {ksk|zsk}" << endl; + return 1; } - else if (cmds.at(0) == "import-tsig-key") { - if (cmds.size() < 4) { - cerr << "Syntax: " << cmds.at(0) << " name algorithm key" << endl; - return 0; - } - DNSName name(cmds.at(1)); - string algo = cmds.at(2); - string key = cmds.at(3); - UeberBackend B("default"); - if (B.setTSIGKey(name, DNSName(algo), key)) { - cout << "Imported TSIG key " << name << " " << algo << endl; - } - else { - cerr << "Failure importing TSIG key " << name << " " << algo << endl; - return 1; - } - return 0; + const string zone = cmds.at(1); + const string filename = cmds.at(2); + const auto algorithm = pdns::checked_stoi(cmds.at(3)); + + errno = 0; + pdns::UniqueFilePtr filePtr{std::fopen(filename.c_str(), "r")}; + if (filePtr == nullptr) { + auto errMsg = pdns::getMessageFromErrno(errno); + throw runtime_error("Failed to open PEM file `" + filename + "`: " + errMsg); } - else if (cmds.at(0) == "delete-tsig-key") { - if (cmds.size() < 2) { - cerr << "Syntax: " << cmds.at(0) << " name" << endl; - return 0; - } - DNSName name(cmds.at(1)); - UeberBackend B("default"); - if (B.deleteTSIGKey(name)) { - cout << "Deleted TSIG key " << name << endl; - } - else { - cerr << "Failure deleting TSIG key " << name << endl; - return 1; - } - return 0; + DNSKEYRecordContent drc; + shared_ptr key{DNSCryptoKeyEngine::makeFromPEMFile(drc, algorithm, *filePtr, filename)}; + if (!key) { + cerr << "Could not convert key from PEM to internal format" << endl; + return 1; } - else if (cmds.at(0) == "list-tsig-keys") { - std::vector keys; - UeberBackend B("default"); - if (B.getTSIGKeys(keys)) { - for (const TSIGKey& key : keys) { - cout << key.name.toString() << " " << key.algorithm.toString() << " " << key.key << endl; - } - } - return 0; + + DNSSECPrivateKey dpk; + + uint8_t algo = 0; + pdns::checked_stoi_into(algo, cmds.at(3)); + if (algo == DNSSECKeeper::RSASHA1NSEC3SHA1) { + algo = DNSSECKeeper::RSASHA1; } - else if (cmds.at(0) == "activate-tsig-key") { - string metaKey; - if (cmds.size() < 4) { - cerr << "Syntax: " << cmds.at(0) << " ZONE NAME {primary|secondary}" << endl; - return 0; - } - DNSName zname(cmds.at(1)); - string name = cmds.at(2); - if (cmds.at(3) == "primary" || cmds.at(3) == "producer") - metaKey = "TSIG-ALLOW-AXFR"; - else if (cmds.at(3) == "secondary" || cmds.at(3) == "consumer") - metaKey = "AXFR-MASTER-TSIG"; - else { - cerr << "Invalid parameter '" << cmds.at(3) << "', expected primary or secondary type" << endl; - return 1; - } - UeberBackend B("default"); - DomainInfo di; - if (!B.getDomainInfo(zname, di)) { - cerr << "Zone '" << zname << "' does not exist" << endl; - return 1; - } - std::vector meta; - if (!B.getDomainMetadata(zname, metaKey, meta)) { - cerr << "Failure enabling TSIG key " << name << " for " << zname << endl; - return 1; - } - bool found = false; - for (const std::string& tmpname : meta) { - if (tmpname == name) { - found = true; - break; - } + + cerr << std::to_string(algo) << endl; + + uint16_t flags = 0; + if (cmds.size() > 4) { + if (pdns_iequals(cmds.at(4), "ZSK")) { + flags = 256; } - if (!found) - meta.push_back(name); - if (B.setDomainMetadata(zname, metaKey, meta)) { - cout << "Enabled TSIG key " << name << " for " << zname << endl; + else if (pdns_iequals(cmds.at(4), "KSK")) { + flags = 257; } else { - cerr << "Failure enabling TSIG key " << name << " for " << zname << endl; + cerr << "Unknown key flag '" << cmds.at(4) << "'" << endl; return 1; } - return 0; } - else if (cmds.at(0) == "deactivate-tsig-key") { - string metaKey; - if (cmds.size() < 4) { - cerr << "Syntax: " << cmds.at(0) << " ZONE NAME {primary|secondary|producer|consumer}" << endl; - return 0; - } - DNSName zname(cmds.at(1)); - string name = cmds.at(2); - if (cmds.at(3) == "primary" || cmds.at(3) == "producer") - metaKey = "TSIG-ALLOW-AXFR"; - else if (cmds.at(3) == "secondary" || cmds.at(3) == "consumer") - metaKey = "AXFR-MASTER-TSIG"; - else { - cerr << "Invalid parameter '" << cmds.at(3) << "', expected primary or secondary type" << endl; - return 1; - } + else { + flags = 257; // ksk + } + dpk.setKey(key, flags, algo); - UeberBackend B("default"); - DomainInfo di; - if (!B.getDomainInfo(zname, di)) { - cerr << "Zone '" << zname << "' does not exist" << endl; - return 1; - } - std::vector meta; - if (!B.getDomainMetadata(zname, metaKey, meta)) { - cerr << "Failure disabling TSIG key " << name << " for " << zname << endl; - return 1; - } - std::vector::iterator iter = meta.begin(); - for (; iter != meta.end(); ++iter) - if (*iter == name) - break; - if (iter != meta.end()) - meta.erase(iter); - if (B.setDomainMetadata(zname, metaKey, meta)) { - cout << "Disabled TSIG key " << name << " for " << zname << endl; - } - else { - cerr << "Failure disabling TSIG key " << name << " for " << zname << endl; - return 1; - } - return 0; + DNSSECKeeper dk; + int64_t id{-1}; + if (!dk.addKey(DNSName(zone), dpk, id)) { + cerr << "Adding key failed, perhaps DNSSEC not enabled in configuration?" << endl; + return 1; } - else if (cmds.at(0) == "get-meta") { - UeberBackend B("default"); - if (cmds.size() < 2) { - cerr << "Syntax: " << cmds.at(0) << " zone [kind kind ..]" << endl; - return 1; - } - DNSName zone(cmds.at(1)); - vector keys; - DomainInfo di; - if (!B.getDomainInfo(zone, di)) { - cerr << "Invalid zone '" << zone << "'" << endl; - return 1; - } - - if (cmds.size() > 2) { - keys.assign(cmds.begin() + 2, cmds.end()); - std::cout << "Metadata for '" << zone << "'" << endl; - for(const auto& kind : keys) { - vector meta; - meta.clear(); - if (B.getDomainMetadata(zone, kind, meta)) { - cout << kind << " = " << boost::join(meta, ", ") << endl; - } - } - } else { - std::map > meta; - std::cout << "Metadata for '" << zone << "'" << endl; - B.getAllDomainMetadata(zone, meta); - for(const auto& each_meta: meta) { - cout << each_meta.first << " = " << boost::join(each_meta.second, ", ") << endl; - } + if (id == -1) { + cerr << std::to_string(id) << "Key was added, but backend does not support returning of key id" << endl; } - return 0; + else if (id < -1) { + cerr << std::to_string(id) << "Key was added, but there was a failure while returning the key id" << endl; } - else if (cmds.at(0) == "set-meta" || cmds.at(0) == "add-meta") { - if (cmds.size() < 3) { - cerr << "Syntax: " << cmds.at(0) << " ZONE KIND [VALUE VALUE ..]" << endl; - return 1; - } - DNSName zone(cmds.at(1)); - string kind = cmds.at(2); - const static std::array multiMetaWhitelist = {"ALLOW-AXFR-FROM", "ALLOW-DNSUPDATE-FROM", - "ALSO-NOTIFY", "TSIG-ALLOW-AXFR", "TSIG-ALLOW-DNSUPDATE", "GSS-ALLOW-AXFR-PRINCIPAL", - "PUBLISH-CDS"}; - bool clobber = true; - if (cmds.at(0) == "add-meta") { - clobber = false; - if (find(multiMetaWhitelist.begin(), multiMetaWhitelist.end(), kind) == multiMetaWhitelist.end() && kind.find("X-") != 0) { - cerr<<"Refusing to add metadata to single-value metadata "< meta(cmds.begin() + 3, cmds.end()); - return addOrSetMeta(zone, kind, meta, clobber); + else { + cout << std::to_string(id) << endl; } - else if (cmds.at(0) == "hsm") { -#ifdef HAVE_P11KIT1 - UeberBackend B("default"); - if (cmds.size() < 2) { - cerr << "Missing sub-command for pdnsutil hsm"<< std::endl; - return 0; - } - else if (cmds.at(1) == "assign") { - DNSCryptoKeyEngine::storvector_t storvect; - DomainInfo di; - std::vector keys; - - if (cmds.size() < 9) { - std::cout << "Usage: pdnsutil hsm assign ZONE ALGORITHM {ksk|zsk} MODULE TOKEN PIN LABEL (PUBLABEL)" << std::endl; - return 1; - } - - DNSName zone(cmds.at(2)); - - // verify zone - if (!B.getDomainInfo(zone, di)) { - cerr << "Unable to assign module to unknown zone '" << zone << "'" << std::endl; - return 1; - } + return 0; +} - int algorithm = DNSSECKeeper::shorthand2algorithm(cmds.at(3)); - if (algorithm<0) { - cerr << "Unable to use unknown algorithm '" << cmds.at(3) << "'" << std::endl; - return 1; - } +static int importZoneKey(vector& cmds) +{ + if(cmds.size() < 3) { + cerr<<"Syntax: pdnsutil import-zone-key ZONE FILE [ksk|zsk] [active|inactive]"< key(DNSCryptoKeyEngine::makeFromISCFile(drc, fname.c_str())); - bool keyOrZone = (cmds.at(4) == "ksk" ? true : false); - string module = cmds.at(5); - string slot = cmds.at(6); - string pin = cmds.at(7); - string label = cmds.at(8); - string pub_label; - if (cmds.size() > 9) - pub_label = cmds.at(9); - else - pub_label = label; - - std::ostringstream iscString; - iscString << "Private-key-format: v1.2" << std::endl << - "Algorithm: " << algorithm << std::endl << - "Engine: " << module << std::endl << - "Slot: " << slot << std::endl << - "PIN: " << pin << std::endl << - "Label: " << label << std::endl << - "PubLabel: " << pub_label << std::endl; - - DNSKEYRecordContent drc; - - shared_ptr dke(DNSCryptoKeyEngine::makeFromISCString(drc, iscString.str())); - if(!dke->checkKey()) { - cerr << "Invalid DNS Private Key in engine " << module << " slot " << slot << std::endl; - return 1; - } - DNSSECPrivateKey dpk; - dpk.setKey(dke, keyOrZone ? 257 : 256); + uint16_t flags = 257; + bool active=true; + bool published=true; - // make sure this key isn't being reused. - B.getDomainKeys(zone, keys); + for(unsigned int n = 3; n < cmds.size(); ++n) { + if (pdns_iequals(cmds.at(n), "ZSK")) + flags = 256; + else if (pdns_iequals(cmds.at(n), "KSK")) + flags = 257; + else if (pdns_iequals(cmds.at(n), "active")) + active = true; + else if (pdns_iequals(cmds.at(n), "passive") || pdns_iequals(cmds.at(n), "inactive")) // passive eventually needs to be removed + active = false; + else if (pdns_iequals(cmds.at(n), "published")) + published = true; + else if (pdns_iequals(cmds.at(n), "unpublished")) + published = false; + else { + cerr << "Unknown key flag '" << cmds.at(n) << "'" << endl; + return 1; + } + } - int64_t id{-1}; - for(DNSBackend::KeyData& kd : keys) { - if (kd.content == iscString.str()) { - // it's this one, I guess... - id = kd.id; - break; - } - } + DNSSECPrivateKey dpk; + uint8_t algo = key->getAlgorithm(); + if (algo == DNSSECKeeper::RSASHA1NSEC3SHA1) { + algo = DNSSECKeeper::RSASHA1; + } + dpk.setKey(key, flags, algo); - if (id > -1) { - cerr << "You have already assigned this key with ID=" << id << std::endl; - return 1; - } + DNSSECKeeper dk; + int64_t id{-1}; + if (!dk.addKey(DNSName(zone), dpk, id, active, published)) { + cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<& cmds) +{ + if(cmds.size() < 3) { + cerr<<"Syntax: pdnsutil export-zone-dnskey ZONE KEY-ID"<(cmds.at(2)); + DNSSECPrivateKey dpk=dk.getKeyById(zone, id); + cout << zone<<" IN DNSKEY "<& cmds) +{ + if(cmds.size() < 2 ) { + cerr << "Syntax: pdnsutil generate-zone-key zsk|ksk [rsasha1|rsasha1-nsec3-sha1|rsasha256|rsasha512|ecdsa256|ecdsa384"; +#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO_ED25519) + cerr << "|ed25519"; +#endif +#if defined(HAVE_LIBCRYPTO_ED448) + cerr << "|ed448"; +#endif + cerr << "] [bits]"< 0) { + algorithm = tmp_algo; + } + else if (pdns::checked_stoi(cmds.at(n)) != 0) + pdns::checked_stoi_into(bits, cmds.at(n)); + else { + cerr << "Unknown algorithm, key flag or size '" << cmds.at(n) << "'" << endl; return 0; } - else if (cmds.at(1) == "create-key") { + } + cerr<<"Generating a " << (keyOrZone ? "KSK" : "ZSK")<<" with algorithm = "< dpk(DNSCryptoKeyEngine::make(algorithm)); + if(!bits) { + if(algorithm <= 10) + bits = keyOrZone ? 2048 : 1024; + else { + if(algorithm == DNSSECKeeper::ECCGOST || algorithm == DNSSECKeeper::ECDSA256 || algorithm == DNSSECKeeper::ED25519) + bits = 256; + else if(algorithm == DNSSECKeeper::ECDSA384) + bits = 384; + else if(algorithm == DNSSECKeeper::ED448) + bits = 456; + else { + throw runtime_error("Can not guess key size for algorithm "+std::to_string(algorithm)); } + } + } + dpk->create(bits); + DNSSECPrivateKey dspk; + dspk.setKey(dpk, keyOrZone ? 257 : 256, algorithm); - pdns::checked_stoi_into(id, cmds.at(3)); - std::vector keys; - if (!B.getDomainKeys(zone, keys)) { - cerr << "No keys found for zone " << zone << std::endl; - return 1; - } + // print key to stdout + cout << "Flags: " << dspk.getFlags() << endl << + dspk.getKey()->convertToISC() << endl; + return 0; +} - std::unique_ptr dke = nullptr; - // lookup correct key - for(DNSBackend::KeyData &kd : keys) { - if (kd.id == id) { - // found our key. - DNSKEYRecordContent dkrc; - dke = DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content); - } - } +static int generateTSIGKey(vector& cmds) +{ + string usage = "Syntax: " + cmds.at(0) + " name (hmac-md5|hmac-sha1|hmac-sha224|hmac-sha256|hmac-sha384|hmac-sha512)"; + if (cmds.size() < 3) { + cerr << usage << endl; + return 0; + } + DNSName name(cmds.at(1)); + DNSName algo(cmds.at(2)); + string key; + try { + key = makeTSIGKey(algo); + } catch(const PDNSException& e) { + cerr << "Could not create new TSIG key " << name << " " << algo << ": "<< e.reason << endl; + return 1; + } - if (!dke) { - cerr << "Could not find key with ID " << id << endl; - return 1; - } - if (cmds.size() > 4) { - pdns::checked_stoi_into(bits, cmds.at(4)); - } - if (bits < 1) { - cerr << "Invalid bit size " << bits << "given, must be positive integer"; - return 1; - } - try { - dke->create(bits); - } catch (PDNSException& e) { - cerr << e.reason << endl; - return 1; - } + UeberBackend B("default"); + if (B.setTSIGKey(name, DNSName(algo), key)) { // you are feeling bored, put up DNSName(algo) up earlier + cout << "Create new TSIG key " << name << " " << algo << " " << key << endl; + } else { + cerr << "Failure storing new TSIG key " << name << " " << algo << " " << key << endl; + return 1; + } + return 0; +} - cerr << "Key of size " << dke->getBits() << " created" << std::endl; - return 0; - } -#else - cerr<<"PKCS#11 support not enabled"<& cmds) +{ + if (cmds.size() < 4) { + cerr << "Syntax: " << cmds.at(0) << " name algorithm key" << endl; + return 0; + } + DNSName name(cmds.at(1)); + string algo = cmds.at(2); + string key = cmds.at(3); + + UeberBackend B("default"); + if (B.setTSIGKey(name, DNSName(algo), key)) { + cout << "Imported TSIG key " << name << " " << algo << endl; + } + else { + cerr << "Failure importing TSIG key " << name << " " << algo << endl; return 1; -#endif } - else if (cmds.at(0) == "b2b-migrate") { - if (cmds.size() < 3) { - cerr << "Usage: b2b-migrate OLD NEW" << endl; - return 1; + return 0; +} + +static int deleteTSIGKey(vector& cmds) +{ + if (cmds.size() < 2) { + cerr << "Syntax: " << cmds.at(0) << " name" << endl; + return 0; + } + DNSName name(cmds.at(1)); + + UeberBackend B("default"); + if (B.deleteTSIGKey(name)) { + cout << "Deleted TSIG key " << name << endl; + } + else { + cerr << "Failure deleting TSIG key " << name << endl; + return 1; + } + return 0; +} + +static int listTSIGKeys([[maybe_unused]] vector& cmds) +{ + std::vector keys; + UeberBackend B("default"); + if (B.getTSIGKeys(keys)) { + for (const TSIGKey& key : keys) { + cout << key.name.toString() << " " << key.algorithm.toString() << " " << key.key << endl; } + } + return 0; +} - if (cmds.at(1) == cmds.at(2)) { - cerr << "Error: b2b-migrate OLD NEW: OLD cannot be the same as NEW" << endl; - return 1; +static int activateTSIGKey(vector& cmds) +{ + string metaKey; + if (cmds.size() < 4) { + cerr << "Syntax: " << cmds.at(0) << " ZONE NAME {primary|secondary}" << endl; + return 0; + } + DNSName zname(cmds.at(1)); + string name = cmds.at(2); + if (cmds.at(3) == "primary" || cmds.at(3) == "producer") + metaKey = "TSIG-ALLOW-AXFR"; + else if (cmds.at(3) == "secondary" || cmds.at(3) == "consumer") + metaKey = "AXFR-MASTER-TSIG"; + else { + cerr << "Invalid parameter '" << cmds.at(3) << "', expected primary or secondary type" << endl; + return 1; + } + UeberBackend B("default"); + DomainInfo di; + if (!B.getDomainInfo(zname, di)) { + cerr << "Zone '" << zname << "' does not exist" << endl; + return 1; + } + std::vector meta; + if (!B.getDomainMetadata(zname, metaKey, meta)) { + cerr << "Failure enabling TSIG key " << name << " for " << zname << endl; + return 1; + } + bool found = false; + for (const std::string& tmpname : meta) { + if (tmpname == name) { + found = true; + break; } + } + if (!found) + meta.push_back(name); + if (B.setDomainMetadata(zname, metaKey, meta)) { + cout << "Enabled TSIG key " << name << " for " << zname << endl; + } + else { + cerr << "Failure enabling TSIG key " << name << " for " << zname << endl; + return 1; + } + return 0; +} - unique_ptr src{nullptr}; - unique_ptr tgt{nullptr}; +static int deactivateTSIGKey(vector& cmds) +{ + string metaKey; + if (cmds.size() < 4) { + cerr << "Syntax: " << cmds.at(0) << " ZONE NAME {primary|secondary|producer|consumer}" << endl; + return 0; + } + DNSName zname(cmds.at(1)); + string name = cmds.at(2); + if (cmds.at(3) == "primary" || cmds.at(3) == "producer") + metaKey = "TSIG-ALLOW-AXFR"; + else if (cmds.at(3) == "secondary" || cmds.at(3) == "consumer") + metaKey = "AXFR-MASTER-TSIG"; + else { + cerr << "Invalid parameter '" << cmds.at(3) << "', expected primary or secondary type" << endl; + return 1; + } - for (auto& backend : BackendMakers().all()) { - if (backend->getPrefix() == cmds.at(1)) { - src = std::move(backend); - } - else if (backend->getPrefix() == cmds.at(2)) { - tgt = std::move(backend); + UeberBackend B("default"); + DomainInfo di; + if (!B.getDomainInfo(zname, di)) { + cerr << "Zone '" << zname << "' does not exist" << endl; + return 1; + } + std::vector meta; + if (!B.getDomainMetadata(zname, metaKey, meta)) { + cerr << "Failure disabling TSIG key " << name << " for " << zname << endl; + return 1; + } + std::vector::iterator iter = meta.begin(); + for (; iter != meta.end(); ++iter) + if (*iter == name) + break; + if (iter != meta.end()) + meta.erase(iter); + if (B.setDomainMetadata(zname, metaKey, meta)) { + cout << "Disabled TSIG key " << name << " for " << zname << endl; + } + else { + cerr << "Failure disabling TSIG key " << name << " for " << zname << endl; + return 1; + } + return 0; +} + +static int getMeta(vector& cmds) +{ + UeberBackend B("default"); + if (cmds.size() < 2) { + cerr << "Syntax: " << cmds.at(0) << " zone [kind kind ..]" << endl; + return 1; + } + DNSName zone(cmds.at(1)); + vector keys; + + DomainInfo di; + if (!B.getDomainInfo(zone, di)) { + cerr << "Invalid zone '" << zone << "'" << endl; + return 1; + } + + if (cmds.size() > 2) { + keys.assign(cmds.begin() + 2, cmds.end()); + std::cout << "Metadata for '" << zone << "'" << endl; + for(const auto& kind : keys) { + vector meta; + meta.clear(); + if (B.getDomainMetadata(zone, kind, meta)) { + cout << kind << " = " << boost::join(meta, ", ") << endl; } } - - if (src == nullptr) { - cerr << "Unknown source backend '" << cmds.at(1) << "'" << endl; - return 1; + } else { + std::map > meta; + std::cout << "Metadata for '" << zone << "'" << endl; + B.getAllDomainMetadata(zone, meta); + for(const auto& each_meta: meta) { + cout << each_meta.first << " = " << boost::join(each_meta.second, ", ") << endl; } - if (tgt == nullptr) { - cerr << "Unknown target backend '" << cmds.at(2) << "'" << endl; + } + return 0; +} + +static int setMeta(vector& cmds) +{ + if (cmds.size() < 3) { + cerr << "Syntax: " << cmds.at(0) << " ZONE KIND [VALUE VALUE ..]" << endl; + return 1; + } + DNSName zone(cmds.at(1)); + string kind = cmds.at(2); + const static std::array multiMetaWhitelist = {"ALLOW-AXFR-FROM", "ALLOW-DNSUPDATE-FROM", + "ALSO-NOTIFY", "TSIG-ALLOW-AXFR", "TSIG-ALLOW-DNSUPDATE", "GSS-ALLOW-AXFR-PRINCIPAL", + "PUBLISH-CDS"}; + bool clobber = true; + if (cmds.at(0) == "add-meta") { + clobber = false; + if (find(multiMetaWhitelist.begin(), multiMetaWhitelist.end(), kind) == multiMetaWhitelist.end() && kind.find("X-") != 0) { + cerr<<"Refusing to add metadata to single-value metadata "< meta(cmds.begin() + 3, cmds.end()); + return addOrSetMeta(zone, kind, meta, clobber); +} + +#ifdef HAVE_P11KIT1 // { +static int HSMAssign(vector& cmds) +{ + DNSCryptoKeyEngine::storvector_t storvect; + DomainInfo di; + std::vector keys; + + if (cmds.size() < 9) { + std::cout << "Usage: pdnsutil hsm assign ZONE ALGORITHM {ksk|zsk} MODULE TOKEN PIN LABEL (PUBLABEL)" << std::endl; + return 1; + } + + UeberBackend B("default"); + DNSName zone(cmds.at(2)); + + // verify zone + if (!B.getDomainInfo(zone, di)) { + cerr << "Unable to assign module to unknown zone '" << zone << "'" << std::endl; + return 1; + } - cout<<"Moving zone(s) from "<getPrefix()<<" to "<getPrefix()< domains; + bool keyOrZone = (cmds.at(4) == "ksk" ? true : false); + string module = cmds.at(5); + string slot = cmds.at(6); + string pin = cmds.at(7); + string label = cmds.at(8); + string pub_label; + if (cmds.size() > 9) + pub_label = cmds.at(9); + else + pub_label = label; - tgt->getAllDomains(&domains, false, true); - if (!domains.empty()) - throw PDNSException("Target backend has zone(s), please clean it first"); + std::ostringstream iscString; + iscString << "Private-key-format: v1.2" << std::endl << + "Algorithm: " << algorithm << std::endl << + "Engine: " << module << std::endl << + "Slot: " << slot << std::endl << + "PIN: " << pin << std::endl << + "Label: " << label << std::endl << + "PubLabel: " << pub_label << std::endl; - src->getAllDomains(&domains, false, true); - // iterate zones - for(const DomainInfo& di: domains) { - size_t nr,nc,nm,nk; - DomainInfo di_new; - DNSResourceRecord rr; - cout<<"Processing '"<createDomain(di.zone, di.kind, di.primaries, di.account)) - throw PDNSException("Failed to create zone"); - if (!tgt->getDomainInfo(di.zone, di_new)) throw PDNSException("Failed to create zone"); - // move records - if (!src->list(di.zone, di.id, true)) throw PDNSException("Failed to list records"); - nr=0; + DNSKEYRecordContent drc; - tgt->startTransaction(di.zone, di_new.id); + shared_ptr dke(DNSCryptoKeyEngine::makeFromISCString(drc, iscString.str())); + if(!dke->checkKey()) { + cerr << "Invalid DNS Private Key in engine " << module << " slot " << slot << std::endl; + return 1; + } + DNSSECPrivateKey dpk; + dpk.setKey(dke, keyOrZone ? 257 : 256); - while(src->get(rr)) { - rr.domain_id = di_new.id; - if (!tgt->feedRecord(rr, DNSName())) throw PDNSException("Failed to feed record"); - nr++; - } + // make sure this key isn't being reused. + B.getDomainKeys(zone, keys); - // move comments - nc=0; - if (src->listComments(di.id)) { - Comment c; - while(src->getComment(c)) { - c.domain_id = di_new.id; - if (!tgt->feedComment(c)) { - throw PDNSException("Target backend does not support comments - remove them first"); - } - nc++; - } - } - // move metadata - nm=0; - std::map > meta; - if (src->getAllDomainMetadata(di.zone, meta)) { - for (const auto& i : meta) { - if (!tgt->setDomainMetadata(di.zone, i.first, i.second)) - throw PDNSException("Failed to feed zone metadata"); - nm++; - } - } - // move keys - nk=0; - // temp var for KeyID - int64_t keyID; - std::vector keys; - if (src->getDomainKeys(di.zone, keys)) { - for(const DNSBackend::KeyData& k: keys) { - tgt->addDomainKey(di.zone, k, keyID); - nk++; - } - } - tgt->commitTransaction(); - cout<<"Moved "< tkeys; - if (src->getTSIGKeys(tkeys)) { - for(auto& tk: tkeys) { - if (!tgt->setTSIGKey(tk.name, tk.algorithm, tk.key)) throw PDNSException("Failed to feed TSIG key"); - ntk++; - } - } - cout<<"Moved "< -1) { + cerr << "You have already assigned this key with ID=" << id << std::endl; + return 1; + } + + DNSSECKeeper dk; + if (!dk.addKey(zone, dpk, id)) { + cerr << "Unable to assign module slot to zone" << std::endl; + return 1; + } - cout<<"Remember to drop the old backend and run rectify-all-zones"<& cmds) +{ + if (cmds.size() < 4) { + cerr << "Usage: pdnsutil hsm create-key ZONE KEY-ID [BITS]" << endl; + return 1; + } + UeberBackend B("default"); + DomainInfo di; + DNSName zone(cmds.at(2)); + unsigned int id; + int bits = 2048; + // verify zone + if (!B.getDomainInfo(zone, di)) { + cerr << "Unable to create key for unknown zone '" << zone << "'" << std::endl; + return 1; } - else if (cmds.at(0) == "backend-cmd") { - if (cmds.size() < 3) { - cerr<<"Usage: backend-cmd BACKEND CMD [CMD..]"< matchingBackend{nullptr}; + pdns::checked_stoi_into(id, cmds.at(3)); + std::vector keys; + if (!B.getDomainKeys(zone, keys)) { + cerr << "No keys found for zone " << zone << std::endl; + return 1; + } - for (auto& backend : BackendMakers().all()) { - if (backend->getPrefix() == cmds.at(1)) { - matchingBackend = std::move(backend); - } + std::unique_ptr dke = nullptr; + // lookup correct key + for(DNSBackend::KeyData &kd : keys) { + if (kd.id == id) { + // found our key. + DNSKEYRecordContent dkrc; + dke = DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content); } + } - if (matchingBackend == nullptr) { - cerr << "Unknown backend '" << cmds.at(1) << "'" << endl; - return 1; - } + if (!dke) { + cerr << "Could not find key with ID " << id << endl; + return 1; + } + if (cmds.size() > 4) { + pdns::checked_stoi_into(bits, cmds.at(4)); + } + if (bits < 1) { + cerr << "Invalid bit size " << bits << "given, must be positive integer"; + return 1; + } + try { + dke->create(bits); + } catch (PDNSException& e) { + cerr << e.reason << endl; + return 1; + } - for (auto i = next(begin(cmds), 2); i != end(cmds); ++i) { - cerr << "== " << *i << endl; - cout << matchingBackend->directBackendCmd(*i); - } + cerr << "Key of size " << dke->getBits() << " created" << std::endl; + return 0; +} +#endif // } +static int HSM([[maybe_unused]] vector& cmds) +{ +#ifdef HAVE_P11KIT1 + if (cmds.size() < 2) { + cerr << "Missing sub-command for pdnsutil hsm"<< std::endl; return 0; } - else if (cmds.at(0) == "backend-lookup") { - if (cmds.size() < 3) { - cerr << "Usage: backend-lookup BACKEND NAME [TYPE [CLIENT-IP-SUBNET]]" << endl; - return 1; + else if (cmds.at(1) == "assign") { + return HSMAssign(cmds); + } + else if (cmds.at(1) == "create-key") { + return HSMCreateKey(cmds); + } + return 1; +#else + cerr<<"PKCS#11 support not enabled"<& cmds) +{ + if (cmds.size() < 3) { + cerr << "Usage: b2b-migrate OLD NEW" << endl; + return 1; + } + + if (cmds.at(1) == cmds.at(2)) { + cerr << "Error: b2b-migrate OLD NEW: OLD cannot be the same as NEW" << endl; + return 1; + } + + unique_ptr src{nullptr}; + unique_ptr tgt{nullptr}; + + for (auto& backend : BackendMakers().all()) { + if (backend->getPrefix() == cmds.at(1)) { + src = std::move(backend); } + else if (backend->getPrefix() == cmds.at(2)) { + tgt = std::move(backend); + } + } - std::unique_ptr matchingBackend{nullptr}; + if (src == nullptr) { + cerr << "Unknown source backend '" << cmds.at(1) << "'" << endl; + return 1; + } + if (tgt == nullptr) { + cerr << "Unknown target backend '" << cmds.at(2) << "'" << endl; + return 1; + } + + cout<<"Moving zone(s) from "<getPrefix()<<" to "<getPrefix()< domains; + + tgt->getAllDomains(&domains, false, true); + if (!domains.empty()) + throw PDNSException("Target backend has zone(s), please clean it first"); - for (auto& backend : BackendMakers().all()) { - if (backend->getPrefix() == cmds.at(1)) { - matchingBackend = std::move(backend); + src->getAllDomains(&domains, false, true); + // iterate zones + for(const DomainInfo& di: domains) { + size_t nr,nc,nm,nk; + DomainInfo di_new; + DNSResourceRecord rr; + cout<<"Processing '"<createDomain(di.zone, di.kind, di.primaries, di.account)) + throw PDNSException("Failed to create zone"); + if (!tgt->getDomainInfo(di.zone, di_new)) throw PDNSException("Failed to create zone"); + // move records + if (!src->list(di.zone, di.id, true)) throw PDNSException("Failed to list records"); + nr=0; + + tgt->startTransaction(di.zone, di_new.id); + + while(src->get(rr)) { + rr.domain_id = di_new.id; + if (!tgt->feedRecord(rr, DNSName())) throw PDNSException("Failed to feed record"); + nr++; + } + + // move comments + nc=0; + if (src->listComments(di.id)) { + Comment c; + while(src->getComment(c)) { + c.domain_id = di_new.id; + if (!tgt->feedComment(c)) { + throw PDNSException("Target backend does not support comments - remove them first"); + } + nc++; } } - - if (matchingBackend == nullptr) { - cerr << "Unknown backend '" << cmds.at(1) << "'" << endl; - return 1; + // move metadata + nm=0; + std::map > meta; + if (src->getAllDomainMetadata(di.zone, meta)) { + for (const auto& i : meta) { + if (!tgt->setDomainMetadata(di.zone, i.first, i.second)) + throw PDNSException("Failed to feed zone metadata"); + nm++; + } + } + // move keys + nk=0; + // temp var for KeyID + int64_t keyID; + std::vector keys; + if (src->getDomainKeys(di.zone, keys)) { + for(const DNSBackend::KeyData& k: keys) { + tgt->addDomainKey(di.zone, k, keyID); + nk++; + } } + tgt->commitTransaction(); + cout<<"Moved "< 3) { - type = DNSRecordContent::TypeToNumber(cmds.at(3)); + int ntk=0; + // move tsig keys + std::vector tkeys; + if (src->getTSIGKeys(tkeys)) { + for(auto& tk: tkeys) { + if (!tgt->setTSIGKey(tk.name, tk.algorithm, tk.key)) throw PDNSException("Failed to feed TSIG key"); + ntk++; } + } + cout<<"Moved "< 4) { - clientNetmask = cmds.at(4); - queryPacket.setRealRemote(clientNetmask); - } + return 0; +} - matchingBackend->lookup(type, name, -1, &queryPacket); +static int backendCmd(vector& cmds) +{ + if (cmds.size() < 3) { + cerr<<"Usage: backend-cmd BACKEND CMD [CMD..]"<get(resultZoneRecord)) { - cout << resultZoneRecord.dr.d_name.toString() << "\t" << std::to_string(resultZoneRecord.dr.d_ttl) << "\t" << QClass(resultZoneRecord.dr.d_class).toString() << "\t" << DNSRecordContent::NumberToType(resultZoneRecord.dr.d_type, resultZoneRecord.dr.d_class) << "\t" << resultZoneRecord.dr.getContent()->getZoneRepresentation(); - if (resultZoneRecord.scopeMask > 0) { - clientNetmask.setBits(resultZoneRecord.scopeMask); - cout << "\t" << "; " << clientNetmask.toString(); - } - cout << endl; - found = true; + std::unique_ptr matchingBackend{nullptr}; + + for (auto& backend : BackendMakers().all()) { + if (backend->getPrefix() == cmds.at(1)) { + matchingBackend = std::move(backend); } - if (!found) { - cerr << "Backend found 0 zone record results"; - if (type != QType::ANY) { - cerr << "- maybe retry with type ANY?"; - } - cerr << endl; - return 1; + } + + if (matchingBackend == nullptr) { + cerr << "Unknown backend '" << cmds.at(1) << "'" << endl; + return 1; + } + + for (auto i = next(begin(cmds), 2); i != end(cmds); ++i) { + cerr << "== " << *i << endl; + cout << matchingBackend->directBackendCmd(*i); + } + + return 0; +} + +static int backendLookup(vector& cmds) +{ + if (cmds.size() < 3) { + cerr << "Usage: backend-lookup BACKEND NAME [TYPE [CLIENT-IP-SUBNET]]" << endl; + return 1; + } + + std::unique_ptr matchingBackend{nullptr}; + + for (auto& backend : BackendMakers().all()) { + if (backend->getPrefix() == cmds.at(1)) { + matchingBackend = std::move(backend); } + } - return 0; + if (matchingBackend == nullptr) { + cerr << "Unknown backend '" << cmds.at(1) << "'" << endl; + return 1; + } + + QType type = QType::ANY; + if (cmds.size() > 3) { + type = DNSRecordContent::TypeToNumber(cmds.at(3)); + } + + DNSName name{cmds.at(2)}; + + DNSPacket queryPacket(true); + Netmask clientNetmask; + if (cmds.size() > 4) { + clientNetmask = cmds.at(4); + queryPacket.setRealRemote(clientNetmask); + } + + matchingBackend->lookup(type, name, -1, &queryPacket); + + bool found = false; + DNSZoneRecord resultZoneRecord; + while (matchingBackend->get(resultZoneRecord)) { + cout << resultZoneRecord.dr.d_name.toString() << "\t" << std::to_string(resultZoneRecord.dr.d_ttl) << "\t" << QClass(resultZoneRecord.dr.d_class).toString() << "\t" << DNSRecordContent::NumberToType(resultZoneRecord.dr.d_type, resultZoneRecord.dr.d_class) << "\t" << resultZoneRecord.dr.getContent()->getZoneRepresentation(); + if (resultZoneRecord.scopeMask > 0) { + clientNetmask.setBits(resultZoneRecord.scopeMask); + cout << "\t" << "; " << clientNetmask.toString(); + } + cout << endl; + found = true; + } + if (!found) { + cerr << "Backend found 0 zone record results"; + if (type != QType::ANY) { + cerr << "- maybe retry with type ANY?"; + } + cerr << endl; + return 1; + } + + return 0; +} + + +// NOLINTNEXTLINE(readability-function-cognitive-complexity): TODO Clean this function up. +int main(int argc, char** argv) +try +{ + po::options_description desc("Allowed options"); + desc.add_options() + ("help,h", "produce help message") + ("version", "show version") + ("verbose,v", "be verbose") + ("force", "force an action") + ("config-name", po::value()->default_value(""), "virtual configuration name") + ("config-dir", po::value()->default_value(SYSCONFDIR), "location of pdns.conf") + ("no-colors", "do not use colors in output") + ("commands", po::value >()); + + po::positional_options_description p; + p.add("commands", -1); + po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), g_vm); + po::notify(g_vm); + + vector cmds; + + if(g_vm.count("commands")) + cmds = g_vm["commands"].as >(); + + g_verbose = g_vm.count("verbose"); + + if (g_vm.count("version")) { + cout<<"pdnsutil "< [params ..]\n" + << endl; + cout << "Commands:" << endl; + cout << "activate-tsig-key ZONE NAME {primary|secondary|producer|consumer}" << endl; + cout << " Enable TSIG authenticated AXFR using the key NAME for ZONE" << endl; + cout << "activate-zone-key ZONE KEY-ID Activate the key with key id KEY-ID in ZONE" << endl; + cout << "add-record ZONE NAME TYPE [ttl] content" << endl; + cout << " [content..] Add one or more records to ZONE" << endl; + cout << "add-autoprimary IP NAMESERVER [account]" << endl; + cout << " Add a new autoprimary " << endl; + cout << "remove-autoprimary IP NAMESERVER Remove an autoprimary" << endl; + cout << "list-autoprimaries List all autoprimaries" << endl; + cout << "add-zone-key ZONE {zsk|ksk} [BITS] [active|inactive] [published|unpublished]" << endl; + cout << " [rsasha1|rsasha1-nsec3-sha1|rsasha256|rsasha512|ecdsa256|ecdsa384"; +#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO_ED25519) + cout << "|ed25519"; +#endif +#if defined(HAVE_LIBCRYPTO_ED448) + cout << "|ed448"; +#endif + cout << "]" << endl; + cout << " Add a ZSK or KSK to zone and specify algo&bits" << endl; + cout << "backend-cmd BACKEND CMD [CMD..] Perform one or more backend commands" << endl; + cout << "backend-lookup BACKEND NAME [[TYPE] CLIENT-IP-SUBNET]" << endl; + cout << " Perform a backend lookup of NAME, TYPE and CLIENT-IP-SUBNET" << endl; + cout << "b2b-migrate OLD NEW Move all data from one backend to another" << endl; + cout << "bench-db [filename] Bench database backend with queries, one zone per line" << endl; + cout << "check-zone ZONE Check a zone for correctness" << endl; + cout << "check-all-zones [exit-on-error] Check all zones for correctness. Set exit-on-error to exit immediately" << endl; + cout << " after finding an error in a zone." << endl; + cout << "clear-zone ZONE Clear all records of a zone, but keep everything else" << endl; + cout << "create-bind-db FNAME Create DNSSEC db for BIND backend (bind-dnssec-db)" << endl; + cout << "create-secondary-zone ZONE primary-ip [primary-ip..]" << endl; + cout << " Create secondary zone ZONE with primary IP address primary-ip" << endl; + cout << "change-secondary-zone-primary ZONE primary-ip [primary-ip..]" << endl; + cout << " Change secondary zone ZONE primary IP address to primary-ip" << endl; + cout << "create-zone ZONE [nsname] Create empty zone ZONE" << endl; + cout << "deactivate-tsig-key ZONE NAME {primary|secondary}" << endl; + cout << " Disable TSIG authenticated AXFR using the key NAME for ZONE" << endl; + cout << "deactivate-zone-key ZONE KEY-ID Deactivate the key with key id KEY-ID in ZONE" << endl; + cout << "delete-rrset ZONE NAME TYPE Delete named RRSET from zone" << endl; + cout << "delete-tsig-key NAME Delete TSIG key (warning! will not unmap key!)" << endl; + cout << "delete-zone ZONE Delete the zone" << endl; + cout << "disable-dnssec ZONE Deactivate all keys and unset PRESIGNED in ZONE" << endl; + cout << "edit-zone ZONE Edit zone contents using $EDITOR" << endl; + cout << "export-zone-dnskey ZONE KEY-ID Export to stdout the public DNSKEY described" << endl; + cout << "export-zone-ds ZONE Export to stdout all KSK DS records for ZONE" << endl; + cout << "export-zone-key ZONE KEY-ID Export to stdout the private key described" << endl; + cout << "export-zone-key-pem ZONE KEY-ID Export to stdout in PEM the private key described" << endl; + cout << "generate-tsig-key NAME ALGORITHM Generate new TSIG key" << endl; + cout << "generate-zone-key {zsk|ksk} [ALGORITHM] [BITS]" << endl; + cout << " Generate a ZSK or KSK to stdout with specified ALGORITHM and BITS" << endl; + cout << "get-meta ZONE [KIND ...] Get zone metadata. If no KIND given, lists all known" << endl; + cout << "hash-password [WORK FACTOR] Ask for a plaintext password or api key and output a hashed and salted version" << endl; + cout << "hash-zone-record ZONE RNAME Calculate the NSEC3 hash for RNAME in ZONE" << endl; +#ifdef HAVE_P11KIT1 + cout << "hsm assign ZONE ALGORITHM {ksk|zsk} MODULE SLOT PIN LABEL" << endl << + " Assign a hardware signing module to a ZONE" << endl; + cout << "hsm create-key ZONE KEY-ID [BITS] Create a key using hardware signing module for ZONE (use assign first)" << endl; + cout << " BITS defaults to 2048" << endl; +#endif + cout << "increase-serial ZONE Increases the SOA-serial by 1. Uses SOA-EDIT" << endl; + cout << "import-tsig-key NAME ALGORITHM KEY Import TSIG key" << endl; + cout << "import-zone-key ZONE FILE Import from a file a private key, ZSK or KSK" << endl; + cout << " [active|inactive] [ksk|zsk] [published|unpublished] Defaults to KSK, active and published" << endl; + cout << "import-zone-key-pem ZONE FILE Import a private key from a PEM file" << endl; + cout << " ALGORITHM {ksk|zsk}" << endl; + cout << "ipdecrypt IP passphrase/key [key] Decrypt IP address using passphrase or base64 key" << endl; + cout << "ipencrypt IP passphrase/key [key] Encrypt IP address using passphrase or base64 key" << endl; + cout << "load-zone ZONE FILE Load ZONE from FILE, possibly creating zone or atomically" << endl; + cout << " replacing contents" << endl; + cout << "list-algorithms [with-backend] List all DNSSEC algorithms supported, optionally also listing the crypto library used" << endl; + cout << "list-keys [ZONE] List DNSSEC keys for ZONE. When ZONE is unset, display all keys for all active zones" << endl; + cout << " --verbose or -v will also include the keys for disabled or empty zones" << endl; + cout << "list-zone ZONE List zone contents" << endl; + cout << "list-all-zones [primary|secondary|native|producer|consumer]" << endl; + cout << " List all active zone names. --verbose or -v will also include disabled or empty zones" << endl; + cout << "list-member-zones CATALOG List all members of catalog zone CATALOG" << endl; + + cout << "list-tsig-keys List all TSIG keys" << endl; + cout << "publish-zone-key ZONE KEY-ID Publish the zone key with key id KEY-ID in ZONE" << endl; + cout << "rectify-zone ZONE [ZONE ..] Fix up DNSSEC fields (order, auth)" << endl; + cout << "rectify-all-zones [quiet] Rectify all zones. Optionally quiet output with errors only" << endl; + cout << "remove-zone-key ZONE KEY-ID Remove key with KEY-ID from ZONE" << endl; + cout << "replace-rrset ZONE NAME TYPE [ttl] Replace named RRSET from zone" << endl; + cout << " content [content..]" << endl; + cout << "secure-all-zones [increase-serial] Secure all zones without keys" << endl; + cout << "secure-zone ZONE [ZONE ..] Add DNSSEC to zone ZONE" << endl; + cout << "set-kind ZONE KIND Change the kind of ZONE to KIND (primary, secondary, native, producer, consumer)" << endl; + cout << "set-options-json ZONE JSON Change the options of ZONE to JSON" << endl; + cout << "set-option ZONE Set or remove an option for ZONE Providing an empty value removes an option" << endl; + cout << " [producer|consumer]" << endl; + cout << " [coo|unique|group] VALUE" << endl; + cout << " [VALUE ...]" << endl; + cout << "set-catalog ZONE CATALOG Change the catalog of ZONE to CATALOG. Setting CATALOG to an empty "" removes ZONE from the catalog it is in" << endl; + cout << "set-account ZONE ACCOUNT Change the account (owner) of ZONE to ACCOUNT" << endl; + cout << "set-nsec3 ZONE ['PARAMS' [narrow]] Enable NSEC3 with PARAMS. Optionally narrow" << endl; + cout << "set-presigned ZONE Use presigned RRSIGs from storage" << endl; + cout << "set-publish-cdnskey ZONE [delete] Enable sending CDNSKEY responses for ZONE. Add 'delete' to publish a CDNSKEY with a" << endl; + cout << " DNSSEC delete algorithm" << endl; + cout << "set-publish-cds ZONE [DIGESTALGOS] Enable sending CDS responses for ZONE, using DIGESTALGOS as signature algorithms" << endl; + cout << " DIGESTALGOS should be a comma separated list of numbers, it is '2' by default" << endl; + cout << "add-meta ZONE KIND VALUE Add zone metadata, this adds to the existing KIND" << endl; + cout << " [VALUE ...]" << endl; + cout << "set-meta ZONE KIND [VALUE] [VALUE] Set zone metadata, optionally providing a value. *No* value clears meta" << endl; + cout << " Note - this will replace all metadata records of KIND!" << endl; + cout << "show-zone ZONE Show DNSSEC (public) key details about a zone" << endl; + cout << "unpublish-zone-key ZONE KEY-ID Unpublish the zone key with key id KEY-ID in ZONE" << endl; + cout << "unset-nsec3 ZONE Switch back to NSEC" << endl; + cout << "unset-presigned ZONE No longer use presigned RRSIGs" << endl; + cout << "unset-publish-cdnskey ZONE Disable sending CDNSKEY responses for ZONE" << endl; + cout << "unset-publish-cds ZONE Disable sending CDS responses for ZONE" << endl; + cout << "test-schema ZONE Test DB schema - will create ZONE" << endl; + cout << "raw-lua-from-content TYPE CONTENT Display record contents in a form suitable for dnsdist's `SpoofRawAction`" << endl; + cout << "zonemd-verify-file ZONE FILE Validate ZONEMD for ZONE" << endl; + cout << "lmdb-get-backend-version Get schema version supported by backend" << endl; + cout << desc << endl; + + return 0; + } + + loadMainConfig(g_vm["config-dir"].as()); + + if (cmds.at(0) == "lmdb-get-backend-version") { + return lmdbGetBackendVersion(cmds); + } + if (cmds.at(0) == "test-algorithm") { + return testAlgorithm(cmds); + } + + if (cmds.at(0) == "ipencrypt" || cmds.at(0) == "ipdecrypt") { + return ipEncrypt(cmds); + } + + if (cmds.at(0) == "test-algorithms") { + return testAlgorithms(cmds); + } + + if (cmds.at(0) == "list-algorithms") { + return listAlgorithms(cmds); + } + + reportAllTypes(); + + if (cmds.at(0) == "create-bind-db") { + return createBindDb(cmds); + } + + if (cmds.at(0) == "raw-lua-from-content") { + return rawLuaFromContent(cmds); + } + else if (cmds.at(0) == "hash-password") { + return hashPassword(cmds); + } + + if(cmds[0] == "zonemd-verify-file") { + return zonemdVerifyFile(cmds); + } + + if (cmds.at(0) == "test-schema") { + return testSchema(cmds); + } + if (cmds.at(0) == "rectify-zone") { + return rectifyZone(cmds); + } + else if (cmds.at(0) == "rectify-all-zones") { + return rectifyAllZones(cmds); + } + else if (cmds.at(0) == "check-zone") { + return checkZone(cmds); + } + else if (cmds.at(0) == "bench-db") { + return benchDb(cmds); + } + else if (cmds.at(0) == "check-all-zones") { + return checkAllZones(cmds); + } + else if (cmds.at(0) == "list-all-zones") { + return listAllZones(cmds); + } + else if (cmds.at(0) == "list-member-zones") { + return listMemberZones(cmds); + } + else if (cmds.at(0) == "test-zone") { + return testZone(cmds); + } + else if (cmds.at(0) == "test-all-zones") { + return testAllZones(cmds); + } + else if (cmds.at(0) == "test-speed") { + return testSpeed(cmds); + } + else if (cmds.at(0) == "verify-crypto") { + return verifyCrypto(cmds); + } + else if (cmds.at(0) == "show-zone") { + return showZone(cmds); + } + else if (cmds.at(0) == "export-zone-ds") { + return exportZoneDS(cmds); + } + else if (cmds.at(0) == "disable-dnssec") { + return disableDNSSEC(cmds); + } + else if (cmds.at(0) == "activate-zone-key") { + return activateZoneKey(cmds); + } + else if (cmds.at(0) == "deactivate-zone-key") { + return deactivateZoneKey(cmds); + } + else if (cmds.at(0) == "publish-zone-key") { + return publishZoneKey(cmds); + } + else if (cmds.at(0) == "unpublish-zone-key") { + return unpublishZoneKey(cmds); + } + + else if (cmds.at(0) == "add-zone-key") { + return addZoneKey(cmds); + } + else if (cmds.at(0) == "remove-zone-key") { + return removeZoneKey(cmds); + } + else if (cmds.at(0) == "delete-zone") { + return deleteZone(cmds); + } + else if (cmds.at(0) == "create-zone") { + return createZone(cmds); + } + else if (cmds.at(0) == "create-secondary-zone") { + return createSecondaryZone(cmds); + } + else if (cmds.at(0) == "change-secondary-zone-primary") { + return changeSecondaryZonePrimary(cmds); + } + else if (cmds.at(0) == "add-record") { + return addRecord(cmds); + } + else if (cmds.at(0) == "add-autoprimary") { + return addAutoprimary(cmds); + } + else if (cmds.at(0) == "remove-autoprimary") { + return removeAutoprimary(cmds); + } + else if (cmds.at(0) == "list-autoprimaries") { + return listAutoprimaries(cmds); + } + else if (cmds.at(0) == "replace-rrset") { + return replaceRRSet(cmds); + } + else if (cmds.at(0) == "delete-rrset") { + return deleteRRSet(cmds); + } + else if (cmds.at(0) == "list-zone") { + return listZone(cmds); + } + else if (cmds.at(0) == "edit-zone") { + return editZone(cmds); + } + else if (cmds.at(0) == "clear-zone") { + return clearZone(cmds); + } + else if (cmds.at(0) == "list-keys") { + return listKeys(cmds); + } + else if (cmds.at(0) == "load-zone") { + return loadZone(cmds); + } + else if (cmds.at(0) == "secure-zone") { + return secureZone(cmds); + } + else if (cmds.at(0) == "secure-all-zones") { + return secureAllZones(cmds); + } + else if (cmds.at(0) == "set-kind") { + return setKind(cmds); + } + else if (cmds.at(0) == "set-options-json") { + return setOptionsJson(cmds); + } + else if (cmds.at(0) == "set-option") { + return setOption(cmds); + } + else if (cmds.at(0) == "set-catalog") { + return setCatalog(cmds); + } + else if (cmds.at(0) == "set-account") { + return setAccount(cmds); + } + else if (cmds.at(0) == "set-nsec3") { + return setNsec3(cmds); + } + else if (cmds.at(0) == "set-presigned") { + return setPresigned(cmds); + } + else if (cmds.at(0) == "set-publish-cdnskey") { + return setPublishCDNSKey(cmds); + } + else if (cmds.at(0) == "set-publish-cds") { + return setPublishCDs(cmds); + } + else if (cmds.at(0) == "unset-presigned") { + return unsetPresigned(cmds); + } + else if (cmds.at(0) == "unset-publish-cdnskey") { + return unsetPublishCDNSKey(cmds); + } + else if (cmds.at(0) == "unset-publish-cds") { + return unsetPublishCDs(cmds); + } + else if (cmds.at(0) == "hash-zone-record") { + return hashZoneRecord(cmds); + } + else if (cmds.at(0) == "unset-nsec3") { + return unsetNSec3(cmds); + } + else if (cmds.at(0) == "export-zone-key") { + return exportZoneKey(cmds); + } + else if (cmds.at(0) == "export-zone-key-pem") { + return exportZoneKeyPEM(cmds); + } + else if (cmds.at(0) == "increase-serial") { + return increaseSerial(cmds); + } + else if (cmds.at(0) == "import-zone-key-pem") { + return importZoneKeyPEM(cmds); + } + else if (cmds.at(0) == "import-zone-key") { + return importZoneKey(cmds); + } + else if (cmds.at(0) == "export-zone-dnskey") { + return expotZoneDNSKey(cmds); + } + else if (cmds.at(0) == "generate-zone-key") { + return generateZoneKey(cmds); + } + else if (cmds.at(0) == "generate-tsig-key") { + return generateTSIGKey(cmds); + } + else if (cmds.at(0) == "import-tsig-key") { + return importTSIGKey(cmds); + } + else if (cmds.at(0) == "delete-tsig-key") { + return deleteTSIGKey(cmds); + } + else if (cmds.at(0) == "list-tsig-keys") { + return listTSIGKeys(cmds); + } + else if (cmds.at(0) == "activate-tsig-key") { + return activateTSIGKey(cmds); + } + else if (cmds.at(0) == "deactivate-tsig-key") { + return deactivateTSIGKey(cmds); + } + else if (cmds.at(0) == "get-meta") { + return getMeta(cmds); + } + else if (cmds.at(0) == "set-meta" || cmds.at(0) == "add-meta") { + return setMeta(cmds); + } + else if (cmds.at(0) == "hsm") { + return HSM(cmds); + } + else if (cmds.at(0) == "b2b-migrate") { + return B2BMigrate(cmds); + } + else if (cmds.at(0) == "backend-cmd") { + return backendCmd(cmds); + } + else if (cmds.at(0) == "backend-lookup") { + return backendLookup(cmds); } else { cerr << "Unknown command '" << cmds.at(0) << "'" << endl;