]> granicus.if.org Git - pdns/commitdiff
hook up webserver and embedded html (!)
authorbert hubert <bert.hubert@netherlabs.nl>
Sun, 29 Mar 2015 19:07:35 +0000 (21:07 +0200)
committerbert hubert <bert.hubert@netherlabs.nl>
Sun, 29 Mar 2015 19:07:35 +0000 (21:07 +0200)
pdns/Makefile.am
pdns/dnsdist-lua.cc
pdns/dnsdist-web.cc [new file with mode: 0644]
pdns/dnsdist.hh
pdns/dnsdistconf.lua
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/configure.ac
pdns/dnsdistdist/incfiles [new file with mode: 0755]
pdns/dnsdistdist/populate

index 0fbfbacdd3a787a1848e91488121288b279bd69f..ea87e050a60bf4120835cd71a1fda6c5806f1575 100644 (file)
@@ -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 ';' ) > $@
 
index 2e99c633830278767fd525aa56cea5129b0d3125..b83f6e1db8e6d32bbe32f68aa575a7cc27e139f7 100644 (file)
@@ -409,6 +409,29 @@ vector<std::function<void(void)>> 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 (file)
index 0000000..2d1213a
--- /dev/null
@@ -0,0 +1,187 @@
+#include "dnsdist.hh"
+#include "sstuff.hh"
+#include "ext/json11/json11.hpp"
+#include "ext/incbin/incbin.h"
+#include "dolog.hh"
+#include <thread>
+#include <sstream>
+#include <yahttp/yahttp.hpp>
+#include "namespaces.hh"
+#include <sys/time.h>
+#include <sys/resource.h>
+#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<string> 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="<h1>Unauthorized</h1>";
+    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: "<<resp.url.path<<endl;
+    resp.status=404;
+  }
+
+  if(!callback.empty()) {
+    resp.body = callback + "(" + resp.body + ");";
+  }
+
+
+
+  std::ostringstream ofs;
+  ofs << resp;
+  string done;
+  done=ofs.str();
+  writen2(sock, done.c_str(), done.size());
+
+  close(sock);
+}
+
+void dnsdistWebserverThread(int sock, const ComboAddress& local, const std::string& password)
+{
+  infolog("Webserver launched on %s", local.toStringWithPort());
+  for(;;) {
+    try {
+      ComboAddress remote(local);
+      int fd = SAccept(sock, remote);
+      vinfolog("Got connection from %s", remote.toStringWithPort());
+      std::thread t(connectionThread, fd, remote, password);
+      t.detach();
+    }
+    catch(std::exception& e) {
+      errlog("Had an error accepting new webserver connection: %s", e.what());
+    }
+  }
+}
index c84a72e07879f7a9ce6fa5735bc44bca7cabb3ed..3598041c2b883f930a5d40543858ea94c1ce8e54 100644 (file)
@@ -276,3 +276,4 @@ std::unique_ptr<T> make_unique(Args&&... args)
 {
     return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
 }
+void dnsdistWebserverThread(int sock, const ComboAddress& local, const string& password);
index 7fd9c554e58f4282922458cb0462f8d6a2af0d6b..ea219e138dd0c0f99ba80b3a73ff7d4f7d9be667 100644 (file)
@@ -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)
index b0e6536f68c155700773d51293600b69be7e1b30..c00c275cf04a09b14644cb00f947a038fc479d01 100644 (file)
@@ -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}
 
index a891cd5195a16a479e95b825e5d5bbb08580e551..958813effb6b738d28973c9a647b102d3912a8f9 100644 (file)
@@ -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 (executable)
index 0000000..b730f12
--- /dev/null
@@ -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<string,string> 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 "};"
index 1c45815c9db08e11bcb94472ccb10d8b6333b0e0..17cf3f2a013b9b05fce2d52fc3bb099a43e2609d 100755 (executable)
@@ -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 -
+