Skip to content
monitor_core_module.inc.php 48.5 KiB
Newer Older
		$sql = 'INSERT INTO monitor_data (server_id, type, created, data, state) ' .
				'VALUES ('.
				$server_id . ', ' .
				"'" . $app->dbmaster->quote($type) . "', " .
				"'" . $app->dbmaster->quote(serialize($data)) . "', " .
				"'" . $state . "'" .
		$app->dbmaster->query($sql);

		/* The new data is written, now we can delete the old one */
		$this->_delOldRecords($type, 4);
	}


	function monitorRaid() {
		global $app;
		global $conf;

		/* the id of the server as int */

		/** The type of the data */
		$type = 'raid_state';

		 * We support several RAID types, but if we can't find any of them, we have no data
		*/
		$state = 'no_state';
		$data['output']= '';

		/*
vogelor's avatar
vogelor committed
             * Fetch the output
			*/
			$data['output'] = shell_exec('cat /proc/mdstat');
vogelor's avatar
vogelor committed
             * Then calc the state.
			*/
			$tmp = explode("\n", $data['output']);
			$state = 'ok';
			for ($i = 0; $i < sizeof($tmp); $i++) {
				/* fetch the next line */
				$line = $tmp[$i];

				if ((strpos($line, '[U_]') !== false) || (strpos($line, '[_U]') !== false)) {
					/* One Disk is not working.
                     * if the next line starts with "[>" or "[=" then
                     * recovery (resync) is in state and the state is
                     * information instead of critical
					*/
					$nextLine = $tmp[$i+1];
					if ((strpos($nextLine, '[>') === false) && (strpos($nextLine, '[=') === false)) {
						$state = $this->_setState($state, 'critical');
					}
					else {
						$state = $this->_setState($state, 'info');
					}
				}
				if (strpos($line, '[__]') !== false) {
					/* both Disk are not working */
					$state = $this->_setState($state, 'error');
				}
				if (strpos($line, '[UU]') !== false) {
					/* The disks are OK.
vogelor's avatar
vogelor committed
                     * if the next line starts with "[>" or "[=" then
                     * recovery (resync) is in state and the state is
                     * information instead of ok
					*/
					$nextLine = $tmp[$i+1];
					if ((strpos($nextLine, '[>') === false) && (strpos($nextLine, '[=') === false)) {
						$state = $this->_setState($state, 'ok');
					}
					else {
						$state = $this->_setState($state, 'info');
					}
				}
			}
		}
		/*
		 * Check, if we have mpt-status installed (LSIsoftware-raid)
		*/
		system('which mpt-status', $retval);
		if($retval === 0) {
			$data['output'] = shell_exec('mpt-status --autoload -n');

			/*
             * Then calc the state.
			*/
			$state = 'ok';
			foreach ($data['output'] as $item) {
				/*
				 * The output contains information for every RAID and every HDD.
				 * We only need the state of the RAID
				*/
				if (strpos($item, 'raidlevel:') !== false) {
					/*
					 * We found a raid, process the state of it
					*/
					if (strpos($item, ' ONLINE ') !== false) {
						$this->_setState($state, 'ok');
					}
					elseif (strpos($item, ' OPTIMAL ') !== false) {
						$this->_setState($state, 'ok');
					}
					elseif (strpos($item, ' INITIAL ') !== false) {
						$this->_setState($state, 'info');
					}
					elseif (strpos($item, ' INACTIVE ') !== false) {
						$this->_setState($state, 'critical');
					}
					elseif (strpos($item, ' RESYNC ') !== false) {
						$this->_setState($state, 'info');
					}
					elseif (strpos($item, ' DEGRADED ') !== false) {
						$this->_setState($state, 'critical');
					}
					else {
						/* we don't know the state. so we set the state to critical, that the
						 * admin is warned, that something is wrong
						*/
						$this->_setState($state, 'critical');
					}
				}
			}
vogelor's avatar
vogelor committed
         * Insert the data into the database
		$sql = 'INSERT INTO monitor_data (server_id, type, created, data, state) ' .
				'VALUES ('.
				$server_id . ', ' .
				"'" . $app->dbmaster->quote($type) . "', " .
				"'" . $app->dbmaster->quote(serialize($data)) . "', " .
				"'" . $state . "'" .
		$app->dbmaster->query($sql);

		/* The new data is written, now we can delete the old one */
		$this->_delOldRecords($type, 4);
vogelor's avatar
vogelor committed
         *  This monitoring is expensive, so do it only once a day
		*/
		$min = date('i');
		$hour = date('H');
		if (!($min == 0 && $hour == 23)) return;
		/* the id of the server as int */
		/** The type of the data */
		$type = 'rkhunter';
		/* This monitoring is only available if rkhunter is installed */
		system('which rkhunter', $retval);
			*/
			$data['output'] = shell_exec('rkhunter --update --checkall --nocolors --skip-keypress');
             * At this moment, there is no state (maybe later)
             * rkhunter is not installed, so there is no data and no state
             *
             * no_state, NOT unknown, because "unknown" is shown as state
             * inside the GUI. no_state is hidden.
             *
             * We have to write NO DATA inside the DB, because the GUI
             * could not know, if there is any dat, or not...
			*/
			$state = 'no_state';
			$data['output']= '';
		}
         * Insert the data into the database
		$sql = 'INSERT INTO monitor_data (server_id, type, created, data, state) ' .
				'VALUES ('.
				$server_id . ', ' .
				"'" . $app->dbmaster->quote($type) . "', " .
				"'" . $app->dbmaster->quote(serialize($data)) . "', " .
				"'" . $state . "'" .
		$app->dbmaster->query($sql);

		/* The new data is written, now we can delete the old one */
		$this->_delOldRecords($type, 4);
	}

	function monitorFail2ban() {
		global $app;
		global $conf;

		/* the id of the server as int */

		/** The type of the data */
		$type = 'log_fail2ban';

		/* This monitoring is only available if fail2ban is installed */
		system('which fail2ban-client', $retval); // Debian, Ubuntu, Fedora
		if($retval !== 0) system('which fail2ban', $retval); // CentOS
			/*  Get the data of the log */
			$data = $this->_getLogData($type);

             * At this moment, there is no state (maybe later)
             * fail2ban is not installed, so there is no data and no state
             *
             * no_state, NOT unknown, because "unknown" is shown as state
             * inside the GUI. no_state is hidden.
             *
             * We have to write NO DATA inside the DB, because the GUI
             * could not know, if there is any dat, or not...
         * Insert the data into the database
		$sql = 'INSERT INTO monitor_data (server_id, type, created, data, state) ' .
				'VALUES ('.
				$server_id . ', ' .
				"'" . $app->dbmaster->quote($type) . "', " .
				"'" . $app->dbmaster->quote(serialize($data)) . "', " .
				"'" . $state . "'" .
		$app->dbmaster->query($sql);

		/* The new data is written, now we can delete the old one */
		$this->_delOldRecords($type, 4);
	}

	function monitorSysLog() {
		global $app;
		global $conf;

		/* the id of the server as int */

		/** The type of the data */
		$type = 'sys_log';
		/*
		 * is there any warning or error for this server?
		$dbData = $app->dbmaster->queryAllRecords('SELECT loglevel FROM sys_log WHERE server_id = ' . $server_id . ' AND loglevel > 0');
			foreach($dbData as $item) {
				if ($item['loglevel'] == 1) $state = $this->_setState($state, 'warning');
				if ($item['loglevel'] == 2) $state = $this->_setState($state, 'error');
			}
		}

		/** There is no monitor-data because the data is in the sys_log table */
         * Insert the data into the database
		$sql = 'INSERT INTO monitor_data (server_id, type, created, data, state) ' .
				'VALUES ('.
				$server_id . ', ' .
				"'" . $app->dbmaster->quote($type) . "', " .
				"'" . $app->dbmaster->quote(serialize($data)) . "', " .
				"'" . $state . "'" .
		$app->dbmaster->query($sql);

		/* The new data is written, now we can delete the old one */
		$this->_delOldRecords($type, 4);
	}

	function monitorMailLog() {
		global $app;
		global $conf;

		/* the id of the server as int */

		/** The type of the data */
		$type = 'log_mail';

		/* Get the data of the log */
		$data = $this->_getLogData($type);

		/*
         * actually this info has no state.
         * maybe someone knows better...???...
        Insert the data into the database
		$sql = 'INSERT INTO monitor_data (server_id, type, created, data, state) ' .
				'VALUES ('.
				$server_id . ', ' .
				"'" . $app->dbmaster->quote($type) . "', " .
				"'" . $app->dbmaster->quote(serialize($data)) . "', " .
				"'" . $state . "'" .
		$app->dbmaster->query($sql);

		/* The new data is written, now we can delete the old one */
		$this->_delOldRecords($type, 4);
	}

	function monitorMailWarnLog() {
		global $app;
		global $conf;

		/* the id of the server as int */

		/** The type of the data */
		$type = 'log_mail_warn';

		/* Get the data of the log */
		$data = $this->_getLogData($type);

		/*
         * actually this info has no state.
         * maybe someone knows better...???...
        Insert the data into the database
		$sql = 'INSERT INTO monitor_data (server_id, type, created, data, state) ' .
				'VALUES ('.
				$server_id . ', ' .
				"'" . $app->dbmaster->quote($type) . "', " .
				"'" . $app->dbmaster->quote(serialize($data)) . "', " .
				"'" . $state . "'" .
		$app->dbmaster->query($sql);

		/* The new data is written, now we can delete the old one */
		$this->_delOldRecords($type, 4);
	}

	function monitorMailErrLog() {
		global $app;
		global $conf;

		/* the id of the server as int */

		/** The type of the data */
		$type = 'log_mail_err';

		/* Get the data of the log */
		$data = $this->_getLogData($type);

		/*
         * actually this info has no state.
         * maybe someone knows better...???...
        Insert the data into the database
		$sql = 'INSERT INTO monitor_data (server_id, type, created, data, state) ' .
				'VALUES ('.
				$server_id . ', ' .
				"'" . $app->dbmaster->quote($type) . "', " .
				"'" . $app->dbmaster->quote(serialize($data)) . "', " .
				"'" . $state . "'" .
		$app->dbmaster->query($sql);

		/* The new data is written, now we can delete the old one */
		$this->_delOldRecords($type, 4);
	function monitorMessagesLog() {
		global $app;
		global $conf;
		/* the id of the server as int */
		/** The type of the data */
		$type = 'log_messages';
		/* Get the data of the log */
		$data = $this->_getLogData($type);
         * actually this info has no state.
         * maybe someone knows better...???...
        Insert the data into the database
		$sql = 'INSERT INTO monitor_data (server_id, type, created, data, state) ' .
				'VALUES ('.
				$server_id . ', ' .
				"'" . $app->dbmaster->quote($type) . "', " .
				"'" . $app->dbmaster->quote(serialize($data)) . "', " .
				"'" . $state . "'" .
		$app->dbmaster->query($sql);

		/* The new data is written, now we can delete the old one */
		$this->_delOldRecords($type, 4);
	}

	function monitorISPCCronLog() {
		global $app;
		global $conf;

		/* the id of the server as int */

		/** The type of the data */
		$type = 'log_ispc_cron';

		/* Get the data of the log */
		$data = $this->_getLogData($type);

		/*
         * actually this info has no state.
         * maybe someone knows better...???...
        Insert the data into the database
		$sql = 'INSERT INTO monitor_data (server_id, type, created, data, state) ' .
				'VALUES ('.
				$server_id . ', ' .
				"'" . $app->dbmaster->quote($type) . "', " .
				"'" . $app->dbmaster->quote(serialize($data)) . "', " .
				"'" . $state . "'" .
		$app->dbmaster->query($sql);

		/* The new data is written, now we can delete the old one */
		$this->_delOldRecords($type, 4);
	}

	function monitorFreshClamLog() {
		global $app;
		global $conf;

		/* the id of the server as int */

		/** The type of the data */
		$type = 'log_freshclam';

		/* Get the data of the log */
		$data = $this->_getLogData($type);

		/* Get the data from the LAST log-Entry.
         * if there can be found:
         * WARNING: Your ClamAV installation is OUTDATED!
         * then the clamav is outdated. This is a warning!
		*/
		$state = 'ok';

		$tmp = explode("\n", $data);
		$lastLog = array();
			/* the log ends with an empty line remove this */
			array_pop($tmp);
		}
		if (strpos($tmp[sizeof($tmp)-1], '-------------') !== false) {
			/* the log ends with "-----..." remove this */
			array_pop($tmp);
		}
		for ($i = sizeof($tmp) -1; $i > 0; $i--) {
			if (strpos($tmp[$i], '---------') === false) {
				/* no delimiter found, so add this to the last-log */
				$lastLog[] = $tmp[$i];
			}
			else {
				/* delimiter found, so there is no more line left! */
				break;
			}
		}

		/*
         * Now we have the last log in the array.
         * Check if the outdated-string is found...
		*/
		foreach($lastLog as $line) {
			if (strpos(strtolower($line), 'outdated') !== false) {
				/*
				 * Outdatet is only info, because if we set this to warning, the server is
				 * as long in state warning, as there is a new version of ClamAv which takes
				 * sometimes weeks!
				*/
				$state = $this->_setState($state, 'info');
        Insert the data into the database
		$sql = 'INSERT INTO monitor_data (server_id, type, created, data, state) ' .
				'VALUES ('.
				$server_id . ', ' .
				"'" . $app->dbmaster->quote($type) . "', " .
				"'" . $app->dbmaster->quote(serialize($data)) . "', " .
				"'" . $state . "'" .
		$app->dbmaster->query($sql);

		/* The new data is written, now we can delete the old one */
		$this->_delOldRecords($type, 4);
	}

	function monitorClamAvLog() {
		global $app;
		global $conf;

		/* the id of the server as int */

		/** The type of the data */
		$type = 'log_clamav';

		/* Get the data of the log */
		$data = $this->_getLogData($type);

		// Todo: the state should be calculated.
		$state = 'ok';

		/*
        Insert the data into the database
		$sql = 'INSERT INTO monitor_data (server_id, type, created, data, state) ' .
				'VALUES ('.
				$server_id . ', ' .
				"'" . $app->dbmaster->quote($type) . "', " .
				"'" . $app->dbmaster->quote(serialize($data)) . "', " .
				"'" . $state . "'" .
		$app->dbmaster->query($sql);

		/* The new data is written, now we can delete the old one */
		$this->_delOldRecords($type, 4);
	}

	function monitorIspConfigLog() {
		global $app;
		global $conf;

		/* the id of the server as int */

		/** The type of the data */
		$type = 'log_ispconfig';

		/* Get the data of the log */
		$data = $this->_getLogData($type);

		// Todo: the state should be calculated.
		$state = 'ok';

		/*
        Insert the data into the database
		$sql = 'INSERT INTO monitor_data (server_id, type, created, data, state) ' .
				'VALUES ('.
				$server_id . ', ' .
				"'" . $app->dbmaster->quote($type) . "', " .
				"'" . $app->dbmaster->quote(serialize($data)) . "', " .
				"'" . $state . "'" .
		$app->dbmaster->query($sql);

		/* The new data is written, now we can delete the old one */
		$this->_delOldRecords($type, 4);
		if(@is_file('/etc/debian_version')) {
			$dist = 'debian';
		} elseif(@is_file('/etc/redhat-release')) {
			$dist = 'redhat';
		} elseif(@is_file('/etc/SuSE-release')) {
			$dist = 'suse';
		} elseif(@is_file('/etc/gentoo-release')) {
			$dist = 'gentoo';
		}
				if($dist == 'debian') { $logfile = '/var/log/mail.log'; }
				elseif($dist == 'redhat') { $logfile = '/var/log/maillog'; }
				elseif($dist == 'suse') { $logfile = '/var/log/mail.info'; }
				elseif($dist == 'gentoo') { $logfile = '/var/log/maillog'; }
				break;
			case 'log_mail_warn':
				if($dist == 'debian') { $logfile = '/var/log/mail.warn'; }
				elseif($dist == 'redhat') { $logfile = '/var/log/maillog'; }
				elseif($dist == 'suse') { $logfile = '/var/log/mail.warn'; }
				elseif($dist == 'gentoo') { $logfile = '/var/log/maillog'; }
				if($dist == 'debian') { $logfile = '/var/log/mail.err'; }
				elseif($dist == 'redhat') { $logfile = '/var/log/maillog'; }
				elseif($dist == 'suse') { $logfile = '/var/log/mail.err'; }
				elseif($dist == 'gentoo') { $logfile = '/var/log/maillog'; }
				if($dist == 'debian') { $logfile = '/var/log/messages'; }
				elseif($dist == 'redhat') { $logfile = '/var/log/messages'; }
				elseif($dist == 'suse') { $logfile = '/var/log/messages'; }
				elseif($dist == 'gentoo') { $logfile = '/var/log/messages'; }
				break;
			case 'log_ispc_cron':
				if($dist == 'debian') { $logfile = $conf['ispconfig_log_dir'].'/cron.log'; }
				elseif($dist == 'redhat') { $logfile = $conf['ispconfig_log_dir'].'/cron.log'; }
				elseif($dist == 'suse') { $logfile = $conf['ispconfig_log_dir'].'/cron.log'; }
				elseif($dist == 'gentoo') { $logfile = '/var/log/cron'; }
				break;
			case 'log_freshclam':
				if($dist == 'debian') { $logfile = '/var/log/clamav/freshclam.log'; }
				elseif($dist == 'redhat') { $logfile = (is_file('/var/log/clamav/freshclam.log') ? '/var/log/clamav/freshclam.log' : '/var/log/freshclam.log'); }
				elseif($dist == 'suse') { $logfile = ''; }
				elseif($dist == 'gentoo') { $logfile = '/var/log/clamav/freshclam.log'; }
				if($dist == 'debian') { $logfile = '/var/log/clamav/clamav.log'; }
				elseif($dist == 'redhat') { $logfile = (is_file('/var/log/clamav/clamd.log') ? '/var/log/clamav/clamd.log' : '/var/log/maillog'); }
				elseif($dist == 'suse') { $logfile = ''; }
				elseif($dist == 'gentoo') { $logfile = '/var/log/clamav/clamd.log'; }
				if($dist == 'debian') { $logfile = '/var/log/fail2ban.log'; }
				elseif($dist == 'redhat') { $logfile = '/var/log/fail2ban.log'; }
				elseif($dist == 'suse') { $logfile = '/var/log/fail2ban.log'; }
				elseif($dist == 'gentoo') { $logfile = '/var/log/fail2ban.log'; }
				break;
			case 'log_ispconfig':
				if($dist == 'debian') { $logfile = $conf['ispconfig_log_dir'].'/ispconfig.log'; }
				elseif($dist == 'redhat') { $logfile = $conf['ispconfig_log_dir'].'/ispconfig.log'; }
				elseif($dist == 'suse') { $logfile = $conf['ispconfig_log_dir'].'/ispconfig.log'; }
				elseif($dist == 'gentoo') { $logfile = $conf['ispconfig_log_dir'].'/ispconfig.log'; }
				break;
			default:
				$logfile = '';
				break;
		}

		// Getting the logfile content
		if($logfile != '') {
			$logfile = escapeshellcmd($logfile);
			if(stristr($logfile, ';') or substr($logfile,0,9) != '/var/log/' or stristr($logfile, '..')) {
				$log = 'Logfile path error.';
			}
			else {
				$log = '';
				if(is_readable($logfile)) {
					if($fd = popen('tail -n 100 '.$logfile, 'r')) {
						while (!feof($fd)) {
							$log .= fgets($fd, 4096);
							$n++;
							if($n > 1000) break;
						}
						fclose($fd);
					}
				} else {
					$log = 'Unable to read '.$logfile;
				}
			}
		}

		return $log;
	}

	function _checkTcp ($host,$port) {

		$fp = @fsockopen ($host, $port, $errno, $errstr, 2);

		if ($fp) {
			fclose($fp);
			return true;
		} else {
			return false;
		}
	}

	function _checkUdp ($host,$port) {

		$fp = @fsockopen ('udp://'.$host, $port, $errno, $errstr, 2);

		if ($fp) {
			fclose($fp);
			return true;
		} else {
			return false;
		}
	}

	function _checkFtp ($host,$port) {

		$conn_id = @ftp_connect($host, $port);

		if($conn_id) {
			@ftp_close($conn_id);
			return true;
		} else {
			return false;
		}
	}

	/*
     Deletes Records older than n.
	*/
	function _delOldRecords($type, $min, $hour=0, $days=0) {
		global $app;

		$now = time();
		$old = $now - ($min * 60) - ($hour * 60 * 60) - ($days * 24 * 60 * 60);
		$sql = 'DELETE FROM monitor_data ' .
				'WHERE ' .
				'type =' . "'" . $app->dbmaster->quote($type) . "' " .
				'AND ' .
				'created < ' . $old;
     * Set the state to the given level (or higher, but not lesser).
     * * If the actual state is critical and you call the method with ok,
     *   then the state is critical.
     *
     * * If the actual state is critical and you call the method with error,
     *   then the state is error.
	*/
	function _setState($oldState, $newState) {
		/*
         * Calculate the weight of the old state
		*/
		switch ($oldState) {
			case 'no_state': $oldInt = 0;
				break;
			case 'ok': $oldInt = 1;
				break;
			case 'unknown': $oldInt = 2;
				break;
			case 'info': $oldInt = 3;
				break;
			case 'warning': $oldInt = 4;
				break;
			case 'critical': $oldInt = 5;
				break;
			case 'error': $oldInt = 6;
				break;
		}
		/*
         * Calculate the weight of the new state
		*/
		switch ($newState) {
			case 'no_state': $newInt = 0 ;
				break;
			case 'ok': $newInt = 1 ;
				break;
			case 'unknown': $newInt = 2 ;
				break;
			case 'info': $newInt = 3 ;
				break;
			case 'warning': $newInt = 4 ;
				break;
			case 'critical': $newInt = 5 ;
				break;
			case 'error': $newInt = 6 ;
				break;
		}

		/*
		*/
		if ($newInt > $oldInt) {
			return $newState;
		}
		else {
			return $oldState;
		}
	}

	function _getIntArray($line) {
		/** The array of float found */
		$res = array();
		/* First build a array from the line */
		$data = explode(' ', $line);
		/* then check if any item is a float */
		foreach ($data as $item) {
			if ($item . '' == (int)$item . '') {
				$res[] = $item;
			}
		}
		return $res;
	}
}