* *NEW* dnsblacklist to make "hosts" style block lists * *NEW* domblacklist to make dnsmasq resolve entries to block entire domains regardless of host or subdomain. * Several fixes * Refactor CLI apps for more code re-use. * More helpful error messages. * Add whole (aka wildcard) domain block handling.master
@@ -0,0 +1,113 @@ | |||||
////////////////////////////////////////////////////////////////////// | |||||
// Base CLI app classes for TrafficMon tools | |||||
// Written by Jonathan A. Foster <jon@jfpossibilities.com> | |||||
// Started December 29th, 2021 | |||||
// Copyright JF Possibilities, Inc. All rights reserved. | |||||
////////////////////////////////////////////////////////////////////// | |||||
#include <stdexcept> | |||||
#include <iostream> | |||||
#include <libgen.h> | |||||
#include "appbase.h" | |||||
////////////////////////////////////////////////////////////////////// | |||||
// TrafficMonBaseApp | |||||
////////////////////////////////////////////////////////////////////// | |||||
cBaseApp &TrafficMonBaseApp::init(int argc, char **argv) { | |||||
if(!config) config = new MonitorBaseConf; | |||||
return cBaseApp::init(argc, argv); | |||||
} | |||||
unsigned TrafficMonBaseApp::do_switch(const char *arg) { | |||||
if(!arg[1] && *arg=='c') return 1; | |||||
return cBaseApp::do_switch(arg); | |||||
} | |||||
void TrafficMonBaseApp::do_switch_arg(const char *sw, const std::string &val) { | |||||
if(!sw[1] && *sw=='c') config->load(val); | |||||
} | |||||
int TrafficMonBaseApp::main() { | |||||
int x; | |||||
try { | |||||
if(x=cBaseApp::main()) return x; // Parse CLI args | |||||
if(!config->traffic_mon.vals.size()) throw CLIerror( | |||||
"You need to load a config file with a [Traffic Mon] section" | |||||
); | |||||
} catch(const CLIerror &e) { | |||||
std::cerr << e.what() << "\n\n"; | |||||
return help(); | |||||
} | |||||
db.open("mysql:user="+qesc(config->traffic_mon.get("db user"))+ | |||||
";password="+qesc(config->traffic_mon.get("db password"))+ | |||||
";host="+qesc(config->traffic_mon.get("db host"))+ | |||||
";database="+qesc(config->traffic_mon.get("db name"))+ | |||||
";@opt_reconnect=1"); | |||||
return 0; | |||||
} | |||||
TrafficMonBaseApp::~TrafficMonBaseApp() { | |||||
if(config) delete(config); | |||||
} | |||||
////////////////////////////////////////////////////////////////////// | |||||
// BlackListBaseApp | |||||
////////////////////////////////////////////////////////////////////// | |||||
int BlackListBaseApp::help() { | |||||
std::cerr << " FORMAT: " << basename(command_args[0]) << " -c {config} [-4 {address}] [-6 {address}]\n" | |||||
<< '\n' | |||||
<< "The config file must have a [Traffic Mon] section with the database\n" | |||||
<< "credentials in it. -4 & -6 set the addresses to pin blocked names to.\n" | |||||
<< "They default to the 'localhost' address in the respective family. Set\n" | |||||
<< "to '' to turn off output of that family." << std::endl; | |||||
return ExitCode = 1; | |||||
} | |||||
unsigned BlackListBaseApp::do_switch(const char *arg) { | |||||
if(!arg[1] && (*arg=='4' || *arg=='6')) return 1; | |||||
return TrafficMonBaseApp::do_switch(arg); | |||||
} | |||||
void BlackListBaseApp::do_switch_arg(const char *sw, const std::string &val) { | |||||
if(!sw[1]) switch(*sw) { | |||||
case '4': ipv4 = val; return; | |||||
case '6': ipv6 = val; return; | |||||
} | |||||
TrafficMonBaseApp::do_switch_arg(sw, val); | |||||
} | |||||
void BlackListBaseApp::do_arg(const char *arg) { | |||||
throw CLIerror("Invalid arguments"); | |||||
} | |||||
int BlackListBaseApp::main() { | |||||
int x; | |||||
if(x=TrafficMonBaseApp::main()) return x; // Parse CLI args, open conf & db | |||||
if(ipv4=="" && ipv6=="") { | |||||
std::cerr << "All address families turned off. Nothing to do." << std::endl; | |||||
return 1; | |||||
} | |||||
return 0; | |||||
} |
@@ -0,0 +1,85 @@ | |||||
////////////////////////////////////////////////////////////////////// | |||||
// Base CLI app classes for TrafficMon tools | |||||
// Written by Jonathan A. Foster <jon@jfpossibilities.com> | |||||
// Started December 29th, 2021 | |||||
// Copyright JF Possibilities, Inc. All rights reserved. | |||||
// | |||||
// | |||||
////////////////////////////////////////////////////////////////////// | |||||
// NOTE: since GNU doesn't discard unused classes these two classes should | |||||
// probably get put in separate sets of files. :-/ | |||||
#ifndef __IDS_MONITOR_BASE_APP_H__ | |||||
#define __IDS_MONITOR_BASE_APP_H__ | |||||
#include <cppdb/frontend.h> | |||||
#include "../cli.h" | |||||
#include "../miniini.h" | |||||
////////////////////////////////////////////////////////////////////// | |||||
// The core configuration file | |||||
// | |||||
// This is designed so that all parts can use the same config. Tools | |||||
// ignore the parts they aren't interested in. | |||||
////////////////////////////////////////////////////////////////////// | |||||
struct MonitorBaseConf: public MiniINI { | |||||
MiniINIvars traffic_mon; // This app's config variables | |||||
MonitorBaseConf() { groups["Traffic Mon"] = &traffic_mon; } | |||||
}; | |||||
////////////////////////////////////////////////////////////////////// | |||||
// The base CLI application class used by the tools in this directory. | |||||
// | |||||
// Essentially this is a CLI app with a DB connection and a place | |||||
// holder for a config file. | |||||
////////////////////////////////////////////////////////////////////// | |||||
struct TrafficMonBaseApp: public cBaseApp { | |||||
cppdb::session db; | |||||
MonitorBaseConf *config; | |||||
// this init() will create a MonitorBaseConf if a config hasn't been assigned. | |||||
virtual cBaseApp &init(int argc, char **argv); | |||||
// process config file switch and load the file | |||||
virtual unsigned do_switch(const char *arg); | |||||
virtual void do_switch_arg(const char *sw, const std::string &val); | |||||
// process CLI args, test for [traffic mon] and connect to DB. | |||||
virtual int main(); | |||||
// close out and free config object. | |||||
virtual ~TrafficMonBaseApp(); | |||||
}; | |||||
////////////////////////////////////////////////////////////////////// | |||||
// Blacklist report base class | |||||
// | |||||
// This provides generic switch handling | |||||
////////////////////////////////////////////////////////////////////// | |||||
struct BlackListBaseApp: public TrafficMonBaseApp { | |||||
std::string ipv4, ipv6; | |||||
BlackListBaseApp(): | |||||
ipv4("127.0.0.1"), | |||||
ipv6("::1") | |||||
{} | |||||
// Display generic CLI help text | |||||
virtual int help(); | |||||
// process -4 & -6 switches. | |||||
virtual unsigned do_switch(const char *sw); | |||||
virtual void do_switch_arg(const char *sw, const std::string &val); | |||||
virtual void do_arg(const char *arg); | |||||
virtual int main(); | |||||
}; | |||||
#endif |
@@ -20,11 +20,9 @@ | |||||
#include <iostream> | #include <iostream> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <libgen.h> | #include <libgen.h> | ||||
#include <cppdb/frontend.h> | |||||
#include "../strutil.h" | #include "../strutil.h" | ||||
#include "../cli.h" | |||||
#include "../miniini.h" | |||||
#include "appbase.h" | |||||
using namespace std; | using namespace std; | ||||
@@ -132,36 +130,19 @@ namespace cppdb { | |||||
} | } | ||||
////////////////////////////////////////////////////////////////////// | |||||
// Our config file. | |||||
// | |||||
// This is designed so that all parts can use the same config. Tools | |||||
// ignore the parts they aren't interested in. | |||||
////////////////////////////////////////////////////////////////////// | |||||
/* TODO: refactor this as a base class... */ | |||||
struct ReportConf: public MiniINI { | |||||
MiniINIvars traffic_mon; // This app's config variables | |||||
ReportConf() { groups["Traffic Mon"] = &traffic_mon; } | |||||
}; | |||||
////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////// | ||||
// Connection Report Generator Application Class | // Connection Report Generator Application Class | ||||
////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////// | ||||
struct appConnectionReport: cBaseApp { | |||||
ReportConf config; | |||||
ReportData rpt; | |||||
cppdb::session db; | |||||
string start_stamp; | |||||
string end_stamp; | |||||
int cli_mode; // which non-switch are we processing | |||||
struct appConnectionReport: TrafficMonBaseApp { | |||||
ReportData rpt; | |||||
string start_stamp; | |||||
string end_stamp; | |||||
int cli_mode; // which non-switch are we processing | |||||
appConnectionReport(): cli_mode(0) {} | |||||
appConnectionReport(): cli_mode(0) { } | |||||
@@ -171,21 +152,7 @@ struct appConnectionReport: cBaseApp { | |||||
<< "The config file must have a [Traffic Mon] section with the database\n" | << "The config file must have a [Traffic Mon] section with the database\n" | ||||
<< "credentials in it. 'start' and 'stop' are the SQL timestamps for\n" | << "credentials in it. 'start' and 'stop' are the SQL timestamps for\n" | ||||
<< "report time span." << endl; | << "report time span." << endl; | ||||
} | |||||
virtual unsigned do_switch(const char *arg) { | |||||
if(*arg=='c' && !arg[1]) return 1; | |||||
throw CLIerror("Invalid switch "+string(arg)); | |||||
} | |||||
virtual void do_switch_arg(const char *sw, const std::string &val) { | |||||
// The only way we get here is with -c | |||||
config.load(val); | |||||
// TODO: config validity checks | |||||
return 1; | |||||
} | } | ||||
@@ -197,30 +164,22 @@ struct appConnectionReport: cBaseApp { | |||||
default: throw CLIerror("Invalid arguments"); | default: throw CLIerror("Invalid arguments"); | ||||
} | } | ||||
} | } | ||||
int main() { | int main() { | ||||
cppdb::result qry; | cppdb::result qry; | ||||
int x; | |||||
/// SETUP & VALIDATE CLI /// | /// SETUP & VALIDATE CLI /// | ||||
try { | try { | ||||
cBaseApp::main(); // Parse CLI args | |||||
if(!config.traffic_mon.vals.size()) throw CLIerror( | |||||
"You need to load a config file with a [Traffic Mon] section" | |||||
); | |||||
if(x = TrafficMonBaseApp::main()) return x; // Parse CLI args | |||||
if(cli_mode!=2) throw CLIerror("Invlaid arguments"); | if(cli_mode!=2) throw CLIerror("Invlaid arguments"); | ||||
} catch(const CLIerror &e) { | } catch(const CLIerror &e) { | ||||
cerr << e.what() << "\n\n"; | cerr << e.what() << "\n\n"; | ||||
return help(); | return help(); | ||||
} | } | ||||
db.open("mysql:user="+qesc(config.traffic_mon.get("db user"))+ | |||||
";password="+qesc(config.traffic_mon.get("db password"))+ | |||||
";host="+qesc(config.traffic_mon.get("db host"))+ | |||||
";database="+qesc(config.traffic_mon.get("db name"))+ | |||||
";@opt_reconnect=1"); | |||||
/// Query & load data /// | /// Query & load data /// | ||||
qry = db << | qry = db << | ||||
@@ -2,6 +2,7 @@ | |||||
# defaults. | # defaults. | ||||
# Configuration file for the TrafficMon server | # Configuration file for the TrafficMon server | ||||
# NOTE: service won't start until this is set | |||||
#CONF=/etc/poorman-ids/sample.conf | #CONF=/etc/poorman-ids/sample.conf | ||||
# Where "run" files are placed. This is the Debian+ default: | # Where "run" files are placed. This is the Debian+ default: | ||||
#RUN=/run | #RUN=/run | ||||
@@ -0,0 +1,139 @@ | |||||
////////////////////////////////////////////////////////////////////// | |||||
// Dump Black Listed DNS entries | |||||
// Written by Jonathan A. Foster <jon@jfpossibilities.com> | |||||
// Started Ocotber 27th, 2021 | |||||
// Copyright JF Possibilities, Inc. All rights reserved. | |||||
// | |||||
// Read the "dns" table and dump all black listed host names as | |||||
// entries for a "hosts" file. This could also be easily done with a | |||||
// script but I want to be able to use the same config file as every- | |||||
// thing else and parsing in SH is clumsy at best. | |||||
////////////////////////////////////////////////////////////////////// | |||||
#include <string> | |||||
#include <map> | |||||
#include <iostream> | |||||
#include <stdio.h> | |||||
#include <libgen.h> | |||||
#include "../strutil.h" | |||||
#include "appbase.h" | |||||
using namespace std; | |||||
////////////////////////////////////////////////////////////////////// | |||||
// Class to manage and test hoset names agains bad domains | |||||
////////////////////////////////////////////////////////////////////// | |||||
struct DomainList: public StringList { | |||||
bool operator==(const std::string host) { | |||||
DomainList::const_iterator i; | |||||
int dl, hl = host.size(); | |||||
for(i=begin(); i!=end(); i++) { | |||||
if(*i==host) return true; | |||||
dl = i->size()+1; | |||||
if(hl>dl && host.substr(hl-dl)=="."+*i) return true; | |||||
} | |||||
return false; | |||||
} | |||||
inline bool operator!=(const std::string host) { return !(*this==host); } | |||||
}; | |||||
namespace cppdb { | |||||
session &operator>>(cppdb::session &db, DomainList &doms) { | |||||
cppdb::result qry; | |||||
std::string s; | |||||
doms.clear(); | |||||
qry = db << "SELECT name FROM dns_wild WHERE status=2"; | |||||
while(qry.next()) { | |||||
qry >> s; | |||||
doms.push_back(s); | |||||
} | |||||
return db; | |||||
} | |||||
} // cppdb | |||||
////////////////////////////////////////////////////////////////////// | |||||
// Connection Report Generator Application Class | |||||
////////////////////////////////////////////////////////////////////// | |||||
struct DNSblackList: BlackListBaseApp { | |||||
bool all; | |||||
unsigned do_switch(const char *arg) { | |||||
if(*arg=='a' && !arg[1]) { all=1; return 0; } | |||||
return BlackListBaseApp::do_switch(arg); | |||||
} | |||||
int help() { | |||||
std::cerr << " FORMAT: " << basename(command_args[0]) << " -c {config} [-a] [-4 {address}] [-6 {address}]\n" | |||||
<< '\n' | |||||
<< "The config file must have a [Traffic Mon] section with the database\n" | |||||
<< "credentials in it. -4 & -6 set the addresses to pin blocked names to.\n" | |||||
<< "They default to the 'localhost' address in the respective family. Set\n" | |||||
<< "to '' to turn off output of that family. -a dumps all blocked host\n" | |||||
<< "names otherwise host names that are covered by a domain block will\n" | |||||
<< "not be shown." << std::endl; | |||||
return ExitCode = 1; | |||||
} | |||||
int main() { | |||||
DomainList baddoms; | |||||
cppdb::result qry; | |||||
string s; | |||||
int x; | |||||
/// SETUP & VALIDATE CLI /// | |||||
all = false; | |||||
if(x=BlackListBaseApp::main()) return x; // Parse CLI args, open conf & db | |||||
if(ipv6!="" && ipv6.size()<8) ipv6+='\t'; // an extra \t to line up columns. :-) | |||||
/// Load list of bad domains /// | |||||
// These should be excluded from the list below since they should be | |||||
// blocked by other means and the point of domain wide blocking is to | |||||
// relieve the burden on the blocking tools (dnsmasq). | |||||
if(!all) db >> baddoms; | |||||
/// Query & load data /// | |||||
qry = db << | |||||
"SELECT name " | |||||
"FROM dns " | |||||
"WHERE status=2 " // 2 = blocked... need this doc'd somewhere... | |||||
"ORDER BY name"; | |||||
while(qry.next()) { | |||||
qry >> s; | |||||
if(all || baddoms!=s) { // exclude blocked domains | |||||
if(ipv4!="") cout << ipv4 << '\t' << s << '\n'; | |||||
if(ipv6!="") cout << ipv6 << '\t' << s << '\n'; | |||||
} | |||||
} | |||||
return 0; | |||||
} | |||||
}; | |||||
////////////////////////////////////////////////////////////////////// | |||||
// Lets run the report and dump it out | |||||
////////////////////////////////////////////////////////////////////// | |||||
MAIN(DNSblackList) |
@@ -0,0 +1,61 @@ | |||||
////////////////////////////////////////////////////////////////////// | |||||
// Dump Black Listed whole domain (*.domain.tld) entries | |||||
// Written by Jonathan A. Foster <jon@jfpossibilities.com> | |||||
// Started December 28th, 2021 | |||||
// Copyright JF Possibilities, Inc. All rights reserved. | |||||
// | |||||
// Read the "dns_wild" table and dump all black listed domain names as | |||||
// "address" entries for a dnsmasq.conf file. This will black list the | |||||
// whole domain, subdomains, hosts and all. | |||||
////////////////////////////////////////////////////////////////////// | |||||
#include <string> | |||||
#include <map> | |||||
#include <iostream> | |||||
#include <stdio.h> | |||||
#include <libgen.h> | |||||
#include "../strutil.h" | |||||
#include "appbase.h" | |||||
using namespace std; | |||||
////////////////////////////////////////////////////////////////////// | |||||
// Connection Report Generator Application Class | |||||
////////////////////////////////////////////////////////////////////// | |||||
struct DomainBlackList: BlackListBaseApp { | |||||
int main() { | |||||
cppdb::result qry; | |||||
string s; | |||||
int x; | |||||
/// SETUP & VALIDATE CLI /// | |||||
if(x=BlackListBaseApp::main()) return x; // Parse CLI args, open conf & db | |||||
/// Query & load data /// | |||||
qry = db << | |||||
"SELECT name " | |||||
"FROM dns_wild " | |||||
"WHERE status=2 " // 2 = blocked... need this doc'd somewhere... | |||||
"ORDER BY name"; | |||||
while(qry.next()) { | |||||
qry >> s; | |||||
if(ipv4!="") cout << "address=/" << s << '/' << ipv4 << '\n'; | |||||
if(ipv6!="") cout << "address=/" << s << '/' << ipv6 << '\n'; | |||||
} | |||||
return 0; | |||||
} | |||||
}; | |||||
////////////////////////////////////////////////////////////////////// | |||||
// Lets run the report and dump it out | |||||
////////////////////////////////////////////////////////////////////// | |||||
MAIN(DomainBlackList) |
@@ -21,7 +21,7 @@ | |||||
NAME="trafficmon" | NAME="trafficmon" | ||||
DAEMON="/usr/sbin/$NAME" | DAEMON="/usr/sbin/$NAME" | ||||
RUN=/run | RUN=/run | ||||
CONF=/etc/poorman-ids/sample.conf | |||||
CONF="" | |||||
SOCK="" | SOCK="" | ||||
# Pull in config | # Pull in config | ||||
@@ -52,11 +52,16 @@ CTRL() { | |||||
do_start() { | do_start() { | ||||
echo -n "Starting Traffic Monitor: " | echo -n "Starting Traffic Monitor: " | ||||
if [ -z "$CONF" ]; then | |||||
echo "NOT CONFIGURED" | |||||
return 0 | |||||
fi | |||||
if CTRL --start --oknodo -- -c "$CONF" -b -i "$PID" -p "$SOCK"; then | if CTRL --start --oknodo -- -c "$CONF" -b -i "$PID" -p "$SOCK"; then | ||||
echo "OK" | echo "OK" | ||||
return 0 #JIC | |||||
else | else | ||||
echo "FAIL" | echo "FAIL" | ||||
exit 1 | |||||
return 1 | |||||
fi | fi | ||||
} | } | ||||
@@ -66,9 +71,10 @@ do_stop() { | |||||
echo -n "Stoping Traffic Monitor: " | echo -n "Stoping Traffic Monitor: " | ||||
if CTRL --stop --remove-pidfile; then | if CTRL --stop --remove-pidfile; then | ||||
echo "OK" | echo "OK" | ||||
return 0 #JIC | |||||
else | else | ||||
echo "FAIL" | echo "FAIL" | ||||
exit 1 | |||||
return 1 | |||||
fi | fi | ||||
} | } | ||||
@@ -78,36 +84,37 @@ do_status() { | |||||
echo -n "Traffic Monitor is: " | echo -n "Traffic Monitor is: " | ||||
if CTRL --status; then | if CTRL --status; then | ||||
echo "Up" | echo "Up" | ||||
return 0 #JIC | |||||
else | else | ||||
echo "Down" | echo "Down" | ||||
exit 1 | |||||
return 1 | |||||
fi | fi | ||||
} | } | ||||
### Main() | |||||
### Main() | |||||
case "$1" in | case "$1" in | ||||
start) | start) | ||||
do_start | do_start | ||||
;; | ;; | ||||
stop) | stop) | ||||
do_stop | do_stop | ||||
;; | ;; | ||||
restart) | restart) | ||||
do_status && do_stop | do_status && do_stop | ||||
do_start | do_start | ||||
;; | ;; | ||||
status) | status) | ||||
do_status | do_status | ||||
;; | ;; | ||||
*) | *) | ||||
echo "$0 {start | stop | restart | status}" | echo "$0 {start | stop | restart | status}" | ||||
;; | ;; | ||||
esac | |||||
esac |
@@ -22,12 +22,11 @@ | |||||
#include <stdexcept> | #include <stdexcept> | ||||
#include <vector> | #include <vector> | ||||
#include <map> | #include <map> | ||||
#include <cppdb/frontend.h> | |||||
#include "../cli.h" | #include "../cli.h" | ||||
#include "../data.h" | #include "../data.h" | ||||
#include "../miniini.h" | |||||
#include "../config.h" | #include "../config.h" | ||||
#include "appbase.h" | |||||
using namespace std; | using namespace std; | ||||
@@ -36,11 +35,10 @@ using namespace std; | |||||
// Monitor Config | // Monitor Config | ||||
////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////// | ||||
struct MonitorConf: public MiniINI { | |||||
MiniINIvars traffic_mon; // This app's config variables | |||||
struct MonitorConf: public MonitorBaseConf { | |||||
INIusList us; | INIusList us; | ||||
MonitorConf() { groups["Traffic Mon"] = &traffic_mon; groups["us"] = &us; } | |||||
MonitorConf() { groups["us"] = &us; } | |||||
}; | }; | ||||
@@ -51,11 +49,9 @@ struct MonitorConf: public MiniINI { | |||||
////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////// | ||||
//#define DEBUG | //#define DEBUG | ||||
struct TrafficMon: public cBaseApp { | |||||
MonitorConf config; | |||||
struct TrafficMon: public TrafficMonBaseApp { | |||||
LogAnalyzer analyze; | LogAnalyzer analyze; | ||||
istream *log; | istream *log; | ||||
cppdb::session db; | |||||
LiveBug bug; | LiveBug bug; | ||||
bool setup_db; | bool setup_db; | ||||
bool piping; // are we sucking on a pipe? | bool piping; // are we sucking on a pipe? | ||||
@@ -76,13 +72,14 @@ struct TrafficMon: public cBaseApp { | |||||
running( false), | running( false), | ||||
line_no( 0) | line_no( 0) | ||||
{ | { | ||||
analyze.us = &(config.us.vals); | |||||
config = new MonitorConf; | |||||
analyze.us = &(((MonitorConf *)config)->us.vals); | |||||
} | } | ||||
void help() { | |||||
cerr << | |||||
int help() { | |||||
cerr << | |||||
"\n" | "\n" | ||||
"trafficmon -c {config file} [-i] [-d] [-b] [-p {pipe name} | [{log name} ...]]\n" | "trafficmon -c {config file} [-i] [-d] [-b] [-p {pipe name} | [{log name} ...]]\n" | ||||
"\n" | "\n" | ||||
@@ -96,7 +93,7 @@ struct TrafficMon: public cBaseApp { | |||||
"Other arguments are log files to be processed. This can be used to bulk\n" | "Other arguments are log files to be processed. This can be used to bulk\n" | ||||
"load data prior to going live with an always on daemon or for catching\n" | "load data prior to going live with an always on daemon or for catching\n" | ||||
"up if the daemon stopped for some reason."; | "up if the daemon stopped for some reason."; | ||||
ExitCode = 1; | |||||
return ExitCode = 1; | |||||
} | } | ||||
@@ -105,13 +102,12 @@ struct TrafficMon: public cBaseApp { | |||||
if(sw[1]==0) { | if(sw[1]==0) { | ||||
switch(*sw) { | switch(*sw) { | ||||
case 'b': background_me = true; return 0; | case 'b': background_me = true; return 0; | ||||
case 'c': return 1; | |||||
case 'd': setup_db = true; return 0; | case 'd': setup_db = true; return 0; | ||||
case 'i': return 1; | case 'i': return 1; | ||||
case 'p': piping = true; return !running; // second pass treats it as a file | case 'p': piping = true; return !running; // second pass treats it as a file | ||||
} | } | ||||
} | } | ||||
throw CLIerror("Unrecognized Switch"); | |||||
return TrafficMonBaseApp::do_switch(sw); | |||||
} | } | ||||
@@ -120,40 +116,16 @@ struct TrafficMon: public cBaseApp { | |||||
// If "running" is set then we've already done this. So skip it! | // If "running" is set then we've already done this. So skip it! | ||||
if(running) return; | if(running) return; | ||||
switch(*sw) { | |||||
if(sw[1]==0) switch(*sw) { | |||||
/// Load config file /// | |||||
case 'c': | |||||
// This is only called with "c". See above | |||||
config.load(val); | |||||
if(!config.us.vals.size()) throw CLIerror( | |||||
"The configuration files MUST contain an [us] section with " | |||||
"appropriate values" | |||||
); | |||||
if(!config.traffic_mon.vals.size()) throw CLIerror( | |||||
"The configuration files MUST contain an [Traffic Mon] section with " | |||||
"appropriate values" | |||||
); | |||||
/// configure resources from config file /// | |||||
// TODO: pre-validate some of these? | |||||
db.open("mysql:user="+qesc(config.traffic_mon.get("db user"))+ | |||||
";password="+qesc(config.traffic_mon.get("db password"))+ | |||||
";host="+qesc(config.traffic_mon.get("db host"))+ | |||||
";database="+qesc(config.traffic_mon.get("db name"))+ | |||||
";@opt_reconnect=1"); | |||||
return; | |||||
/// PID file to write ID in if we're daemonizing /// | /// PID file to write ID in if we're daemonizing /// | ||||
case 'i': | case 'i': | ||||
pid_file = val; | pid_file = val; | ||||
return; | return; | ||||
/// Make pipe if requested /// | /// Make pipe if requested /// | ||||
case 'p': | case 'p': | ||||
// This can't wait for "running" since we want it to fail in foreground | // This can't wait for "running" since we want it to fail in foreground | ||||
// Make read/write by process owner (root) only | // Make read/write by process owner (root) only | ||||
@@ -163,6 +135,8 @@ struct TrafficMon: public cBaseApp { | |||||
} | } | ||||
inp_ct++; | inp_ct++; | ||||
} | } | ||||
TrafficMonBaseApp::do_switch_arg(sw, val); | |||||
} | } | ||||
@@ -200,7 +174,8 @@ restart: | |||||
// probably should daemonize around here. | // probably should daemonize around here. | ||||
int run() { | int run() { | ||||
string l; | string l; | ||||
cppdb::statement db_add = db << // prepare insert statement | |||||
// prepare insert statement | |||||
cppdb::statement db_add = db << | |||||
"INSERT INTO connections " | "INSERT INTO connections " | ||||
"(us, us_port, them, them_port, them_name, protocol, inbound) " | "(us, us_port, them, them_port, them_name, protocol, inbound) " | ||||
"VALUES (?,?,?,?,?,?,?)"; | "VALUES (?,?,?,?,?,?,?)"; | ||||
@@ -262,20 +237,42 @@ restart: | |||||
db << "CREATE TABLE dns (" | db << "CREATE TABLE dns (" | ||||
"name CHAR(128) NOT NULL PRIMARY KEY," | "name CHAR(128) NOT NULL PRIMARY KEY," | ||||
"decided TIMESTAMP NOT NULL," | "decided TIMESTAMP NOT NULL," | ||||
"status TINYINT(1) NOT NULL DEFAULT 0" | |||||
"status TINYINT(1) NOT NULL DEFAULT 0," | |||||
"note CHAR(128) NOT NULL DEFAULT ''" | |||||
") Engine=MyISAM" | |||||
<< cppdb::exec; | |||||
/// wild card DNS list /// | |||||
// NOTE: All of these names are treated as if prefixed with "*.". At this | |||||
// time there are only plans to implement this as a black list. | |||||
// Many domains are sevices with threat potential and discovering | |||||
// all of the host and subdomains may not be viable. Think ad and | |||||
// tracking services. | |||||
db << "CREATE TABLE dns_wild (" | |||||
"name CHAR(128) NOT NULL PRIMARY KEY," | |||||
"decided TIMESTAMP NOT NULL," | |||||
"status TINYINT(1) NOT NULL DEFAULT 2," | |||||
"note CHAR(128) NOT NULL DEFAULT ''" | |||||
") Engine=MyISAM" | ") Engine=MyISAM" | ||||
<< cppdb::exec; | << cppdb::exec; | ||||
} | } | ||||
int main() { | int main() { | ||||
int x; | |||||
try { | try { | ||||
cBaseApp::main(); | |||||
if(!config.us.vals.size()) | |||||
// Since -c requires something in [us] we'll only get here if a config | |||||
// wasn't loaded. | |||||
throw CLIerror("You must specify a config file to load"); | |||||
if(x=TrafficMonBaseApp::main()) return x; | |||||
if(!((MonitorConf*)config)->us.vals.size()) throw CLIerror( | |||||
"The configuration files MUST contain an [us] section with " | |||||
"appropriate values" | |||||
); | |||||
if(!config->traffic_mon.vals.size()) throw CLIerror( | |||||
"The configuration files MUST contain an [Traffic Mon] section with " | |||||
"appropriate values" | |||||
); | |||||
if(piping && inp_ct!=1) throw CLIerror( | if(piping && inp_ct!=1) throw CLIerror( | ||||
"Pipe requires one and only one file name to read from." | "Pipe requires one and only one file name to read from." | ||||
); | ); | ||||
@@ -304,6 +301,8 @@ restart: | |||||
try { | try { | ||||
// CLI processed now lets analyze data. | // CLI processed now lets analyze data. | ||||
running = true; | running = true; | ||||
// TODO: this is going to break things? Probably should prevent reloading conf. DB is opened in TrafficMonBaseApp::main() | |||||
// Actually I think it may actualy work... | |||||
cBaseApp::main(); // re-run CLI args for inputs | cBaseApp::main(); // re-run CLI args for inputs | ||||
if(!log) { | if(!log) { | ||||
// no inputs spec'd on CLI assume stdin (we're not a daemon) | // no inputs spec'd on CLI assume stdin (we're not a daemon) | ||||
@@ -322,8 +321,6 @@ restart: | |||||
return ExitCode; | return ExitCode; | ||||
} | } | ||||
}; | }; | ||||