From 51c71b42c80ce12917570e2dc337cee96bcb53e7 Mon Sep 17 00:00:00 2001 From: Morten Stevens Date: Aug 31 2013 18:24:07 +0000 Subject: Add patch to fix Remote backend --- diff --git a/pdns-fix-backend-remote.patch b/pdns-fix-backend-remote.patch new file mode 100644 index 0000000..3874f22 --- /dev/null +++ b/pdns-fix-backend-remote.patch @@ -0,0 +1,573 @@ +diff --git a/modules/remotebackend/Makefile.am b/modules/remotebackend/Makefile.am +index c4bf579..04d110a 100644 +--- a/modules/remotebackend/Makefile.am ++++ b/modules/remotebackend/Makefile.am +@@ -31,7 +31,7 @@ libtestremotebackend_la_SOURCES=../../pdns/dnsbackend.hh ../../pdns/dnsbackend.c + ../../pdns/aes/dns_random.cc ../../pdns/packetcache.hh ../../pdns/packetcache.cc \ + ../../pdns/aes/aescpp.h ../../pdns/dns.hh ../../pdns/dns.cc ../../pdns/json.hh ../../pdns/json.cc \ + ../../pdns/aes/aescrypt.c ../../pdns/aes/aes.h ../../pdns/aes/aeskey.c ../../pdns/aes/aes_modes.c ../../pdns/aes/aesopt.h \ +- ../../pdns/aes/aestab.c ../../pdns/aes/aestab.h ../../pdns/aes/brg_endian.h ../../pdns/aes/brg_types.h ../pipebackend/coprocess.cc \ ++ ../../pdns/aes/aestab.c ../../pdns/aes/aestab.h ../../pdns/aes/brg_endian.h ../../pdns/aes/brg_types.h \ + remotebackend.hh remotebackend.cc unixconnector.cc httpconnector.cc pipeconnector.cc + + libtestremotebackend_la_CFLAGS=$(BOOST_CPPFLAGS) @THREADFLAGS@ $(LIBCURL_CFLAGS) -g -O0 -I../../pdns +diff --git a/modules/remotebackend/pipeconnector.cc b/modules/remotebackend/pipeconnector.cc +index 9e28980..f86fd28 100644 +--- a/modules/remotebackend/pipeconnector.cc ++++ b/modules/remotebackend/pipeconnector.cc +@@ -1,3 +1,5 @@ ++#include ++#include + #include "remotebackend.hh" + + PipeConnector::PipeConnector(std::map options) { +@@ -7,26 +9,92 @@ + } + this->command = options.find("command")->second; + this->options = options; +- this->coproc = NULL; ++ d_timeout=2000; ++ ++ if (options.find("timeout") != options.end()) { ++ d_timeout = boost::lexical_cast(options.find("timeout")->second); ++ } ++ ++ d_pid = -1; ++ d_fp = NULL; + launch(); + } + + PipeConnector::~PipeConnector(){ +- if (this->coproc != NULL) +- delete coproc; ++ int status; ++ // just in case... ++ if (d_pid == -1) return; ++ ++ if(!waitpid(d_pid, &status, WNOHANG)) { ++ kill(d_pid, 9); ++ waitpid(d_pid, &status, 0); ++ } ++ ++ close(d_fd1[1]); ++ if (d_fp != NULL) fclose(d_fp); + } + + void PipeConnector::launch() { +- if (coproc != NULL) return; ++ // no relaunch ++ if (d_pid > 0 && checkStatus()) return; ++ ++ std::vector v; ++ split(v, command, is_any_of(" ")); ++ ++ const char *argv[v.size()+1]; ++ argv[v.size()]=0; ++ ++ for (size_t n = 0; n < v.size(); n++) ++ argv[n]=v[n].c_str(); ++ ++ signal(SIGPIPE, SIG_IGN); ++ ++ if(access(argv[0],X_OK)) // check before fork so we can throw ++ throw AhuException("Command '"+string(argv[0])+"' cannot be executed: "+stringerror()); ++ ++ if(pipe(d_fd1)<0 || pipe(d_fd2)<0) ++ throw AhuException("Unable to open pipe for coprocess: "+string(strerror(errno))); ++ ++ if((d_pid=fork())<0) ++ throw AhuException("Unable to fork for coprocess: "+stringerror()); ++ else if(d_pid>0) { // parent speaking ++ close(d_fd1[0]); ++ Utility::setCloseOnExec(d_fd1[1]); ++ close(d_fd2[1]); ++ Utility::setCloseOnExec(d_fd2[0]); ++ if(!(d_fp=fdopen(d_fd2[0],"r"))) ++ throw AhuException("Unable to associate a file pointer with pipe: "+stringerror()); ++ setbuf(d_fp,0); // no buffering please, confuses select ++ } ++ else if(!d_pid) { // child ++ signal(SIGCHLD, SIG_DFL); // silence a warning from perl ++ close(d_fd1[1]); ++ close(d_fd2[0]); ++ ++ if(d_fd1[0]!= 0) { ++ dup2(d_fd1[0], 0); ++ close(d_fd1[0]); ++ } ++ ++ if(d_fd2[1]!= 1) { ++ dup2(d_fd2[1], 1); ++ close(d_fd2[1]); ++ } ++ ++ // stdin & stdout are now connected, fire up our coprocess! ++ ++ if(execv(argv[0], const_cast(argv))<0) // now what ++ exit(123); ++ ++ /* not a lot we can do here. We shouldn't return because that will leave a forked process around. ++ no way to log this either - only thing we can do is make sure that our parent catches this soonest! */ ++ } ++ + rapidjson::Value val; + rapidjson::Document init,res; +- int timeout=2000; +- if (options.find("timeout") != options.end()) { +- timeout = boost::lexical_cast(options.find("timeout")->second); +- } +- coproc = new CoProcess(this->command, timeout); + init.SetObject(); + val = "initialize"; ++ + init.AddMember("method",val, init.GetAllocator()); + val.SetObject(); + init.AddMember("parameters", val, init.GetAllocator()); +@@ -44,42 +112,83 @@ void PipeConnector::launch() { + + int PipeConnector::send_message(const rapidjson::Document &input) + { +- std::string data; ++ std::string line; ++ line = makeStringFromDocument(input); ++ launch(); + +- data = makeStringFromDocument(input); ++ line.append(1,'\n'); + +- launch(); +- try { +- coproc->send(data); +- return 1; ++ unsigned int sent=0; ++ int bytes; ++ ++ // writen routine - socket may not accept al data in one go ++ while(sent , rapidjson::MemoryPoolAllocator<> > r; + std::string tmp; + std::string s_output; +- + launch(); +- try { +- while(1) { +- coproc->receive(tmp); +- s_output.append(tmp); +- rapidjson::StringStream ss(s_output.c_str()); +- output.ParseStream<0>(ss); +- if (output.HasParseError() == false) +- return s_output.size(); +- } +- } catch(AhuException &ae) { +- L<(ss); ++ if (output.HasParseError() == false) ++ return s_output.size(); + } ++ return 0; ++} ++ ++bool PipeConnector::checkStatus() ++{ ++ int status; ++ int ret=waitpid(d_pid, &status, WNOHANG); ++ if(ret<0) ++ throw AhuException("Unable to ascertain status of coprocess "+itoa(d_pid)+" from "+itoa(getpid())+": "+string(strerror(errno))); ++ else if(ret) { ++ if(WIFEXITED(status)) { ++ int ret=WEXITSTATUS(status); ++ throw AhuException("Coprocess exited with code "+itoa(ret)); ++ } ++ if(WIFSIGNALED(status)) { ++ int sig=WTERMSIG(status); ++ string reason="CoProcess died on receiving signal "+itoa(sig); ++#ifdef WCOREDUMP ++ if(WCOREDUMP(status)) ++ reason+=". Dumped core"; ++#endif ++ ++ throw AhuException(reason); ++ } ++ } ++ return true; + } +diff --git a/modules/remotebackend/remotebackend.cc b/modules/remotebackend/remotebackend.cc +index 91d426a..7adedf4 100644 +--- a/modules/remotebackend/remotebackend.cc ++++ b/modules/remotebackend/remotebackend.cc +@@ -49,11 +49,14 @@ bool Connector::recv(rapidjson::Document &value) { + RemoteBackend::RemoteBackend(const std::string &suffix) + { + setArgPrefix("remote"+suffix); +- build(getArg("connection-string")); ++ ++ this->d_connstr = getArg("connection-string"); + this->d_result = NULL; + this->d_dnssec = mustDo("dnssec"); + this->d_index = -1; + this->d_trxid = 0; ++ ++ build(); + } + + RemoteBackend::~RemoteBackend() { +@@ -62,11 +65,40 @@ bool Connector::recv(rapidjson::Document &value) { + } + } + ++bool RemoteBackend::send(rapidjson::Document &value) { ++ try { ++ return connector->send(value); ++ } catch (AhuException &ex) { ++ L<connector; ++ build(); ++ return false; ++} ++ ++bool RemoteBackend::recv(rapidjson::Document &value) { ++ try { ++ return connector->recv(value); ++ } catch (AhuException &ex) { ++ L<connector; ++ build(); ++ return false; ++} ++ ++ + /** + * Builds connector based on options + * Currently supports unix,pipe and http + */ +-int RemoteBackend::build(const std::string &connstr) { ++int RemoteBackend::build() { + std::vector parts; + std::string type; + std::string opts; +@@ -74,12 +106,12 @@ int RemoteBackend::build(const std::string &connstr) { + + // connstr is of format "type:options" + size_t pos; +- pos = connstr.find_first_of(":"); ++ pos = d_connstr.find_first_of(":"); + if (pos == std::string::npos) + throw AhuException("Invalid connection string: malformed"); + +- type = connstr.substr(0, pos); +- opts = connstr.substr(pos+1); ++ type = d_connstr.substr(0, pos); ++ opts = d_connstr.substr(pos+1); + + // tokenize the string on comma + stringtok(parts, opts, ","); +@@ -155,7 +187,7 @@ void RemoteBackend::lookup(const QType &qtype, const std::string &qdomain, DNSPa + + d_result = new rapidjson::Document(); + +- if (connector->send(query) == false || connector->recv(*d_result) == false) { ++ if (this->send(query) == false || this->recv(*d_result) == false) { + delete d_result; + return; + } +@@ -186,7 +218,7 @@ bool RemoteBackend::list(const std::string &target, int domain_id) { + + d_result = new rapidjson::Document(); + +- if (connector->send(query) == false || connector->recv(*d_result) == false) { ++ if (this->send(query) == false || this->recv(*d_result) == false) { + delete d_result; + return false; + } +@@ -245,7 +277,7 @@ bool RemoteBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::strin + JSON_ADD_MEMBER(parameters, "qname", qname.c_str(), query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + + unhashed = getString(answer["result"]["unhashed"]); +@@ -266,13 +298,13 @@ bool RemoteBackend::getDomainMetadata(const std::string& name, const std::string + JSON_ADD_MEMBER(parameters, "kind", kind.c_str(), query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false) ++ if (this->send(query) == false) + return false; + + meta.clear(); + + // not mandatory to implement +- if (connector->recv(answer) == false) ++ if (this->recv(answer) == false) + return true; + + if (answer["result"].IsArray()) { +@@ -301,7 +333,7 @@ bool RemoteBackend::setDomainMetadata(const string& name, const std::string& kin + parameters.AddMember("value", val, query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + + return getBool(answer["result"]); +@@ -321,7 +353,7 @@ bool RemoteBackend::getDomainKeys(const std::string& name, unsigned int kind, st + JSON_ADD_MEMBER(parameters, "kind", kind, query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + + keys.clear(); +@@ -351,7 +383,7 @@ bool RemoteBackend::removeDomainKey(const string& name, unsigned int id) { + JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + + return true; +@@ -374,7 +406,7 @@ int RemoteBackend::addDomainKey(const string& name, const KeyData& key) { + parameters.AddMember("key", jkey, query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + + return getInt(answer["result"]); +@@ -394,7 +426,7 @@ bool RemoteBackend::activateDomainKey(const string& name, unsigned int id) { + JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + + return true; +@@ -414,7 +446,7 @@ bool RemoteBackend::deactivateDomainKey(const string& name, unsigned int id) { + JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + + return true; +@@ -436,7 +468,7 @@ bool RemoteBackend::getTSIGKey(const std::string& name, std::string* algorithm, + JSON_ADD_MEMBER(parameters, "name", name.c_str(), query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + + if (algorithm != NULL) +@@ -459,7 +491,7 @@ bool RemoteBackend::getDomainInfo(const string &domain, DomainInfo &di) { + JSON_ADD_MEMBER(parameters, "name", domain.c_str(), query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + + // make sure we got zone & kind +@@ -506,7 +538,7 @@ void RemoteBackend::setNotified(uint32_t id, uint32_t serial) { + JSON_ADD_MEMBER(parameters, "serial", serial, query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) { ++ if (this->send(query) == false || this->recv(answer) == false) { + L<send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + + // we are the backend +@@ -565,7 +597,7 @@ bool RemoteBackend::createSlaveDomain(const string &ip, const string &domain, co + JSON_ADD_MEMBER(parameters, "account", account.c_str(), query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + return true; + } +@@ -600,7 +632,7 @@ bool RemoteBackend::replaceRRSet(uint32_t domain_id, const string& qname, const + parameters.AddMember("rrset", rj_rrset, query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + + return true; +@@ -630,7 +662,7 @@ bool RemoteBackend::feedRecord(const DNSResourceRecord &rr, string *ordername) { + + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + return true; // XXX FIXME this API should not return 'true' I think -ahu + } +@@ -651,7 +683,7 @@ bool RemoteBackend::feedEnts(int domain_id, set& nonterm) { + parameters.AddMember("nonterm", nts, query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + return true; + } +@@ -677,7 +709,7 @@ bool RemoteBackend::feedEnts3(int domain_id, const string &domain, set & + parameters.AddMember("nonterm", nts, query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + return true; + } +@@ -696,7 +728,7 @@ bool RemoteBackend::startTransaction(const string &domain, int domain_id) { + + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) { ++ if (this->send(query) == false || this->recv(answer) == false) { + d_trxid = -1; + return false; + } +@@ -714,7 +746,7 @@ bool RemoteBackend::commitTransaction() { + query.AddMember("parameters", parameters, query.GetAllocator()); + + d_trxid = -1; +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + return true; + } +@@ -730,7 +762,7 @@ bool RemoteBackend::abortTransaction() { + query.AddMember("parameters", parameters, query.GetAllocator()); + + d_trxid = -1; +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + return true; + } +@@ -759,7 +791,7 @@ bool RemoteBackend::calculateSOASerial(const string& domain, const SOAData& sd, + parameters.AddMember("sd", soadata, query.GetAllocator()); + query.AddMember("parameters", parameters, query.GetAllocator()); + +- if (connector->send(query) == false || connector->recv(answer) == false) ++ if (this->send(query) == false || this->recv(answer) == false) + return false; + + serial = getInt64(answer["result"]); +diff --git a/modules/remotebackend/remotebackend.hh b/modules/remotebackend/remotebackend.hh +index 18b6a97..2f2d717 100644 +--- a/modules/remotebackend/remotebackend.hh ++++ b/modules/remotebackend/remotebackend.hh +@@ -92,9 +92,15 @@ class PipeConnector: public Connector { + private: + + void launch(); +- CoProcess *coproc; ++ bool checkStatus(); ++ + std::string command; + std::map options; ++ ++ int d_fd1[2], d_fd2[2]; ++ int d_pid; ++ int d_timeout; ++ FILE *d_fp; + }; + + class RemoteBackend : public DNSBackend +@@ -133,12 +139,13 @@ class RemoteBackend : public DNSBackend + static DNSBackend *maker(); + + private: +- int build(const std::string &connstr); ++ int build(); + Connector *connector; + bool d_dnssec; + rapidjson::Document *d_result; + int d_index; + int64_t d_trxid; ++ std::string d_connstr; + + bool getBool(rapidjson::Value &value); + int getInt(rapidjson::Value &value); +@@ -146,5 +153,8 @@ class RemoteBackend : public DNSBackend + int64_t getInt64(rapidjson::Value &value); + std::string getString(rapidjson::Value &value); + double getDouble(rapidjson::Value &value); ++ ++ bool send(rapidjson::Document &value); ++ bool recv(rapidjson::Document &value); + }; + #endif + diff --git a/pdns.spec b/pdns.spec index a698ba3..8b53898 100644 --- a/pdns.spec +++ b/pdns.spec @@ -3,7 +3,7 @@ Name: pdns Version: 3.3 -Release: 4%{?dist} +Release: 5%{?dist} Summary: A modern, advanced and high performance authoritative-only nameserver Group: System Environment/Daemons License: GPLv2 @@ -11,6 +11,7 @@ URL: http://powerdns.com Source0: http://downloads.powerdns.com/releases/%{name}-%{version}.tar.gz Source1: pdns.service Patch0: pdns-default-config.patch +Patch1: pdns-fix-backend-remote.patch Requires(pre): shadow-utils Requires(post): systemd-sysv @@ -113,6 +114,7 @@ This package contains the SQLite backend for %{name} %prep %setup -q %patch0 -p1 -b .default-config-patch +%patch1 -p1 -b .fix-backend-remote %build autoreconf -v -f -i @@ -232,6 +234,9 @@ exit 0 %{_libdir}/%{name}/libgsqlite3backend.so %changelog +* Sat Aug 31 2013 Morten Stevens - 3.3-5 +- Add patch to fix Remote backend + * Wed Aug 21 2013 Morten Stevens - 3.3-4 - Add Remote backend