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)
--- /dev/null
+remotebackend-access.log
+test_remotebackend_http
+test_remotebackend_pipe
#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)
}
// 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<std::string>(input.GetUint());
else if (input.IsInt()) output = lexical_cast<std::string>(input.GetInt());
- else output = "inconvertible value";
+ else return false;
+ return true;
}
void HTTPConnector::addUrlComponent(const rapidjson::Value ¶meters, const char *element, std::stringstream& ss) {
// 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") {
} 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<std::string>(index) + "]", itr, d_c);
}
} 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"];
// 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();
} 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);
!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);
}
@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
}
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
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);
}
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());
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) {
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());
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;
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());
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());
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)
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());
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) {
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);
};
--- /dev/null
+#include "pdns/namespaces.hh"
+#include <pdns/dns.hh>
+#include <pdns/dnsbackend.hh>
+#include <pdns/dnspacket.hh>
+#include <pdns/ueberbackend.hh>
+#include <pdns/ahuexception.hh>
+#include <pdns/logger.hh>
+#include <pdns/arguments.hh>
+#include <boost/lexical_cast.hpp>
+#include <rapidjson/rapidjson.h>
+#include <rapidjson/document.h>
+#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 <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/foreach.hpp>
+#include <boost/tuple/tuple.hpp>
+
+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 <iostream>
+
+int main(void) {
+ std::cout << "No HTTP support in remotebackend - skipping test" << std::endl;
+ return 0;
+}
+
+#endif
--- /dev/null
+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=") };
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MAIN
+#define BOOST_TEST_MODULE unit
+
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/foreach.hpp>
+#include <boost/tuple/tuple.hpp>
+#include "pdns/namespaces.hh"
+#include <pdns/dns.hh>
+#include <pdns/dnsbackend.hh>
+#include <pdns/dnspacket.hh>
+#include <pdns/ueberbackend.hh>
+#include <pdns/ahuexception.hh>
+#include <pdns/logger.hh>
+#include <pdns/arguments.hh>
+#include "pdns/dnsrecords.hh"
+#include <boost/lexical_cast.hpp>
+#include <rapidjson/rapidjson.h>
+#include <rapidjson/document.h>
+#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 );
+
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/foreach.hpp>
+#include <boost/tuple/tuple.hpp>
+#include "pdns/namespaces.hh"
+#include <pdns/dns.hh>
+#include <pdns/dnsbackend.hh>
+#include <pdns/dnspacket.hh>
+#include <pdns/ueberbackend.hh>
+#include <pdns/ahuexception.hh>
+#include <pdns/logger.hh>
+#include <pdns/arguments.hh>
+#include <boost/lexical_cast.hpp>
+#include <rapidjson/rapidjson.h>
+#include <rapidjson/document.h>
+#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<std::string> 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<std::string> 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<DNSBackend::KeyData> 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<DNSResourceRecord> 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<DNSResourceRecord> 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<string> 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<string> 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();
--- /dev/null
+#!/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
--- /dev/null
+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
+
--- /dev/null
+#!/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
--- /dev/null
+#!/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