Project

General

Profile

Bug #9211 » ntopng.inc

YP Lo, 05/23/2019 07:30 AM

 
1
<?php
2
/*
3
 * ntopng.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2015-2017 Rubicon Communications, LLC (Netgate)
7
 * All rights reserved.
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 * http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21

    
22
require_once("config.inc");
23
require_once("globals.inc");
24
require_once("interfaces.inc");
25
require_once("pkg-utils.inc");
26
require_once("service-utils.inc");
27
require_once("util.inc");
28
require_once("certs.inc");
29

    
30

    
31
global $redis_path;
32
$redis_path = "/usr/local/bin";
33

    
34
function ntopng_php_install_command() {
35
	/* Create dirs for Redis DB, data and graphs */
36
	ntopng_create_datadir();
37
}
38

    
39
function ntopng_php_deinstall_command() {
40
	global $config;
41

    
42
	/* Wipe data and settings if the user does not wish to keep them */
43
	init_config_arr(array('installedpackages', 'ntopng', 'config', 0));
44
	$ntopng_config = $config['installedpackages']['ntopng']['config'][0];
45
	if ($ntopng_config['keepdata'] != "on") {
46
		if (is_dir("/var/db/ntopng/")) {
47
			exec("rm -rf /var/db/ntopng/");
48
		}
49
		if (is_array($config['installedpackages']['ntopng'])) {
50
			unset($config['installedpackages']['ntopng']);
51
			write_config("[ntopng] Removed package settings on uninstall.");
52
		}
53
		log_error(gettext("[ntopng] Removed package data and settings since 'Keep Data/Settings' is disabled."));
54
	}
55
}
56

    
57
function ntopng_write_cert_file($file, $cert) {
58
	$fd = fopen($file, "w");
59
	if (!$fd) {
60
		log_error("ERROR: Could not open {$file} for writing");
61
		return;
62
	}
63
	chmod($file, 0600);
64
	/* newline to deal with certs/keys lacking newline at end */
65
	fwrite($fd, base64_decode($cert['crt']) . "\n");
66
	fwrite($fd, base64_decode($cert['prv']) . "\n");
67
	fclose($fd);
68
}
69

    
70

    
71
function ntopng_sync_package() {
72
	global $config, $ntopng_config, $redis_path;
73
	/* These are done via ntopng_validate_input(), just return */
74
	if ($_POST['Submit'] == "Update GeoIP Data") {
75
		return;
76
	}
77
	if ($_POST['Delete'] == "Delete Data") {
78
		return;
79
	}
80

    
81
	$ifaces = "";
82
	init_config_arr(array('installedpackages', 'ntopng', 'config', 0));
83
	$ntopng_config = &$config['installedpackages']['ntopng']['config'][0];
84

    
85
	/* Just stop services and unlink rc script if disabled */
86
	if ($ntopng_config['enable'] != "on") {
87
		ntopng_services_stop();
88
		unlink_if_exists("/usr/local/etc/rc.d/ntopng.sh");
89
		unlink_if_exists("/usr/local/share/ntopng/httpdocs/ssl/ntopng-cert.pem");
90
		return;
91
	}
92

    
93
	foreach ($ntopng_config['interface_array'] as $iface) {
94
		$if = convert_friendly_interface_to_real_interface_name($iface);
95
		if ($if) {
96
			$ifaces .= " -i " . escapeshellarg("{$if}");
97
		}
98
	}
99

    
100
	/* DNS Mode */
101
	if (is_numeric($ntopng_config['dns_mode']) && ($ntopng_config['dns_mode'] >= 0) && ($ntopng_config['dns_mode'] <= 3)) {
102
		$dns_mode = "--dns-mode " . escapeshellarg($ntopng_config['dns_mode']);
103
	}
104

    
105
	/* Local Networks */
106
	switch ($ntopng_config['local_networks']) {
107
		case "selected":
108
			$nets = array();
109
			foreach ($ntopng_config['interface_array'] as $iface) {
110
				if (is_ipaddr(get_interface_ip($iface))) {
111
					$nets[] = gen_subnet(get_interface_ip($iface), get_interface_subnet($iface)) . '/' . get_interface_subnet($iface);
112
				}
113
			}
114
			if (!empty($nets)) {
115
				$local_networks = "--local-networks " . escapeshellarg(implode(",", $nets));
116
			}
117
			break;
118
		case "lanonly":
119
			if (is_ipaddr(get_interface_ip('lan'))) {
120
				$local_networks = "--local-networks " . escapeshellarg(gen_subnet(get_interface_ip('lan'), get_interface_subnet('lan')) . '/' . get_interface_subnet('lan'));
121
			}
122
			break;
123
		case "custom":
124
			$nets = array();
125
			foreach ($ntopng_config['row'] as $net) {
126
				if (is_subnet($net['cidr'])) {
127
					$nets[] = trim($net['cidr']);
128
				}
129
			}
130
			if (!empty($nets)) {
131
				$local_networks = "--local-networks " . escapeshellarg(implode(",", $nets));
132
			}
133
			break;
134
		case "rfc1918":
135
		default:
136
			$local_networks = "--local-networks '192.168.0.0/16,172.16.0.0/12,10.0.0.0/8'";
137
			break;
138
	}
139

    
140
	// Pending rework - see https://redmine.pfsense.org/issues/7000
141
	/* Historical Data Storage, Dump expired flows
142
	if ($ntopng_config['dump_flows'] == "on") {
143
		$dump_flows = "-F";
144
	}
145
	*/
146

    
147
	if ($config['system']['webgui']['protocol'] == "https") {
148
		$cert = lookup_cert($config['system']['webgui']['ssl-certref']);
149
		ntopng_write_cert_file("/usr/local/share/ntopng/httpdocs/ssl/ntopng-cert.pem", $cert);
150
		$http_args = "-w 0 -W 3000";
151
	} else {
152
		unlink_if_exists("/usr/local/share/ntopng/httpdocs/ssl/ntopng-cert.pem");
153
		$http_args = "-w 3000";
154
	}
155

    
156
	/* Create rc script */
157
	$stop = <<<EOD
158
# Kill ntopng and redis
159
	/usr/bin/killall ntopng redis-cli redis-server
160
EOD;
161

    
162
	$start = <<<EOD
163
### Make sure library path cache is updated
164
	/etc/rc.d/ldconfig start
165
# Create DB dir before starting, in case it was removed. Otherwise redis will fail.
166
	/bin/mkdir -p /var/db/ntopng
167
	{$redis_path}/redis-server --bind 127.0.0.1 ::1 --dir /var/db/ntopng/ --dbfilename ntopng.rdb &
168
	/usr/local/bin/ntopng -d /var/db/ntopng -G /var/run/ntopng.pid -s -e {$http_args} {$disable_alerts} {$dump_flows} {$ifaces} {$dns_mode} {$aggregations} {$local_networks} &
169
EOD;
170
	// TODO:
171
	// Add support for --data-dir /somewhere, --httpdocs-dir /somewhereelse,
172
	// --dump-timeline (on/off) --http-port, --https-port
173

    
174
	write_rcfile(array("file" => "ntopng.sh", "start" => $start, "stop" => $stop));
175

    
176
	/* Set up admin password */
177
	ntopng_set_redis_password();
178
	
179
	/* (Re)start services if not booting */
180
	if (!platform_booting()) {
181
		ntopng_services_stop();
182
		start_service("ntopng");
183
		sleep(20);
184
	}
185
}
186

    
187
function ntopng_services_stop() {
188
	if ((is_process_running("redis-server")) || (is_process_running("ntopng"))) {
189
		stop_service("ntopng");
190
	}
191
	for ($i = 0; $i <= 10; $i++) {
192
		if ((!is_process_running("redis-server")) && (!is_process_running("ntopng"))) {
193
			break;
194
		}
195
		sleep(2);
196
	}
197
}
198

    
199
function ntopng_redis_started() {
200
	global $redis_path, $redis_started;
201
	$redis_started = false;
202

    
203
	if (!is_process_running("redis-server")) {
204
		exec_bg("{$redis_path}/redis-server --bind 127.0.0.1 ::1 --dir /var/db/ntopng/ --dbfilename ntopng.rdb");
205
		for ($i = 0; $i <= 10; $i++) {
206
			if (is_process_running("redis-server")) {
207
				$redis_started = true;
208
				break;
209
			}
210
			sleep(1);
211
		}
212
	} else {
213
		$redis_started = true;
214
	}
215
	return $redis_started;
216
}
217

    
218
function ntopng_set_redis_password() {
219
	global $config, $ntopng_config, $redis_path;
220
	init_config_arr(array('installedpackages', 'ntopng', 'config', 0));
221
	$ntopng_config = $config['installedpackages']['ntopng']['config'][0];
222

    
223
	if (!empty($ntopng_config['redis_password'])) {
224
		$password = md5($ntopng_config['redis_password']);
225
		if (ntopng_redis_started()) {
226
			exec("{$redis_path}/redis-cli SET ntopng.user.admin.password " . escapeshellarg($password));
227
			// Make sure the preferences menu is accessible (Bug #6999)
228
			exec("{$redis_path}/redis-cli SET ntopng.user.admin.group administrator");
229
			exec("{$redis_path}/redis-cli save");
230
		} else {
231
			log_error(gettext("[ntopng] Cannot set admin password - redis-server is not running."));
232
		}
233
	}
234
}
235

    
236
function ntopng_create_datadir() {
237
	safe_mkdir("/var/db/ntopng/rrd/graphics", 0755);
238
	exec("/bin/chmod -R 755 /var/db/ntopng");
239
	exec("/usr/sbin/chown -R nobody:nobody /var/db/ntopng");
240
}
241

    
242
function ntopng_update_geoip() {
243
	global $config;
244
	$fetchcmd = "/usr/bin/fetch";
245
	$geolite_city = "https://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz";
246
	$geoip_asnum = "https://geolite.maxmind.com/download/geoip/database/GeoLite2-ASN.tar.gz";
247
	$output_dir = "/usr/local/share/ntopng";
248
	
249
	exec("{$fetchcmd} -o {$output_dir} -T 5 {$geolite_city}");
250
	exec("{$fetchcmd} -o {$output_dir} -T 5 {$geoip_asnum}");
251

    
252
	ntopng_fixup_geoip();
253

    
254
	/* Do not (re)start services on package (re)install, only on manual GeoIP updates via the GUI */
255
	if ($_POST['Submit'] == "Update GeoIP Data") {
256
		init_config_arr(array('installedpackages', 'ntopng', 'config', 0));
257
		$ntopng_config = $config['installedpackages']['ntopng']['config'][0];
258
		ntopng_services_stop();
259
		if ($ntopng_config['enable'] == "on") {
260
			start_service("ntopng");
261
		}
262
	}
263
}
264

    
265
function ntopng_fixup_geoip() {
266
	$target_dir = "/usr/local/share/ntopng/httpdocs/geoip";
267
	$source_dir = "/usr/local/share/ntopng";
268

    
269
	safe_mkdir($target_dir, 0755);
270

    
271
	foreach(glob("{$source_dir}/Geo*.tar.gz") as $geofile) {
272
		/* Decompress if needed. */
273
		if (substr($geofile, -7, 7) == ".tar.gz") {			
274
			exec("tar -C {$source_dir} -f {$geofile} --strip 1 -xz '*.mmdb'");
275
		}
276
	}
277

    
278
	/* Use a separate glob since the filenames could have changed since the last run */
279
	foreach(glob("{$source_dir}/Geo*.mmdb") as $geofile) {
280
		$target_file = $target_dir . '/' . basename($geofile);
281
		if (!file_exists($target_file)) {
282
			symlink($geofile, $target_file);
283
		}
284
	}
285
}
286

    
287
function ntopng_flush_historical_data() {
288
	global $config, $ntopng_config, $redis_path;
289
	init_config_arr(array('installedpackages', 'ntopng', 'config', 0));
290
	$ntopng_config = $config['installedpackages']['ntopng']['config'][0];
291

    
292
	if (ntopng_redis_started()) {
293
		/* Delete all the keys of all the existing Redis databases */
294
		exec("{$redis_path}/redis-cli flushall");
295
		log_error(gettext("[ntopng] Flushed Redis DB."));
296
		/* Set admin password while redis-server is still running */
297
		ntopng_set_redis_password();
298
		log_error(gettext("[ntopng] Set admin password for Redis DB."));
299
		/* Stop services and delete all graphs, data and dump flows */
300
		ntopng_services_stop();
301
		if (is_dir("/var/db/ntopng/")) {
302
			exec("rm -rf /var/db/ntopng/");
303
			log_error(gettext("[ntopng] Deleted ntopng traffic data and graphs."));
304
		} else {
305
			log_error(gettext("[ntopng] Nothing to delete; /var/db/ntopng/ directory not found."));
306
		}
307
		/* Re-create the required directory structure with proper permissions */
308
		ntopng_create_datadir();
309
		log_error(gettext("[ntopng] Re-created required data directory structure."));
310
		/* Resync settings and restart services if enabled */
311
		unset($_POST['Delete']);
312
		ntopng_sync_package();
313
		log_error(gettext("[ntopng] Resynced ntopng settings."));
314
	} else {
315
		$error = "Cannot delete data - redis-server is not running.";
316
		log_error(gettext("[ntopng] {$error}"));
317
		file_notice("ntopng", $error, "ntopng Delete Data", "");
318
	}
319
}
320

    
321
function ntopng_validate_input($post, &$input_errors) {
322
	if (empty($post['redis_password']) || empty($post['redis_passwordagain'])) {
323
		$input_errors[] = "You must provide (and confirm) ntopng's password.";
324
	}
325
	if ((strlen($post['redis_password']) < 5) || (strlen($post['redis_passwordagain']) < 5)) {
326
		$input_errors[] = "Password must have at least 5 characters.";
327
	}
328
	if ($post['redis_password'] != $post['redis_passwordagain']) {
329
		$input_errors[] = "The provided passwords did not match.";
330
	}
331
	if($_POST["local_networks"] == "custom") {
332
		$idx = 0;
333
		while (isset($_POST["cidr{$idx}"])) {
334
			$cidr = $_POST["cidr" . $idx++];
335
			if (!is_subnet($cidr)) {
336
				$input_errors[] = "Invalid CIDR in custom local networks list at position {$idx}.";
337
			}
338
		}
339
	}
340
	if ($post['Submit'] == "Update GeoIP Data") {
341
		ntopng_update_geoip();
342
	}
343
	if ($post['Delete'] == "Delete Data") {
344
		ntopng_flush_historical_data();
345
	}
346
}
347

    
348
?>
(1-1/3)