Source

quechua / modules / channel / dionaeaHarvester / dionaeaHarvester.cc

/* 
 * Quechua - the lightweight data mining framework
 *
 * Copyright (C) 2012 Marek Denis <quechua@octogan.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "dionaeaHarvester.h"


bool exec_query(dbwork_t& w,dbresult_t& r, const char* q, bool commit) {
    

    LOG(DEBUG) << "Trying to execute SQL query: " << q;
    try {
        r = w.exec(q);
        if(commit)
            w.commit();
    } catch(connection_ex& ex) {
        LOG(ERROR) << "DionaeaHarvester, check your database and/or connection";
        return false;
    } catch (undefined_column_ex& ex) {
        LOG(ERROR) << "Missing column? Check your SQL query and/or database\n"
                   << "Query executed: " << q;
        return false;
        
    } catch (commit_ex& ex) {
        LOG(WARN) << "Not sure whether transaction was commited.";
        return false;

    } catch(undef_table_ex& ex) {
        LOG(ERROR) << "Trying to read from non existing table while executing SQL: " 
                   << q;
        return false;
    } catch(sql_ex& ex) {
        LOG(ERROR) << "For SQL: " << q
                   << " an SQL exception was caught, discarding the data";
        return false;
    }
    catch(std::exception& ex) {
        LOG(CRITIC) << "While executing SQL: " << q << " unhandled exception was catched, rethrowing";
        throw ex;
    }

    return true;
}

DionaeaHarvester::DionaeaHarvester(): Channel(), connection(NULL) {
    memset(formated_query,0,QUERY_LIMIT);
};
DionaeaHarvester::~DionaeaHarvester() {
    stop();
};


/**
 * What we need here is:
 * - db hostname
 * - user
 * - pass
 * - database name
 **/
bool DionaeaHarvester::load_misc_conf(const setting_t& misc) {
    string_t raw_interval = "1D";
    try {
        misc.lookupValue("user",credentials.user);
        misc.lookupValue("password",credentials.password);
        misc.lookupValue("hostname",credentials.hostname);
        misc.lookupValue("database",credentials.database);
        

    } catch(setting_ex& ex) {
        LOG(WARN) << "One of the required settings was not found. "
                  << "You must specify: "
                  << "-user\n-pass\n-hostname\n-database name\n";
        return false;
    }
    
    prepare_select_query(misc);
    return true;
}

bool DionaeaHarvester::prepare() {
    return true;
}

bool DionaeaHarvester::connect() {

    static string_t connection_credentials = "dbname=" + credentials.database + 
                                      " user=" + credentials.user +
                                      " password=" + credentials.password + 
                                      " host=" + credentials.hostname;

    // let's call it always, just to avoid memleaks and stuff
    // BTW, should we delete dbconnection_t object?
    disconnect();
    try {
        connection = new dbconnection_t(connection_credentials);
    } catch(alloc_ex& ex) {
        LOG(ERROR) << "DionaeaHarvester: Cannot allocate memory for connection object";
        return false;
    } catch(connection_ex& ex) {
        LOG(ERROR) << "DionaeaHarvester, check your database and/or connection " << ex.what() ;
        delete connection;
        connection = NULL;
        return false;
    } catch(std::exception& ex) {
        LOG(WARN) << "DionaeaHarvester: Unexpected exception catched: " << ex.what();
        delete connection;
        connection = NULL;
        return false;
    }

    LOG(INFO) << "Connected to "<< credentials.user << "@" 
              << credentials.hostname << ":" << credentials.database;
    return true;
};

bool DionaeaHarvester::notify() {
    connect();
    fetch_data();
    disconnect();
}

bool DionaeaHarvester::start() {
    return true;
}

bool DionaeaHarvester::stop() {
    if(check_connection(connection))
        disconnect();
    return true;
}
bool DionaeaHarvester::disconnect() {
    if(check_connection(connection)) {
        connection->disconnect();
        LOG(INFO) << "Disconnected from "<< credentials.user << "@"
                  << credentials.hostname << ":" << credentials.database;
        delete connection;
        connection=NULL;
    }
};

void DionaeaHarvester::fetch_data() {

    update_select_query();
    DionaeaConnections *connections = NULL;
    try {
        dbwork_t work(*connection);
        dbresult_t result;

        if(!exec_query(work,result,formated_query,true)) {
            LOG(WARN) << "DionaeaHarvester query execution failed, discarding data";
            return;
        }

        connections = new DionaeaConnections();

        DionaeaConnections::unindexedTransaction* txn;
        for(int i=0;i<result.size();++i) {
            txn = new DionaeaConnections::unindexedTransaction();
            txn->protocol = result[i][2].as<const char*>();
            txn->dst_host = result[i][3].as<const char*>();
            txn->dst_port = result[i][4].as<u_int16_t>();
            txn->src_host = result[i][5].as<const char*>();
            txn->src_port = result[i][6].as<u_int16_t>();
            connections->rows.push_back(txn);
        }
        
        connections->set_dbresult(result);
        connections->set_date_range(range.from,range.to);

        notify_workflows(connections);
        connections = NULL; //forget about it

    } catch(alloc_ex& ex) {
        LOG(CRITIC) << "Cannot allocate memory, discarding data";
    } catch(connection_ex& ex) {
        LOG(ERROR) << "DionaeaHarvester, check your database and/or connection";
    } catch(std::exception& ex) {
        LOG(CRITIC) << "Unhandled exception was caught, discarding data";
        if(connections) delete connections;
    }
};

void DionaeaHarvester::update_select_query() {
    if(fetch == INTERVAL) {
        Python::calculate_ranges_from_interval(range.interval,range.from, range.to);
    }
    
    if(fetch == ALL)
        snprintf(formated_query,QUERY_LIMIT,select_query);
    else
        snprintf(formated_query,QUERY_LIMIT,select_query,range.from.c_str(),range.to.c_str());

};

void DionaeaHarvester::prepare_select_query(const setting_t& misc) {
     if(misc.exists("interval")) {
        setup_select_query_interval(misc);
    } else if(misc.exists("from") && misc.exists("to")  && from_to_zeroed(misc)) {
        setup_select_query_all();
    } else if(misc.exists("from") && misc.exists("to")  && !from_to_zeroed(misc)) {
        setup_select_query_range(misc);
    } else {
        setup_default_query();
    }
};


void DionaeaHarvester::setup_select_query_interval(const setting_t& misc) {
   select_query = ChannelSelects::fetch_interval_connections;
   fetch = INTERVAL;
   misc.lookupValue("interval",range.interval);
};

void DionaeaHarvester::setup_select_query_range(const setting_t& misc) {
   select_query = ChannelSelects::fetch_from_to_connections;
   LOG(DEBUG) << "setup_select_query_range";
   fetch = RANGE;
   string_t from,to;
   misc.lookupValue("from",from);
   misc.lookupValue("to",to);
   Python::sqlize_date_string(from,range.from);
   Python::sqlize_date_string(to,range.to);
};

void DionaeaHarvester::setup_select_query_all() {
   select_query = ChannelSelects::fetch_all_connections;
   fetch = ALL;
   range.from="null";
   range.to  ="null";
};

void DionaeaHarvester::setup_default_query() {
   setup_select_query_all(); // just for now
};

bool DionaeaHarvester::from_to_zeroed(const setting_t& misc) {
    string_t from,to;
    misc.lookupValue("from",from);
    misc.lookupValue("to",to);
    return (!from.compare("0") && !to.compare("0"));
};

inline bool DionaeaHarvester::check_connection(const dbconnection_t* c) {
    return c && c->is_open();
};

inline bool DionaeaHarvester::check_and_complain_connection(const dbconnection_t* c) {
    if(check_connection(c))
        return true;
    LOG(ERROR) << internal->name << ": check your database and/or connection";
    return false;
};

/* A SIMPLE FACTORY FOR CREATING OBJECTS */
extern "C" Channel* create_channel() {
    return new(nothrow) DionaeaHarvester();
};
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.