From: Aki Tuomi Date: Sun, 2 Jun 2013 16:55:24 +0000 (+0300) Subject: Now adds parameters to calculateSOASerial X-Git-Tag: rec-3.6.0-rc1~698^2~11 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0bc67a4f93228dfe19d4eecae97682b7e9195d0b;p=thirdparty%2Fpdns.git Now adds parameters to calculateSOASerial Test driver for remotebackend Unit test helper for remotebackend tests Ignore test_remotebackend Refactored code with split pipe and http Metadata testing Added new binaries to ignore Fixed metadata handling Fixed domain metadata tests Added Makefile var REMOTEBACKEND_HTTP for test suite Support for automation with or without http connector Only compile libtestremotebackend.la when testing Do not use libremotebackend.la on test compilation Domainkeys and getBeforeAndAfterNamesAbsolute Key can now be marked (in)active with int or boolean Fixed wrong method name in removeDomainKey Retain test command exit value domain key handling tests Two test keys for test purposes moved doesDNSSEC before tests that depends on it Fixed make dist Fixed setNotified to actually send the new serial setNotified support setNotified support Fixed /dns/ into /dns Tests for all non-slave methods Fixed rapidjson usage on superMaster and feedRecord Change array handling to array[foo] format Change json2string to return true/false whether conversion succeeded Added SOA, NS, A record content registrations for helpers Fixed createSlaveDomain to do POST superMasterBackends sets ddb = 0 when failure createSlaveDomain support supermaster and createslavedomain support domain_id handling fixed, now uses post for transactions feedRecord stores rr in parameter rr Fix various url patterns Rest of the methods --- diff --git a/configure.ac b/configure.ac index 04e0d70d98..d8c37ccf15 100644 --- a/configure.ac +++ b/configure.ac @@ -255,10 +255,12 @@ AM_CONDITIONAL(REMOTEBACKEND_HTTP,test x"$enable_remotebackend_http" = "xyes") if test "x$enable_remotebackend_http" = "xyes" then PKG_CHECK_MODULES(LIBCURL, libcurl, HAVE_LIBCURL=yes, AC_MSG_ERROR([Could not find libcurl])) + REMOTEBACKEND_HTTP=yes AC_SUBST(LIBCURL_LIBS) AC_SUBST(LIBCURL_CFLAGS) AC_DEFINE(HAVE_LIBCURL,1,[If we have libcurl]) AC_DEFINE(REMOTEBACKEND_HTTP,1,[If we want HTTP connector]) + AC_SUBST(REMOTEBACKEND_HTTP) fi AC_MSG_CHECKING(whether we should build static binaries) diff --git a/modules/remotebackend/.gitignore b/modules/remotebackend/.gitignore new file mode 100644 index 0000000000..6b621dc026 --- /dev/null +++ b/modules/remotebackend/.gitignore @@ -0,0 +1,3 @@ +remotebackend-access.log +test_remotebackend_http +test_remotebackend_pipe diff --git a/modules/remotebackend/Makefile.am b/modules/remotebackend/Makefile.am index a47f8bbae6..6ee7318a4f 100644 --- a/modules/remotebackend/Makefile.am +++ b/modules/remotebackend/Makefile.am @@ -5,9 +5,46 @@ AM_CPPFLAGS=@THREADFLAGS@ $(BOOST_CPPFLAGS) $(LIBCURL_CFLAGS) -I../../pdns/ext/r #endif EXTRA_DIST=OBJECTFILES OBJECTLIBS -lib_LTLIBRARIES = libremotebackend.la +EXTRA_PROGRAMS=test_remotebackend_pipe test_remotebackend_http +EXTRA_LTLIBRARIES=libtestremotebackend.la + +lib_LTLIBRARIES = libremotebackend.la libremotebackend_la_SOURCES=remotebackend.hh remotebackend.cc unixconnector.cc httpconnector.cc pipeconnector.cc libremotebackend_la_LDFLAGS=-module -avoid-version libremotebackend_la_LIBS=$(LIBCURL_LIBS) + +TESTS_ENVIRONMENT = env BOOST_TEST_LOG_LEVEL=message REMOTEBACKEND_HTTP=$(REMOTEBACKEND_HTTP) ./testrunner.sh +TESTS=test_remotebackend_pipe test_remotebackend_http + +BUILT_SOURCES=../../pdns/dnslabeltext.cc + +../../pdns/dnslabeltext.cc: ../../pdns/dnslabeltext.rl + make -C ../../pdns dnslabeltext.cc + +libtestremotebackend_la_SOURCES=../../pdns/dnsbackend.hh ../../pdns/dnsbackend.cc ../../pdns/ueberbackend.hh ../../pdns/ueberbackend.cc \ + ../../pdns/nameserver.cc ../../pdns/misc.cc ../../pdns/arguments.hh \ + ../../pdns/unix_utility.cc ../../pdns/logger.cc ../../pdns/statbag.cc ../../pdns/arguments.hh ../../pdns/arguments.cc ../../pdns/qtype.cc ../../pdns/dnspacket.cc \ + ../../pdns/dnswriter.cc ../../pdns/base64.cc ../../pdns/base32.cc ../../pdns/dnsrecords.cc ../../pdns/dnslabeltext.cc ../../pdns/dnsparser.cc \ + ../../pdns/rcpgenerator.cc ../../pdns/ednssubnet.cc ../../pdns/nsecrecords.cc ../../pdns/sillyrecords.cc ../../pdns/dnssecinfra.cc \ + ../../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 \ + remotebackend.hh remotebackend.cc unixconnector.cc httpconnector.cc pipeconnector.cc + +libtestremotebackend_la_CFLAGS=$(BOOST_CPPFLAGS) @THREADFLAGS@ $(LIBCURL_CFLAGS) -g -O0 -I../../pdns +libtestremotebackend_la_CXXFLAGS=$(BOOST_CPPFLAGS) @THREADFLAGS@ $(LIBCURL_CFLAGS) -g -O0 -I../../pdns + +test_remotebackend_pipe_SOURCES=test-remotebackend.cc test-remotebackend-pipe.cc + +test_remotebackend_http_SOURCES=test-remotebackend.cc test-remotebackend-http.cc ../../config.h + +test_remotebackend_pipe_CFLAGS=$(BOOST_CPPFLAGS) @THREADFLAGS@ $(LIBCURL_CFLAGS) -g -O0 -I../../pdns +test_remotebackend_pipe_CXXFLAGS=$(BOOST_CPPFLAGS) @THREADFLAGS@ $(LIBCURL_CFLAGS) -g -O0 -I../../pdns +test_remotebackend_pipe_LDADD=libtestremotebackend.la @DYNLINKFLAGS@ @THREADFLAGS@ $(BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS) ../../pdns/ext/polarssl-1.1.2/library/libpolarssl.a $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) $(BOOST_SERIALIZATION_LIBS) $(BOOST_PROGRAM_OPTIONS_LIBS) @LIBDL@ $(LIBCURL_LIBS) + +test_remotebackend_http_CFLAGS=$(BOOST_CPPFLAGS) @THREADFLAGS@ $(LIBCURL_CFLAGS) -g -O0 -I../../pdns +test_remotebackend_http_CXXFLAGS=$(BOOST_CPPFLAGS) @THREADFLAGS@ $(LIBCURL_CFLAGS) -g -O0 -I../../pdns +test_remotebackend_http_LDADD=libtestremotebackend.la @DYNLINKFLAGS@ @THREADFLAGS@ $(BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS) ../../pdns/ext/polarssl-1.1.2/library/libpolarssl.a $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) $(BOOST_SERIALIZATION_LIBS) $(BOOST_PROGRAM_OPTIONS_LIBS) @LIBDL@ $(LIBCURL_LIBS) diff --git a/modules/remotebackend/httpconnector.cc b/modules/remotebackend/httpconnector.cc index c5b1a1673c..b52d858cb8 100644 --- a/modules/remotebackend/httpconnector.cc +++ b/modules/remotebackend/httpconnector.cc @@ -40,12 +40,13 @@ size_t httpconnector_write_data(void *buffer, size_t size, size_t nmemb, void *u } // converts json value into string -void HTTPConnector::json2string(const rapidjson::Value &input, std::string &output) { +bool HTTPConnector::json2string(const rapidjson::Value &input, std::string &output) { if (input.IsString()) output = input.GetString(); else if (input.IsNull()) output = ""; else if (input.IsUint()) output = lexical_cast(input.GetUint()); else if (input.IsInt()) output = lexical_cast(input.GetInt()); - else output = "inconvertible value"; + else return false; + return true; } void HTTPConnector::addUrlComponent(const rapidjson::Value ¶meters, const char *element, std::stringstream& ss) { @@ -104,16 +105,13 @@ void HTTPConnector::requestbuilder(const std::string &method, const rapidjson::V // id must be first due to the fact that the qname/name can be empty addUrlComponent(parameters, "id", ss); + addUrlComponent(parameters, "domain_id", ss); addUrlComponent(parameters, "zonename", ss); addUrlComponent(parameters, "qname", ss); addUrlComponent(parameters, "name", ss); addUrlComponent(parameters, "kind", ss); addUrlComponent(parameters, "qtype", ss); - // finally add suffix - ss << d_url_suffix; - curl_easy_setopt(d_c, CURLOPT_URL, ss.str().c_str()); - (*slist) = NULL; // set the correct type of request based on method if (method == "activateDomainKey" || method == "deactivateDomainKey") { @@ -150,11 +148,18 @@ void HTTPConnector::requestbuilder(const std::string &method, const rapidjson::V } else if (method == "createSlaveDomain") { addUrlComponent(parameters, "ip", ss); addUrlComponent(parameters, "domain", ss); - addUrlComponent(parameters, "account", ss); + if (parameters.HasMember("account")) { + std::string out = parameters["account"].GetString(); + curl_easy_setopt(d_c, CURLOPT_POSTFIELDSIZE, out.size()); + curl_easy_setopt(d_c, CURLOPT_COPYPOSTFIELDS, out.c_str()); + } else { + curl_easy_setopt(d_c, CURLOPT_POST, 1); + curl_easy_setopt(d_c, CURLOPT_POSTFIELDSIZE, 0); + } } else if (method == "replaceRRSet") { std::stringstream ss2; size_t index = 0; - for(rapidjson::Value::ConstValueIterator itr = parameters["nsset"].Begin(); itr != parameters["nsset"].End(); itr++) { + for(rapidjson::Value::ConstValueIterator itr = parameters["rrset"].Begin(); itr != parameters["rrset"].End(); itr++) { index++; ss2 << buildMemberListArgs("rrset[" + boost::lexical_cast(index) + "]", itr, d_c); } @@ -191,13 +196,18 @@ void HTTPConnector::requestbuilder(const std::string &method, const rapidjson::V } else if (method == "startTransaction") { addUrlComponent(parameters, "domain", ss); addUrlComponent(parameters, "trxid", ss); + curl_easy_setopt(d_c, CURLOPT_POST, 1); + curl_easy_setopt(d_c, CURLOPT_POSTFIELDSIZE, 0); } else if (method == "commitTransaction" || method == "abortTransaction") { addUrlComponent(parameters, "trxid", ss); + curl_easy_setopt(d_c, CURLOPT_POST, 1); + curl_easy_setopt(d_c, CURLOPT_POSTFIELDSIZE, 0); } else if (method == "calculateSOASerial") { addUrlComponent(parameters, "domain", ss); std::string out = buildMemberListArgs("sd", ¶meters["sd"], d_c); + curl_easy_setopt(d_c, CURLOPT_POSTFIELDSIZE, out.size()); + curl_easy_setopt(d_c, CURLOPT_COPYPOSTFIELDS, out.c_str()); } else if (method == "setDomainMetadata") { - int n=0; // copy all metadata values into post std::stringstream ss2; const rapidjson::Value& param = parameters["value"]; @@ -205,7 +215,7 @@ void HTTPConnector::requestbuilder(const std::string &method, const rapidjson::V // this one has values too if (param.IsArray()) { for(rapidjson::Value::ConstValueIterator i = param.Begin(); i != param.End(); i++) { - ss2 << "value" << (++n) << "=" << i->GetString() << "&"; + ss2 << "value[]=" << i->GetString() << "&"; } } sparam = ss2.str(); @@ -214,6 +224,12 @@ void HTTPConnector::requestbuilder(const std::string &method, const rapidjson::V } else if (method == "removeDomainKey") { // this one is delete curl_easy_setopt(d_c, CURLOPT_CUSTOMREQUEST, "DELETE"); + } else if (method == "setNotified") { + tmpstr = (char*)malloc(128); + snprintf(tmpstr, 128, "serial=%u", parameters["serial"].GetInt()); + curl_easy_setopt(d_c, CURLOPT_POSTFIELDSIZE, strlen(tmpstr)); + curl_easy_setopt(d_c, CURLOPT_COPYPOSTFIELDS, tmpstr); + free(tmpstr); } else { // perform normal get curl_easy_setopt(d_c, CURLOPT_HTTPGET, 1); @@ -228,11 +244,16 @@ void HTTPConnector::requestbuilder(const std::string &method, const rapidjson::V !strncmp(member,"name",4) || !strncmp(member,"kind",4) || !strncmp(member,"qtype",5) || !strncmp(member,"id",2) || !strncmp(member,"key",3)) continue; - json2string(parameters[member], sparam); - snprintf(header, sizeof header, "X-RemoteBackend-%s: %s", iter->name.GetString(), sparam.c_str()); - (*slist) = curl_slist_append((*slist), header); + if (json2string(parameters[member], sparam)) { + snprintf(header, sizeof header, "X-RemoteBackend-%s: %s", iter->name.GetString(), sparam.c_str()); + (*slist) = curl_slist_append((*slist), header); + } }; + // finally add suffix and store url + ss << d_url_suffix; + curl_easy_setopt(d_c, CURLOPT_URL, ss.str().c_str()); + // store headers into request curl_easy_setopt(d_c, CURLOPT_HTTPHEADER, *slist); } diff --git a/modules/remotebackend/regression-tests/dnsbackend.rb b/modules/remotebackend/regression-tests/dnsbackend.rb index dbf9e95835..aaac5a5b7f 100644 --- a/modules/remotebackend/regression-tests/dnsbackend.rb +++ b/modules/remotebackend/regression-tests/dnsbackend.rb @@ -8,6 +8,28 @@ class DNSBackendHandler < WEBrick::HTTPServlet::AbstractServlet @f = File.open("/tmp/tmp.txt","a") end + def parse_arrays(params) + newparams = {} + params.each do |key,val| + if key=~/^(.*)\[(.*)\]\[(.*)\]/ + newparams[$1] = {} unless newparams.has_key? $1 + newparams[$1][$2] = {} unless newparams[$1].has_key? $2 + newparams[$1][$2][$3] = val + params.delete key + elsif key=~/^(.*)\[(.*)\]/ + if $2 == "" + newparams[$1] = [] unless newparams.has_key? $1 + newparams[$1] << val + else + newparams[$1] = {} unless newparams.has_key? $1 + newparams[$1][$2] = val + end + params.delete key + end + end + params.merge newparams + end + def parse_url(url) url = url.split('/') method = url.shift.downcase @@ -75,13 +97,8 @@ class DNSBackendHandler < WEBrick::HTTPServlet::AbstractServlet } end - if method == "do_setdomainmetadata" - args["value"] = [] - args.each do |k,a| - args["value"] << a if k[/^value/] - end - end - + args = parse_arrays args + @f.puts method @f.puts args diff --git a/modules/remotebackend/remotebackend.cc b/modules/remotebackend/remotebackend.cc index c6b58bc1ce..e81a6f3c85 100644 --- a/modules/remotebackend/remotebackend.cc +++ b/modules/remotebackend/remotebackend.cc @@ -331,7 +331,10 @@ bool RemoteBackend::getDomainKeys(const std::string& name, unsigned int kind, st DNSBackend::KeyData key; key.id = (*iter)["id"].GetUint(); key.flags = (*iter)["flags"].GetUint(); - key.active = (*iter)["active"].GetBool(); + if ((*iter)["active"].IsBool()) + key.active = (*iter)["active"].GetBool(); + else + key.active = ((*iter)["active"].GetInt() != 0 ? true : false ); // case where it's returned as non-boolean key.content = (*iter)["content"].GetString(); keys.push_back(key); } @@ -346,7 +349,7 @@ bool RemoteBackend::removeDomainKey(const string& name, unsigned int id) { if (d_dnssec == false) return false; query.SetObject(); - JSON_ADD_MEMBER(query, "method", "getDomainKeys", query.GetAllocator()); + JSON_ADD_MEMBER(query, "method", "removeDomainKey", query.GetAllocator()); parameters.SetObject(); JSON_ADD_MEMBER(parameters, "name", name.c_str(), query.GetAllocator()); JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator()); @@ -503,7 +506,7 @@ void RemoteBackend::setNotified(uint32_t id, uint32_t serial) { JSON_ADD_MEMBER(query, "method", "setNotified", query.GetAllocator()); parameters.SetObject(); JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator()); - JSON_ADD_MEMBER(parameters, "serial", id, query.GetAllocator()); + JSON_ADD_MEMBER(parameters, "serial", serial, query.GetAllocator()); query.AddMember("parameters", parameters, query.GetAllocator()); if (connector->send(query) == false || connector->recv(answer) == false) { @@ -525,7 +528,7 @@ bool RemoteBackend::superMasterBackend(const string &ip, const string &domain, c rrset.SetArray(); rrset.Reserve(nsset.size(), query.GetAllocator()); for(rapidjson::SizeType i = 0; i < nsset.size(); i++) { - rapidjson::Value &rr = rrset[i]; + rapidjson::Value rr; rr.SetObject(); JSON_ADD_MEMBER(rr, "qtype", nsset[i].qtype.getName().c_str(), query.GetAllocator()); JSON_ADD_MEMBER(rr, "qname", nsset[i].qname.c_str(), query.GetAllocator()); @@ -534,10 +537,13 @@ bool RemoteBackend::superMasterBackend(const string &ip, const string &domain, c JSON_ADD_MEMBER(rr, "ttl", nsset[i].ttl, query.GetAllocator()); JSON_ADD_MEMBER(rr, "priority", nsset[i].priority, query.GetAllocator()); JSON_ADD_MEMBER(rr, "auth", nsset[i].auth, query.GetAllocator()); + rrset.PushBack(rr, query.GetAllocator()); } parameters.AddMember("nsset", rrset, query.GetAllocator()); query.AddMember("parameters", parameters, query.GetAllocator()); + *ddb = 0; + if (connector->send(query) == false || connector->recv(answer) == false) return false; @@ -577,11 +583,13 @@ bool RemoteBackend::replaceRRSet(uint32_t domain_id, const string& qname, const JSON_ADD_MEMBER(parameters, "domain_id", domain_id, query.GetAllocator()); JSON_ADD_MEMBER(parameters, "qname", qname.c_str(), query.GetAllocator()); JSON_ADD_MEMBER(parameters, "qtype", qtype.getName().c_str(), query.GetAllocator()); + JSON_ADD_MEMBER(parameters, "trxid", d_trxid, query.GetAllocator()); + rj_rrset.SetArray(); rj_rrset.Reserve(rrset.size(), query.GetAllocator()); for(rapidjson::SizeType i = 0; i < rrset.size(); i++) { - rapidjson::Value &rr = rj_rrset[i]; + rapidjson::Value rr; rr.SetObject(); JSON_ADD_MEMBER(rr, "qtype", rrset[i].qtype.getName().c_str(), query.GetAllocator()); JSON_ADD_MEMBER(rr, "qname", rrset[i].qname.c_str(), query.GetAllocator()); @@ -590,6 +598,7 @@ bool RemoteBackend::replaceRRSet(uint32_t domain_id, const string& qname, const JSON_ADD_MEMBER(rr, "ttl", rrset[i].ttl, query.GetAllocator()); JSON_ADD_MEMBER(rr, "priority", rrset[i].priority, query.GetAllocator()); JSON_ADD_MEMBER(rr, "auth", rrset[i].auth, query.GetAllocator()); + rj_rrset.PushBack(rr, query.GetAllocator()); } parameters.AddMember("rrset", rj_rrset, query.GetAllocator()); query.AddMember("parameters", parameters, query.GetAllocator()); @@ -602,20 +611,26 @@ bool RemoteBackend::replaceRRSet(uint32_t domain_id, const string& qname, const bool RemoteBackend::feedRecord(const DNSResourceRecord &rr, string *ordername) { rapidjson::Document query,answer; - rapidjson::Value parameters; + rapidjson::Value parameters,rj_rr; query.SetObject(); JSON_ADD_MEMBER(query, "method", "feedRecord", query.GetAllocator()); parameters.SetObject(); - JSON_ADD_MEMBER(parameters, "qtype", rr.qtype.getName().c_str(), query.GetAllocator()); - JSON_ADD_MEMBER(parameters, "qname", rr.qname.c_str(), query.GetAllocator()); - JSON_ADD_MEMBER(parameters, "qclass", QClass::IN, query.GetAllocator()); - JSON_ADD_MEMBER(parameters, "content", rr.content.c_str(), query.GetAllocator()); - JSON_ADD_MEMBER(parameters, "ttl", rr.ttl, query.GetAllocator()); - JSON_ADD_MEMBER(parameters, "priority", rr.priority, query.GetAllocator()); - JSON_ADD_MEMBER(parameters, "auth", rr.auth, query.GetAllocator()); + rj_rr.SetObject(); + JSON_ADD_MEMBER(rj_rr, "qtype", rr.qtype.getName().c_str(), query.GetAllocator()); + JSON_ADD_MEMBER(rj_rr, "qname", rr.qname.c_str(), query.GetAllocator()); + JSON_ADD_MEMBER(rj_rr, "qclass", QClass::IN, query.GetAllocator()); + JSON_ADD_MEMBER(rj_rr, "content", rr.content.c_str(), query.GetAllocator()); + JSON_ADD_MEMBER(rj_rr, "ttl", rr.ttl, query.GetAllocator()); + JSON_ADD_MEMBER(rj_rr, "priority", rr.priority, query.GetAllocator()); + JSON_ADD_MEMBER(rj_rr, "auth", rr.auth, query.GetAllocator()); + parameters.AddMember("rr", rj_rr, query.GetAllocator()); + + JSON_ADD_MEMBER(parameters, "trxid", d_trxid, query.GetAllocator()); + if (ordername) { JSON_ADD_MEMBER(parameters, "ordername", ordername->c_str(), query.GetAllocator()); } + query.AddMember("parameters", parameters, query.GetAllocator()); if (connector->send(query) == false || connector->recv(answer) == false) @@ -631,6 +646,7 @@ bool RemoteBackend::feedEnts(int domain_id, set& nonterm) { JSON_ADD_MEMBER(query, "method", "feedEnts", query.GetAllocator()); parameters.SetObject(); JSON_ADD_MEMBER(parameters, "domain_id", domain_id, query.GetAllocator()); + JSON_ADD_MEMBER(parameters, "trxid", d_trxid, query.GetAllocator()); nts.SetArray(); BOOST_FOREACH(const string &t, nonterm) { nts.PushBack(t.c_str(), query.GetAllocator()); @@ -655,6 +671,7 @@ bool RemoteBackend::feedEnts3(int domain_id, const string &domain, set & JSON_ADD_MEMBER(parameters, "times", times, query.GetAllocator()); JSON_ADD_MEMBER(parameters, "salt", salt.c_str(), query.GetAllocator()); JSON_ADD_MEMBER(parameters, "narrow", narrow, query.GetAllocator()); + JSON_ADD_MEMBER(parameters, "trxid", d_trxid, query.GetAllocator()); nts.SetArray(); BOOST_FOREACH(const string &t, nonterm) { diff --git a/modules/remotebackend/remotebackend.hh b/modules/remotebackend/remotebackend.hh index 8984aa089f..9e7d052f65 100644 --- a/modules/remotebackend/remotebackend.hh +++ b/modules/remotebackend/remotebackend.hh @@ -66,7 +66,7 @@ class HTTPConnector: public Connector { CURL *d_c; std::string d_data; int timeout; - void json2string(const rapidjson::Value &input, std::string &output); + bool json2string(const rapidjson::Value &input, std::string &output); void requestbuilder(const std::string &method, const rapidjson::Value ¶meters, struct curl_slist **slist); void addUrlComponent(const rapidjson::Value ¶meters, const char *element, std::stringstream& ss); }; diff --git a/modules/remotebackend/test-remotebackend-http.cc b/modules/remotebackend/test-remotebackend-http.cc new file mode 100644 index 0000000000..f91d05ad9f --- /dev/null +++ b/modules/remotebackend/test-remotebackend-http.cc @@ -0,0 +1,73 @@ +#include "pdns/namespaces.hh" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pdns/json.hh" +#include "pdns/statbag.hh" +#include "pdns/packetcache.hh" + +StatBag S; +PacketCache PC; +ArgvMap &arg() +{ + static ArgvMap arg; + return arg; +}; + +class RemoteLoader +{ + public: + RemoteLoader(); +}; + +DNSBackend *be; + +#ifdef REMOTEBACKEND_HTTP + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MAIN +#define BOOST_TEST_MODULE unit + +#include +#include +#include +#include + +struct RemotebackendSetup { + RemotebackendSetup() { + be = 0; + try { + // setup minimum arguments + ::arg().set("module-dir")=""; + new RemoteLoader(); + BackendMakers().launch("remote"); + // then get us a instance of it + ::arg().set("remote-connection-string")="http:url=http://localhost:62434/dns"; + ::arg().set("remote-dnssec")="yes"; + be = BackendMakers().all()[0]; + } catch (AhuException &ex) { + BOOST_TEST_MESSAGE("Cannot start remotebackend: " << ex.reason ); + }; + } + ~RemotebackendSetup() { } +}; + +BOOST_GLOBAL_FIXTURE( RemotebackendSetup ); + +#else + +#include + +int main(void) { + std::cout << "No HTTP support in remotebackend - skipping test" << std::endl; + return 0; +} + +#endif diff --git a/modules/remotebackend/test-remotebackend-keys.hh b/modules/remotebackend/test-remotebackend-keys.hh new file mode 100644 index 0000000000..2ccc9b42ba --- /dev/null +++ b/modules/remotebackend/test-remotebackend-keys.hh @@ -0,0 +1,3 @@ +DNSBackend::KeyData k1 = {1, 257, true, 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=") }; + +DNSBackend::KeyData k2 = {2, 256, true, 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=") }; diff --git a/modules/remotebackend/test-remotebackend-pipe.cc b/modules/remotebackend/test-remotebackend-pipe.cc new file mode 100644 index 0000000000..9a4eb15547 --- /dev/null +++ b/modules/remotebackend/test-remotebackend-pipe.cc @@ -0,0 +1,65 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MAIN +#define BOOST_TEST_MODULE unit + +#include +#include +#include +#include +#include "pdns/namespaces.hh" +#include +#include +#include +#include +#include +#include +#include +#include "pdns/dnsrecords.hh" +#include +#include +#include +#include "pdns/json.hh" +#include "pdns/statbag.hh" +#include "pdns/packetcache.hh" + +StatBag S; +PacketCache PC; +ArgvMap &arg() +{ + static ArgvMap arg; + return arg; +}; + +class RemoteLoader +{ + public: + RemoteLoader(); +}; + +DNSBackend *be; + +struct RemotebackendSetup { + RemotebackendSetup() { + be = 0; + try { + // setup minimum arguments + ::arg().set("module-dir")=""; + new RemoteLoader(); + BackendMakers().launch("remote"); + // then get us a instance of it + ::arg().set("remote-connection-string")="pipe:command=unittest_pipe.rb"; + ::arg().set("remote-dnssec")="yes"; + be = BackendMakers().all()[0]; + // load few record types to help out + SOARecordContent::report(); + NSRecordContent::report(); + ARecordContent::report(); + } catch (AhuException &ex) { + BOOST_TEST_MESSAGE("Cannot start remotebackend: " << ex.reason ); + }; + } + ~RemotebackendSetup() { } +}; + +BOOST_GLOBAL_FIXTURE( RemotebackendSetup ); + diff --git a/modules/remotebackend/test-remotebackend.cc b/modules/remotebackend/test-remotebackend.cc new file mode 100644 index 0000000000..28427c8a6f --- /dev/null +++ b/modules/remotebackend/test-remotebackend.cc @@ -0,0 +1,247 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN + +#include +#include +#include +#include +#include "pdns/namespaces.hh" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pdns/json.hh" +#include "pdns/statbag.hh" +#include "pdns/packetcache.hh" + +#include "test-remotebackend-keys.hh" + +extern DNSBackend *be; + +BOOST_AUTO_TEST_SUITE(test_remotebackend_so) + +BOOST_AUTO_TEST_CASE(test_method_lookup) { + BOOST_TEST_MESSAGE("Testing lookup method"); + DNSResourceRecord rr; + be->lookup(QType(QType::SOA), "unit.test"); + // then try to get() + BOOST_CHECK(be->get(rr)); // and this should be TRUE. + // then we check rr contains what we expect + BOOST_CHECK_EQUAL(rr.qname, "unit.test"); + BOOST_CHECK_MESSAGE(rr.qtype == QType::SOA, "returned qtype was not SOA"); + BOOST_CHECK_EQUAL(rr.content, "ns.unit.test hostmaster.unit.test 1 2 3 4 5 6"); + BOOST_CHECK_EQUAL(rr.ttl, 300); +} + +BOOST_AUTO_TEST_CASE(test_method_list) { + int record_count = 0; + DNSResourceRecord rr; + + BOOST_TEST_MESSAGE("Testing list method"); + be->list("unit.test", -1); + while(be->get(rr)) record_count++; + + BOOST_CHECK_EQUAL(record_count, 5); // number of records our test domain has +} + +BOOST_AUTO_TEST_CASE(test_method_doesDNSSEC) { + BOOST_TEST_MESSAGE("Testing doesDNSSEC method"); + BOOST_CHECK(be->doesDNSSEC()); // should be true +} + +BOOST_AUTO_TEST_CASE(test_method_setDomainMetadata) { + std::vector meta; + meta.push_back("VALUE"); + BOOST_TEST_MESSAGE("Testing setDomainMetadata method"); + BOOST_CHECK(be->setDomainMetadata("unit.test","TEST", meta)); +} + +BOOST_AUTO_TEST_CASE(test_method_getDomainMetadata) { + std::vector meta; + BOOST_TEST_MESSAGE("Testing getDomainMetadata method"); + be->getDomainMetadata("unit.test","TEST", meta); + BOOST_CHECK_EQUAL(meta.size(), 1); + // in case we got more than one value, which would be unexpected + // but not fatal + if (meta.size() > 0) + BOOST_CHECK_EQUAL(meta[0], "VALUE"); +} + +BOOST_AUTO_TEST_CASE(test_method_addDomainKey) { + BOOST_TEST_MESSAGE("Testing addDomainKey method"); + BOOST_CHECK_EQUAL(be->addDomainKey("unit.test",k1), 1); + BOOST_CHECK_EQUAL(be->addDomainKey("unit.test",k2), 2); +} + +BOOST_AUTO_TEST_CASE(test_method_getDomainKeys) { + std::vector keys; + BOOST_TEST_MESSAGE("Testing getDomainKeys method"); + // we expect to get two keys + be->getDomainKeys("unit.test",0,keys); + BOOST_CHECK_EQUAL(keys.size(), 2); + // in case we got more than 2 keys, which would be unexpected + // but not fatal + if (keys.size() > 1) { + // check that we have two keys + BOOST_FOREACH(DNSBackend::KeyData &kd, keys) { + BOOST_CHECK(kd.id > 0); + BOOST_CHECK(kd.flags == 256 || kd.flags == 257); + BOOST_CHECK(kd.active == true); + BOOST_CHECK(kd.content.size() > 500); + } + } +} + +BOOST_AUTO_TEST_CASE(test_method_deactivateDomainKey) { + BOOST_TEST_MESSAGE("Testing deactivateDomainKey method"); + BOOST_CHECK(be->deactivateDomainKey("unit.test",1)); +} + +BOOST_AUTO_TEST_CASE(test_method_activateDomainKey) { + BOOST_TEST_MESSAGE("Testing activateDomainKey method"); + BOOST_CHECK(be->activateDomainKey("unit.test",1)); +} + +BOOST_AUTO_TEST_CASE(test_method_removeDomainKey) { + BOOST_CHECK(be->removeDomainKey("unit.test",2)); + BOOST_CHECK(be->removeDomainKey("unit.test",1)); +} + +BOOST_AUTO_TEST_CASE(test_method_getBeforeAndAfterNamesAbsolute) { + std::string unhashed,before,after; + BOOST_TEST_MESSAGE("Testing getBeforeAndAfterNamesAbsolute method"); + + be->getBeforeAndAfterNamesAbsolute(-1, "middle.unit.test", unhashed, before, after); + BOOST_CHECK_EQUAL(unhashed, "middle"); + BOOST_CHECK_EQUAL(before, "begin"); + BOOST_CHECK_EQUAL(after, "stop"); +} + +BOOST_AUTO_TEST_CASE(test_method_getTSIGKey) { + std::string algorithm, content; + BOOST_TEST_MESSAGE("Testing getTSIGKey method"); + be->getTSIGKey("unit.test",&algorithm,&content); + BOOST_CHECK_EQUAL(algorithm, "NULL"); + BOOST_CHECK_EQUAL(content, "NULL"); +} + +BOOST_AUTO_TEST_CASE(test_method_setNotified) { + BOOST_TEST_MESSAGE("Testing setNotified method"); + be->setNotified(1, 2); + BOOST_CHECK(true); // we check this on next step +} + +BOOST_AUTO_TEST_CASE(test_method_getDomainInfo) { + DomainInfo di; + BOOST_TEST_MESSAGE("Testing getDomainInfo method"); + be->getDomainInfo("unit.test", di); + BOOST_CHECK_EQUAL(di.zone, "unit.test"); + BOOST_CHECK_EQUAL(di.serial, 2); + BOOST_CHECK_EQUAL(di.notified_serial, 2); + BOOST_CHECK_EQUAL(di.kind, DomainInfo::Native); + BOOST_CHECK_EQUAL(di.backend, be); +} + +BOOST_AUTO_TEST_CASE(test_method_superMasterBackend) { + DNSResourceRecord rr; + std::vector nsset; + DNSBackend *dbd; + BOOST_TEST_MESSAGE("Testing superMasterBackend method"); + + rr.qname = "example.com"; + rr.qtype = QType::NS; + rr.qclass = QClass::IN; + rr.ttl = 300; + rr.content = "ns1.example.com"; + nsset.push_back(rr); + rr.qname = "example.com"; + rr.qtype = QType::NS; + rr.qclass = QClass::IN; + rr.ttl = 300; + rr.content = "ns2.example.com"; + nsset.push_back(rr); + + BOOST_CHECK(be->superMasterBackend("10.0.0.1", "example.com", nsset, NULL, &dbd)); + + // let's see what we got + BOOST_CHECK_EQUAL(dbd, be); +} + +BOOST_AUTO_TEST_CASE(test_method_createSlaveDomain) { + BOOST_TEST_MESSAGE("Testing createSlaveDomain method"); + BOOST_CHECK(be->createSlaveDomain("10.0.0.1", "pirate.unit.test", "")); +} + +BOOST_AUTO_TEST_CASE(test_method_feedRecord) { + DNSResourceRecord rr; + BOOST_TEST_MESSAGE("Testing feedRecord method"); + be->startTransaction("example.com",2); + rr.qname = "example.com"; + rr.qtype = QType::SOA; + rr.qclass = QClass::IN; + rr.ttl = 300; + rr.content = "ns1.example.com hostmaster.example.com 2013013441 7200 3600 1209600 300"; + BOOST_CHECK(be->feedRecord(rr, NULL)); + rr.qname = "replace.example.com"; + rr.qtype = QType::A; + rr.qclass = QClass::IN; + rr.ttl = 300; + rr.content = "127.0.0.1"; + BOOST_CHECK(be->feedRecord(rr, NULL)); + be->commitTransaction(); +} + +BOOST_AUTO_TEST_CASE(test_method_replaceRRSet) { + be->startTransaction("example.com",2); + DNSResourceRecord rr; + std::vector rrset; + BOOST_TEST_MESSAGE("Testing replaceRRSet method"); + rr.qname = "replace.example.com"; + rr.qtype = QType::A; + rr.qclass = QClass::IN; + rr.ttl = 300; + rr.content = "1.1.1.1"; + rrset.push_back(rr); + BOOST_CHECK(be->replaceRRSet(2, "replace.example.com", QType(QType::A), rrset)); + be->commitTransaction(); +} + +BOOST_AUTO_TEST_CASE(test_method_feedEnts) { + BOOST_TEST_MESSAGE("Testing feedEnts method"); + be->startTransaction("example.com",2); + set nonterm = boost::assign::list_of("_udp")("_sip._udp"); + BOOST_CHECK(be->feedEnts(2, nonterm)); + be->commitTransaction(); +} + +BOOST_AUTO_TEST_CASE(test_method_feedEnts3) { + BOOST_TEST_MESSAGE("Testing feedEnts3 method"); + be->startTransaction("example.com",2); + set nonterm = boost::assign::list_of("_udp")("_sip._udp"); + BOOST_CHECK(be->feedEnts3(2, "example.com", nonterm, 1, "\xaa\xbb\xcc\xdd", 0)); + be->commitTransaction(); +} + +BOOST_AUTO_TEST_CASE(test_method_abortTransaction) { + BOOST_TEST_MESSAGE("Testing abortTransaction method"); + be->startTransaction("example.com",2); + BOOST_CHECK(be->abortTransaction()); +} + +BOOST_AUTO_TEST_CASE(test_method_calculateSOASerial) { + SOAData sd; + time_t serial; + + be->getSOA("unit.test",sd); + BOOST_CHECK(be->calculateSOASerial("unit.test",sd,serial)); + + BOOST_CHECK_EQUAL(serial, 2013060300); +} + +BOOST_AUTO_TEST_SUITE_END(); diff --git a/modules/remotebackend/testrunner.sh b/modules/remotebackend/testrunner.sh new file mode 100755 index 0000000000..2828ad061b --- /dev/null +++ b/modules/remotebackend/testrunner.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +webrick_pid="" + +if [ x"$REMOTEBACKEND_HTTP" == "xyes" ]; then + +if [ `basename "$1"` == "test_remotebackend_http" ]; then + ./unittest_http.rb & + webrick_pid=$! + sleep 1 +fi + +$1 +rv=$? + +if [ ! -z "$webrick_pid" ]; then + kill -TERM $webrick_pid + # wait a moment for it to die + i=0 + while [ $i -lt 5 ]; do + sleep 1 + kill -0 $webrick_pid 2>/dev/null + if [ $? -ne 0 ]; then break; fi + let i=i+1 + done +fi + +else + +$1 +rv=$? + +fi + +exit $rv diff --git a/modules/remotebackend/unittest.rb b/modules/remotebackend/unittest.rb new file mode 100644 index 0000000000..69ae27fe83 --- /dev/null +++ b/modules/remotebackend/unittest.rb @@ -0,0 +1,224 @@ +require 'rubygems' +require 'json' + +# define a simple $domain + +$ttl = 300 +$notified_serial = 1 + +$domain = { + "unit.test" => { + "SOA" => ["ns.unit.test hostmaster.unit.test 1 2 3 4 5 6"], + "NS" => ["ns1.unit.test", "ns2.unit.test"], + }, + "ns1.unit.test" => { + "A" => ["10.0.0.1"] + }, + "ns2.unit.test" => { + "A" => ["10.0.0.2"] + } +} + +$meta = {} + +$keys = {} + +class Handler + def initialize + end + + def rr(qname, qtype, content, ttl, priority = 0, auth = 1, domain_id = -1) + {:qname => qname, :qtype => qtype, :content => content, :ttl => ttl.to_i, :priority => priority.to_i, :auth => auth.to_i, :domain_id => domain_id.to_i} + end + + def do_initialize(*args) + return true, "Test bench initialized" + end + + def do_lookup(args) + ret = [] + if $domain.has_key?(args["qname"]) + if $domain[args["qname"]].has_key?(args["qtype"]) + $domain[args["qname"]][args["qtype"]].each do |rd| + ret << rr(args["qname"], args["qtype"], rd, $ttl) + end + elsif args["qtype"] == 'ANY' + $domain[args["qname"]].each do |qt,qr| + qr.each do |rd| + ret << rr(args["qname"], qt, rd, $ttl) + end + end + end + end + [false] unless ret.size>0 + [ret] + end + + def do_list(args) + ret = [] + if args["zonename"] == "unit.test" + $domain.each do |qname,rdata| + rdata.each do |rtype,rc| + rc.each do |rd| + ret << rr(qname,rtype,rd,$ttl) + end + end + end + end + [false] unless ret.size>0 + [ret] + end + + def do_getdomainmetadata(args) + return [ $meta[args["name"]][args["kind"]] ] if $meta.has_key?(args["name"]) and $meta[args["name"]].has_key?(args["kind"]) + return [false] + end + + def do_setdomainmetadata(args) + $meta[args["name"].to_s] = {} unless $meta.has_key? args["name"] + $meta[args["name"].to_s][args["kind"].to_s] = args["value"].to_a + [true] + end + + def do_adddomainkey(args) + $keys[args["name"]] = [] unless $keys.has_key? args["name"] + id=$keys[args["name"]].size + 1 + args["key"]["id"] = id + $keys[args["name"]] << args["key"] + [id] + end + + def do_getdomainkeys(args) + if $keys.has_key? args["name"] + return [ $keys[args["name"]] ] + end + [false] + end + + def do_activatedomainkey(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]["active"] = true + return [true] + end + end + [false] + end + + def do_deactivatedomainkey(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]["active"] = false + return [true] + end + end + [false] + end + + def do_removedomainkey(args) + args["id"] = args["id"].to_i + if $keys.has_key? args["name"] + if $keys[args["name"]][args["id"]-1] + $keys[args["name"]].delete_at args["id"]-1 + return [true] + end + end + [false] + end + + def do_getbeforeandafternamesabsolute(args) + return [ { :unhashed => "middle", :before => "begin", :after => "stop" } ] if args["qname"] == 'middle.unit.test' + [false] + end + + def do_gettsigkey(args) + if args["name"] == "unit.test" + return [{:algorithm => "NULL", :content => "NULL"}] + end + [false] + end + + def do_setnotified(args) + if args["id"].to_i == 1 + $notified_serial = args["serial"].to_i + return [true] + end + [false] + end + + def do_getdomaininfo(args) + if args["name"] == "unit.test" + return [{ + :id => 1, + :zone => "unit.test", + :masters => ["10.0.0.1"], + :notified_serial => $notified_serial, + :serial => $notified_serial, + :last_check => Time.now.to_i, + :kind => 'native' + }] + end + [false] + end + + def do_supermasterbackend(args) + $domain[args["domain"]] = { + "NS" => args["nsset"] + } + [true] + end + + def do_createslavedomain(args) + $domain[args["domain"]] = { + } + [true] + end + + def do_feedrecord(args) + args.delete "trxid" + rr = args["rr"] + name = rr["qname"] + qtype = rr["qtype"] + $domain[name] = {} unless $domain.has_key? name + $domain[name][qtype] = [] unless $domain[name].has_key? qtype + $domain[name][qtype] << rr["content"] + [true] + end + + def do_replacerrset(args) + $domain[args["qname"]].delete args["qtype"] if $domain.has_key?(args["qname"]) and $domain[args["qname"]].has_key?(args["qtype"]) + args["rrset"] = args["rrset"].values if args["rrset"].is_a?(Hash) + args["rrset"].each do |rr| + self.do_feedrecord({"trxid" => args["trxid"], "rr" => rr}) + end + [true] + end + + def do_feedents(args) + [true] + end + + def do_feedents3(args) + [true] + end + + def do_starttransaction(args) + [true] + end + + def do_committransaction(args) + [true] + end + + def do_aborttransaction(args) + [true] + end + + def do_calculatesoaserial(args) + return [2013060300] if args["sd"]["qname"] == "unit.test" + [false] + end +end + diff --git a/modules/remotebackend/unittest_http.rb b/modules/remotebackend/unittest_http.rb new file mode 100755 index 0000000000..25b9f36898 --- /dev/null +++ b/modules/remotebackend/unittest_http.rb @@ -0,0 +1,179 @@ +#!/usr/bin/ruby + +require 'json' +require 'thread' +require "rubygems" +require "webrick" +require "./unittest" + +class DNSBackendHandler < WEBrick::HTTPServlet::AbstractServlet + def initialize(server, dnsbackend) + @dnsbackend = dnsbackend + @semaphore = Mutex.new + @f = File.open("/tmp/tmp.txt","a") + end + + def parse_arrays(params) + newparams = {} + params.each do |key,val| + if key=~/^(.*)\[(.*)\]\[(.*)\]/ + newparams[$1] = {} unless newparams.has_key? $1 + newparams[$1][$2] = {} unless newparams[$1].has_key? $2 + newparams[$1][$2][$3] = val + params.delete key + elsif key=~/^(.*)\[(.*)\]/ + if $2 == "" + newparams[$1] = [] unless newparams.has_key? $1 + newparams[$1] << val + else + newparams[$1] = {} unless newparams.has_key? $1 + newparams[$1][$2] = val + end + params.delete key + end + end + params.merge newparams + end + + def parse_url(url) + url = url.split('/') + method = url.shift.downcase + + # do some determining based on method names + args = case method + when "lookup" + { + "qname" => url.shift, + "qtype" => url.shift + } + when "list" + { + "zonename" => url.shift + } + when "getbeforeandafternamesabsolute", "getbeforeandafternames" + { + "id" => url.shift.to_i, + "qname" => url.shift + } + when "getdomainmetadata", "setdomainmetadata", "getdomainkeys" + { + "name" => url.shift, + "kind" => url.shift + } + when "removedomainkey", "activatedomainkey", "deactivatedomainkey" + { + "id" => url.shift.to_i, + "name" => url.shift + } + when "adddomainkey", "gettsigkey", "getdomaininfo" + { + "name" => url.shift + } + when "setnotified", "feedents" + { + "id" => url.shift.to_i + } + when "supermasterbackend", "createslavedomain" + { + "ip" => url.shift, + "domain" => url.shift + } + when "feedents3" + { + "id" => url.shift.to_i, + "domain" => url.shift + } + when "starttransaction" + { + "id" => url.shift.to_i, + "domain" => url.shift, + "trxid" => url.shift.to_i + } + when "committransaction", "aborttransaction" + { + "trxid" => url.shift.to_i + } + when "replacerrset" + { + "id" => url.shift.to_i, + "qname" => url.shift, + "qtype" => url.shift + } + else + {} + end + + [method, args] + end + + def do_GET(req,res) + req.continue + + tmp = req.path[/dns\/(.*)/,1] + return 400, "Bad request" if (tmp.nil?) + + method, args = parse_url(tmp) + + method = "do_#{method}" + + # get more arguments + req.each do |k,v| + attr = k[/X-RemoteBackend-(.*)/,1] + if attr + args[attr] = v + end + end + + args = args.merge req.query + + if method == "do_adddomainkey" + args["key"] = { + "flags" => args.delete("flags").to_i, + "active" => args.delete("active").to_i, + "content" => args.delete("content") + } + end + + args = parse_arrays args + + @f.puts method + @f.puts args + + @semaphore.synchronize do + if @dnsbackend.respond_to?(method.to_sym) + result, log = @dnsbackend.send(method.to_sym, args) + body = {:result => result, :log => log} + res.status = 200 + res["Content-Type"] = "application/javascript; charset=utf-8" + res.body = body.to_json + else + res.status = 404 + res["Content-Type"] = "application/javascript; charset=utf-8" + res.body = ({:result => false, :log => ["Method not found"]}).to_json + end + end + end + + def do_DELETE(req,res) + do_GET(req,res) + end + + def do_POST(req,res) + do_GET(req,res) + end +end + +server = WEBrick::HTTPServer.new( + :Port=>62434, + :BindAddress=>"localhost", +# Logger: WEBrick::Log.new("remotebackend-server.log"), + :AccessLog=>[ [ File.open("remotebackend-access.log", "w"), WEBrick::AccessLog::COMBINED_LOG_FORMAT ] ] +) + +be = Handler.new +server.mount "/dns", DNSBackendHandler, be + +trap('INT') { server.stop } +trap('TERM') { server.stop } + +server.start diff --git a/modules/remotebackend/unittest_pipe.rb b/modules/remotebackend/unittest_pipe.rb new file mode 100755 index 0000000000..ea24e130bd --- /dev/null +++ b/modules/remotebackend/unittest_pipe.rb @@ -0,0 +1,38 @@ +#!/usr/bin/ruby + +require 'rubygems' +require 'json' +require './unittest' + +h = Handler.new() +f = File.open "/tmp/tmp.txt","a" + +STDOUT.sync = true +begin + STDIN.each_line do |line| + f.puts line + # expect json + input = {} + line = line.strip + next if line.empty? + begin + input = JSON.parse(line) + method = "do_#{input["method"].downcase}" + args = input["parameters"] + + if h.respond_to?(method.to_sym) == false + res = false + elsif args.size > 0 + res, log = h.send(method,args) + else + res, log = h.send(method) + end + puts ({:result => res, :log => log}).to_json + f.puts({:result => res, :log => log}).to_json + rescue JSON::ParserError + puts ({:result => false, :log => "Cannot parse input #{line}"}).to_json + next + end + end +rescue SystemExit, Interrupt +end