From: bert hubert Date: Sun, 29 Mar 2015 19:07:35 +0000 (+0200) Subject: hook up webserver and embedded html (!) X-Git-Tag: dnsdist-1.0.0-alpha1~248^2~88^2~33 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=50bed8816f5b961d66645b2de0941db050fdb410;p=thirdparty%2Fpdns.git hook up webserver and embedded html (!) --- diff --git a/pdns/Makefile.am b/pdns/Makefile.am index 0fbfbacdd3..ea87e050a6 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -560,23 +560,26 @@ dnsdist_SOURCES = \ base64.hh \ dnsdist.cc \ dnsdist-lua.cc \ + dnsdist-web.cc \ dnslabeltext.cc \ dnsname.cc dnsname.hh \ dnswriter.cc \ dolog.hh \ iputils.cc \ + htmfiles.h \ misc.cc misc.hh \ qtype.cc \ sholder.hh \ sodcrypto.cc sodcrypto.hh \ - sstuff.hh + sstuff.hh \ + ext/json11/json11.cpp dnsdist_LDFLAGS = \ $(AM_LDFLAGS) dnsdist_LDADD = \ -lreadline -lrt -ltermcap \ - $(LUA_LIBS) ${libsodium_LIBS} + $(LUA_LIBS) ${libsodium_LIBS} $(YAHTTP_LIBS) nsec3dig_SOURCES = \ base32.cc \ @@ -1059,6 +1062,9 @@ endif dnslabeltext.cc: dnslabeltext.rl $(AM_V_GEN)$(RAGEL) $< -o dnslabeltext.cc +htmlfiles.h: dnsdistdist/html/* + ./dnsdistdist/incfiles dnsdistdist > $@ + bind-dnssec.schema.sqlite3.sql.h: bind-dnssec.schema.sqlite3.sql ( echo 'static char sqlCreate[] __attribute__((unused))=' ; sed 's/$$/"/g' $< | sed 's/^/"/g' ; echo ';' ) > $@ diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index 2e99c63383..b83f6e1db8 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -409,6 +409,29 @@ vector> setupLua(bool client, const std::string& confi g_lua.registerFunction("add",(void (SuffixMatchNode::*)(const DNSName&)) &SuffixMatchNode::add); g_lua.registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check); + g_lua.writeFunction("webserver", [client](const std::string& address, const std::string& password) { + if(client) + return; + ComboAddress local(address); + try { + int sock = socket(local.sin4.sin_family, SOCK_STREAM, 0); + SSetsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1); + SBind(sock, local); + SListen(sock, 5); + auto launch=[sock, local, password]() { + thread t(dnsdistWebserverThread, sock, local, password); + t.detach(); + }; + if(g_launchWork) + g_launchWork->push_back(launch); + else + launch(); + } + catch(std::exception& e) { + errlog("Unable to bind to webserver socket on %s: %s", local.toStringWithPort(), e.what()); + } + + }); g_lua.writeFunction("controlSocket", [client](const std::string& str) { ComboAddress local(str, 5199); diff --git a/pdns/dnsdist-web.cc b/pdns/dnsdist-web.cc new file mode 100644 index 0000000000..2d1213aefd --- /dev/null +++ b/pdns/dnsdist-web.cc @@ -0,0 +1,187 @@ +#include "dnsdist.hh" +#include "sstuff.hh" +#include "ext/json11/json11.hpp" +#include "ext/incbin/incbin.h" +#include "dolog.hh" +#include +#include +#include +#include "namespaces.hh" +#include +#include +#include "ext/incbin/incbin.h" +#include "htmlfiles.h" +#include "base64.hh" + +static int uptimeOfProcess() +{ + static time_t start=time(0); + return time(0) - start; +} + + +bool compareAuthorization(YaHTTP::Request& req, const string &expected_password) +{ + // validate password + YaHTTP::strstr_map_t::iterator header = req.headers.find("authorization"); + bool auth_ok = false; + if (header != req.headers.end() && toLower(header->second).find("basic ") == 0) { + string cookie = header->second.substr(6); + + string plain; + B64Decode(cookie, plain); + + vector cparts; + stringtok(cparts, plain, ":"); + + // this gets rid of terminating zeros + auth_ok = (cparts.size()==2 && (0==strcmp(cparts[1].c_str(), expected_password.c_str()))); + } + return auth_ok; +} + + +static void connectionThread(int sock, ComboAddress remote, string password) +{ + using namespace json11; + infolog("Webserver handling connection from %s", remote.toStringWithPort()); + FILE* fp=fdopen(sock, "r"); + + string line; + string request; + while(stringfgets(fp, line)) { + request+=line; + trim(line); + + if(line.empty()) + break; + } + + std::istringstream ifs(request); + YaHTTP::Request req; + ifs >> req; + + string command=req.getvars["command"]; + + string callback; + + if(req.getvars.count("callback")) { + callback=req.getvars["callback"]; + req.getvars.erase("callback"); + } + + req.getvars.erase("_"); // jQuery cache buster + + YaHTTP::Response resp(req); + + if (!compareAuthorization(req, password)) { + errlog("HTTP Request \"%s\" from %s: Web Authentication failed", req.url.path, remote.toStringWithPort()); + resp.status=401; + resp.body="

Unauthorized

"; + resp.headers["WWW-Authenticate"] = "basic realm=\"PowerDNS\""; + + } + else if(command=="stats") { + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + + resp.status=200; + Json my_json = Json::object { + { "questions", (int)g_stats.queries }, + { "servfail-answers", (int)g_stats.servfailResponses }, + { "packetcache-hits", 0}, + { "packetcache-misses", 0}, + { "user-msec", (int)(ru.ru_utime.tv_sec*1000ULL + ru.ru_utime.tv_usec/1000) }, + { "sys-msec", (int)(ru.ru_stime.tv_sec*1000ULL + ru.ru_stime.tv_usec/1000) }, + { "over-capacity-drops", 0 }, + { "too-old-drops", 0 }, + { "uptime", uptimeOfProcess()}, + { "qa-latency", 1234}, + { "something", Json::array { 1, 2, 3 } }, + }; + + resp.headers["Content-Type"] = "application/json"; + resp.body=my_json.dump(); + } + else if(req.url.path=="/servers/localhost") { + resp.status=200; + + Json::array servers; + auto localServers = g_dstates.getCopy(); + int num=0; + for(const auto& a : localServers) { + string status; + if(a->availability == DownstreamState::Availability::Up) + status = "UP"; + else if(a->availability == DownstreamState::Availability::Down) + status = "DOWN"; + else + status = (a->upStatus ? "up" : "down"); + + Json::object server{ + {"id", num++}, + {"address", a->remote.toStringWithPort()}, + {"state", status}, + {"qps", (int)a->queryLoad}, + {"qpsLimit", (int)a->qps.getRate()}, + {"outstanding", (int)a->outstanding}, + {"weight", (int)a->weight}, + {"order", (int)a->order}, + {"queries", (int)a->queries}}; + + servers.push_back(server); + } + + Json my_json = Json::object { + { "daemon_type", "dnsdist" }, + { "version", "0.1"}, + { "servers", servers} + }; + resp.headers["Content-Type"] = "application/json"; + resp.body=my_json.dump(); + + } + else if(!resp.url.path.empty() && g_urlmap.count(resp.url.path.c_str()+1)) { + resp.body.assign(g_urlmap[resp.url.path.c_str()+1]); + resp.status=200; + } + else if(resp.url.path=="/") { + resp.body.assign(g_urlmap["index.html"]); + resp.status=200; + } + else { + // cerr<<"404 for: "< make_unique(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } +void dnsdistWebserverThread(int sock, const ComboAddress& local, const string& password); diff --git a/pdns/dnsdistconf.lua b/pdns/dnsdistconf.lua index 7fd9c554e5..ea219e138d 100644 --- a/pdns/dnsdistconf.lua +++ b/pdns/dnsdistconf.lua @@ -1,4 +1,5 @@ controlSocket("0.0.0.0") +webserver("0.0.0.0:8083", "geheim2") addLocal("0.0.0.0:5200") setKey("MXNeLFWHUe4363BBKrY06cAsH8NWNb+Se2eXU5+Bb74=") @@ -57,8 +58,8 @@ end newServer{address="2001:888:2000:1d::2", pool={"auth", "dnssec"}} newServer{address="2a01:4f8:110:4389::2", pool={"auth", "dnssec"}} -setDNSSECPool("dnssec") -topRule() +--setDNSSECPool("dnssec") +--topRule() function splitSetup(servers, remote, qname, qtype, dh) if(dh:getRD() == false) diff --git a/pdns/dnsdistdist/Makefile.am b/pdns/dnsdistdist/Makefile.am index b0e6536f68..c00c275cf0 100644 --- a/pdns/dnsdistdist/Makefile.am +++ b/pdns/dnsdistdist/Makefile.am @@ -1,8 +1,12 @@ -AM_CPPFLAGS = -I pdns $(LUA_CFLAGS) -O3 -Wall -pthread +AM_CPPFLAGS = -I pdns $(LUA_CFLAGS) $(YAHTTP_CFLAGS) -O3 -Wall -pthread + +SUBDIRS=pdns/ext/yahttp dnslabeltext.cc: dnslabeltext.rl ragel $< -o dnslabeltext.cc +htmlfiles.h: html/* + ./incfiles > $@ EXTRA_DIST=dnslabeltext.rl dnsdistconf.lua README.md @@ -12,6 +16,7 @@ dnsdist_SOURCES = \ dns.hh \ dnsdist.cc dnsdist.hh \ dnsdist-lua.cc \ + dnsdist-web.cc \ dnslabeltext.cc \ dnsname.cc dnsname.hh \ dnsparser.hh \ @@ -25,13 +30,14 @@ dnsdist_SOURCES = \ qtype.cc qtype.hh \ sholder.hh \ sodcrypto.cc sodcrypto.hh \ - sstuff.hh pdns/ext/luawrapper/include/LuaContext.hpp + sstuff.hh pdns/ext/luawrapper/include/LuaContext.hpp \ + pdns/ext/json11/json11.cpp dnsdist_LDFLAGS = \ $(AM_LDFLAGS) \ - -pthread + -pthread dnsdist_LDADD = \ -lreadline -lrt -ltermcap \ - $(LUA_LIBS) ${libsodium_LIBS} + $(LUA_LIBS) $(YAHTTP_LIBS) ${libsodium_LIBS} diff --git a/pdns/dnsdistdist/configure.ac b/pdns/dnsdistdist/configure.ac index a891cd5195..958813effb 100644 --- a/pdns/dnsdistdist/configure.ac +++ b/pdns/dnsdistdist/configure.ac @@ -1,5 +1,5 @@ AC_INIT([dnsdist], [0.1]) -AM_INIT_AUTOMAKE([foreign dist-bzip2 parallel-tests 1.11]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 parallel-tests 1.11 subdir-objects]) AM_SILENT_RULES([yes]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([config.h]) @@ -9,10 +9,14 @@ PKG_CHECK_MODULES([libsodium], [libsodium], [AC_DEFINE([HAVE_LIBSODIUM], [1], [D AC_PROG_LIBTOOL BOOST_REQUIRE([1.35]) BOOST_FOREACH - +AC_SUBST([YAHTTP_CFLAGS], ['-I$(top_srcdir)/pdns/ext/yahttp']) +AC_SUBST([YAHTTP_LIBS], ['-L$(top_builddir)/pdns/ext/yahttp/yahttp -lyahttp']) PDNS_WITH_LUA AX_CXX_COMPILE_STDCXX_11(ext,mandatory) AM_CONDITIONAL([CXX2011],[test "$HAVE_CXX11" = "1"]) - -AC_OUTPUT([Makefile]) +AC_CONFIG_FILES([Makefile + pdns/ext/yahttp/Makefile + pdns/ext/yahttp/yahttp/Makefile]) + +AC_OUTPUT diff --git a/pdns/dnsdistdist/incfiles b/pdns/dnsdistdist/incfiles new file mode 100755 index 0000000000..b730f12622 --- /dev/null +++ b/pdns/dnsdistdist/incfiles @@ -0,0 +1,21 @@ +#!/bin/bash + +if [ -n "$1" ] +then + DIR=$1/ +fi + +for a in $(find ${DIR}html -type f | grep -v \~) +do + c=$(echo $a | sed s:${DIR}html/:: | tr "/.-" "___") + echo "INCBIN(${c}, \"$a\");" +done + +echo "map g_urlmap={" +for a in $(find ${DIR}html -type f | grep -v \~) +do + b=$(echo $a | sed s:${DIR}html/::g) + c=$(echo $b | tr "/.-" "___") + echo "{\"$b\", string((const char*)g${c}Data, g${c}Size)}," +done +echo "};" diff --git a/pdns/dnsdistdist/populate b/pdns/dnsdistdist/populate index 1c45815c9d..17cf3f2a01 100755 --- a/pdns/dnsdistdist/populate +++ b/pdns/dnsdistdist/populate @@ -3,11 +3,20 @@ ln -fs ../base32.hh ../base64.hh ../dnsdist.cc ../dnsdist.hh ../dnsdist-lua.cc ../dns.hh \ ../dnslabeltext.rl ../dnsname.cc ../dnsname.hh ../dnsparser.hh ../dnsrulactions.hh ../dnswriter.cc ../dnswriter.hh \ ../dolog.hh ../iputils.cc ../iputils.hh ../misc.cc ../misc.hh ../namespaces.hh \ -../pdnsexception.hh ../qtype.cc ../qtype.hh ../sholder.hh ../sodcrypto.cc ../sodcrypto.hh ../sstuff.hh . +../pdnsexception.hh ../qtype.cc ../qtype.hh ../sholder.hh ../sodcrypto.cc ../sodcrypto.hh \ +../dnsdist-web.cc ../sstuff.hh . ln -fs ../README-dnsdist.md README.md ln -fs ../dnsdistconf.lua . mkdir -p pdns/ext/luawrapper/include +mkdir -p pdns/ext/yahttp/yahttp +mkdir -p pdns/ext/json11 ln -sf ../../../../../ext/luawrapper/include/LuaContext.hpp pdns/ext/luawrapper/include +ln -sf ../../../../ext/yahttp/Makefile.am pdns/ext/yahttp +ln -sf ../../../../ext/json11/json11.{hpp,cpp} pdns/ext/json11 +cd pdns/ext/yahttp/yahttp +ln -sf ../../../../../ext/yahttp/yahttp/{Makefile.am,*.cpp,*.hpp,*.h} . +cd - +