////////////////////////////////////////////////////////////////////// // Traffic Montor Control HTTP server // Written by Jonathan A. Foster // Started August 13th, 2021 // Copyright JF Possibilities, Inc. All rights reserved. // // Provide a control panel to manage which domains we want to watch, // ignore and block. ////////////////////////////////////////////////////////////////////// // TODO: put the note fields to use (dns,dns_wild) // TODO: Any purpose in wild-card selection "accepted" host names? #include #include #include #include /// C++CMS/DB /// #include #include #include #include #include #include #include #include /// Our app /// #include "../strutil.h" #include "data.h" #include "nametools.h" /// Build flags /// // TODO: better application of C++CMS booster logging //#define DEBUGGIN ////////////////////////////////////////////////////////////////////// // C++CMS App to manage the state of all known domain names. ////////////////////////////////////////////////////////////////////// const std::string filter_titles[] = { "Undecided", "Accepted", "Blocked" }; const std::string actions[] = { "Reset", "Accept", "Block" }; std::string root_uri = ""; struct app: public cppcms::application { std::auto_ptr sql; int items_per_page; std::string numlist(const std::string &field) { std::string r; const cppcms::http::request::form_type &POST = request().post(); for( cppcms::http::request::form_type::const_iterator it = POST.find(field); it!=POST.end() && it->first==field; it++ ) { if(it->second!="") { if(r!="") r+=","; r+="'"+sql->escape(it->second)+"'"; } } return r; } void list(Domain::STATUS sid) { int i; std::string s; DomainList c; cppdb::result r; // TODO: put this someplace else? /// Form processing /// if(request().request_method()=="POST") { c.op = request().post("op"); // nothing to do without a valid "op" if(c.op=="0" || c.op=="1" || c.op=="2") { // eliminate NOP busywork if((s=numlist("id"))!="" && sid!=atoi(c.op.c_str())) { *sql << "UPDATE dns SET status="+c.op+" WHERE name IN ("+s+")" << cppdb::exec; } if(s=="*" || s=="*.") { c.error = "'*' and '*.' are not acceptable."; } else if((s=request().post("domain"))!="") { // wild card handling if(s.substr(0,2)=="*.") { s = s.substr(2); if(c.op=="0") c.error = "Wild cards have no value with \"undecided\"."; else *sql << "INSERT INTO dns_wild (name,status) VALUES (?,?)" << s << c.op << cppdb::exec; } // regardless move all existing matches to the specified status. *sql << "UPDATE dns SET status=? " "WHERE status=? AND (name=? OR name LIKE ?)" << c.op << sid << s << ("%."+s) << cppdb::exec; } } } /// Produce list of names of the desired STATUS /// c.filter = filter_titles[sid]; s = request().get("pg"); if(s=="") c.page = 1; else c.page = atoi(s.c_str()); if(c.page < 1 || c.page > 999999) c.page = 1; r = *sql << "SELECT name, decided, status FROM dns WHERE status=? " "LIMIT "+str((c.page-1)*items_per_page)+","+str(items_per_page) << sid; for(i = c.list.size(); r.next(); i++) { c.list.resize(i+1); r >> c.list[i].name >> c.list[i].decided >> c.list[i].status; } r = *sql << "SELECT count(*) FROM dns WHERE status=?" << sid << cppdb::row; r >> c.count; c.page_size = items_per_page; c.pages = (c.count+items_per_page-1)/items_per_page; render("mainskin", "domain_list", c); } void undecided() { list(Domain::undecided); } void accepted() { list(Domain::accepted ); } void blocked() { list(Domain::blocked ); } app(cppcms::service &s): cppcms::application(s), items_per_page(50) { #ifdef DEBUGGIN std::cerr << "spawning app object" << std::endl; #endif sql.reset(new cppdb::session()); sql->open(settings().get("trafficctrl.db")); mapper().root(root_uri); mapper().assign("blocked", "/blocked"); dispatcher().assign("/blocked/?", &app::blocked, this); mapper().assign("accepted", "/accepted"); dispatcher().assign("/accepted/?", &app::accepted, this); mapper().assign(""); dispatcher().assign("/?", &app::undecided, this); } // logging void main(const std::string url) { #ifdef DEBUGGIN std::cerr << "request: " << url << '\n' << " INFO: " << request().path_info() << '\n' << " SCRIPT: " << request().script_name() << '\n' << std::endl; #endif cppcms::application::main(url); } }; ////////////////////////////////////////////////////////////////////// // main() - Launch C++CMS with my test app on "/" ////////////////////////////////////////////////////////////////////// int main(int argc, char **args) { // create server object cppcms::service srv(argc, args); // Get root URI from configuration file. root_uri = srv.settings().get("trafficctrl.root_uri", ""); // Mount our app in the server srv.applications_pool().mount( cppcms::create_pool(), cppcms::mount_point(root_uri) ); // Serve it! // TODO: log crashes. #ifdef DEBUGGIN std::cerr << "Launching" << std::endl; #endif srv.run(); return 0; }