#include "zoneparser-tng.hh"
#include "signingpipe.hh"
#include "dns_random.hh"
+#include "ipcipher.hh"
#include <fstream>
#include <termios.h> //termios, TCSANOW, ECHO, ICANON
#include "opensslsigners.hh"
exit(0);
}
- if(::arg()["config-name"]!="")
+ if(::arg()["config-name"]!="")
s_programname+="-"+::arg()["config-name"];
string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
g_log.toConsole(Logger::Error); // so we print any errors
BackendMakers().launch(::arg()["launch"]); // vrooooom!
if(::arg().asNum("loglevel") >= 3) // so you can't kill our errors
- g_log.toConsole((Logger::Urgency)::arg().asNum("loglevel"));
+ g_log.toConsole((Logger::Urgency)::arg().asNum("loglevel"));
//cerr<<"Backend: "<<::arg()["launch"]<<", '" << ::arg()["gmysql-dbname"] <<"'" <<endl;
S.declare("qsize-q","Number of questions waiting for database attention");
-
+
::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
- ::arg().set("cache-ttl","Seconds to store packets in the PacketCache")="20";
+ ::arg().set("cache-ttl","Seconds to store packets in the PacketCache")="20";
::arg().set("negquery-cache-ttl","Seconds to store negative query results in the QueryCache")="60";
- ::arg().set("query-cache-ttl","Seconds to store query results in the QueryCache")="20";
+ ::arg().set("query-cache-ttl","Seconds to store query results in the QueryCache")="20";
::arg().set("default-soa-name","name to insert in the SOA record if none set in the backend")="a.misconfigured.powerdns.server";
::arg().set("default-soa-mail","mail address to insert in the SOA record if none set in the backend")="";
::arg().set("soa-refresh-default","Default SOA refresh")="10800";
::arg().set("soa-retry-default","Default SOA retry")="3600";
::arg().set("soa-expire-default","Default SOA expire")="604800";
- ::arg().set("soa-minimum-ttl","Default SOA minimum ttl")="3600";
+ ::arg().set("soa-minimum-ttl","Default SOA minimum ttl")="3600";
::arg().set("chroot","Switch to this chroot jail")="";
::arg().set("dnssec-key-cache-ttl","Seconds to cache DNSSEC keys from the database")="30";
::arg().set("domain-metadata-cache-ttl","Seconds to cache domain metadata from the database")="60";
dt.set();
unsigned int hits=0, misses=0;
for(; n < 10000; ++n) {
- DNSName domain(domains[random() % domains.size()]);
+ DNSName domain(domains[dns_random(domains.size())]);
B.lookup(QType(QType::NS), domain);
while(B.get(rr)) {
hits++;
int checkZone(DNSSECKeeper &dk, UeberBackend &B, const DNSName& zone, const vector<DNSResourceRecord>* suppliedrecords=0)
{
+ uint64_t numerrors=0, numwarnings=0;
+
+ DomainInfo di;
+ try {
+ if (!B.getDomainInfo(zone, di)) {
+ cout<<"[Error] Unable to get domain information for zone '"<<zone<<"'"<<endl;
+ return 1;
+ }
+ } catch(const PDNSException &e) {
+ if (di.kind == DomainInfo::Slave) {
+ cout<<"[Error] non-IP address for masters: "<<e.reason<<endl;
+ numerrors++;
+ }
+ }
+
SOAData sd;
if(!B.getSOAUncached(zone, sd)) {
- cout<<"[error] No SOA record present, or active, in zone '"<<zone<<"'"<<endl;
- cout<<"Checked 0 records of '"<<zone<<"', 1 errors, 0 warnings."<<endl;
+ cout<<"[Error] No SOA record present, or active, in zone '"<<zone<<"'"<<endl;
+ numerrors++;
+ cout<<"Checked 0 records of '"<<zone<<"', "<<numerrors<<" errors, 0 warnings."<<endl;
return 1;
}
vector<string> checkKeyErrors;
bool validKeys=dk.checkKeys(zone, &checkKeyErrors);
- uint64_t numerrors=0, numwarnings=0;
-
if (haveNSEC3) {
if(isSecure && zone.wirelength() > 222) {
numerrors++;
records.push_back(drr);
}
}
- else
+ else
records=*suppliedrecords;
for(auto &rr : records) { // we modify this
NSEC3PARAMRecordContent ns3pr;
bool narrow;
bool haveNSEC3=dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
-
+
DNSName ordername;
if(haveNSEC3) {
if(!narrow)
spacelen = (std::to_string(key.first.getKey()->getBits()).length() >= 8) ? 1 : 8 - std::to_string(key.first.getKey()->getBits()).length();
if (key.first.getKey()->getBits() < 1) {
cout<<"invalid "<<endl;
- continue;
+ continue;
} else {
cout<<key.first.getKey()->getBits()<<string(spacelen, ' ');
}
int listZone(const DNSName &zone) {
UeberBackend B;
DomainInfo di;
-
+
if (! B.getDomainInfo(zone, di)) {
cerr<<"Domain '"<<zone<<"' not found!"<<endl;
return EXIT_FAILURE;
while(di.backend->get(rr)) {
if(rr.qtype.getCode()) {
- if ( (rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::SRV || rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::CNAME) && !rr.content.empty() && rr.content[rr.content.size()-1] != '.')
+ if ( (rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::SRV || rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::CNAME) && !rr.content.empty() && rr.content[rr.content.size()-1] != '.')
rr.content.append(1, '.');
-
+
cout<<rr.qname<<"\t"<<rr.ttl<<"\tIN\t"<<rr.qtype.getName()<<"\t"<<rr.content<<"\n";
}
}
}
// lovingly copied from http://stackoverflow.com/questions/1798511/how-to-avoid-press-enter-with-any-getchar
-int read1char(){
- int c;
+int read1char(){
+ int c;
static struct termios oldt, newt;
/*tcgetattr gets the parameters of the current terminal
/*ICANON normally takes care that one line at a time will be processed
that means it will return if it sees a "\n" or an EOF or an EOL*/
- newt.c_lflag &= ~(ICANON);
+ newt.c_lflag &= ~(ICANON);
/*Those new settings will be set to STDIN
TCSANOW tells tcsetattr to change attributes immediately. */
int clearZone(DNSSECKeeper& dk, const DNSName &zone) {
UeberBackend B;
DomainInfo di;
-
+
if (! B.getDomainInfo(zone, di)) {
cerr<<"Domain '"<<zone<<"' not found!"<<endl;
return EXIT_FAILURE;
int editZone(DNSSECKeeper& dk, const DNSName &zone) {
UeberBackend B;
DomainInfo di;
-
+
if (! B.getDomainInfo(zone, di)) {
cerr<<"Domain '"<<zone<<"' not found!"<<endl;
return EXIT_FAILURE;
cerr<<"\n";
if(c!='a')
post.clear();
- if(c=='e')
+ if(c=='e')
goto editMore;
else if(c=='r')
goto editAgain;
return EXIT_SUCCESS;
}
+static int xcryptIP(const std::string& cmd, const std::string& ip, const std::string& rkey)
+{
+
+ ComboAddress ca(ip), ret;
+
+ if(cmd=="ipencrypt")
+ ret = encryptCA(ca, rkey);
+ else
+ ret = decryptCA(ca, rkey);
+
+ cout<<ret.toString()<<endl;
+ return EXIT_SUCCESS;
+}
+
int loadZone(DNSName zone, const string& fname) {
UeberBackend B;
else {
cerr<<"Creating '"<<zone<<"'"<<endl;
B.createDomain(zone);
-
+
if(!B.getDomainInfo(zone, di)) {
cerr<<"Domain '"<<zone<<"' was not created - perhaps backend ("<<::arg()["launch"]<<") does not support storing new zones."<<endl;
return EXIT_FAILURE;
}
DNSBackend* db = di.backend;
ZoneParserTNG zpt(fname, zone);
-
+
DNSResourceRecord rr;
if(!db->startTransaction(zone, di.id)) {
cerr<<"Unable to start transaction for load of zone '"<<zone<<"'"<<endl;
return EXIT_FAILURE;
}
- rr.domain_id=di.id;
+ rr.domain_id=di.id;
bool haveSOA = false;
while(zpt.get(rr)) {
if(!rr.qname.isPartOf(zone) && rr.qname!=zone) {
rr.auth = 1;
rr.ttl = ::arg().asNum("default-ttl");
rr.qtype = "SOA";
-
+
string soa = (boost::format("%s %s 1")
% (nsname.empty() ? ::arg()["default-soa-name"] : nsname.toString())
% (::arg().isEmpty("default-soa-mail") ? (DNSName("hostmaster.") + zone).toString() : ::arg()["default-soa-mail"])
rr.content=nsname.toStringNoDot();
di.backend->feedRecord(rr, DNSName());
}
-
+
di.backend->commitTransaction();
return EXIT_SUCCESS;
DNSName name;
if(cmds[2]=="@")
name=zone;
- else
+ else
name=DNSName(cmds[2])+zone;
rr.qtype = DNSRecordContent::TypeToNumber(cmds[3]);
newrrs.push_back(rr);
}
-
+
di.backend->replaceRRSet(di.id, name, rr.qtype, newrrs);
// need to be explicit to bypass the ueberbackend cache!
di.backend->lookup(rr.qtype, name, 0, di.id);
}
// delete-rrset zone name type
-int deleteRRSet(const std::string& zone_, const std::string& name_, const std::string& type_)
+int deleteRRSet(const std::string& zone_, const std::string& name_, const std::string& type_)
{
UeberBackend B;
DomainInfo di;
DNSName name;
if(name_=="@")
name=zone;
- else
+ else
name=DNSName(name_)+zone;
QType qt(QType::chartocode(type_.c_str()));
rr.ttl=3600;
rr.auth=1;
rr.qclass = QClass::IN;
-
+
UeberBackend db("key-only");
-
+
if ( ! db.backends.size() )
{
throw runtime_error("No backends available for DNSSEC key storage");
}
ChunkedSigningPipe csp(DNSName(zone), 1, cores);
-
+
vector<DNSZoneRecord> signatures;
uint32_t rnd;
unsigned char* octets = (unsigned char*)&rnd;
DTime dt;
dt.set();
for(unsigned int n=0; n < 100000; ++n) {
- rnd = random();
- snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
+ rnd = dns_random(UINT32_MAX);
+ snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
octets[0], octets[1], octets[2], octets[3]);
rr.content=tmp;
-
+
snprintf(tmp, sizeof(tmp), "r-%u", rnd);
rr.qname=DNSName(tmp)+zone;
DNSZoneRecord dzr;
toSign.push_back(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content));
}
}
-
+
string msg = getMessageForRRSET(qname, rrc, toSign);
cerr<<"Verify: "<<DNSCryptoKeyEngine::makeFromPublicKeyString(drc.d_algorithm, drc.d_key)->verify(msg, rrc.d_signature)<<endl;
if(dsrc.d_digesttype) {
sort(keys.begin(),keys.end());
reverse(keys.begin(),keys.end());
- bool shown=false;
for(const auto& key : keys) {
string algname = DNSSECKeeper::algorithm2name(key.d_algorithm);
cout << "DNSKEY = " <<zone.toString()<<" IN DNSKEY "<< key.getZoneRepresentation() << "; ( " + algname + " ) " <<endl;
}
- if (shown) continue;
- shown=true;
-
const std::string prefix(exportDS ? "" : "DS = ");
cout<<prefix<<zone.toString()<<" IN DS "<<makeDSFromDNSKey(zone, key, DNSSECKeeper::SHA1).getZoneRepresentation() << " ; ( SHA1 digest )" << endl;
cout<<prefix<<zone.toString()<<" IN DS "<<makeDSFromDNSKey(zone, key, DNSSECKeeper::SHA256).getZoneRepresentation() << " ; ( SHA256 digest )" << endl;
int main(int argc, char** argv)
try
-{
+{
po::options_description desc("Allowed options");
desc.add_options()
("help,h", "produce help message")
#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<<"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] Defaults to KSK and active"<<endl;
+ cout<<" [active|inactive] [ksk|zsk] Defaults to KSK and active"<<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<<" replacing contents"<<endl;
cout<<"list-algorithms [with-backend] List all DNSSEC algorithms supported, optionally also listing the crypto library used"<<endl;
cout<<"set-presigned ZONE Use presigned RRSIGs from storage"<<endl;
cout<<"set-publish-cdnskey ZONE Enable sending CDNSKEY responses for ZONE"<<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, is is '1,2' by default"<<endl;
+ cout<<" DIGESTALGOS should be a comma separated list of numbers, it is '1,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;
return 1;
}
+ if(cmds[0] == "ipencrypt" || cmds[0]=="ipdecrypt") {
+ if(cmds.size() < 3 || (cmds.size()== 4 && cmds[3]!="key")) {
+ cerr<<"Syntax: pdnsutil [ipencrypt|ipdecrypt] IP passphrase [key]"<<endl;
+ return 0;
+ }
+ string key;
+ if(cmds.size()==4) {
+ if(B64Decode(cmds[2], key) < 0) {
+ cerr<<"Could not parse '"<<cmds[3]<<"' as base64"<<endl;
+ return 0;
+ }
+ }
+ else {
+ key = makeIPCipherKey(cmds[2]);
+ }
+ exit(xcryptIP(cmds[0], cmds[1], key));
+ }
+
+
if(cmds[0] == "test-algorithms") {
if (testAlgorithms())
return 0;
return 0;
}
unsigned int exitCode = 0;
- for(unsigned int n = 1; n < cmds.size(); ++n)
- if (!rectifyZone(dk, DNSName(cmds[n])))
+ for(unsigned int n = 1; n < cmds.size(); ++n)
+ if (!rectifyZone(dk, DNSName(cmds[n])))
exitCode = 1;
return exitCode;
}
active=false;
} else if(pdns_stou(cmds[n])) {
bits = pdns_stou(cmds[n]);
- } else {
+ } else {
cerr<<"Unknown algorithm, key flag or size '"<<cmds[n]<<"'"<<endl;
exit(EXIT_FAILURE);;
}
}
dk.commitTransaction();
}
-
+
for(const auto& zone : mustRectify)
rectifyZone(dk, zone);
else if(cmds[0]=="set-presigned") {
if(cmds.size() < 2) {
cerr<<"Syntax: pdnsutil set-presigned ZONE"<<endl;
- return 0;
+ return 0;
}
if (! dk.setPresigned(DNSName(cmds[1]))) {
cerr << "Could not set presigned for " << cmds[1] << " (is DNSSEC enabled in your backend?)" << endl;
else if(cmds[0]=="unset-presigned") {
if(cmds.size() < 2) {
cerr<<"Syntax: pdnsutil unset-presigned ZONE"<<endl;
- return 0;
+ return 0;
}
if (! dk.unsetPresigned(DNSName(cmds[1]))) {
cerr << "Could not unset presigned on for " << cmds[1] << endl;
if(narrow) {
cerr<<"The '"<<zone<<"' zone uses narrow NSEC3, but calculating hash anyhow"<<endl;
}
-
+
cout<<toBase32Hex(hashQNameWithSalt(ns3pr, record))<<endl;
}
else if(cmds[0]=="unset-nsec3") {
unsigned int id=pdns_stou(cmds[2]);
DNSSECPrivateKey dpk=dk.getKeyById(DNSName(zone), id);
cout << dpk.getKey()->convertToISC() <<endl;
- }
+ }
else if(cmds[0]=="increase-serial") {
if (cmds.size() < 2) {
cerr<<"Syntax: pdnsutil increase-serial ZONE"<<endl;
DNSKEYRecordContent drc;
shared_ptr<DNSCryptoKeyEngine> key(DNSCryptoKeyEngine::makeFromPEMString(drc, raw));
dpk.setKey(key);
-
+
dpk.d_algorithm = pdns_stou(cmds[3]);
-
+
if(dpk.d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1)
dpk.d_algorithm = DNSSECKeeper::RSASHA1;
-
+
cerr<<(int)dpk.d_algorithm<<endl;
-
+
if(cmds.size() > 4) {
if(pdns_iequals(cmds[4], "ZSK"))
dpk.d_flags = 256;
} else {
cout<<std::to_string(id)<<endl;
}
-
+
}
else if(cmds[0]=="import-zone-key") {
if(cmds.size() < 3) {
shared_ptr<DNSCryptoKeyEngine> key(DNSCryptoKeyEngine::makeFromISCFile(drc, fname.c_str()));
dpk.setKey(key);
dpk.d_algorithm = drc.d_algorithm;
-
+
if(dpk.d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1)
dpk.d_algorithm = DNSSECKeeper::RSASHA1;
-
- dpk.d_flags = 257;
+
+ dpk.d_flags = 257;
bool active=true;
for(unsigned int n = 3; n < cmds.size(); ++n) {
active = 1;
else if(pdns_iequals(cmds[n], "passive") || pdns_iequals(cmds[n], "inactive")) // passive eventually needs to be removed
active = 0;
- else {
+ else {
cerr<<"Unknown key flag '"<<cmds[n]<<"'"<<endl;
exit(1);
- }
+ }
}
int64_t id;
if (!dk.addKey(DNSName(zone), dpk, id, active)) {
}
}
}
- dpk->create(bits);
- dspk.setKey(dpk);
- dspk.d_algorithm = algorithm;
- dspk.d_flags = keyOrZone ? 257 : 256;
+ dpk->create(bits);
+ dspk.setKey(dpk);
+ dspk.d_algorithm = algorithm;
+ dspk.d_flags = keyOrZone ? 257 : 256;
- // print key to stdout
- cout << "Flags: " << dspk.d_flags << endl <<
- dspk.getKey()->convertToISC() << endl;
+ // print key to stdout
+ cout << "Flags: " << dspk.d_flags << endl <<
+ dspk.getKey()->convertToISC() << endl;
} else if (cmds[0]=="generate-tsig-key") {
string usage = "Syntax: " + cmds[0] + " name (hmac-md5|hmac-sha1|hmac-sha224|hmac-sha256|hmac-sha384|hmac-sha512)";
if (cmds.size() < 3) {
return 1;
}
UeberBackend B("default");
- std::vector<std::string> meta;
+ std::vector<std::string> meta;
if (!B.getDomainMetadata(zname, metaKey, meta)) {
cerr << "Failure enabling TSIG key " << name << " for " << zname << endl;
return 1;
for(const auto& each_meta: meta) {
cout << each_meta.first << " = " << boost::join(each_meta.second, ", ") << endl;
}
- }
+ }
return 0;
} else if (cmds[0]=="set-meta" || cmds[0]=="add-meta") {
pub_label = label;
std::ostringstream iscString;
- iscString << "Private-key-format: v1.2" << std::endl <<
- "Algorithm: " << algorithm << std::endl <<
+ iscString << "Private-key-format: v1.2" << std::endl <<
+ "Algorithm: " << algorithm << std::endl <<
"Engine: " << module << std::endl <<
"Slot: " << slot << std::endl <<
- "PIN: " << pin << std::endl <<
+ "PIN: " << pin << std::endl <<
"Label: " << label << std::endl <<
"PubLabel: " << pub_label << std::endl;
cerr << "Unable to create key for unknown zone '" << zone << "'" << std::endl;
return 1;
}
-
+
id = pdns_stou(cmds[3]);
- std::vector<DNSBackend::KeyData> keys;
+ std::vector<DNSBackend::KeyData> keys;
if (!B.getDomainKeys(zone, keys)) {
cerr << "No keys found for zone " << zone << std::endl;
return 1;
- }
+ }
std::shared_ptr<DNSCryptoKeyEngine> dke = nullptr;
- // lookup correct key
+ // lookup correct key
for(DNSBackend::KeyData &kd : keys) {
if (kd.id == id) {
- // found our key.
+ // found our key.
DNSKEYRecordContent dkrc;
dke = DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content);
}
}
#else
cerr<<"PKCS#11 support not enabled"<<endl;
- return 1;
+ return 1;
#endif
} else if (cmds[0] == "b2b-migrate") {
if (cmds.size() < 3) {
// 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)) {
nk++;
}
}
+ tgt->commitTransaction();
cout<<"Moved "<<nr<<" record(s), "<<nc<<" comment(s), "<<nm<<" metadata(s) and "<<nk<<" cryptokey(s)"<<endl;
}