Commit d322ae34 authored by François Grisez's avatar François Grisez

Autoconfiguration of the monitor by using the list of trusted hosts

parent ab63a877
......@@ -23,19 +23,39 @@ import time
import logging
import argparse
import test
import md5
def md5sum(string):
ctx = md5.new()
ctx.update(string)
return ctx.hexdigest()
def generate_username(host):
return "monitor-" + md5sum(host)
def generate_password(host, salt):
return md5sum(host + salt)
parser = argparse.ArgumentParser(description="daemon for testing availability of each server of a Flexisip cluster")
parser.add_argument("proxy_config", nargs='+', help="configuration of each client\n" +
"format: identity_uri/proxy_uri")
parser.add_argument("domain", help="domain handle by the cluster")
parser.add_argument("salt", help="salt used to generate passwords")
parser.add_argument("nodes", nargs='+', help="list of nodes to test")
parser.add_argument("--interval", type=int, help="set time interval in seconds between successive tests", dest="test_interval", default=30)
parser.add_argument("--log", help="log file path", dest="log_file", default="./flexisip_monitor.log")
parser.add_argument("--port", "-p", help="port to switch off when test fails", dest="port", type=int, default=12345)
args = parser.parse_args()
configs = []
for config_str in args.proxy_config:
configs.append(tuple(config_str.split('/')))
for node in args.nodes:
username = generate_username(node)
password = generate_password(node, args.salt)
uid = "sip:{0}:{1}@{2}".format(username, password, args.domain)
proxy = "sip:{0};transport=tls".format(args.domain)
configs.append((uid, proxy))
logging.basicConfig(level=logging.INFO, filename=args.log_file)
action = test.TcpPortAction(args.port)
......
......@@ -617,12 +617,12 @@ int main(int argc, char *argv[]){
/*
NEVER NEVER create pthreads before this point : threads do not survive the fork below !!!!!!!!!!
*/
bool monitorEnabled = cfg->getRoot()->get<GenericStruct>("monitor")->get<ConfigBoolean>("enabled")->read();
if (daemon){
/*now that we have successfully loaded the config, there is nothing that can prevent us to start (normally).
So we can detach.*/
bool autoRespawn = cfg->getGlobal()->get<ConfigBoolean>("auto-respawn")->read();
bool startMonitor = cfg->getRoot()->get<GenericStruct>("monitor")->get<ConfigBoolean>("enable")->read();
forkAndDetach(pidfile, autoRespawn, startMonitor);
forkAndDetach(pidfile, autoRespawn, monitorEnabled);
}
LOGN("Starting flexisip version %s (git %s)", VERSION, FLEXISIP_GIT_VERSION);
......@@ -644,6 +644,15 @@ int main(int argc, char *argv[]){
if (!configOverride.empty()) cfg->applyOverrides(true); // using default + overrides
a->loadConfig (cfg);
// Create temporary test accounts for the Flexisip monitor if necessary
if(monitorEnabled) {
try {
Monitor::createAccounts();
} catch(const FlexisipException &e) {
LOGE("Could not create test accounts for the monitor. %s", e.str().c_str());
}
}
increase_fd_limit();
......
......@@ -18,21 +18,23 @@
#include "monitor.hh"
#include "configmanager.hh"
#include "agent.hh"
#include "authdb.hh"
#include <sofia-sip/su_md5.h>
using namespace std;
Monitor::Init Monitor::sInit;
const string Monitor::PYTHON_INTERPRETOR = "/usr/bin/python2";
const string Monitor::SCRIPT_PATH = "/home/francois/projects/flexisip/flexisip_monitor/flexisip_monitor.py";
const string Monitor::USERNAME_PREFIX = "monitor-";
Monitor::Init::Init() {
ConfigItemDescriptor items[] = {
{ Boolean , "enable" , "Enable or disable the Flexisip monitor daemon", "false" },
{ StringList, "identities" , "List of SIP identities which will be used to test the Flexisip nodes. There must be exactly as many SIP identities as Flexisip nodes", ""},
{ Integer , "test-interval", "Time between two consecutive tests", "30"},
{ String , "logfile" , "Path to the log file", "/etc/flexisip/flexisip_monitor.log"},
{ Integer , "switch-port" , "Port to open/close folowing the test succeed or not", "12345"},
{ Boolean , "enabled" , "Enable or disable the Flexisip monitor daemon", "false" },
{ Integer , "test-interval" , "Time between two consecutive tests", "30"},
{ String , "logfile" , "Path to the log file", "/etc/flexisip/flexisip_monitor.log"},
{ Integer , "switch-port" , "Port to open/close folowing the test succeed or not", "12345"},
{ String , "password-salt" , "Salt used to generate the passwords of each test account", "" },
config_item_end
};
......@@ -46,33 +48,35 @@ void Monitor::exec(int socket) {
su_root_t *root = NULL;
shared_ptr<Agent> a = make_shared<Agent>(root);
GenericManager::get()->loadStrict();
GenericStruct *monitorParams = GenericManager::get()->getRoot()->get<GenericStruct>("monitor");
GenericStruct *authParams = GenericManager::get()->getRoot()->get<GenericStruct>("module::Authentication");
string interval = monitorParams->get<ConfigValue>("test-interval")->get();
string logfile = monitorParams->get<ConfigString>("logfile")->read();
string port = monitorParams->get<ConfigValue>("switch-port")->get();
GenericStruct *authParams = GenericManager::get()->getRoot()->get<GenericStruct>("module::Authentication");
string salt = monitorParams->get<ConfigString>("password-salt")->read();
list<string> trustedHosts = authParams->get<ConfigStringList>("trusted-hosts")->read();
list<string> identities = monitorParams->get<ConfigStringList>("identities")->read();
trustedHosts.remove_if(isLocalhost);
if(identities.size() != trustedHosts.size()) {
LOGE("Flexisip monitor: there is not as many SIP indentities as trusted-hosts");
string domain;
try {
domain = findDomain();
} catch(const FlexisipException &e) {
LOGE("Monitor: cannot find domain. %s", e.str().c_str());
exit(-1);
}
list<string> proxyConfigs;
list<string>::const_iterator itI;
list<string>::const_iterator itH;
for(itI = identities.cbegin(), itH = trustedHosts.cbegin();
itI != identities.cend();
itI++, itH++) {
string proxyURI = string("sip:") + itH->data() + string(";transport=tls");
string proxyConfig = itI->data() + string("/") + proxyURI;
proxyConfigs.push_back(proxyConfig);
if(salt.empty()) {
LOGE("Monitor: no salt set");
exit(-1);
}
char **args = new char *[proxyConfigs.size() + 9];
if(trustedHosts.empty()) {
LOGE("Monitor: no nodes declared in module::Registrar::trusted-hosts");
exit(-1);
}
char **args = new char *[9];
args[0] = strdup(PYTHON_INTERPRETOR.c_str());
args[1] = strdup(SCRIPT_PATH.c_str());
args[2] = strdup("--interval");
......@@ -81,17 +85,81 @@ void Monitor::exec(int socket) {
args[5] = strdup(logfile.c_str());
args[6] = strdup("--port");
args[7] = strdup(port.c_str());
int i=6;
for(string proxyConfig : proxyConfigs) {
args[i] = strdup(proxyConfig.c_str());
args[8] = strdup(domain.c_str());
args[9] = strdup(salt.c_str());
int i=10;
for(string node : trustedHosts) {
args[i] = strdup(node.c_str());
i++;
}
args[i] = NULL;
if(write(socket, "ok", 3) == -1) {
exit(-1);
}
close(socket);
execvp(args[0], args);
}
void Monitor::createAccounts() {
AuthDb *authDb = AuthDb::get();
GenericStruct *authConf = GenericManager::get()->getRoot()->get<GenericStruct>("module::Authentication");
GenericStruct *monitorConf = GenericManager::get()->getRoot()->get<GenericStruct>("monitor");
string salt = monitorConf->get<ConfigString>("password-salt")->read();
list<string> trustedHosts = authConf->get<ConfigStringList>("trusted-hosts")->read();
string domain = findDomain();
for(string trustedHost : trustedHosts) {
const char *username = generateUsername(trustedHost).c_str();
const char *password = generatePassword(trustedHost, salt).c_str();
url_t url;
url.url_user = username;
url.url_host = domain.c_str();
authDb->createAccount(&url, username, password, -1);
}
}
bool Monitor::isLocalhost(string host) {
return host == "localhost" ||
host == "127.0.0.1" ||
host == "::1" ||
host == "localhost.localdomain";
}
bool Monitor::notLocalhost(string host) {
return !isLocalhost(host);
}
string Monitor::md5sum(string s) {
char digest[2*SU_MD5_DIGEST_SIZE+1];
su_md5_t ctx;
su_md5_init(&ctx);
su_md5_strupdate(&ctx, s.c_str());
su_md5_hexdigest(&ctx, digest);
return digest;
}
string Monitor::generateUsername(string host) {
return USERNAME_PREFIX + md5sum(host);
}
string Monitor::generatePassword(string host, string salt) {
return md5sum(host + salt);
}
string Monitor::findDomain() {
GenericStruct *registrarConf = GenericManager::get()->getRoot()->get<GenericStruct>("module::Registrar");
list<string> domains = registrarConf->get<ConfigStringList>("reg-domains")->read();
if(domains.size() == 0) {
throw FlexisipException("No domain declared in the registar module parameters");
}
list<string>::const_iterator it = find_if(domains.cbegin(), domains.cend(), notLocalhost);
if(it == domains.cend()) {
throw FlexisipException("Only localhost is declared as registrar domain");
}
return *it;
}
......@@ -20,19 +20,30 @@
#define monitor_hh
#include <string>
#include "agent.hh"
class Monitor {
public:
static void exec(int socket);
static void createAccounts();
private:
class Init {
public:
Init();
};
static bool isLocalhost(std::string host);
static bool notLocalhost(std::string host);
static std::string md5sum(std::string s);
static std::string generateUsername(std::string host);
static std::string generatePassword(std::string host, std::string salt);
static std::string findDomain();
static Init sInit;
static const std::string PYTHON_INTERPRETOR;
static const std::string SCRIPT_PATH;
static const std::string USERNAME_PREFIX;
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment