- ``activate-domain-key-query``: Called to set a cryptokey to active.
- ``deactivate-domain-key-query``: Called to set a cryptokey to
inactive.
+- ``publish-domain-key-query``: Called to set a cryptokey to published.
+- ``unpublish-domain-key-query``: Called to set a cryptokey to unpublished.
- ``clear-domain-all-keys-query``: Called to remove all DNSSEC keys for
a zone.
- ``remove-domain-key-query``: Called to remove a crypto key.
- int id - Key ID
- int flags - Key flags
- bool active - Is key active
+ - bool published - Is key published
- string content - Key itself
NOTES:
~~~~~~~~~~~~~~~~~
Retrieves any keys of kind. The id, flags are unsigned integers, and
-active is boolean. Content must be valid key record in format that
-PowerDNS understands. You are encouraged to implement :ref:`the section
-called "addDomainKey" <remote-adddomainkey>`, as you can use
+active and published are boolean. Content must be valid key record in format
+that PowerDNS understands. You are encouraged to implement :ref:`the
+section called "addDomainKey" <remote-adddomainkey>`, as you can use
:doc:`../manpages/pdnsutil.1` to provision keys.
- Mandatory: for DNSSEC
- Parameters: name, kind
-- Reply: array of ``id, flags, active, content``
+- Reply: array of ``id, flags, active, published, content``
Example JSON/RPC
''''''''''''''''
.. code-block:: json
- {"result":[{"id":1,"flags":256,"active":true,"content":"Private-key-format: v1.2
+ {"result":[{"id":1,"flags":256,"active":true,"published":true,"content":"Private-key-format: v1.2
Algorithm: 8 (RSASHA256)
Modulus: r+vmQll38ndQqNSCx9eqRBUbSOLcH4PZFX824sGhY2NSQChqt1G4ZfndzRwgjXMUwiE7GkkqU2Vbt/g4iP67V/+MYecMV9YHkCRnEzb47nBXvs9JCf8AHMCnma567GQjPECh4HevPE9wmcOfpy/u7UN1oHKSKRWuZJadUwcjbp8=
PublicExponent: AQAB
HTTP/1.1 200 OK
Content-Type: text/javascript; charset=utf-8
- {"result":[{"id":1,"flags":256,"active":true,"content":"Private-key-format: v1.2
+ {"result":[{"id":1,"flags":256,"active":true,"published":true,"content":"Private-key-format: v1.2
Algorithm: 8 (RSASHA256)
Modulus: r+vmQll38ndQqNSCx9eqRBUbSOLcH4PZFX824sGhY2NSQChqt1G4ZfndzRwgjXMUwiE7GkkqU2Vbt/g4iP67V/+MYecMV9YHkCRnEzb47nBXvs9JCf8AHMCnma567GQjPECh4HevPE9wmcOfpy/u7UN1oHKSKRWuZJadUwcjbp8=
PublicExponent: AQAB
Adds key into local storage. See :ref:`remote-getdomainkeys` for more information.
- Mandatory: No
-- Parameters: name, key=\ ``<flags,active,content>``, id
+- Parameters: name, key=\ ``<flags,active,published,content>``, id
- Reply: true for success, false for failure
Example JSON/RPC
.. code-block:: json
- {"method":"adddomainkey", "parameters":{"key":{"id":1,"flags":256,"active":true,"content":"Private-key-format: v1.2
+ {"method":"adddomainkey", "parameters":{"key":{"id":1,"flags":256,"active":true,"published":true,"content":"Private-key-format: v1.2
Algorithm: 8 (RSASHA256)
Modulus: r+vmQll38ndQqNSCx9eqRBUbSOLcH4PZFX824sGhY2NSQChqt1G4ZfndzRwgjXMUwiE7GkkqU2Vbt/g4iP67V/+MYecMV9YHkCRnEzb47nBXvs9JCf8AHMCnma567GQjPECh4HevPE9wmcOfpy/u7UN1oHKSKRWuZJadUwcjbp8=
PublicExponent: AQAB
Content-Type: application/x-www-form-urlencoded
Content-Length: 965
- flags=256&active=1&content=Private-key-format: v1.2
+ flags=256&active=1&published=1&content=Private-key-format: v1.2
Algorithm: 8 (RSASHA256)
Modulus: r+vmQll38ndQqNSCx9eqRBUbSOLcH4PZFX824sGhY2NSQChqt1G4ZfndzRwgjXMUwiE7GkkqU2Vbt/g4iP67V/+MYecMV9YHkCRnEzb47nBXvs9JCf8AHMCnma567GQjPECh4HevPE9wmcOfpy/u7UN1oHKSKRWuZJadUwcjbp8=
PublicExponent: AQAB
{"result": true}
+``publishDomainKey``
+~~~~~~~~~~~~~~~~~~~~
+
+Publish key id for domain name.
+
+- Mandatory: No
+- Parameters: name, id
+- Reply: true for success, false for failure
+
+Example JSON/RPC
+''''''''''''''''
+
+Query:
+
+.. code-block:: json
+
+ {"method":"publishdomainkey","parameters":{"name":"example.com","id":1}}
+
+Response:
+
+.. code-block:: json
+
+ {"result": true}
+
+Example HTTP/RPC
+''''''''''''''''
+
+Query:
+
+.. code-block:: http
+
+ POST /dnsapi/publishdomainkey/example.com/1 HTTP/1.1
+
+Response:
+
+.. code-block:: http
+
+ HTTP/1.1 200 OK
+ Content-Type: text/javascript; utf-8
+
+ {"result": true}
+
+
+``unpublishDomainKey``
+~~~~~~~~~~~~~~~~~~~~~~
+
+Unpublish key id for domain name.
+
+- Mandatory: No
+- Parameters: name, id
+- Reply: true for success, false for failure
+
+Example JSON/RPC
+''''''''''''''''
+
+Query:
+
+.. code-block:: json
+
+ {"method":"unpublishdomainkey","parameters":{"name":"example.com","id":1}}
+
+Response:
+
+.. code-block:: json
+
+ {"result": true}
+
+Example HTTP/RPC
+''''''''''''''''
+
+Query:
+
+.. code-block:: http
+
+ POST /dnsapi/unpublishdomainkey/example.com/1 HTTP/1.1
+
+Response:
+
+.. code-block:: http
+
+ HTTP/1.1 200 OK
+ Content-Type: text/javascript; utf-8
+
+ {"result": true}
+
+
``getTSIGKey``
~~~~~~~~~~~~~~
active:
type: boolean
description: 'Whether or not the key is in active use'
+ published:
+ type: boolean
+ descriptioon: 'Whether or not the DNSKEY record is published in the zone'
dnskey:
type: string
description: 'The DNSKEY record for this key'
activate-zone-key *ZONE* *KEY-ID*
Activate a key with id *KEY-ID* within a zone called *ZONE*.
-add-zone-key *ZONE* {**KSK**,\ **ZSK**} [**active**,\ **inactive**] *KEYBITS* *ALGORITHM*
+add-zone-key *ZONE* {**KSK**,\ **ZSK**} [**active**,\ **inactive**] [**published**,\ **unpublished**] *KEYBITS* *ALGORITHM*
Create a new key for zone *ZONE*, and make it a KSK or a ZSK, with
the specified algorithm. The key is inactive by default, set it to
- **active** to immediately use it to sign *ZONE*. Prints the id of
- the added key.
+ **active** to immediately use it to sign *ZONE*. The key is published
+ in the zone by default, set it to **unpublished** to keep it from
+ being returned in a DNSKEY query, which is useful for algorithm
+ rollovers. Prints the id of the added key.
create-bind-db *FILE*
Create DNSSEC database (sqlite3) at *FILE* for the BIND backend.
Remember to set ``bind-dnssec-db=*FILE*`` in your ``pdns.conf``.
format used is compatible with BIND and NSD/LDNS. **KSK** or **ZSK**
specifies the flags this key should have on import. Prints the id of
the added key.
+publish-zone-key *ZONE* *KEY-ID*
+ Publish the key with id *KEY-ID* within a zone called *ZONE*.
remove-zone-key *ZONE* *KEY-ID*
Remove a key with id *KEY-ID* from a zone called *ZONE*.
set-nsec3 *ZONE* ['*HASH-ALGORITHM* *FLAGS* *ITERATIONS* *SALT*'] [**narrow**]
commandline is: ``pdnsutil set-nsec3 powerdnssec.org '1 1 1 ab' narrow``.
**WARNING**: If running in RSASHA1 mode (algorithm 5 or 7), switching
from NSEC to NSEC3 will require a DS update in the parent zone.
+unpublish-zone-key *ZONE* *KEY-ID*
+ Unpublish the key with id *KEY-ID* within a zone called *ZONE*.
unset-nsec3 *ZONE*
Converts *ZONE* to NSEC operations. **WARNING**: If running in
RSASHA1 mode (algorithm 5 or 7), switching from NSEC to NSEC3 will
bool addDomainKey(const DNSName& name, const KeyData& key, int64_t& id) override;
bool activateDomainKey(const DNSName& name, unsigned int id) override;
bool deactivateDomainKey(const DNSName& name, unsigned int id) override;
+ bool publishDomainKey(const DNSName& name, unsigned int id) override;
+ bool unpublishDomainKey(const DNSName& name, unsigned int id) override;
bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content) override;
bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content) override;
bool deleteTSIGKey(const DNSName& name) override;
unique_ptr<SSqlStatement> d_GetLastInsertedKeyIdQuery_stmt;
unique_ptr<SSqlStatement> d_activateDomainKeyQuery_stmt;
unique_ptr<SSqlStatement> d_deactivateDomainKeyQuery_stmt;
+ unique_ptr<SSqlStatement> d_publishDomainKeyQuery_stmt;
+ unique_ptr<SSqlStatement> d_unpublishDomainKeyQuery_stmt;
unique_ptr<SSqlStatement> d_getTSIGKeyQuery_stmt;
unique_ptr<SSqlStatement> d_setTSIGKeyQuery_stmt;
unique_ptr<SSqlStatement> d_deleteTSIGKeyQuery_stmt;
bool Bind2Backend::deactivateDomainKey(const DNSName& name, unsigned int id)
{ return false; }
+bool Bind2Backend::publishDomainKey(const DNSName& name, unsigned int id)
+{ return false; }
+
+bool Bind2Backend::unpublishDomainKey(const DNSName& name, unsigned int id)
+{ return false; }
+
bool Bind2Backend::getTSIGKey(const DNSName& name, DNSName* algorithm, string* content)
{ return false; }
d_getDomainMetadataQuery_stmt = d_dnssecdb->prepare("select content from domainmetadata where domain=:domain and kind=:kind",2);
d_deleteDomainMetadataQuery_stmt = d_dnssecdb->prepare("delete from domainmetadata where domain=:domain and kind=:kind",2);
d_insertDomainMetadataQuery_stmt = d_dnssecdb->prepare("insert into domainmetadata (domain, kind, content) values (:domain,:kind,:content)",3);
- d_getDomainKeysQuery_stmt = d_dnssecdb->prepare("select id,flags, active, content from cryptokeys where domain=:domain",1);
+ d_getDomainKeysQuery_stmt = d_dnssecdb->prepare("select id,flags, active, published, content from cryptokeys where domain=:domain",1);
d_deleteDomainKeyQuery_stmt = d_dnssecdb->prepare("delete from cryptokeys where domain=:domain and id=:key_id",2);
- d_insertDomainKeyQuery_stmt = d_dnssecdb->prepare("insert into cryptokeys (domain, flags, active, content) values (:domain, :flags, :active, :content)", 4);
+ d_insertDomainKeyQuery_stmt = d_dnssecdb->prepare("insert into cryptokeys (domain, flags, active, published, content) values (:domain, :flags, :active, :published, :content)", 5);
d_GetLastInsertedKeyIdQuery_stmt = d_dnssecdb->prepare("select last_insert_rowid()", 0);
d_activateDomainKeyQuery_stmt = d_dnssecdb->prepare("update cryptokeys set active=1 where domain=:domain and id=:key_id", 2);
d_deactivateDomainKeyQuery_stmt = d_dnssecdb->prepare("update cryptokeys set active=0 where domain=:domain and id=:key_id", 2);
+ d_publishDomainKeyQuery_stmt = d_dnssecdb->prepare("update cryptokeys set published=1 where domain=:domain and id=:key_id", 2);
+ d_unpublishDomainKeyQuery_stmt = d_dnssecdb->prepare("update cryptokeys set published=0 where domain=:domain and id=:key_id", 2);
d_getTSIGKeyQuery_stmt = d_dnssecdb->prepare("select algorithm, secret from tsigkeys where name=:key_name", 1);
d_setTSIGKeyQuery_stmt = d_dnssecdb->prepare("replace into tsigkeys (name,algorithm,secret) values(:key_name, :algorithm, :content)", 3);
d_deleteTSIGKeyQuery_stmt = d_dnssecdb->prepare("delete from tsigkeys where name=:key_name", 1);
d_GetLastInsertedKeyIdQuery_stmt.reset();
d_activateDomainKeyQuery_stmt.reset();
d_deactivateDomainKeyQuery_stmt.reset();
+ d_publishDomainKeyQuery_stmt.reset();
+ d_unpublishDomainKeyQuery_stmt.reset();
d_getTSIGKeyQuery_stmt.reset();
d_setTSIGKeyQuery_stmt.reset();
d_deleteTSIGKeyQuery_stmt.reset();
kd.id = pdns_stou(row[0]);
kd.flags = pdns_stou(row[1]);
kd.active = (row[2] == "1");
- kd.content = row[3];
+ kd.published = (row[3] == "1");
+ kd.content = row[4];
keys.push_back(kd);
}
bind("domain", name)->
bind("flags", key.flags)->
bind("active", key.active)->
+ bind("published", key.published)->
bind("content", key.content)->
execute()->
reset();
return true;
}
+bool Bind2Backend::publishDomainKey(const DNSName& name, unsigned int id)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ try {
+ d_publishDomainKeyQuery_stmt->
+ bind("domain", name)->
+ bind("key_id", id)->
+ execute()->
+ reset();
+ }
+ catch(SSqlException& se) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, publishDomainKey(): "+se.txtReason());
+ }
+ return true;
+}
+
+bool Bind2Backend::unpublishDomainKey(const DNSName& name, unsigned int id)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ try {
+ d_unpublishDomainKeyQuery_stmt->
+ bind("domain", name)->
+ bind("key_id", id)->
+ execute()->
+ reset();
+ }
+ catch(SSqlException& se) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, unpublishDomainKey(): "+se.txtReason());
+ }
+ return true;
+}
+
+
bool Bind2Backend::getTSIGKey(const DNSName& name, DNSName* algorithm, string* content)
{
if(!d_dnssecdb || d_hybrid)
DNSBackend::KeyData kd;
kd.id = pdns_stou(glob_result.gl_pathv[i]+regm[3].rm_so);
kd.active = !strncmp(glob_result.gl_pathv[i]+regm[4].rm_so, "1", 1);
+ kd.published = true;
kd.flags = pdns_stou(glob_result.gl_pathv[i]+regm[2].rm_so);
ifstream ifs(glob_result.gl_pathv[i]);
ostringstream content;
ostringstream newpath;
newpath << getArg("dnssec-keydir") << "/" << dom.domain.toStringNoDot() << "." << pdns_stou(glob_result.gl_pathv[i]+regm[2].rm_so) << "." << kid << ".1.key";
if (rename(glob_result.gl_pathv[i], newpath.str().c_str())) {
- cerr << "Cannot active key: " << strerror(errno) << endl;
+ cerr << "Cannot activate key: " << strerror(errno) << endl;
}
}
}
return false;
}
+bool GeoIPBackend::publishDomainKey(const DNSName& name, unsigned int id) {
+ return false;
+}
+
+bool GeoIPBackend::unpublishDomainKey(const DNSName& name, unsigned int id) {
+ return false;
+}
+
+
bool GeoIPBackend::hasDNSSECkey(const DNSName& name) {
ostringstream pathname;
pathname << getArg("dnssec-keydir") << "/" << name.toStringNoDot() << "*.key";
bool addDomainKey(const DNSName& name, const KeyData& key, int64_t& id) override;
bool activateDomainKey(const DNSName& name, unsigned int id) override;
bool deactivateDomainKey(const DNSName& name, unsigned int id) override;
+ bool publishDomainKey(const DNSName& name, unsigned int id) override;
+ bool unpublishDomainKey(const DNSName& name, unsigned int id) override;
private:
static pthread_rwlock_t s_state_lock;
--- /dev/null
+ALTER TABLE cryptokeys ADD COLUMN published BOOL DEFAULT 1;
+
declare(suffix,"delete-rrset-query","","delete from records where domain_id=? and name=? and type=?");
declare(suffix,"delete-names-query","","delete from records where domain_id=? and name=?");
- declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, ?, ?, ? from domains where name=?");
+ declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, published, content) select id, ?, ?, ?, ? from domains where name=?");
declare(suffix,"get-last-inserted-key-id-query", "", "select LAST_INSERT_ID()");
- declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=?");
+ declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, active, published, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=?");
declare(suffix,"get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=?");
declare(suffix,"get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=? and domainmetadata.kind=?");
declare(suffix,"clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=?) and domainmetadata.kind=?");
declare(suffix,"set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, ?, ? from domains where name=?");
declare(suffix,"activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
declare(suffix,"deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
+ declare(suffix,"publish-domain-key-query","", "update cryptokeys set published=1 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
+ declare(suffix,"unpublish-domain-key-query","", "update cryptokeys set published=0 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
declare(suffix,"remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
declare(suffix,"clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=?)");
declare(suffix,"get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=?");
domain_id INT NOT NULL,
flags INT NOT NULL,
active BOOL,
+ published BOOL DEFAULT 1,
content TEXT,
PRIMARY KEY(id)
) Engine=InnoDB CHARACTER SET 'latin1';
--- /dev/null
+ALTER TABLE cryptokeys ADD COLUMN published BIT DEFAULT 1;
declare(suffix,"delete-rrset-query","","delete from records where domain_id=? and name=? and type=?");
declare(suffix,"delete-names-query","","delete from records where domain_id=? and name=?");
- declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, ?, ?, ? from domains where name=?");
+ declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, published, content) select id, ?, ?, ?, ? from domains where name=?");
declare(suffix,"get-last-inserted-key-id-query", "", "select ident_current('cryptokeys')");
- declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=?");
+ declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, active, published, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=?");
declare(suffix,"get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=?");
declare(suffix,"get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=? and domainmetadata.kind=?");
declare(suffix,"clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=?) and domainmetadata.kind=?");
declare(suffix,"set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, ?, ? from domains where name=?");
declare(suffix,"activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
declare(suffix,"deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
+ declare(suffix,"publish-domain-key-query","", "update cryptokeys set published=1 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
+ declare(suffix,"unpublish-domain-key-query","", "update cryptokeys set published=0 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
declare(suffix,"remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
declare(suffix,"clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=?)");
declare(suffix,"get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=?");
domain_id INT NOT NULL,
flags INT NOT NULL,
active BIT,
+ published BIT DEFAULT 1,
content VARCHAR(MAX),
PRIMARY KEY(id)
);
--- /dev/null
+ALTER TABLE cryptokeys ADD COLUMN published BOOL DEFAULT true;
declare(suffix,"delete-rrset-query","","delete from records where domain_id=$1 and name=$2 and type=$3");
declare(suffix,"delete-names-query","","delete from records where domain_id=$1 and name=$2");
- declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, $1, $2, $3 from domains where name=$4");
+ declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, published, content) select id, $1, $2, $3, $4 from domains where name=$5");
declare(suffix,"get-last-inserted-key-id-query","", "select lastval()");
- declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, case when active then 1 else 0 end as active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=$1");
+ declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, case when active then 1 else 0 end as active, case when published then 1 else 0 end as published, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=$1");
declare(suffix,"get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=$1");
declare(suffix,"get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=$1 and domainmetadata.kind=$2");
declare(suffix,"clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=$1) and domainmetadata.kind=$2");
declare(suffix,"set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, $1, $2 from domains where name=$3");
declare(suffix,"activate-domain-key-query","", "update cryptokeys set active=true where domain_id=(select id from domains where name=$1) and cryptokeys.id=$2");
declare(suffix,"deactivate-domain-key-query","", "update cryptokeys set active=false where domain_id=(select id from domains where name=$1) and cryptokeys.id=$2");
+ declare(suffix,"publish-domain-key-query","", "update cryptokeys set published=true where domain_id=(select id from domains where name=$1) and cryptokeys.id=$2");
+ declare(suffix,"unpublish-domain-key-query","", "update cryptokeys set published=false where domain_id=(select id from domains where name=$1) and cryptokeys.id=$2");
declare(suffix,"remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=$1) and cryptokeys.id=$2");
declare(suffix,"clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=$1)");
declare(suffix,"get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=$1");
domain_id INT REFERENCES domains(id) ON DELETE CASCADE,
flags INT NOT NULL,
active BOOL,
+ published BOOL DEFAULT true,
content TEXT
);
--- /dev/null
+ALTER TABLE cryptokeys ADD published BOOL DEFAULT 1;
declare(suffix, "delete-rrset-query", "", "delete from records where domain_id=:domain_id and name=:qname and type=:qtype");
declare(suffix, "delete-names-query", "", "delete from records where domain_id=:domain_id and name=:qname");
- declare(suffix, "add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, :flags,:active, :content from domains where name=:domain");
+ declare(suffix, "add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, published, content) select id, :flags, :active, :published, :content from domains where name=:domain");
declare(suffix, "get-last-inserted-key-id-query", "", "select last_insert_rowid()");
- declare(suffix, "list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=:domain");
+ declare(suffix, "list-domain-keys-query","", "select cryptokeys.id, flags, active, published, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=:domain");
declare(suffix, "get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=:domain");
declare(suffix, "get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=:domain and domainmetadata.kind=:kind");
declare(suffix, "clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=:domain) and domainmetadata.kind=:kind");
declare(suffix, "set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, :kind, :content from domains where name=:domain");
declare(suffix, "activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id");
declare(suffix, "deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id");
+ declare(suffix, "publish-domain-key-query","", "update cryptokeys set published=1 where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id");
+ declare(suffix, "unpublish-domain-key-query","", "update cryptokeys set published=0 where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id");
declare(suffix, "remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id");
declare(suffix, "clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=:domain)");
declare(suffix, "get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=:key_name");
domain_id INT NOT NULL,
flags INT NOT NULL,
active BOOL,
+ published BOOL DEFAULT 1,
content TEXT,
FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE
);
#include "lmdbbackend.hh"
-#define SCHEMAVERSION 1
+#define SCHEMAVERSION 2
+#define SCHEMAVERSION_TEXT "2"
+// List the class version here. Default is 0
+BOOST_CLASS_VERSION(LMDBBackend::KeyDataDB, 1)
LMDBBackend::LMDBBackend(const std::string& suffix)
{
auto pdnsdbi = d_tdomains->getEnv()->openDB("pdns", MDB_CREATE);
auto txn = d_tdomains->getEnv()->getRWTransaction();
+ uint32_t schemaversion = 1;
MDBOutVal _schemaversion;
if(!txn->get(pdnsdbi, "schemaversion", _schemaversion)) {
- auto schemaversion = _schemaversion.get<uint32_t>();
- if (schemaversion != SCHEMAVERSION) {
+ schemaversion = _schemaversion.get<uint32_t>();
+ }
+
+ if (schemaversion != SCHEMAVERSION) {
+ if (getArgAsNum("schema-version") != SCHEMAVERSION) {
throw std::runtime_error("Expected LMDB schema version "+std::to_string(SCHEMAVERSION)+" but got "+std::to_string(schemaversion));
}
- }
- else {
txn->put(pdnsdbi, "schemaversion", SCHEMAVERSION);
}
+
MDBOutVal shards;
if(!txn->get(pdnsdbi, "shards", shards)) {
}
template<class Archive>
-void serialize(Archive & ar, LMDBBackend::KeyDataDB& g, const unsigned int version)
+void save(Archive & ar, const LMDBBackend::KeyDataDB& g, const unsigned int version)
+{
+ ar & g.domain & g.content & g.flags & g.active & g.published;
+}
+
+template<class Archive>
+void load(Archive & ar, LMDBBackend::KeyDataDB& g, const unsigned int version)
{
ar & g.domain & g.content & g.flags & g.active;
+ if (version >= 1) {
+ ar & g.published;
+ } else {
+ g.published = true;
+ }
}
+
template<class Archive>
void serialize(Archive & ar, TSIGKey& g, const unsigned int version)
{
BOOST_SERIALIZATION_SPLIT_FREE(DNSName);
BOOST_SERIALIZATION_SPLIT_FREE(QType);
+BOOST_SERIALIZATION_SPLIT_FREE(LMDBBackend::KeyDataDB);
BOOST_IS_BITWISE_SERIALIZABLE(ComboAddress);
template<>
auto txn = d_tkdb->getROTransaction();
auto range = txn.equal_range<0>(name);
for(auto& iter = range.first; iter != range.second; ++iter) {
- KeyData kd{iter->content, iter.getID(), iter->flags, iter->active};
+ KeyData kd{iter->content, iter.getID(), iter->flags, iter->active, iter->published};
keys.push_back(kd);
}
bool LMDBBackend::addDomainKey(const DNSName& name, const KeyData& key, int64_t& id)
{
auto txn = d_tkdb->getRWTransaction();
- KeyDataDB kdb{name, key.content, key.flags, key.active};
+ KeyDataDB kdb{name, key.content, key.flags, key.active, key.published};
id = txn.put(kdb);
txn.commit();
return true;
}
}
- // cout << "??? wanted to activate domain key for domain "<<name<<" with id "<<id<<", could not find it"<<endl;
+ // cout << "??? wanted to deactivate domain key for domain "<<name<<" with id "<<id<<", could not find it"<<endl;
return true;
}
+bool LMDBBackend::publishDomainKey(const DNSName& name, unsigned int id)
+{
+ auto txn = d_tkdb->getRWTransaction();
+ KeyDataDB kdb;
+ if(txn.get(id, kdb)) {
+ if(kdb.domain == name) {
+ txn.modify(id, [](KeyDataDB& kdbarg)
+ {
+ kdbarg.published = true;
+ });
+ txn.commit();
+ return true;
+ }
+ }
+
+ // cout << "??? wanted to hide domain key for domain "<<name<<" with id "<<id<<", could not find it"<<endl;
+ return true;
+}
+
+bool LMDBBackend::unpublishDomainKey(const DNSName& name, unsigned int id)
+{
+ auto txn = d_tkdb->getRWTransaction();
+ KeyDataDB kdb;
+ if(txn.get(id, kdb)) {
+ if(kdb.domain == name) {
+ txn.modify(id, [](KeyDataDB& kdbarg)
+ {
+ kdbarg.published = false;
+ });
+ txn.commit();
+ return true;
+ }
+ }
+ // cout << "??? wanted to unhide domain key for domain "<<name<<" with id "<<id<<", could not find it"<<endl;
+ return true;
+}
+
+
bool LMDBBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after)
{
// cout << __PRETTY_FUNCTION__<< ": "<<id <<", "<<qname << " " << unhashed<<endl;
declare(suffix,"filename","Filename for lmdb","./pdns.lmdb");
declare(suffix,"sync-mode","Synchronisation mode: nosync, nometasync, mapasync, sync","mapasync");
// there just is no room for more on 32 bit
- declare(suffix,"shards","Records database will be split into this number of shards", (sizeof(long) == 4) ? "2" : "64");
+ declare(suffix,"shards","Records database will be split into this number of shards", (sizeof(long) == 4) ? "2" : "64");
+ declare(suffix,"schema-version","Maximum allowed schema version to run on this DB. If a lower version is found, auto update is performed", SCHEMAVERSION_TEXT);
}
DNSBackend *make(const string &suffix="")
{
bool addDomainKey(const DNSName& name, const KeyData& key, int64_t& id) override;
bool activateDomainKey(const DNSName& name, unsigned int id) override;
bool deactivateDomainKey(const DNSName& name, unsigned int id) override;
+ bool publishDomainKey(const DNSName& name, unsigned int id) override;
+ bool unpublishDomainKey(const DNSName& name, unsigned int id) override;
// TSIG
bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content) override;
std::string content;
unsigned int flags;
bool active;
+ bool published;
};
private:
for(const auto& row: boost::get<vector<pair<int, keydata_result_t> > >(result)) {
DNSBackend::KeyData key;
+ key.published = true;
for(const auto& item: row.second) {
if (item.first == "content")
key.content = boost::get<string>(item.second);
key.flags = static_cast<unsigned int>(boost::get<int>(item.second));
else if (item.first == "active")
key.active = boost::get<bool>(item.second);
+ else if (item.first == "published")
+ key.published = boost::get<bool>(item.second);
else
g_log<<Logger::Warning<<"["<<getPrefix()<<"] Unsupported key '"<<item.first<<"' in keydata result"<<endl;
}
- logResult("id="<<key.id<<",flags="<<key.flags<<",active="<<(key.active ? "true" : "false"));
+ logResult("id="<<key.id<<",flags="<<key.flags<<",active="<<(key.active ? "true" : "false")<<",published="<<(key.published ? "true" : "false"));
keys.push_back(key);
}
"id" => 1,
"flags" => 257,
"active" => true,
+ "published" => true,
"content" => "Private-key-format: v1.2
Algorithm: 8 (RSASHA256)
Modulus: ovvzf1fHdptdXsBrBLSqmGqdEKwR2B9st/KBgh8xQKoQzTGUG00CsPjF/J59IBU+EU/IIInMn0MxLLTyUKa2DJUkR6i7UKif5jKX1c7yvWzrFKLGOHjugUX2++r+o789biUte1qpWp3Kc2RYL18oPco4zpo6JcsPmhOK3aUCDJXmuWgHl1KudCQIiPkISArXVn4oOp+skQq+mUBl1Pysc4D+6sl77ERR2fW6xJ4ZRPOIKr445RJJmKgoMG8yRrR3it1RmV49hZlvMosQjBUoNcqhqOI0n4l8HOLyna7KIzoNKG62GtUCZh8uy8IjdUiWPYGEtkZ9zE0bnnF+R7HGvQ==
"id" => 2,
"flags" => 256,
"active" => true,
+ "published" => true,
"content" => "Private-key-format: v1.2
Algorithm: 8 (RSASHA256)
Modulus: wKPNcDwkCd2DKxfdkMqTFOV2ITdgxIDaOd4vQ2QtphMBY9yYwmEkNsVdVFz7VVuQHdls20JUe+brFUhs1zEMMbokulFP/qVAItAeEWcqtkPULT+mmX5HsexpFVAZ5+UXuerObk/HMiIMt1CvkIWhmjSIkAI6dFRlf/93zTjy0+vwrNWZPXSzLccK5TfJmxdYdGPcsHkg6UmqEFPQuyZpmlmpg3IwjL5YddTDobAoABz/BrH7WsW0q/PyVubITo8JuFiBI5Fmw+3ef3PVUt1jtUCGASvtqNXW4wtWrgqvQKg/odthpceQ4QagV9XSlOdml527thnf9cMpm0Gh4Ox5HQ==
addUrlComponent(parameters, "qtype", ss);
// set the correct type of request based on method
- if (method == "activateDomainKey" || method == "deactivateDomainKey") {
+ if (method == "activateDomainKey" || method == "deactivateDomainKey" || method == "publishDomainKey" || method == "unpublishDomainKey") {
// create an empty post
req.preparePost();
verb = "POST";
const Json& param = parameters["key"];
req.POST()["flags"] = asString(param["flags"]);
req.POST()["active"] = (param["active"].bool_value() ? "1" : "0");
+ req.POST()["published"] = (param["published"].bool_value() ? "1" : "0");
req.POST()["content"] = param["content"].string_value();
req.preparePost();
verb = "PUT";
def do_getdomainkeys(args)
ret = []
- db.execute("SELECT cryptokeys.id,flags,active,content FROM domains JOIN cryptokeys ON domains.id = cryptokeys.domain_id WHERE domains.name = ?", [args["name"]]) do |row|
- ret << {:id => row[0].to_i, :flags => row[1].to_i, :active => !(row[2].to_i.zero?), :content => row[3]}
+ db.execute("SELECT cryptokeys.id,flags,active, published, content FROM domains JOIN cryptokeys ON domains.id = cryptokeys.domain_id WHERE domains.name = ?", [args["name"]]) do |row|
+ ret << {:id => row[0].to_i, :flags => row[1].to_i, :active => !(row[2].to_i.zero?), :published => row[3], :content => row[4]}
end
return false if ret.empty?
return [ret,nil]
def do_adddomainkey(args)
d_id = db.get_first_value("SELECT id FROM domains WHERE name = ?", args["name"])
return false if d_id.nil?
- sql = "INSERT INTO cryptokeys (domain_id, flags, active, content) VALUES(?,?,?,?)"
+ sql = "INSERT INTO cryptokeys (domain_id, flags, active, published, content) VALUES(?,?,?,?,?)"
active = args["key"]["active"]
if (active)
active = 1
else
active = 0
end
+ published = args["key"]["published"]
+ if (published)
+ published = 1
+ else
+ published = 0
+ end
db do |tx|
- tx.execute(sql, [d_id, args["key"]["flags"].to_i, active, args["key"]["content"]])
+ tx.execute(sql, [d_id, args["key"]["flags"].to_i, active, published, args["key"]["content"]])
end
return db.get_first_value("SELECT last_insert_rowid()").to_i
end
return true
end
+ def do_unpublishdomainkey(args)
+ d_id = db.get_first_value("SELECT id FROM domains WHERE name = ?", args["name"])
+ return false if d_id.nil?
+ db do |tx|
+ tx.execute("UPDATE cryptokeys SET published = 0 WHERE domain_id = ? AND id = ?", [d_id, args["id"]])
+ end
+ return true
+ end
+
+ def do_publishdomainkey(args)
+ d_id = db.get_first_value("SELECT id FROM domains WHERE name = ?", args["name"])
+ return false if d_id.nil?
+ db do |tx|
+ db.execute("UPDATE cryptokeys SET published = 1 WHERE domain_id = ? AND id = ?", [d_id, args["id"]])
+ end
+ return true
+ end
+
def do_getdomainmetadata(args)
ret = []
sql = "SELECT content FROM domainmetadata JOIN domains WHERE name = :name AND kind = :kind"
args["key"] = {
"flags" => args.delete("flags").to_i,
"active" => args.delete("active").to_i,
+ "published" => args.delete("published").to_i,
"content" => args.delete("content")
}
end
domain_id INT NOT NULL,
flags INT NOT NULL,
active BOOL,
+ published BOOL,
content TEXT
);
key.id = intFromJson(jsonKey, "id");
key.flags = intFromJson(jsonKey, "flags");
key.active = asBool(jsonKey["active"]);
+ key.published = boolFromJson(jsonKey, "published", true);
key.content = stringFromJson(jsonKey, "content");
keys.push_back(key);
}
{ "key", Json::object {
{ "flags", static_cast<int>(key.flags) },
{ "active", key.active },
+ { "published", key.published },
{ "content", key.content }
}}
}}
return true;
}
+bool RemoteBackend::publishDomainKey(const DNSName& name, unsigned int id) {
+ // no point doing dnssec if it's not supported
+ if (d_dnssec == false) return false;
+
+ Json query = Json::object{
+ { "method", "publishDomainKey" },
+ { "parameters", Json::object {
+ { "name", name.toString() },
+ { "id", static_cast<int>(id) }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return true;
+}
+
+bool RemoteBackend::unpublishDomainKey(const DNSName& name, unsigned int id) {
+ // no point doing dnssec if it's not supported
+ if (d_dnssec == false) return false;
+
+ Json query = Json::object{
+ { "method", "unpublishDomainKey" },
+ { "parameters", Json::object {
+ { "name", name.toString() },
+ { "id", static_cast<int>(id) }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return true;
+}
+
+
bool RemoteBackend::doesDNSSEC() {
return d_dnssec;
}
bool addDomainKey(const DNSName& name, const KeyData& key, int64_t& id) override;
bool activateDomainKey(const DNSName& name, unsigned int id) override;
bool deactivateDomainKey(const DNSName& name, unsigned int id) override;
+ bool publishDomainKey(const DNSName& name, unsigned int id) override;
+ bool unpublishDomainKey(const DNSName& name, unsigned int id) override;
bool getDomainInfo(const DNSName& domain, DomainInfo& di, bool getSerial=true ) override;
void setNotified(uint32_t id, uint32_t serial) override;
bool doesDNSSEC() override;
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-DNSBackend::KeyData k1 = {std::string("Private-key-format: v1.2\nAlgorithm: 5 (RSASHA1)\nModulus: qpe9fxlN4dBT38cLPWtqljZhcJjbqRprj9XsYmf2/uFu4kA5sHYrlQY7H9lpzGJPRfOAfxShBpKs1AVaVInfJQ==\nPublicExponent: AQAB\nPrivateExponent: Ad3YogzXvVDLsWuAfioY571QlolbdTbzVlhLEMLD6dSRx+xcZgw6c27ak2HAH00iSKTvqK3AyeaK8Eqy/oJ5QQ==\nPrime1: wo8LZrdU2y0xLGCeLhwziQDDtTMi18NEIwlx8tUPnhs=\nPrime2: 4HcuFqgo7NOiXFvN+V2PT+QaIt2+oi6D2m8/qtTDS78=\nExponent1: GUdCoPbi9JM7l1t6Ud1iKMPLqchaF5SMTs0UXAuous8=\nExponent2: nzgKqimX9f1corTAEw0pddrwKyEtcu8ZuhzFhZCsAxM=\nCoefficient: YGNxbulf5GTNiIu0oNKmAF0khNtx9layjOPEI0R4/RY="), 1, 257, true };
+DNSBackend::KeyData k1 = {std::string("Private-key-format: v1.2\nAlgorithm: 5 (RSASHA1)\nModulus: qpe9fxlN4dBT38cLPWtqljZhcJjbqRprj9XsYmf2/uFu4kA5sHYrlQY7H9lpzGJPRfOAfxShBpKs1AVaVInfJQ==\nPublicExponent: AQAB\nPrivateExponent: Ad3YogzXvVDLsWuAfioY571QlolbdTbzVlhLEMLD6dSRx+xcZgw6c27ak2HAH00iSKTvqK3AyeaK8Eqy/oJ5QQ==\nPrime1: wo8LZrdU2y0xLGCeLhwziQDDtTMi18NEIwlx8tUPnhs=\nPrime2: 4HcuFqgo7NOiXFvN+V2PT+QaIt2+oi6D2m8/qtTDS78=\nExponent1: GUdCoPbi9JM7l1t6Ud1iKMPLqchaF5SMTs0UXAuous8=\nExponent2: nzgKqimX9f1corTAEw0pddrwKyEtcu8ZuhzFhZCsAxM=\nCoefficient: YGNxbulf5GTNiIu0oNKmAF0khNtx9layjOPEI0R4/RY="), 1, 257, true, true };
-DNSBackend::KeyData k2 = {std::string("Private-key-format: v1.2\nAlgorithm: 5 (RSASHA1)\nModulus: tY2TAMgL/whZdSbn2aci4wcMqohO24KQAaq5RlTRwQ33M8FYdW5fZ3DMdMsSLQUkjGnKJPKEdN3Qd4Z5b18f+w==\nPublicExponent: AQAB\nPrivateExponent: BB6xibPNPrBV0PUp3CQq0OdFpk9v9EZ2NiBFrA7osG5mGIZICqgOx/zlHiHKmX4OLmL28oU7jPKgogeuONXJQQ==\nPrime1: yjxe/iHQ4IBWpvCmuGqhxApWF+DY9LADIP7bM3Ejf3M=\nPrime2: 5dGWTyYEQRBVK74q1a64iXgaNuYm1pbClvvZ6ccCq1k=\nExponent1: TwM5RebmWeAqerzJFoIqw5IaQugJO8hM4KZR9A4/BTs=\nExponent2: bpV2HSmu3Fvuj7jWxbFoDIXlH0uJnrI2eg4/4hSnvSk=\nCoefficient: e2uDDWN2zXwYa2P6VQBWQ4mR1ZZjFEtO/+YqOJZun1Y="), 2, 256, true };
+DNSBackend::KeyData k2 = {std::string("Private-key-format: v1.2\nAlgorithm: 5 (RSASHA1)\nModulus: tY2TAMgL/whZdSbn2aci4wcMqohO24KQAaq5RlTRwQ33M8FYdW5fZ3DMdMsSLQUkjGnKJPKEdN3Qd4Z5b18f+w==\nPublicExponent: AQAB\nPrivateExponent: BB6xibPNPrBV0PUp3CQq0OdFpk9v9EZ2NiBFrA7osG5mGIZICqgOx/zlHiHKmX4OLmL28oU7jPKgogeuONXJQQ==\nPrime1: yjxe/iHQ4IBWpvCmuGqhxApWF+DY9LADIP7bM3Ejf3M=\nPrime2: 5dGWTyYEQRBVK74q1a64iXgaNuYm1pbClvvZ6ccCq1k=\nExponent1: TwM5RebmWeAqerzJFoIqw5IaQugJO8hM4KZR9A4/BTs=\nExponent2: bpV2HSmu3Fvuj7jWxbFoDIXlH0uJnrI2eg4/4hSnvSk=\nCoefficient: e2uDDWN2zXwYa2P6VQBWQ4mR1ZZjFEtO/+YqOJZun1Y="), 2, 256, true, true };
BOOST_CHECK(kd.id > 0);
BOOST_CHECK(kd.flags == 256 || kd.flags == 257);
BOOST_CHECK(kd.active == true);
+ BOOST_CHECK(kd.published == true);
BOOST_CHECK(kd.content.size() > 500);
}
}
[false]
end
+ def do_publishdomainkey(args)
+ args["id"] = args["id"].to_i
+ if $keys.has_key? args["name"]
+ if $keys[args["name"]][args["id"]-1]
+ $keys[args["name"]][args["id"]-1]["published"] = true
+ return [true]
+ end
+ end
+ [false]
+ end
+
+ def do_unpublishdomainkey(args)
+ args["id"] = args["id"].to_i
+ if $keys.has_key? args["name"]
+ if $keys[args["name"]][args["id"]-1]
+ $keys[args["name"]][args["id"]-1]["published"] = false
+ return [true]
+ end
+ end
+ [false]
+ end
+
def do_removedomainkey(args)
args["id"] = args["id"].to_i
if $keys.has_key? args["name"]
args["key"] = {
"flags" => args.delete("flags").to_i,
"active" => args.delete("active").to_i,
+ "published" => args.delete("published").to_i,
"content" => args.delete("content")
}
end
d_ActivateDomainKeyQuery = getArg("activate-domain-key-query");
d_DeactivateDomainKeyQuery = getArg("deactivate-domain-key-query");
+ d_PublishDomainKeyQuery = getArg("publish-domain-key-query");
+ d_UnpublishDomainKeyQuery = getArg("unpublish-domain-key-query");
d_RemoveDomainKeyQuery = getArg("remove-domain-key-query");
d_ClearDomainAllKeysQuery = getArg("clear-domain-all-keys-query");
d_RemoveDomainKeyQuery_stmt = NULL;
d_ActivateDomainKeyQuery_stmt = NULL;
d_DeactivateDomainKeyQuery_stmt = NULL;
+ d_PublishDomainKeyQuery_stmt = NULL;
+ d_UnpublishDomainKeyQuery_stmt = NULL;
d_ClearDomainAllKeysQuery_stmt = NULL;
d_getTSIGKeyQuery_stmt = NULL;
d_setTSIGKeyQuery_stmt = NULL;
d_AddDomainKeyQuery_stmt->
bind("flags", key.flags)->
bind("active", key.active)->
+ bind("published", key.published)->
bind("content", key.content)->
bind("domain", name)->
execute()->
return true;
}
+bool GSQLBackend::publishDomainKey(const DNSName& name, unsigned int id)
+{
+ if(!d_dnssecQueries)
+ return false;
+
+ try {
+ reconnectIfNeeded();
+
+ d_PublishDomainKeyQuery_stmt->
+ bind("domain", name)->
+ bind("key_id", id)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to publish key with id "+ std::to_string(id) + " for domain '" + name.toLogString() + "': "+e.txtReason());
+ }
+ return true;
+}
+
+bool GSQLBackend::unpublishDomainKey(const DNSName& name, unsigned int id)
+{
+ if(!d_dnssecQueries)
+ return false;
+
+ try {
+ reconnectIfNeeded();
+
+ d_UnpublishDomainKeyQuery_stmt->
+ bind("domain", name)->
+ bind("key_id", id)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to unpublish key with id "+ std::to_string(id) + " for domain '" + name.toLogString() + "': "+e.txtReason());
+ }
+ return true;
+}
+
+
+
bool GSQLBackend::removeDomainKey(const DNSName& name, unsigned int id)
{
if(!d_dnssecQueries)
KeyData kd;
while(d_ListDomainKeysQuery_stmt->hasNextRow()) {
d_ListDomainKeysQuery_stmt->nextRow(row);
- ASSERT_ROW_COLUMNS("list-domain-keys-query", row, 4);
+ ASSERT_ROW_COLUMNS("list-domain-keys-query", row, 5);
//~ for(const auto& val: row) {
//~ cerr<<"'"<<val<<"'"<<endl;
//~ }
kd.id = pdns_stou(row[0]);
kd.flags = pdns_stou(row[1]);
kd.active = row[2] == "1";
- kd.content = row[3];
+ kd.published = row[3] == "1";
+ kd.content = row[4];
keys.push_back(kd);
}
d_nullifyOrderNameAndUpdateAuthTypeQuery_stmt = d_db->prepare(d_nullifyOrderNameAndUpdateAuthTypeQuery, 4);
d_RemoveEmptyNonTerminalsFromZoneQuery_stmt = d_db->prepare(d_RemoveEmptyNonTerminalsFromZoneQuery, 1);
d_DeleteEmptyNonTerminalQuery_stmt = d_db->prepare(d_DeleteEmptyNonTerminalQuery, 2);
- d_AddDomainKeyQuery_stmt = d_db->prepare(d_AddDomainKeyQuery, 4);
+ d_AddDomainKeyQuery_stmt = d_db->prepare(d_AddDomainKeyQuery, 5);
d_GetLastInsertedKeyIdQuery_stmt = d_db->prepare(d_GetLastInsertedKeyIdQuery, 0);
d_ListDomainKeysQuery_stmt = d_db->prepare(d_ListDomainKeysQuery, 1);
d_GetAllDomainMetadataQuery_stmt = d_db->prepare(d_GetAllDomainMetadataQuery, 1);
d_RemoveDomainKeyQuery_stmt = d_db->prepare(d_RemoveDomainKeyQuery, 2);
d_ActivateDomainKeyQuery_stmt = d_db->prepare(d_ActivateDomainKeyQuery, 2);
d_DeactivateDomainKeyQuery_stmt = d_db->prepare(d_DeactivateDomainKeyQuery, 2);
+ d_PublishDomainKeyQuery_stmt = d_db->prepare(d_PublishDomainKeyQuery, 2);
+ d_UnpublishDomainKeyQuery_stmt = d_db->prepare(d_UnpublishDomainKeyQuery, 2);
d_ClearDomainAllKeysQuery_stmt = d_db->prepare(d_ClearDomainAllKeysQuery, 1);
d_getTSIGKeyQuery_stmt = d_db->prepare(d_getTSIGKeyQuery, 1);
d_setTSIGKeyQuery_stmt = d_db->prepare(d_setTSIGKeyQuery, 3);
d_RemoveDomainKeyQuery_stmt.reset();
d_ActivateDomainKeyQuery_stmt.reset();
d_DeactivateDomainKeyQuery_stmt.reset();
+ d_PublishDomainKeyQuery_stmt.reset();
+ d_UnpublishDomainKeyQuery_stmt.reset();
d_ClearDomainAllKeysQuery_stmt.reset();
d_getTSIGKeyQuery_stmt.reset();
d_setTSIGKeyQuery_stmt.reset();
bool removeDomainKey(const DNSName& name, unsigned int id) override;
bool activateDomainKey(const DNSName& name, unsigned int id) override;
bool deactivateDomainKey(const DNSName& name, unsigned int id) override;
+ bool publishDomainKey(const DNSName& name, unsigned int id) override;
+ bool unpublishDomainKey(const DNSName& name, unsigned int id) override;
bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content) override;
bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content) override;
string d_RemoveDomainKeyQuery;
string d_ActivateDomainKeyQuery;
string d_DeactivateDomainKeyQuery;
+ string d_PublishDomainKeyQuery;
+ string d_UnpublishDomainKeyQuery;
string d_ClearDomainAllKeysQuery;
string d_getTSIGKeyQuery;
unique_ptr<SSqlStatement> d_RemoveDomainKeyQuery_stmt;
unique_ptr<SSqlStatement> d_ActivateDomainKeyQuery_stmt;
unique_ptr<SSqlStatement> d_DeactivateDomainKeyQuery_stmt;
+ unique_ptr<SSqlStatement> d_PublishDomainKeyQuery_stmt;
+ unique_ptr<SSqlStatement> d_UnpublishDomainKeyQuery_stmt;
unique_ptr<SSqlStatement> d_ClearDomainAllKeysQuery_stmt;
unique_ptr<SSqlStatement> d_getTSIGKeyQuery_stmt;
unique_ptr<SSqlStatement> d_setTSIGKeyQuery_stmt;
--- /dev/null
+ALTER TABLE cryptokeys ADD published BOOL DEFAULT 1;
domain VARCHAR(255) COLLATE NOCASE,
flags INT NOT NULL,
active BOOL,
+ published BOOL,
content TEXT
);
return meta=="1";
}
-bool DNSSECKeeper::addKey(const DNSName& name, bool setSEPBit, int algorithm, int64_t& id, int bits, bool active)
+bool DNSSECKeeper::addKey(const DNSName& name, bool setSEPBit, int algorithm, int64_t& id, int bits, bool active, bool published)
{
if(!bits) {
if(algorithm <= 10)
dspk.setKey(dpk);
dspk.d_algorithm = algorithm;
dspk.d_flags = setSEPBit ? 257 : 256;
- return addKey(name, dspk, id, active);
+ return addKey(name, dspk, id, active, published);
}
void DNSSECKeeper::clearAllCaches() {
}
-bool DNSSECKeeper::addKey(const DNSName& name, const DNSSECPrivateKey& dpk, int64_t& id, bool active)
+bool DNSSECKeeper::addKey(const DNSName& name, const DNSSECPrivateKey& dpk, int64_t& id, bool active, bool published)
{
clearCaches(name);
DNSBackend::KeyData kd;
kd.flags = dpk.d_flags; // the dpk doesn't get stored, only they key part
kd.active = active;
+ kd.published = published;
kd.content = dpk.getKey()->convertToISC();
// now store it
return d_keymetadb->addDomainKey(name, kd, id);
return d_keymetadb->activateDomainKey(zname, id);
}
+bool DNSSECKeeper::unpublishKey(const DNSName& zname, unsigned int id)
+{
+ clearCaches(zname);
+ return d_keymetadb->unpublishDomainKey(zname, id);
+}
+
+bool DNSSECKeeper::publishKey(const DNSName& zname, unsigned int id)
+{
+ clearCaches(zname);
+ return d_keymetadb->publishDomainKey(zname, id);
+}
+
void DNSSECKeeper::getFromMetaOrDefault(const DNSName& zname, const std::string& key, std::string& value, const std::string& defaultvalue)
{
if (getFromMeta(zname, key, value))
KeyMetaData kmd;
kmd.active = kd.active;
+ kmd.published = kd.published;
kmd.hasSEPBit = (kd.flags == 257);
kmd.id = kd.id;
unsigned int id;
unsigned int flags;
bool active;
+ bool published;
};
virtual bool getDomainKeys(const DNSName& name, std::vector<KeyData>& keys) { return false;}
virtual bool addDomainKey(const DNSName& name, const KeyData& key, int64_t& id){ return false; }
virtual bool activateDomainKey(const DNSName& name, unsigned int id) { return false; }
virtual bool deactivateDomainKey(const DNSName& name, unsigned int id) { return false; }
+ virtual bool publishDomainKey(const DNSName& name, unsigned int id) { return false; }
+ virtual bool unpublishDomainKey(const DNSName& name, unsigned int id) { return false; }
virtual bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content) { return false; }
virtual bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content) { return false; }
bool active;
keytype_t keyType;
bool hasSEPBit;
+ bool published;
};
typedef std::pair<DNSSECPrivateKey, KeyMetaData> keymeta_t;
typedef std::vector<keymeta_t > keyset_t;
keyset_t getEntryPoints(const DNSName& zname);
keyset_t getKeys(const DNSName& zone, bool useCache = true);
DNSSECPrivateKey getKeyById(const DNSName& zone, unsigned int id);
- bool addKey(const DNSName& zname, bool setSEPBit, int algorithm, int64_t& id, int bits=0, bool active=true);
- bool addKey(const DNSName& zname, const DNSSECPrivateKey& dpk, int64_t& id, bool active=true);
+ bool addKey(const DNSName& zname, bool setSEPBit, int algorithm, int64_t& id, int bits=0, bool active=true, bool published=true);
+ bool addKey(const DNSName& zname, const DNSSECPrivateKey& dpk, int64_t& id, bool active=true, bool published=true);
bool removeKey(const DNSName& zname, unsigned int id);
bool activateKey(const DNSName& zname, unsigned int id);
bool deactivateKey(const DNSName& zname, unsigned int id);
+ bool publishKey(const DNSName& zname, unsigned int id);
+ bool unpublishKey(const DNSName& zname, unsigned int id);
bool checkKeys(const DNSName& zname, vector<string>* errorMessages = nullptr);
bool getNSEC3PARAM(const DNSName& zname, NSEC3PARAMRecordContent* n3p=0, bool* narrow=0);
DNSSECKeeper::keyset_t entryPoints = d_dk.getEntryPoints(p.qdomain);
for(const auto& value: entryPoints) {
+ if (!value.second.published) {
+ continue;
+ }
rr.dr.d_type=QType::CDNSKEY;
rr.dr.d_ttl=sd.default_ttl;
rr.dr.d_name=p.qdomain;
DNSSECKeeper::keyset_t keyset = d_dk.getKeys(p.qdomain);
for(const auto& value: keyset) {
+ if (!value.second.published) {
+ continue;
+ }
rr.dr.d_type=QType::DNSKEY;
rr.dr.d_ttl=sd.default_ttl;
rr.dr.d_name=p.qdomain;
DNSSECKeeper::keyset_t keyset = d_dk.getEntryPoints(p.qdomain);
for(auto const &value : keyset) {
+ if (!value.second.published) {
+ continue;
+ }
for(auto const &digestAlgo : digestAlgos){
rr.dr.d_content=std::make_shared<DSRecordContent>(makeDSFromDNSKey(p.qdomain, value.first.getDNSKEY(), pdns_stou(digestAlgo)));
r->addRecord(rr);
if (!exportDS) {
cout<<", flags = "<<std::to_string(value.first.d_flags);
cout<<", tag = "<<value.first.getDNSKEY().getTag();
- cout<<", algo = "<<(int)value.first.d_algorithm<<", bits = "<<value.first.getKey()->getBits()<<"\t"<<((int)value.second.active == 1 ? " A" : "Ina")<<"ctive ( " + algname + " ) "<<endl;
+ cout<<", algo = "<<(int)value.first.d_algorithm<<", bits = "<<value.first.getKey()->getBits()<<"\t"<<((int)value.second.active == 1 ? " A" : "Ina")<<"ctive\t"<<(value.second.published ? " Published" : " Unpublished")<<" ( " + algname + " ) "<<endl;
}
if (!exportDS) {
int k_real_algo = DNSSECKeeper::shorthand2algorithm(k_algo);
- if (!dk.addKey(zone, true, k_real_algo, id, k_size, true)) {
+ if (!dk.addKey(zone, true, k_real_algo, id, k_size, true, true)) {
cerr<<"No backend was able to secure '"<<zone<<"', most likely because no DNSSEC"<<endl;
cerr<<"capable backends are loaded, or because the backends have DNSSEC disabled."<<endl;
cerr<<"For the Generic SQL backends, set the 'gsqlite3-dnssec', 'gmysql-dnssec' or"<<endl;
int z_real_algo = DNSSECKeeper::shorthand2algorithm(z_algo);
- if (!dk.addKey(zone, false, z_real_algo, id, z_size, true)) {
+ if (!dk.addKey(zone, false, z_real_algo, id, z_size, true, true)) {
cerr<<"No backend was able to secure '"<<zone<<"', most likely because no DNSSEC"<<endl;
cerr<<"capable backends are loaded, or because the backends have DNSSEC disabled."<<endl;
cerr<<"For the Generic SQL backends, set the 'gsqlite3-dnssec', 'gmysql-dnssec' or"<<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-zone-key ZONE {zsk|ksk} [BITS] [active|inactive]"<<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_LIBDECAF) || defined(HAVE_LIBCRYPTO_ED25519)
cout<<"|ed25519";
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] Defaults to KSK and active"<<endl;
+ cout<<" [active|inactive] [ksk|zsk] [published|unpublished] Defaults to KSK, active and published"<<endl;
cout<<"ipdecrypt IP passphrase/key [key] Encrypt 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<<"list-all-zones [master|slave|native]"<<endl;
cout<<" List all zone names"<<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<<"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;
}
return 0;
}
+ else if(cmds[0] == "publish-zone-key") {
+ if(cmds.size() != 3) {
+ cerr << "Syntax: pdnsutil publish-zone-key ZONE KEY-ID"<<endl;
+ return 0;
+ }
+ DNSName zone(cmds[1]);
+ unsigned int id=atoi(cmds[2].c_str()); // if you make this pdns_stou, the error gets worse
+ if(!id)
+ {
+ cerr<<"Invalid KEY-ID '"<<cmds[2]<<"'"<<endl;
+ return 1;
+ }
+ if (!dk.publishKey(zone, id)) {
+ cerr<<"Publishing of key failed"<<endl;
+ return 1;
+ }
+ return 0;
+ }
+ else if(cmds[0] == "unpublish-zone-key") {
+ if(cmds.size() != 3) {
+ cerr << "Syntax: pdnsutil unpublish-zone-key ZONE KEY-ID"<<endl;
+ return 0;
+ }
+ DNSName zone(cmds[1]);
+ unsigned int id=atoi(cmds[2].c_str()); // if you make this pdns_stou, the error gets worse
+ if(!id)
+ {
+ cerr<<"Invalid KEY-ID '"<<cmds[2]<<"'"<<endl;
+ return 1;
+ }
+ if (!dk.unpublishKey(zone, id)) {
+ cerr<<"Unpublishing of key failed"<<endl;
+ return 1;
+ }
+ return 0;
+ }
+
else if(cmds[0] == "add-zone-key") {
if(cmds.size() < 3 ) {
cerr << "Syntax: pdnsutil add-zone-key ZONE zsk|ksk [BITS] [active|inactive] [rsasha1|rsasha1-nsec3-sha1|rsasha256|rsasha512|ecdsa256|ecdsa384";
int bits=0;
int algorithm=DNSSECKeeper::ECDSA256;
bool active=false;
+ bool published=true;
for(unsigned int n=2; n < cmds.size(); ++n) {
if(pdns_iequals(cmds[n], "zsk"))
keyOrZone = false;
active=true;
} else if(pdns_iequals(cmds[n], "inactive") || pdns_iequals(cmds[n], "passive")) { // 'passive' eventually needs to be removed
active=false;
+ } else if(pdns_iequals(cmds[n], "published")) {
+ published = true;
+ } else if(pdns_iequals(cmds[n], "unpublished")) {
+ published = false;
} else if(pdns_stou(cmds[n])) {
bits = pdns_stou(cmds[n]);
} else {
}
}
int64_t id;
- if (!dk.addKey(zone, keyOrZone, algorithm, id, bits, active)) {
+ if (!dk.addKey(zone, keyOrZone, algorithm, id, bits, active, published)) {
cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl;
exit(1);
} else {
dpk.d_flags = 257;
bool active=true;
+ bool published=true;
for(unsigned int n = 3; n < cmds.size(); ++n) {
if(pdns_iequals(cmds[n], "ZSK"))
active = 1;
else if(pdns_iequals(cmds[n], "passive") || pdns_iequals(cmds[n], "inactive")) // passive eventually needs to be removed
active = 0;
+ else if(pdns_iequals(cmds[n], "published"))
+ published = 1;
+ else if(pdns_iequals(cmds[n], "unpublished"))
+ published = 0;
else {
cerr<<"Unknown key flag '"<<cmds[n]<<"'"<<endl;
exit(1);
}
}
int64_t id;
- if (!dk.addKey(DNSName(zone), dpk, id, active)) {
+ if (!dk.addKey(DNSName(zone), dpk, id, active, published)) {
cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl;
exit(1);
}
entryPointIds.insert(value.second.id);
for(const DNSSECKeeper::keyset_t::value_type& value : keys) {
+ if (!value.second.published) {
+ continue;
+ }
zrr.dr.d_type = QType::DNSKEY;
zrr.dr.d_content = std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY());
DNSName keyname = NSEC3Zone ? DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, zrr.dr.d_name))) : zrr.dr.d_name;
return false;
}
+bool UeberBackend::publishDomainKey(const DNSName& name, unsigned int id)
+{
+ for(DNSBackend* db : backends) {
+ if(db->publishDomainKey(name, id))
+ return true;
+ }
+ return false;
+}
+
+bool UeberBackend::unpublishDomainKey(const DNSName& name, unsigned int id)
+{
+ for(DNSBackend* db : backends) {
+ if(db->unpublishDomainKey(name, id))
+ return true;
+ }
+ return false;
+}
+
+
bool UeberBackend::removeDomainKey(const DNSName& name, unsigned int id)
{
for(DNSBackend* db : backends) {
bool removeDomainKey(const DNSName& name, unsigned int id);
bool activateDomainKey(const DNSName& name, unsigned int id);
bool deactivateDomainKey(const DNSName& name, unsigned int id);
+ bool publishDomainKey(const DNSName& name, unsigned int id);
+ bool unpublishDomainKey(const DNSName& name, unsigned int id);
bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content);
bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content);
{ "type", "Cryptokey" },
{ "id", (int)value.second.id },
{ "active", value.second.active },
+ { "published", value.second.published },
{ "keytype", keyType },
{ "flags", (uint16_t)value.first.d_flags },
{ "dnskey", value.first.getDNSKEY().getZoneRepresentation() },
privatekey_fieldname = "content";
}
bool active = boolFromJson(document, "active", false);
+ bool published = boolFromJson(document, "published", true);
bool keyOrZone;
if (stringFromJson(document, "keytype") == "ksk" || stringFromJson(document, "keytype") == "csk") {
}
try {
- if (!dk->addKey(zonename, keyOrZone, algorithm, insertedId, bits, active)) {
+ if (!dk->addKey(zonename, keyOrZone, algorithm, insertedId, bits, active, published)) {
throw ApiException("Adding key failed, perhaps DNSSEC not enabled in configuration?");
}
} catch (std::runtime_error& error) {
catch (std::runtime_error& error) {
throw ApiException("Key could not be parsed. Make sure your key format is correct.");
} try {
- if (!dk->addKey(zonename, dpk,insertedId, active)) {
+ if (!dk->addKey(zonename, dpk,insertedId, active, published)) {
throw ApiException("Adding key failed, perhaps DNSSEC not enabled in configuration?");
}
} catch (std::runtime_error& error) {
auto document = req->json();
//throws an exception if the key does not exist or is not a bool
bool active = boolFromJson(document, "active");
+ bool published = boolFromJson(document, "published", true);
if (active) {
if (!dk->activateKey(zonename, inquireKeyId)) {
resp->setErrorResult("Could not activate Key: " + req->parameters["key_id"] + " in Zone: " + zonename.toString(), 422);
return;
}
}
+
+ if (published) {
+ if (!dk->publishKey(zonename, inquireKeyId)) {
+ resp->setErrorResult("Could not publish Key: " + req->parameters["key_id"] + " in Zone: " + zonename.toString(), 422);
+ return;
+ }
+ } else {
+ if (!dk->unpublishKey(zonename, inquireKeyId)) {
+ resp->setErrorResult("Could not unpublish Key: " + req->parameters["key_id"] + " in Zone: " + zonename.toString(), 422);
+ return;
+ }
+ }
+
resp->body = "";
resp->status = 204;
return;
u'type': u'Cryptokey',
u'keytype': u'csk',
u'flags': 257,
+ u'published': True,
u'id': 1}
self.assertEquals(key0, expected)
self.remove_zone_key(self.keyid)
# Adding a key to self.zone using the pdnsutil command
- def add_zone_key(self, status='inactive'):
- return pdnsutil("add-zone-key", self.zone_nodot, "ksk", status)
+ def add_zone_key(self, status=['inactive']):
+ return pdnsutil("add-zone-key", self.zone_nodot, "ksk", *status)
# Removes a key from self.zone by id using the pdnsutil command
def remove_zone_key(self, key_id):
self.keyid = self.add_zone_key()
payload = {
- 'active': True
+ 'active': True,
+ 'published': True,
}
r = self.session.put(
self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
self.assertIn("Active", out)
def test_put_deactivate_key(self):
- self.keyid = self.add_zone_key(status='active')
+ self.keyid = self.add_zone_key(status=['active'])
# deactivate key
payload2 = {
- 'active': False
+ 'active': False,
+ 'published': True,
}
r = self.session.put(
# deactivate key
payload = {
- 'active': False
+ 'active': False,
+ 'published': True,
}
r = self.session.put(
self.assertIn("Inactive", out)
def test_put_activate_active_key(self):
- self.keyid =self.add_zone_key(status='active')
+ self.keyid = self.add_zone_key(status=['active'])
# activate key
payload2 = {
- 'active': True
+ 'active': True,
+ 'published': True,
}
r = self.session.put(
self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
# check if key is activated
out = pdnsutil("show-zone", self.zone_nodot)
self.assertIn("Active", out)
+
+ def test_put_unpublish_key(self):
+ self.keyid = self.add_zone_key(status=['active'])
+
+ payload = {
+ 'active': True,
+ 'published': False,
+ }
+ r = self.session.put(
+ self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
+ data=json.dumps(payload),
+ headers={'content-type': 'application/json'})
+ self.assertEquals(r.status_code, 204)
+ self.assertEquals(r.content, b"")
+
+ # check if key is activated
+ out = pdnsutil("show-zone", self.zone_nodot)
+ self.assertIn("Unpublished", out)
+
+ def test_put_publish_key(self):
+ self.keyid = self.add_zone_key(status=['active', 'unpublished'])
+ # deactivate key
+ payload2 = {
+ 'active': True,
+ 'published': True,
+ }
+
+ r = self.session.put(
+ self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
+ data=json.dumps(payload2),
+ headers={'content-type': 'application/json'})
+ self.assertEquals(r.status_code, 204)
+ self.assertEquals(r.content, b"")
+
+ # check if key is deactivated
+ out = pdnsutil("show-zone", self.zone_nodot)
+ self.assertIn("Published", out)
+
+ def test_put_publish_published_key(self):
+ self.keyid = self.add_zone_key(status=['active'])
+
+ # deactivate key
+ payload = {
+ 'active': True,
+ 'published': True,
+ }
+
+ r = self.session.put(
+ self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
+ data=json.dumps(payload),
+ headers={'content-type': 'application/json'})
+ self.assertEquals(r.status_code, 204)
+ self.assertEquals(r.content, b"")
+
+ # check if key is still deactivated
+ out = pdnsutil("show-zone", self.zone_nodot)
+ self.assertIn("Published", out)
+
+ def test_put_unpublish_unpublished_key(self):
+ self.keyid = self.add_zone_key(status=['active', 'unpublished'])
+
+ # activate key
+ payload2 = {
+ 'active': True,
+ 'published': False,
+ }
+ r = self.session.put(
+ self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
+ data=json.dumps(payload2),
+ headers={'content-type': 'application/json'})
+ self.assertEquals(r.status_code, 204)
+ self.assertEquals(r.content, b"")
+
+ # check if key is activated
+ out = pdnsutil("show-zone", self.zone_nodot)
+ self.assertIn("Unpublished", out)
b1f775045fa2cf0a3b91aa834af06e49 ../regression-tests/zones/stest.com
a98864b315f16bcf49ce577426063c42 ../regression-tests/zones/cdnskey-cds-test.com
9aeed2c26d0c3ba3baf22dfa9568c451 ../regression-tests/zones/2.0.192.in-addr.arpa
+99c73e8b5db5781fec1ac3fa6a2662a9 ../regression-tests/zones/cryptokeys.org
52a95993ada0b4ed986a2fe6463a27e0 ../modules/tinydnsbackend/data.cdb
then
$PDNSUTIL --config-dir=. --config-name=bind set-nsec3 $zone '1 1 1 abcd' narrow 2>&1
fi
+ if [ $zone = cryptokeys.org ]
+ then
+ $PDNSUTIL --config-dir=. --config-name=bind add-zone-key $zone zsk 384 active unpublished ecdsa384
+ $PDNSUTIL --config-dir=. --config-name=bind add-zone-key $zone zsk 2048 inactive published rsasha512
+ $PDNSUTIL --config-dir=. --config-name=bind add-zone-key $zone zsk 2048 inactive unpublished rsasha256
+ fi
fi
if [ "$zone" = "tsig.com" ]; then
$PDNSUTIL --config-dir=. --config-name=bind import-tsig-key test $ALGORITHM $KEY
# ../pdns/pdns_server --module-dir=./modules/ --launch=gsqlite3 --config | grep gsqlite3 | grep query | grep = | cut -c3- | perl -pe 's/^gsqlite3/godbc/; s/:\w+/?/g'
godbc-activate-domain-key-query=update cryptokeys set active=1 where domain_id=(select id from domains where name=?) and cryptokeys.id=?
-godbc-add-domain-key-query=insert into cryptokeys (domain_id, flags, active, content) select id, ?,?, ? from domains where name=?
+godbc-add-domain-key-query=insert into cryptokeys (domain_id, flags, active, published, content) select id, ?, ?, ?, ? from domains where name=?
godbc-any-id-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and name=? and domain_id=?
godbc-any-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and name=?
godbc-basic-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and type=? and name=?
godbc-get-order-last-query=select ordername, name from records where disabled=0 and ordername != '' and domain_id=? and ordername is not null order by 1 desc limit 1
godbc-get-tsig-key-query=select algorithm, secret from tsigkeys where name=?
godbc-get-tsig-keys-query=select name,algorithm, secret from tsigkeys
+godbc-publish-domain-key-query=update cryptokeys set published=1 where domain_id=(select id from domains where name=?) and cryptokeys.id=?
godbc-id-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and type=? and name=? and domain_id=?
godbc-info-all-master-query=select id,name,master,last_check,notified_serial,type from domains where type='MASTER'
godbc-info-all-slaves-query=select id,name,master,last_check from domains where type='SLAVE'
godbc-insert-record-query=insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth) values (?,?,?,?,?,?,?,?,?)
godbc-insert-zone-query=insert into domains (type,name,master,account,last_check,notified_serial) values(?, ?, ?, ?, null, null)
godbc-list-comments-query=SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=?
-godbc-list-domain-keys-query=select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=?
+godbc-list-domain-keys-query=select cryptokeys.id, flags, active, published, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=?
godbc-list-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE (disabled=0 OR ?) and domain_id=? order by name, type
godbc-list-subzone-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and (name=? OR name like ?) and domain_id=?
godbc-nullify-ordername-and-update-auth-query=update records set ordername=NULL,auth=? where domain_id=? and name=? and disabled=0
godbc-set-domain-metadata-query=insert into domainmetadata (domain_id, kind, content) select id, ?, ? from domains where name=?
godbc-set-tsig-key-query=replace into tsigkeys (name,algorithm,secret) values(?,?,?)
godbc-supermaster-query=select account from supermasters where ip=? and nameserver=?
+godbc-unpublish-domain-key-query=update cryptokeys set published=0 where domain_id=(select id from domains where name=?) and cryptokeys.id=?
godbc-update-account-query=update domains set account=? where name=?
godbc-update-kind-query=update domains set type=? where name=?
godbc-update-lastcheck-query=update domains set last_check=? where id=?
$PDNSUTIL --config-dir=. --config-name=$backend set-nsec3 $zone '1 1 1 abcd' narrow 2>&1
fi
securezone $zone ${backend}
+ if [ $zone = cryptokeys.org ]
+ then
+ $PDNSUTIL --config-dir=. --config-name=$backend add-zone-key $zone zsk 384 active unpublished ecdsa384
+ $PDNSUTIL --config-dir=. --config-name=$backend add-zone-key $zone zsk 2048 inactive published rsasha512
+ $PDNSUTIL --config-dir=. --config-name=$backend add-zone-key $zone zsk 2048 inactive unpublished rsasha256
+ fi
else
$PDNSUTIL --config-dir=. --config-name=$backend rectify-zone $zone 2>&1
fi
$PDNSUTIL --config-dir=. --config-name=lmdb set-nsec3 $zone '1 1 1 abcd' narrow 2>&1
fi
securezone $zone lmdb
+ if [ $zone = cryptokeys.org ]
+ then
+ $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 384 active unpublished ecdsa384
+ $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 2048 inactive published rsasha512
+ $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 2048 inactive unpublished rsasha256
+ fi
fi
else
$PDNSUTIL --config-dir=. --config-name=lmdb rectify-zone $zone 2>&1
type master;
file "2.0.192.in-addr.arpa";
};
+
+zone "cryptokeys.org"{
+ type master;
+ file "cryptokeys.org";
+};
+
--- /dev/null
+#!/bin/sh
+cleandig cryptokeys.org DNSKEY dnssec
--- /dev/null
+Test all possible combinations between active, inactive, published and unpublished keys.
--- /dev/null
+0 cryptokeys.org. IN DNSKEY 3600 256 3 10 ...
+0 cryptokeys.org. IN DNSKEY 3600 257 3 13 ...
+0 cryptokeys.org. IN RRSIG 3600 DNSKEY 13 2 3600 [expiry] [inception] [keytag] cryptokeys.org. ...
+0 cryptokeys.org. IN RRSIG 3600 DNSKEY 14 2 3600 [expiry] [inception] [keytag] cryptokeys.org. ...
+2 . IN OPT 32768
+Rcode: 0 (No Error), RD: 0, QR: 1, TC: 0, AA: 1, opcode: 0
+Reply to question for qname='cryptokeys.org.', qtype=DNSKEY
#!/usr/bin/env bash
-for zone in $(grep 'zone ' named.conf | cut -f2 -d\" | grep -v '^\(example.com\|nztest.com\|insecure.dnssec-parent.com\)$')
+for zone in $(grep 'zone ' named.conf | cut -f2 -d\" | grep -v '^\(cryptokeys.org\|example.com\|nztest.com\|insecure.dnssec-parent.com\)$')
do
TFILE=$(mktemp tmp.XXXXXXXXXX)
drill -p $port axfr $zone @$nameserver | ldns-read-zone -z -u CDS -u CDNSKEY > $TFILE
/*.bind
/*.com-slave
/*.dyndns-slave
+/*.org-slave
/2.0.192.in-addr.arpa-slave
/*.signed
/*.nsd