declare(suffix,"insert-slave-query","", "insert into domains (type,name,master,account) values('SLAVE','%s','%s','%s')");
declare(suffix,"insert-record-query","", "insert into records (content,ttl,prio,type,domain_id,name) values ('%s',%d,%d,'%s',%d,'%s')");
- declare(suffix,"get-order-before-query","DNSSEC Ordering Query, before", "select max(ordername) from records where ordername < '%s' and auth=1 and domain_id=%d");
+ declare(suffix,"get-order-before-query","DNSSEC Ordering Query, before", "select ordername, name from records where ordername <= '%s' and auth=1 and domain_id=%d order by 1 desc limit 1");
declare(suffix,"get-order-after-query","DNSSEC Ordering Query, afer", "select min(ordername) from records where ordername > '%s' and auth=1 and domain_id=%d");
declare(suffix,"set-order-and-auth-query", "DNSSEC set ordering query", "update records set ordername='%s',auth=%d where name='%s' and domain_id='%d'");
d_db->doCommand(output);
return true;
}
-bool GSQLBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& before, std::string& after)
+bool GSQLBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& unhashed, std::string& before, std::string& after)
{
cerr<<"gsql before/after called for id="<<id<<", qname="<<qname<<endl;
+ unhashed.clear(); before.clear(); after.clear();
string lcqname=toLower(qname);
-
+
SSql::row_t row;
char output[1024];
- snprintf(output, sizeof(output)-1, d_afterOrderQuery.c_str(), sqlEscape(lcqname).c_str(), id);
+ string tmp=lcqname;
+
+retryAfter:
+ snprintf(output, sizeof(output)-1, d_afterOrderQuery.c_str(), sqlEscape(tmp).c_str(), id);
d_db->doQuery(output);
while(d_db->getRow(row)) {
after=row[0];
}
+ if(after.empty() && !tmp.empty()) {
+ cerr<<"Oops, have to pick the first, there as no last!"<<endl;
+ tmp.clear();
+ goto retryAfter;
+ }
+
+retryBefore:
+
snprintf(output, sizeof(output)-1, d_beforeOrderQuery.c_str(), sqlEscape(lcqname).c_str(), id);
d_db->doQuery(output);
while(d_db->getRow(row)) {
before=row[0];
+ unhashed=row[1];
+ }
+
+ if(before.empty() && lcqname!="{") {
+ cerr<<"Oops, have to pick the last!"<<endl;
+ lcqname="{";
+ goto retryBefore;
}
return true;
void getUpdatedMasters(vector<DomainInfo> *updatedDomains);
bool getDomainInfo(const string &domain, DomainInfo &di);
void setNotified(uint32_t domain_id, uint32_t serial);
- virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& before, std::string& after);
+ virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& unhashed, std::string& before, std::string& after);
bool updateDNSSECOrderAndAuth(uint32_t domain_id, const std::string& zonename, const std::string& qname, bool auth);
virtual bool updateDNSSECOrderAndAuthAbsolute(uint32_t domain_id, const std::string& qname, const std::string& ordername, bool auth);
lcqname=makeRelative(qname, zonename);
lcqname=labelReverse(lcqname);
- bool ret = this->getBeforeAndAfterNamesAbsolute(id, lcqname, before, after);
+ string dnc;
+ bool ret = this->getBeforeAndAfterNamesAbsolute(id, lcqname, dnc, before, after);
before=dotConcat(labelReverse(before), zonename);
after=dotConcat(labelReverse(after), zonename);
virtual void lookup(const QType &qtype, const string &qdomain, DNSPacket *pkt_p=0, int zoneId=-1)=0;
virtual bool get(DNSResourceRecord &)=0; //!< retrieves one DNSResource record, returns false if no more were available
- virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& before, std::string& after)
+ virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& unhashed, std::string& before, std::string& after)
{
std::cerr<<"Default beforeAndAfterAbsolute called!"<<std::endl;
return false;
drc.d_key.append(exponent);
drc.d_key.append(modulus);
drc.d_protocol=3;
- drc.d_algorithm = 5;
+ drc.d_algorithm = 0; // should not be filled out here..
fclose(fp);
return drc;
}
sha2((unsigned char*)toHash.c_str(), toHash.length(), hash, 0);
DSRecordContent dsrc;
- dsrc.d_algorithm=5;
+ dsrc.d_algorithm= drc.d_algorithm;
dsrc.d_digesttype=digest;
dsrc.d_tag=const_cast<DNSKEYRecordContent&>(drc).getTag();
dsrc.d_digest.assign((const char*)hash, digest == 1 ? 20 : 32);
return dsrc;
}
-DNSKEYRecordContent makeDNSKEYFromRSAKey(rsa_context* rc)
+DNSKEYRecordContent makeDNSKEYFromRSAKey(rsa_context* rc, uint8_t algorithm)
{
DNSKEYRecordContent drc;
char tmp[256];
drc.d_key.append(modulus);
drc.d_protocol=3;
- drc.d_algorithm = 5;
+ drc.d_algorithm = algorithm;
drc.d_flags=256 + (modulus.length()>128); // oops, I just made this up..
DNSKEYRecordContent drc =getDNSKEYFor(keyrepodir, rrc.d_signer, withKSK, &rc);
rrc.d_tag = drc.getTag();
+ rrc.d_algorithm = drc.d_algorithm;
if(g_rrsigs.count(make_pair(hash, rrc.d_tag))) {
cerr<<"RRSIG cache hit !"<<endl;
return -1;
rrc.d_type=signQType;
- rrc.d_algorithm=5; // rsasha1
+
+ // d_algorithm gets filled out by fillOutRRSIG, since it gets the key
rrc.d_labels=countLabels(signQName);
rrc.d_originalttl=signTTL;
rrc.d_siginception=getCurrentInception();;
void makeRSAPublicKeyFromDNS(rsa_context* rc, const DNSKEYRecordContent& dkrc);
bool sharedDNSSECCompare(const boost::shared_ptr<DNSRecordContent>& a, const shared_ptr<DNSRecordContent>& b);
string getSHA1HashForRRSET(const std::string& qname, const RRSIGRecordContent& rrc, std::vector<boost::shared_ptr<DNSRecordContent> >& signRecords);
-DNSKEYRecordContent makeDNSKEYFromRSAKey(rsa_context* rc);
+DNSKEYRecordContent makeDNSKEYFromRSAKey(rsa_context* rc, uint8_t algorithm);
DSRecordContent makeDSFromDNSKey(const std::string& qname, const DNSKEYRecordContent& drc, int digest=1);
bool getSignerFor(const std::string& keyrepodir, const std::string& qname, std::string &signer);
unlink((d_dirname +"/"+ zname +"/zsks/"+fname).c_str());
}
+bool DNSSECKeeper::getNSEC3PARAM(const std::string& zname, NSEC3PARAMRecordContent* ns3p)
+{
+ fs::path full_path = fs::system_complete( fs::path(d_dirname + "/" + zname + "/nsec3param" ) );
+ ifstream ifs(full_path.external_directory_string().c_str());
+ cerr<<"called for nsec3param..."<<endl;
+ if(!ifs)
+ return false;
+
+ if(ns3p) {
+ string descr;
+ getline(ifs, descr);
+ NSEC3PARAMRecordContent* tmp=dynamic_cast<NSEC3PARAMRecordContent*>(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, descr));
+ if(!tmp) {
+ cerr<<"Could not parse "<< full_path.external_directory_string() <<endl;
+ cerr<<"descr: '"<<descr<<"'\n";
+ }
+ *ns3p = *tmp;
+ delete tmp;
+
+ cerr<<"hmm salt: "<<makeHexDump(ns3p->d_salt)<<endl;
+/*
+ ns3p->d_algorithm=1;
+ ns3p->d_iterations= 100;
+ ns3p->d_salt.assign("\xab\xcd", 2);
+ ns3p->d_saltlength=2;
+ ns3p->d_flags=0;
+ */
+ }
+ return true;
+}
+
+void DNSSECKeeper::setNSEC3PARAM(const std::string& zname, const NSEC3PARAMRecordContent* ns3p)
+{
+ fs::path full_path = fs::system_complete( fs::path(d_dirname + "/" + zname + "/nsec3param" ) );
+ if(ns3p) {
+ string descr = ns3p->getZoneRepresentation();
+
+
+ ofstream of(full_path.external_directory_string().c_str());
+ of << descr;
+ }
+ else {
+ unlink(full_path.external_directory_string().c_str());
+ }
+}
+
+
DNSSECKeeper::zskset_t DNSSECKeeper::getZSKsFor(const std::string& zone, bool all)
{
zskset_t zskset;
//cerr<<"Hit!"<<endl;
DNSSECPrivateKey dpk;
getRSAKeyFromISC(&dpk.d_key.getContext(), dir_itr->path().file_string().c_str());
+
+ if(getNSEC3PARAM(zone)) {
+ dpk.d_algorithm = 7;
+ }
+ else {
+ dpk.d_algorithm = 5;
+ }
struct tm ts1, ts2;
DNSKEYRecordContent DNSSECPrivateKey::getDNSKEY()
{
- return makeDNSKEYFromRSAKey(&d_key.getContext());
+ return makeDNSKEYFromRSAKey(&d_key.getContext(), d_algorithm);
}
RSAContext d_key;
DNSKEYRecordContent getDNSKEY();
+ uint8_t d_algorithm;
};
class DNSSECKeeper
void deleteZSKFor(const std::string& zname, const std::string& fname);
void addZone(const std::string& fname);
-
-
+ bool getNSEC3PARAM(const std::string& zname, NSEC3PARAMRecordContent* n3p=0);
+ void setNSEC3PARAM(const std::string& zname, const NSEC3PARAMRecordContent* n3p);
private:
std::string d_dirname;
return 0;
}
-/** This catches version requests. Returns 1 if it was handled, 0 if it wasn't */
+/** This catches DNSKEY requests. Returns 1 if it was handled, 0 if it wasn't */
int PacketHandler::doDNSKEYRequest(DNSPacket *p, DNSPacket *r)
{
+ if(p->qtype.getCode()!=QType::DNSKEY)
+ return false;
+
DNSResourceRecord rr;
DNSSECKeeper dk(::arg()["key-repository"]);
- if(p->qtype.getCode()!=QType::DNSKEY)
- return false;
bool haveOne=false;
DNSSECPrivateKey dpk;
-
if(dk.haveKSKFor(p->qdomain, &dpk)) {
rr.qtype=QType::DNSKEY;
rr.ttl=3600;
}
+/** This catches DNSKEY requests. Returns 1 if it was handled, 0 if it wasn't */
+int PacketHandler::doNSEC3PARAMRequest(DNSPacket *p, DNSPacket *r)
+{
+ if(p->qtype.getCode()!=QType::NSEC3PARAM)
+ return false;
+
+ DNSResourceRecord rr;
+ DNSSECKeeper dk(::arg()["key-repository"]);
+
+ NSEC3PARAMRecordContent ns3prc;
+ if(dk.getNSEC3PARAM(p->qdomain, &ns3prc)) {
+ rr.qtype=QType::NSEC3PARAM;
+ rr.ttl=3600;
+ rr.qname=p->qdomain;
+ rr.content=ns3prc.getZoneRepresentation();
+ rr.auth = true;
+ r->addRecord(rr);
+ return true;
+ }
+ return false;
+}
+
+
/** This catches version requests. Returns 1 if it was handled, 0 if it wasn't */
int PacketHandler::doVersionRequest(DNSPacket *p, DNSPacket *r, string &target)
{
r->addRecord(rr);
}
-void PacketHandler::emitNSEC3(NSEC3PARAMRecordContent *ns3rc, const std::string& auth, const std::string& begin, const std::string& end, const std::string& toNSEC3, DNSPacket *r, int mode)
+void PacketHandler::emitNSEC3(const NSEC3PARAMRecordContent& ns3prc, const std::string& auth, const std::string& unhashed, const std::string& begin, const std::string& end, const std::string& toNSEC3, DNSPacket *r, int mode)
{
cerr<<"We should emit NSEC3 '"<<toBase32Hex(begin)<<"' - ('"<<toNSEC3<<"') - '"<<toBase32Hex(end)<<"'"<<endl;
NSEC3RecordContent n3rc;
n3rc.d_set.insert(QType::RRSIG);
- n3rc.d_set.insert(QType::NSEC3);
- n3rc.d_salt=ns3rc->d_salt;
- n3rc.d_iterations = ns3rc->d_iterations;
- n3rc.d_algorithm = 1;
+ n3rc.d_salt=ns3prc.d_salt;
+ n3rc.d_flags = 0;
+ n3rc.d_iterations = ns3prc.d_iterations;
+ n3rc.d_algorithm = 1; // ?
DNSResourceRecord rr;
- B.lookup(QType(QType::ANY), begin);
+ B.lookup(QType(QType::ANY), unhashed);
while(B.get(rr)) {
n3rc.d_set.insert(rr.qtype.getCode());
}
+
+ if(unhashed == auth) {
+ n3rc.d_set.insert(QType::NSEC3PARAM);
+ }
n3rc.d_nexthash=end;
*/
void PacketHandler::addNSECX(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, int mode)
{
+ DNSSECKeeper dk(::arg()["key-repository"]);
+ NSEC3PARAMRecordContent ns3rc;
cerr<<"Doing NSEC3PARAM lookup for '"<<auth<<"'"<<endl;
- B.lookup(QType(QType::NSEC3PARAM), auth, p);
- DNSResourceRecord rr, nsec3param;
- while(B.get(rr)) {
- nsec3param = rr;
- }
- if(!nsec3param.qname.empty())
- addNSEC3(p, r, target, auth, nsec3param, mode);
+ if(dk.getNSEC3PARAM(auth, &ns3rc))
+ addNSEC3(p, r, target, auth, ns3rc, mode);
else
addNSEC(p, r, target, auth, mode);
}
-void PacketHandler::addNSEC3(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, const DNSResourceRecord& nsec3param, int mode)
+void PacketHandler::addNSEC3(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, const NSEC3PARAMRecordContent& ns3rc, int mode)
{
- cerr<<"NSEC3 generator called!"<<endl;
- cerr<<nsec3param.content<<endl;
- NSEC3PARAMRecordContent *ns3rc=dynamic_cast<NSEC3PARAMRecordContent*>(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, nsec3param.content));
- string hashed=toBase32Hex(hashQNameWithSalt(ns3rc->d_iterations, ns3rc->d_salt, p->qdomain));
- cerr<<"NSEC3 hash, "<<ns3rc->d_iterations<<" iterations, salt '"<<makeHexDump(ns3rc->d_salt)<<"': "<<hashed<<endl;
-
+ string hashed;
+
SOAData sd;
sd.db = (DNSBackend*)-1;
if(!B.getSOA(auth, sd)) {
cerr<<"Could not get SOA for domain in NSEC3\n";
return;
}
-
- string before,after;
- cerr<<"Calling getBeforeandAfterAbsolute!"<<endl;
- sd.db->getBeforeAndAfterNamesAbsolute(sd.domain_id, hashed, before, after);
- cerr<<"Done calling, before='"<<before<<"', after='"<<after<<"'"<<endl;
- emitNSEC3( ns3rc, auth, fromBase32Hex(before), fromBase32Hex(after), target, r, mode);
+ cerr<<"salt in ph: '"<<makeHexDump(ns3rc.d_salt)<<"'"<<endl;
+ string unhashed, before,after;
+
+ // now add the closest encloser
+ hashed=toBase32Hex(hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, auth));
+ sd.db->getBeforeAndAfterNamesAbsolute(sd.domain_id, hashed, unhashed, before, after);
+ cerr<<"Done calling for closest encloser, before='"<<before<<"', after='"<<after<<"'"<<endl;
+ emitNSEC3(ns3rc, auth, unhashed, fromBase32Hex(before), fromBase32Hex(after), target, r, mode);
+
+ // now add the main nsec3
+ hashed=toBase32Hex(hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, p->qdomain));
+ sd.db->getBeforeAndAfterNamesAbsolute(sd.domain_id, hashed, unhashed, before, after);
+ cerr<<"Done calling for main, before='"<<before<<"', after='"<<after<<"'"<<endl;
+ emitNSEC3( ns3rc, auth, unhashed, fromBase32Hex(before), fromBase32Hex(after), target, r, mode);
+
+
+ // now add the *
+ hashed=toBase32Hex(hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, dotConcat("*", auth)));
+ sd.db->getBeforeAndAfterNamesAbsolute(sd.domain_id, hashed, unhashed, before, after);
+ cerr<<"Done calling for '*', before='"<<before<<"', after='"<<after<<"'"<<endl;
+ emitNSEC3( ns3rc, auth, unhashed, fromBase32Hex(before), fromBase32Hex(after), target, r, mode);
}
void PacketHandler::addNSEC(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, int mode)
if(doDNSKEYRequest(p,r))
goto sendit;
+ if(doNSEC3PARAMRequest(p,r))
+ goto sendit;
+
if(doVersionRequest(p,r,target)) // catch version.bind requests
goto sendit;
int doFancyRecords(DNSPacket *p, DNSPacket *r, string &target);
int doVersionRequest(DNSPacket *p, DNSPacket *r, string &target);
int doDNSKEYRequest(DNSPacket *p, DNSPacket *r);
+ int doNSEC3PARAMRequest(DNSPacket *p, DNSPacket *r);
bool getAuth(DNSPacket *p, SOAData *sd, const string &target, int *zoneId);
bool getTLDAuth(DNSPacket *p, SOAData *sd, const string &target, int *zoneId);
int doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r);
bool doDNSSECProcessing(DNSPacket* p, DNSPacket *r);
void addNSECX(DNSPacket *p, DNSPacket* r, const string &target, const std::string& auth, int mode);
void addNSEC(DNSPacket *p, DNSPacket* r, const string &target, const std::string& auth, int mode);
- void addNSEC3(DNSPacket *p, DNSPacket* r, const string &target, const std::string& auth, const DNSResourceRecord& nsec3param, int mode);
+ void addNSEC3(DNSPacket *p, DNSPacket* r, const string &target, const std::string& auth, const NSEC3PARAMRecordContent& nsec3param, int mode);
void emitNSEC(const std::string& before, const std::string& after, const std::string& toNSEC, DNSPacket *r, int mode);
- void emitNSEC3(NSEC3PARAMRecordContent *ns3rc, const std::string& auth, const std::string& begin, const std::string& end, const std::string& toNSEC3, DNSPacket *r, int mode);
+ void emitNSEC3(const NSEC3PARAMRecordContent &ns3rc, const std::string& auth, const std::string& unhashed, const std::string& begin, const std::string& end, const std::string& toNSEC3, DNSPacket *r, int mode);
void synthesiseRRSIGs(DNSPacket* p, DNSPacket* r);
void makeNXDomain(DNSPacket* p, DNSPacket* r, const std::string& target, SOAData& sd);
UeberBackend::go();
}
-void orderZone(const std::string& zone)
+void orderZone(DNSSECKeeper& dk, const std::string& zone)
{
loadMainConfig();
-
+ reportAllTypes();
UeberBackend* B = new UeberBackend("default");
SOAData sd;
string salt;
char tmp[]={0xab, 0xcd};
salt.assign(tmp, 2);
+
+ NSEC3PARAMRecordContent ns3pr;
+ dk.getNSEC3PARAM(zone, &ns3pr);
+ string hashed;
BOOST_FOREACH(const string& qname, qnames)
{
- string hashed=toBase32Hex(hashQNameWithSalt(100, salt, qname));
- cerr<<"'"<<qname<<"' -> '"<< hashed <<"'"<<endl;
- sd.db->updateDNSSECOrderAndAuthAbsolute(sd.domain_id, qname, hashed, true);
- // sd.db->updateDNSSECOrderAndAuth(sd.domain_id, zone, qname, true);
+ if(ns3pr.d_salt.empty()) // NSEC
+ sd.db->updateDNSSECOrderAndAuth(sd.domain_id, zone, qname, true);
+ else {
+ hashed=toLower(toBase32Hex(hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, qname)));
+ cerr<<"'"<<qname<<"' -> '"<< hashed <<"'"<<endl;
+ sd.db->updateDNSSECOrderAndAuthAbsolute(sd.domain_id, qname, hashed, true);
+ }
}
cerr<<"Done listing"<<endl;
}
cmds = g_vm["commands"].as<vector<string> >();
if(cmds.empty() || g_vm.count("help")) {
- cerr<<"Usage: \npdnssec [options] [show-zone] [sign-zone] [update-zone-keys]\n";
+ cerr<<"Usage: \npdnssec [options] [show-zone] [secure-zone] [alter-zone] [order-zone] [update-zone-keys]\n";
cerr<<desc<<endl;
return 0;
}
cerr << "Error: "<<cmds[0]<<" takes exactly 1 parameter"<<endl;
return 0;
}
- orderZone(cmds[1]);
+ orderZone(dk, cmds[1]);
}
else if(cmds[0] == "update-zone-keys") {
if(cmds.size() != 2) {
}
}
}
- else if(cmds[0] == "sign-zone") {
+ else if(cmds[0] == "secure-zone") {
if(cmds.size() != 2) {
cerr << "Error: "<<cmds[0]<<" takes exactly 1 parameter"<<endl;
return 0;