monitor.cc 5.97 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
    Flexisip, a flexible SIP proxy server with media capabilities.
    Copyright (C) 2014  Belledonne Communications SARL.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero 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 Affero General Public License for more details.
 
    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "monitor.hh"
#include "configmanager.hh"
21 22
#include "authdb.hh"
#include <sofia-sip/su_md5.h>
23
#include <ortp/rtpsession.h>
24 25 26 27 28 29

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";
30 31
const string Monitor::CALLER_PREFIX = "monitor-caller";
const string Monitor::CALLEE_PREFIX = "monitor-callee";
32 33 34

Monitor::Init::Init() {
	ConfigItemDescriptor items[] = {
35 36 37 38 39
		{ 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", "" },
40 41 42 43 44 45 46 47
		config_item_end 
	};
	
	GenericStruct *s = new GenericStruct("monitor", "Flexisip monitor parameters", 0);
	GenericManager::get()->getRoot()->addChild(s);
	s->addChildrenValues(items);
}

48
void Monitor::exec(int socket) {
49 50 51 52
	// Create a temporary agent to load all modules
	su_root_t *root = NULL;
	shared_ptr<Agent> a = make_shared<Agent>(root);
	GenericManager::get()->loadStrict();
53
    
54
	GenericStruct *monitorParams = GenericManager::get()->getRoot()->get<GenericStruct>("monitor");
55
	GenericStruct *cluster = GenericManager::get()->getRoot()->get<GenericStruct>("cluster");
56 57 58
	string interval = monitorParams->get<ConfigValue>("test-interval")->get();
	string logfile = monitorParams->get<ConfigString>("logfile")->read();
	string port = monitorParams->get<ConfigValue>("switch-port")->get();
59
	string salt = monitorParams->get<ConfigString>("password-salt")->read();
60
	list<string> nodes = cluster->get<ConfigStringList>("nodes")->read();
François Grisez's avatar
François Grisez committed
61
    
62 63 64 65
	string domain;
	try {
		domain = findDomain();
	} catch(const FlexisipException &e) {
66
		LOGF("Monitor: cannot find domain. %s", e.str().c_str());
67 68 69
		exit(-1);
	}
	
70
	if(salt.empty()) {
71
		LOGF("Monitor: no salt set");
72
		exit(-1);
73
	}
74
	
75
	if(nodes.empty()) {
76
		LOGF("Monitor: no nodes declared in the cluster section");
77 78 79
		exit(-1);
	}

80
	char **args = new char *[10 + nodes.size()];
81 82 83 84 85 86 87 88
	args[0] = strdup(PYTHON_INTERPRETOR.c_str());
	args[1] = strdup(SCRIPT_PATH.c_str());
	args[2] = strdup("--interval");
	args[3] = strdup(interval.c_str());
	args[4] = strdup("--log");
	args[5] = strdup(logfile.c_str());
	args[6] = strdup("--port");
	args[7] = strdup(port.c_str());
89 90 91
	args[8] = strdup(domain.c_str());
	args[9] = strdup(salt.c_str());
	int i=10;
92
	for(string node : nodes) {
93
		args[i] = strdup(node.c_str());
94 95 96
		i++;
	}
	args[i] = NULL;
97

98 99 100 101
	if(write(socket, "ok", 3) == -1) {
		exit(-1);
	}
	close(socket);
102

103 104
	execvp(args[0], args);
}
105

106 107 108 109 110 111 112 113 114 115 116
string Monitor::findLocalAddress(const list<string> &nodes) {
	RtpSession *session = rtp_session_new(RTP_SESSION_RECVONLY);
	for(const string & node : nodes) {
		if(rtp_session_set_local_addr(session, node.c_str(), 0, 0) != -1) {
			rtp_session_destroy(session);
			return node;
		}
	}
	return "";
}

117
void Monitor::createAccounts() {
118
    url_t url;
119
	AuthDb *authDb = AuthDb::get();
120
	GenericStruct *cluster = GenericManager::get()->getRoot()->get<GenericStruct>("cluster");
121 122
	GenericStruct *monitorConf = GenericManager::get()->getRoot()->get<GenericStruct>("monitor");
	string salt = monitorConf->get<ConfigString>("password-salt")->read();
123 124 125 126 127 128 129 130 131
	list<string> nodes = cluster->get<ConfigStringList>("nodes")->read();

    url.url_host = findDomain().c_str();
    
	string localIP = findLocalAddress(nodes);
	if(localIP == "") {
		SLOGA << "Could not find local IP address";
		exit(-1);
	}
132
	
133 134 135
	const char *password = generatePassword(localIP, salt).c_str();
	url.url_user = generateUsername(CALLER_PREFIX, localIP).c_str();
    authDb->createAccount(&url, "", password, INT_MAX);
136
	
137 138
    url.url_user = generateUsername(CALLEE_PREFIX, localIP).c_str();
    authDb->createAccount(&url, "", password, INT_MAX);
139 140
}

141
bool Monitor::isLocalhost(const string &host) {
142 143 144 145 146 147
	return host == "localhost" ||
	       host == "127.0.0.1" ||
	       host == "::1" ||
	       host == "localhost.localdomain";
}

148
bool Monitor::notLocalhost(const string &host) {
149 150 151
	return !isLocalhost(host);
}

152
string Monitor::md5sum(const string &s) {
153 154 155 156 157 158 159 160
	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;
}

161 162
string Monitor::generateUsername(const string &prefix, const string &host) {
	return prefix + "-" + md5sum(host);
163 164
}

165
string Monitor::generatePassword(const string &host, const string &salt) {
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
	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;
}