From: bert hubert Date: Wed, 22 Oct 2014 14:55:06 +0000 (+0200) Subject: implement security polling for auth X-Git-Tag: rec-3.7.0-rc1~197 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=199631c68417637b6ed16404bdd4057e5f4a5e3c;p=thirdparty%2Fpdns.git implement security polling for auth --- diff --git a/pdns/Makefile.am b/pdns/Makefile.am index 6ab9c7ae8c..550b941138 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -163,6 +163,7 @@ pdns_server_SOURCES = \ resolver.cc resolver.hh \ responsestats.cc responsestats.hh \ rfc2136handler.cc \ + secpoll-auth.cc secpoll-auth.hh \ serialtweaker.cc \ sha.hh \ signingpipe.cc signingpipe.hh \ diff --git a/pdns/common_startup.cc b/pdns/common_startup.cc index 7fdf047485..824f8e8fd1 100644 --- a/pdns/common_startup.cc +++ b/pdns/common_startup.cc @@ -21,6 +21,7 @@ */ #include "common_startup.hh" #include "ws-auth.hh" +#include "secpoll-auth.hh" bool g_anyToTcp; typedef Distributor DNSDistributor; @@ -160,6 +161,7 @@ void declareArguments() ::arg().set("max-nsec3-iterations","Limit the number of NSEC3 hash iterations")="500"; // RFC5155 10.3 ::arg().set("include-dir","Include *.conf files from this directory"); + ::arg().set("security-poll-suffix","Domain name from which to query security update notifications")="secpoll.powerdns.com."; } void declareStats(void) @@ -199,7 +201,7 @@ void declareStats(void) S.declare("servfail-packets","Number of times a server-failed packet was sent out"); S.declare("latency","Average number of microseconds needed to answer a question"); S.declare("timedout-packets","Number of packets which weren't answered within timeout set"); - + S.declare("security-status", "Security status based on regular polling"); S.declareRing("queries","UDP Queries Received"); S.declareRing("nxdomain-queries","Queries for non-existent records within existent domains"); S.declareRing("noerror-queries","Queries for existing records, but for type we don't have"); @@ -363,6 +365,9 @@ void mainthread() DNSPacket::s_udpTruncationThreshold = std::max(512, ::arg().asNum("udp-truncation-threshold")); DNSPacket::s_doEDNSSubnetProcessing = ::arg().mustDo("edns-subnet-processing"); + + doSecPoll(true); // this must be BEFORE chroot + if(!::arg()["chroot"].empty()) { if(::arg().mustDo("master") || ::arg().mustDo("slave")) gethostbyname("a.root-servers.net"); // this forces all lookup libraries to be loaded @@ -400,13 +405,16 @@ void mainthread() TN->go(); // tcp nameserver launch pthread_create(&qtid,0,carbonDumpThread, 0); // runs even w/o carbon, might change @ runtime + // fork(); (this worked :-)) unsigned int max_rthreads= ::arg().asNum("receiver-threads", 1); for(unsigned int n=0; n < max_rthreads; ++n) pthread_create(&qtid,0,qthread, reinterpret_cast(n)); // receives packets - void *p; - pthread_join(qtid, &p); + for(;;) { + sleep(1800); + doSecPoll(false); + } L< +#include "sstuff.hh" +#include "dnswriter.hh" +#include "dns_random.hh" +#include "namespaces.hh" +#include "statbag.hh" +#ifndef PACKAGEVERSION +#define PACKAGEVERSION PDNS_VERSION +#endif + +string g_security_message; + +extern StatBag S; + +static vector parseResolveConf() +{ + vector ret; + ifstream ifs("/etc/resolv.conf"); + if(!ifs) + return ret; + + string line; + while(std::getline(ifs, line)) { + boost::trim_right_if(line, is_any_of(" \r\n\x1a")); + boost::trim_left(line); // leading spaces, let's be nice + + string::size_type tpos = line.find_first_of(";#"); + if(tpos != string::npos) + line.resize(tpos); + + if(boost::starts_with(line, "nameserver ") || boost::starts_with(line, "nameserver\t")) { + vector parts; + stringtok(parts, line, " \t,"); // be REALLY nice + for(vector::const_iterator iter = parts.begin()+1; iter != parts.end(); ++iter) { + + try { + ret.push_back(ComboAddress(*iter, 53)); + } + catch(...) + { + } + } + } + + } + + return ret; +} + +int doResolve(const string& qname, uint16_t qtype, vector& ret) +{ + vector packet; + + DNSPacketWriter pw(packet, qname, qtype); + pw.getHeader()->id=dns_random(0xffff); + pw.getHeader()->rd=1; + + static vector s_servers; + vector servers = parseResolveConf(); + if(!servers.empty()) + s_servers = servers; // in case we chrooted in the meantime + + if(s_servers.empty()) + L< sizeof(struct dnsheader)) { + struct dnsheader d; + memcpy(&d, reply.c_str(), sizeof(d)); + if(d.id != pw.getHeader()->id) + goto retry; + } + } + catch(...) { + continue; + } + MOADNSParser mdp(reply); + if(mdp.d_header.rcode == RCode::ServFail) + continue; + + + for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) { + if(i->first.d_place == 1 && i->first.d_type==QType::TXT) { + DNSResourceRecord rr; + rr.qname = i->first.d_label; + rr.qtype = QType(i->first.d_type); + rr.content = i->first.d_content->getZoneRepresentation(); + rr.ttl=i->first.d_ttl; + ret.push_back(rr); + } + } + + return mdp.d_header.rcode; + } + return RCode::ServFail; +} + +void doSecPoll(bool first) +{ + if(::arg()["security-poll-suffix"].empty()) + return; + + struct timeval now; + gettimeofday(&now, 0); + + string query = "auth-" PACKAGEVERSION ".security-status."+::arg()["security-poll-suffix"]; + + if(*query.rbegin()!='.') + query+='.'; + + boost::replace_all(query, "+", "_"); + + vector ret; + + int res=doResolve(query, QType::TXT, ret); + + int security_status; + + if(!res && !ret.empty()) { + string content=ret.begin()->content; + if(!content.empty() && content[0]=='"' && content[content.size()-1]=='"') { + content=content.substr(1, content.length()-2); + } + + pair split = splitField(content, ' '); + + security_status = atoi(split.first.c_str()); + g_security_message = split.second; + + } + else { + L< +#include "namespaces.hh" + +void doSecPoll(bool first); +extern std::string g_security_message; + +#endif