From: bert hubert Date: Thu, 26 Feb 2015 16:19:08 +0000 (+0100) Subject: implement remote control with libsodium X-Git-Tag: dnsdist-1.0.0-alpha1~248^2~88^2~116 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6d01c80c516dd02f8cf7e8e31eadda9e53ca584e;p=thirdparty%2Fpdns.git implement remote control with libsodium --- diff --git a/.travis.yml b/.travis.yml index 94bdf6e8c6..3a55b2ac2b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -76,6 +76,8 @@ before_script: - sudo chmod 0644 /etc/softhsm/softhsm.conf - sudo chmod 0777 /var/lib/softhsm - p11-kit -l # ensure it's ok + - wget https://xs.powerdns.com/tmp/libsodium_1.0.2-1_amd64.deb + - sudo dpkg -i libsodium_1.0.2-1_amd64.deb script: - ./bootstrap - ./configure diff --git a/configure.ac b/configure.ac index d1c175aa35..8b03630f34 100644 --- a/configure.ac +++ b/configure.ac @@ -103,6 +103,8 @@ AC_CHECK_HEADERS( ) PDNS_CHECK_RAGEL +PKG_CHECK_MODULES([libsodium], [libsodium]) + BOOST_REQUIRE([1.35]) BOOST_FOREACH diff --git a/pdns/Makefile.am b/pdns/Makefile.am index 257afb0be5..e8214988c4 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -575,6 +575,7 @@ dnsdist_SOURCES = \ qtype.cc \ rcpgenerator.cc rcpgenerator.hh \ sillyrecords.cc \ + sodcrypto.cc sodcrypto.hh \ sstuff.hh \ statbag.cc \ unix_utility.cc @@ -585,7 +586,7 @@ dnsdist_LDFLAGS = \ dnsdist_LDADD = \ $(POLARSSL_LIBS) -lreadline \ - $(BOOST_PROGRAM_OPTIONS_LIBS) $(LUA_LIBS) + $(BOOST_PROGRAM_OPTIONS_LIBS) $(LUA_LIBS) ${libsodium_LIBS} nsec3dig_SOURCES = \ base32.cc \ diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index 98dbe9fcd7..a07a7a3fb3 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -36,8 +36,10 @@ #include #include "dnsname.hh" #include "dnswriter.hh" +#include "base64.hh" #include - +#include +#include "sodcrypto.hh" #undef L @@ -188,7 +190,6 @@ struct IDState atomic age; }; - struct DownstreamState { DownstreamState(const ComboAddress& remote_); @@ -326,7 +327,7 @@ shared_ptr roundrobin(const ComboAddress& remote, const DNSName } -#if 0 + static void daemonize(void) { if(fork()) @@ -344,12 +345,12 @@ static void daemonize(void) close(i); } } -#endif SuffixMatchNode g_suffixMatchNodeFilter; SuffixMatchNode g_abuseSMN; NetmaskGroup g_abuseNMG; shared_ptr g_abuseDSS; +ComboAddress g_serverControl; // listens to incoming queries, sends out to downstream servers, noting the intended return path void* udpClientThread(ClientState* cs) @@ -533,7 +534,6 @@ public: // Should not be called simultaneously! void addTCPClientThread() { - vinfolog("Adding TCP Client thread"); int pipefds[2]; @@ -712,9 +712,68 @@ void* maintThread() return 0; } +struct { + string pub; + string sec; +} g_accessKeys, g_serverKeys; +void controlClientThread(int fd, ComboAddress client) +try +{ + for(;;) { + uint16_t len; + getMsgLen(fd, &len); + char msg[len]; + readn2(fd, msg, len); + + string line(msg, len); + line = sodDecrypt(line, g_accessKeys.pub, g_serverKeys.sec); + // cerr<<"Have decrypted line: "< lock(g_luamutex); + auto ret=g_lua.executeCode>("return "+line); + if(ret) + response=*ret; + } + catch(std::exception& e) { + cerr<<"Error: "<= 0) + close(fd); +} + + +void controlThread(int fd, ComboAddress local) +try +{ + ComboAddress client; + int sock; + warnlog("Accepting control connections on %s", local.toStringWithPort()); + while((sock=SAccept(fd, client)) >= 0) { + warnlog("Got control connection from %s", client.toStringWithPort()); + thread t(controlClientThread, sock, client); + t.detach(); + } +} +catch(std::exception& e) +{ + close(fd); + errlog("Control connection died: %s", e.what()); +} -void setupLua() +void setupLua(bool client) { g_lua.writeFunction("newServer", [](const std::string& address, boost::optional qps) @@ -771,18 +830,15 @@ void setupLua() g_lua.writeFunction("addDomainBlock", [](const std::string& domain) { g_suffixMatchNodeFilter.add(DNSName(domain)); }); g_lua.writeFunction("listServers", []() { try { - string ret; + ostringstream ret; boost::format fmt("%1$-3d %2% %|30t|%3$5s %|36t|%4$7.1f %|41t|%5$7d %|48t|%6$10d %|59t|%7$7d %|69t|%8$2.1f %|78t|%9$5.1f" ); - cout << (fmt % "#" % "Address" % "State" % "Qps" % "Qlim" % "Queries" % "Drops" % "Drate" % "Lat") << endl; + ret << (fmt % "#" % "Address" % "State" % "Qps" % "Qlim" % "Queries" % "Drops" % "Drate" % "Lat") << endl; uint64_t totQPS{0}, totQueries{0}, totDrops{0}; int counter=0; for(auto& s : g_dstates) { - if(!ret.empty()) ret+="\n"; - ret+=s->remote.toStringWithPort() + " " + std::to_string(s->queries.load()) + " " + std::to_string(s->outstanding.load()); - string status; if(s->availability == DownstreamState::Availability::Up) status = "UP"; @@ -791,7 +847,7 @@ void setupLua() else status = (s->upStatus ? "up" : "down"); - cout<< (fmt % counter % s->remote.toStringWithPort() % + ret << (fmt % counter % s->remote.toStringWithPort() % status % s->queryLoad % s->qps.getRate() % s->queries.load() % s->reuseds.load() % (s->dropRate) % (s->latencyUsec/1000.0)) << endl; @@ -800,11 +856,11 @@ void setupLua() totDrops += s->reuseds.load(); ++counter; } - cout<< (fmt % "All" % "" % "" + ret<< (fmt % "All" % "" % "" % (double)totQPS % "" % totQueries % totDrops % "" % "") << endl; - return ret; + return ret.str(); }catch(std::exception& e) { cerr< params) { + if(B64Decode(params[1], g_accessKeys.pub)) + throw std::runtime_error("Unable to decode "+params[1]+" as Base64"); + if(B64Decode(params[2], g_accessKeys.sec)) + throw std::runtime_error("Unable to decode "+params[2]+" as Base64"); + }); + + g_lua.writeFunction("serverKeys", [](std::unordered_map params) { + if(B64Decode(params[1], g_serverKeys.pub)) + throw std::runtime_error("Unable to decode "+params[1]+" as Base64"); + if(B64Decode(params[2], g_serverKeys.sec)) + throw std::runtime_error("Unable to decode "+params[2]+" as Base64"); + }); + + + g_lua.writeFunction("testCrypto", [](string testmsg) + { + string encrypted = sodEncrypt(testmsg, g_accessKeys.sec, g_serverKeys.pub); + string decrypted = sodDecrypt(encrypted, g_accessKeys.pub, g_serverKeys.sec); + + if(testmsg == decrypted) + cerr<<"Everything is ok!"< dupper; + { + ifstream history(".history"); + string line; + while(getline(history, line)) + add_history(line.c_str()); + } + ofstream history(".history", std::ios_base::app); + string lastline; + for(;;) { + char* sline = readline("> "); + if(!sline) + break; + + string line(sline); + if(!line.empty() && line != lastline) { + add_history(sline); + history << sline < dupper; + { + ifstream history(".history"); + string line; + while(getline(history, line)) + add_history(line.c_str()); + } + ofstream history(".history", std::ios_base::app); + string lastline; + for(;;) { + char* sline = readline("> "); + if(!sline) + break; + + string line(sline); + if(!line.empty() && line != lastline) { + add_history(sline); + history << sline < lock(g_luamutex); + auto ret=g_lua.executeCode< + boost::optional< + boost::variant< + string, + shared_ptr + > + > + >("return "+line); + + if(ret) { + if (const auto strValue = boost::get>(&*ret)) { + cout<<(*strValue)->remote.toStringWithPort()<(&*ret)) { + cout<<*strValue<()->default_value("dnsdistconf.lua"), "Filename with our configuration") - // ("daemon", po::value()->default_value(true), "run in background") + ("client", "be a client") + ("daemon", po::value()->default_value(true), "run in background") ("local", po::value >(), "Listen on which addresses") ("max-outstanding", po::value()->default_value(65535), "maximum outstanding queries per downstream") ("regex-drop", po::value(), "If set, block queries matching this regex. Mind trailing dot!") @@ -902,17 +1125,13 @@ try g_maxOutstanding = g_vm["max-outstanding"].as(); g_policy = firstAvailable; - setupLua(); - if(g_vm.count("remotes")) { - for(const auto& address : g_vm["remotes"].as>()) { - auto ret=std::shared_ptr(new DownstreamState(ComboAddress(address, 53))); - ret->tid = move(thread(responderThread, ret)); - g_dstates.push_back(ret); - } - } - /* + if(g_vm.count("client")) { + setupLua(true); + doClient(g_serverControl); + exit(EXIT_SUCCESS); + } if(g_vm["daemon"].as()) { g_console=false; daemonize(); @@ -920,7 +1139,18 @@ try else { vinfolog("Running in the foreground"); } - */ + + + setupLua(false); + if(g_vm.count("remotes")) { + for(const auto& address : g_vm["remotes"].as>()) { + auto ret=std::shared_ptr(new DownstreamState(ComboAddress(address, 53))); + ret->tid = move(thread(responderThread, ret)); + g_dstates.push_back(ret); + } + } + + for(auto& dss : g_dstates) { if(dss->availability==DownstreamState::Availability::Auto) { @@ -972,53 +1202,22 @@ try } thread stattid(maintThread); - stattid.detach(); - - set dupper; - { - ifstream history(".history"); - string line; - while(getline(history, line)) - add_history(line.c_str()); + + if(!g_vm["daemon"].as()) { + stattid.detach(); + doConsole(); } - ofstream history(".history", std::ios_base::app); - string lastline; - for(;;) { - char* sline = readline("> "); - if(!sline) - break; - - string line(sline); - if(!line.empty() && line != lastline) { - add_history(sline); - history << sline < lock(g_luamutex); - g_lua.executeCode(line); - } - catch(std::exception& e) { - cerr<<"Error: "< +#include +#include "namespaces.hh" +#include "misc.hh" +#include "base64.hh" + +string newKeypair() +{ + unsigned char alice_publickey[crypto_box_PUBLICKEYBYTES]; + unsigned char alice_secretkey[crypto_box_SECRETKEYBYTES]; + crypto_box_keypair(alice_publickey, alice_secretkey); + + string ret("{\""); + ret+=Base64Encode(string((char*)alice_publickey, crypto_box_PUBLICKEYBYTES)); + ret+="\",\""; + ret+=Base64Encode(string((char*)alice_secretkey, crypto_box_SECRETKEYBYTES)); + ret+="\"}"; + return ret; +} + +// return: nonce + ciphertext + +std::string sodEncrypt(const std::string& msg, const std::string& secretSource, + const std::string& publicDest) +{ + unsigned char nonce[crypto_box_NONCEBYTES]; + unsigned char ciphertext[msg.length() + crypto_box_MACBYTES]; + randombytes_buf(nonce, sizeof nonce); + /* + cerr<<"Encrypt plen: "< + +void sodTest(); +std::string newKeypair(); + +std::string sodEncrypt(const std::string& msg, const std::string& secretSource, + const std::string& publicDest); + + +std::string sodDecrypt(const std::string& msg, const std::string& publicSource, + const std::string& secretDest); + +