tbrehm
2009-09-03 5421462b39a5b41014569af59d3861b9ffe8a44f
commit | author | age
0d0cd9 1 <?php
V 2 /*
fb4c27 3 Copyright (c) 2007-2008, Till Brehm, projektfarm Gmbh and Oliver Vogel www.muv.com
0d0cd9 4 All rights reserved.
V 5
6 Redistribution and use in source and binary forms, with or without modification,
7 are permitted provided that the following conditions are met:
8
9     * Redistributions of source code must retain the above copyright notice,
10       this list of conditions and the following disclaimer.
11     * Redistributions in binary form must reproduce the above copyright notice,
12       this list of conditions and the following disclaimer in the documentation
13       and/or other materials provided with the distribution.
14     * Neither the name of ISPConfig nor the names of its contributors
15       may be used to endorse or promote products derived from this software without
16       specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
436ed8 29
0d0cd9 30 class monitor_core_module {
8793b3 31     /* TODO: this should be a config - var instead of a "constant" */
V 32     var $interval = 5; // do the monitoring every 5 minutes
0d0cd9 33
8793b3 34     var $module_name = 'monitor_core_module';
V 35     var $class_name = 'monitor_core_module';
36     /* No actions at this time. maybe later... */
37     var $actions_available = array();
bf47aa 38
392450 39     //* This function is called during ispconfig installation to determine
T 40     //  if a symlink shall be created for this plugin.
41     function onInstall() {
42         global $conf;
43         
44         return true;
45         
46     }
47     
48     /*
8793b3 49         This function is called when the module is loaded
V 50     */
51     function onLoad() {
52         global $app;
bf47aa 53
8793b3 54         /*
V 55         Annonce the actions that where provided by this module, so plugins
56         can register on them.
57         */
58         /* none at them moment */
59         //$app->plugins->announceEvents($this->module_name,$this->actions_available);
b7489f 60
8793b3 61         /*
V 62         As we want to get notified of any changes on several database tables,
63         we register for them.
b7489f 64
8793b3 65         The following function registers the function "functionname"
V 66             to be executed when a record for the table "dbtable" is
67             processed in the sys_datalog. "classname" is the name of the
68             class that contains the function functionname.
69         */
70         /* none at them moment */
71         //$app->modules->registerTableHook('mail_access','mail_module','process');
b7489f 72
8793b3 73         /*
V 74         Do the monitor every n minutes and write the result in the db
75         */
76         $min = date('i');
77         if (($min % $this->interval) == 0)
78         {
79             $this->doMonitor();
80         }
81     }
82
83     /*
84      This function is called when a change in one of the registered tables is detected.
85      The function then raises the events for the plugins.
86     */
87     function process($tablename, $action, $data) {
88         //        global $app;
89         //
90         //        switch ($tablename) {
91         //            case 'mail_access':
92         //                if($action == 'i') $app->plugins->raiseEvent('mail_access_insert',$data);
93         //                if($action == 'u') $app->plugins->raiseEvent('mail_access_update',$data);
94         //                if($action == 'd') $app->plugins->raiseEvent('mail_access_delete',$data);
95         //                break;
96         //        } // end switch
97     } // end function
98
99     /*
100     This method is called every n minutes, when the module ist loaded.
101     The method then does a system-monitoring
102     */
103     // TODO: what monitoring is done should be a config-var
104     function doMonitor()
105     {
106         /* Calls the single Monitoring steps */
107         $this->monitorServer();
108         $this->monitorDiskUsage();
109         $this->monitorMemUsage();
110         $this->monitorCpu();
111         $this->monitorServices();
112         $this->monitorMailLog();
113         $this->monitorMailWarnLog();
114         $this->monitorMailErrLog();
115         $this->monitorMessagesLog();
641cb3 116         $this->monitorISPCCronLog();
8793b3 117         $this->monitorFreshClamLog();
V 118         $this->monitorClamAvLog();
119         $this->monitorIspConfigLog();
716255 120         $this->monitorSystemUpdate();
V 121         $this->monitorMailQueue();
36d307 122         $this->monitorRaid();
V 123         $this->monitorRkHunter();
476a60 124         $this->monitorFail2ban();
671a41 125         $this->monitorSysLog();
8793b3 126     }
V 127
128     function monitorServer(){
129         global $app;
130         global $conf;
131
132         /* the id of the server as int */
133         $server_id = intval($conf["server_id"]);
134
135         /** The type of the data */
136         $type = 'server_load';
137
138         /*
139         Fetch the data into a array
140         */
141         $procUptime = shell_exec("cat /proc/uptime | cut -f1 -d' '");
142         $data['up_days'] = floor($procUptime/86400);
143         $data['up_hours'] = floor(($procUptime-$data['up_days']*86400)/3600);
144         $data['up_minutes'] = floor(($procUptime-$data['up_days']*86400-$data['up_hours']*3600)/60);
145
146         $data['uptime'] = shell_exec("uptime");
147
fb4c27 148         $tmp = explode(",", $data['uptime'], 4);
V 149         $tmpUser = explode(" ", trim($tmp[2]));
8793b3 150         $data['user_online'] = intval($tmpUser[0]);
V 151
fb4c27 152         $loadTmp = explode(":" , trim($tmp[3]));
8793b3 153         $load = explode(",",  $loadTmp[1]);
V 154         $data['load_1'] = floatval(trim($load[0]));
155         $data['load_5'] = floatval(trim($load[1]));
156         $data['load_15'] = floatval(trim($load[2]));
157
158         /** The state of the server-load. */
159         $state = 'ok';
160         if ($data['load_1'] > 20 ) $state = 'info';
161         if ($data['load_1'] > 50 ) $state = 'warning';
162         if ($data['load_1'] > 100 ) $state = 'critical';
163         if ($data['load_1'] > 150 ) $state = 'error';
164
165         /*
166         Insert the data into the database
167         */
168         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
169             "VALUES (".
170         $server_id . ", " .
273547 171             "'" . $app->dbmaster->quote($type) . "', " .
8793b3 172         time() . ", " .
273547 173             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
8793b3 174             "'" . $state . "'" .
V 175             ")";
bfbabf 176         $app->dbmaster->query($sql);
fb4c27 177
V 178         /* The new data is written, now we can delete the old one */
179         $this->_delOldRecords($type, 10);
8793b3 180     }
V 181
182     function monitorDiskUsage() {
183         global $app;
184         global $conf;
185
186         /* the id of the server as int */
187         $server_id = intval($conf["server_id"]);
188
189         /** The type of the data */
190         $type = 'disk_usage';
191
192         /** The state of the disk-usage */
193         $state = 'ok';
194
2ae58a 195         /** Fetch the data of ALL devices into a array (needed for monitoring!)*/
V 196         $dfData = shell_exec("df -hT");
8793b3 197
V 198         // split into array
199         $df = explode("\n", $dfData);
200
201         /*
202          * ignore the first line, process the rest
203          */
204         for($i=1; $i <= sizeof($df); $i++){
205             if ($df[$i] != '')
206             {
207                 /*
208                  * Make a array of the data
209                  */
210                 $s = preg_split ("/[\s]+/", $df[$i]);
211                 $data[$i]['fs'] = $s[0];
e403c9 212                 $data[$i]['type'] = $s[1];
A 213                 $data[$i]['size'] = $s[2];
214                 $data[$i]['used'] = $s[3];
215                 $data[$i]['available'] = $s[4];
216                 $data[$i]['percent'] = $s[5];
217                 $data[$i]['mounted'] = $s[6];
8793b3 218                 /*
V 219                  * calculate the state
220                  */
221                 $usePercent = floatval($data[$i]['percent']);
0239ac 222                 
T 223                 //* We dont want to check the cdrom drive as a cd / dvd is always 100% full
68e917 224                 if($data[$i]['type'] != 'iso9660' && $data[$i]['type'] != 'cramfs' && $data[$i]['type'] != 'udf') {
0239ac 225                     if ($usePercent > 75) $state = $this->_setState($state, 'info');
T 226                     if ($usePercent > 80) $state = $this->_setState($state, 'warning');
227                     if ($usePercent > 90) $state = $this->_setState($state, 'critical');
228                     if ($usePercent > 95) $state = $this->_setState($state, 'error');
229                 }
8793b3 230             }
V 231         }
232
233
234         /*
235         Insert the data into the database
236         */
237         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
238             "VALUES (".
239         $server_id . ", " .
273547 240             "'" . $app->dbmaster->quote($type) . "', " .
8793b3 241         time() . ", " .
273547 242             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
8793b3 243             "'" . $state . "'" .
V 244             ")";
bfbabf 245         $app->dbmaster->query($sql);
fb4c27 246
V 247         /* The new data is written, now we can delete the old one */
248         $this->_delOldRecords($type, 10);
8793b3 249     }
V 250
251
252     function monitorMemUsage()
253     {
254         global $app;
255         global $conf;
256
257         /* the id of the server as int */
258         $server_id = intval($conf["server_id"]);
259
260         /** The type of the data */
261         $type = 'mem_usage';
262
263         /*
264         Fetch the data into a array
265         */
266         $miData = shell_exec("cat /proc/meminfo");
267
268         $memInfo = explode("\n", $miData);
269
270         foreach($memInfo as $line){
043a0a 271             $part = preg_split("/:/", $line);
8793b3 272             $key = trim($part[0]);
V 273             $tmp = explode(" ", trim($part[1]));
274             $value = 0;
275             if ($tmp[1] == 'kB') $value = $tmp[0] * 1024;
276             $data[$key] = $value;
277         }
278
279         /*
280          * actually this info has no state.
281          * maybe someone knows better...???...
282          */
283         $state = 'no_state';
284
285         /*
286         Insert the data into the database
287         */
288         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
289             "VALUES (".
290         $server_id . ", " .
273547 291             "'" . $app->dbmaster->quote($type) . "', " .
8793b3 292         time() . ", " .
273547 293             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
8793b3 294             "'" . $state . "'" .
V 295             ")";
bfbabf 296         $app->dbmaster->query($sql);
fb4c27 297
V 298         /* The new data is written, now we can delete the old one */
299         $this->_delOldRecords($type, 10);
8793b3 300     }
V 301
302
303     function monitorCpu()
304     {
305         global $app;
306         global $conf;
307
308         /* the id of the server as int */
309         $server_id = intval($conf["server_id"]);
310
311         /** The type of the data */
312         $type = 'cpu_info';
313
314         /*
315         Fetch the data into a array
316         */
317         $cpuData = shell_exec("cat /proc/cpuinfo");
318         $cpuInfo = explode("\n", $cpuData);
1fd9f1 319         $processor = 0;
8793b3 320
V 321         foreach($cpuInfo as $line){
1fd9f1 322             
T 323             $part = preg_split("/:/", $line);
8793b3 324             $key = trim($part[0]);
V 325             $value = trim($part[1]);
1fd9f1 326             if($key == 'processor') $processor = intval($value);
9e64a7 327             if($key != '') $data[$key.' '.$processor] = $value;
8793b3 328         }
V 329
330         /* the cpu has no state. It is, what it is */
331         $state = 'no_state';
332
333         /*
334         Insert the data into the database
335         */
336         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
337             "VALUES (".
338         $server_id . ", " .
273547 339             "'" . $app->dbmaster->quote($type) . "', " .
8793b3 340         time() . ", " .
273547 341             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
8793b3 342             "'" . $state . "'" .
V 343             ")";
bfbabf 344         $app->dbmaster->query($sql);
fb4c27 345
V 346         /* The new data is written, now we can delete the old one */
347         $this->_delOldRecords($type, 10);
8793b3 348     }
V 349
350
351     function monitorServices()
352     {
353         global $app;
354         global $conf;
355
356         /** the id of the server as int */
357         $server_id = intval($conf["server_id"]);
358
359         /** get the "active" Services of the server from the DB */
bfbabf 360         $services = $app->dbmaster->queryOneRecord("SELECT * FROM server WHERE server_id = " . $server_id);
8793b3 361
V 362         /* The type of the Monitor-data */
363         $type = 'services';
364
365         /** the State of the monitoring */
366         /* ok, if ALL aktive services are running,
367          * error, if not
368          * There is no other state!
369          */
370         $state = 'ok';
371
372         /* Monitor Webserver */
373         $data['webserver'] = -1; // unknown - not needed
374         if ($services['web_server'] == 1)
375         {
376             if($this->_checkTcp('localhost', 80)) {
377                 $data['webserver'] = 1;
378             } else {
379                 $data['webserver'] = 0;
380                 $state = 'error'; // because service is down
381             }
382         }
383
384         /* Monitor FTP-Server */
385         $data['ftpserver'] = -1; // unknown - not needed
386         if ($services['file_server'] == 1)
387         {
388             if($this->_checkFtp('localhost', 21)) {
389                 $data['ftpserver'] = 1;
390             } else {
391                 $data['ftpserver'] = 0;
392                 $state = 'error'; // because service is down
393             }
394         }
395
396         /* Monitor SMTP-Server */
397         $data['smtpserver'] = -1; // unknown - not needed
398         if ($services['mail_server'] == 1)
399         {
400             if($this->_checkTcp('localhost', 25)) {
401                 $data['smtpserver'] = 1;
402             } else {
403                 $data['smtpserver'] = 0;
404                 $state = 'error'; // because service is down
405             }
406         }
407
408         /* Monitor POP3-Server */
409         $data['pop3server'] = -1; // unknown - not needed
410         if ($services['mail_server'] == 1)
411         {
412             if($this->_checkTcp('localhost', 110)) {
413                 $data['pop3server'] = 1;
414             } else {
415                 $data['pop3server'] = 0;
416                 $state = 'error'; // because service is down
417             }
418         }
419
420         /* Monitor IMAP-Server */
421         $data['imapserver'] = -1; // unknown - not needed
422         if ($services['mail_server'] == 1)
423         {
424             if($this->_checkTcp('localhost', 143)) {
425                 $data['imapserver'] = 1;
426             } else {
427                 $data['imapserver'] = 0;
428                 $state = 'error'; // because service is down
429             }
430         }
431
432         /* Monitor BIND-Server */
433         $data['bindserver'] = -1; // unknown - not needed
434         if ($services['dns_server'] == 1)
435         {
436             if($this->_checkTcp('localhost', 53)) {
437                 $data['bindserver'] = 1;
438             } else {
439                 $data['bindserver'] = 0;
440                 $state = 'error'; // because service is down
441             }
442         }
443
444         /* Monitor MYSQL-Server */
445         $data['mysqlserver'] = -1; // unknown - not needed
446         if ($services['db_server'] == 1)
447         {
448             if($this->_checkTcp('localhost', 3306)) {
449                 $data['mysqlserver'] = 1;
450             } else {
451                 $data['mysqlserver'] = 0;
452                 $state = 'error'; // because service is down
453             }
454         }
455
456
457         /*
458         Insert the data into the database
459         */
460         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
461             "VALUES (".
462         $server_id . ", " .
273547 463             "'" . $app->dbmaster->quote($type) . "', " .
8793b3 464         time() . ", " .
273547 465             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
8793b3 466             "'" . $state . "'" .
V 467             ")";
bfbabf 468         $app->dbmaster->query($sql);
8793b3 469
fb4c27 470         /* The new data is written, now we can delete the old one */
V 471         $this->_delOldRecords($type, 10);
8793b3 472     }
716255 473
V 474
475     function monitorSystemUpdate(){
476         /*
fb4c27 477          *  This monitoring is expensive, so do it only once a hour
716255 478          */
V 479         $min = date('i');
fb4c27 480         if ($min != 0) return;
716255 481
V 482         /*
483          * OK - here we go...
484          */
485         global $app;
486         global $conf;
487
488         /* the id of the server as int */
489         $server_id = intval($conf["server_id"]);
490
491         /** The type of the data */
492         $type = 'system_update';
493
36d307 494         /* This monitoring is only available at debian or Ubuntu */
V 495         if(file_exists('/etc/debian_version')){
716255 496
36d307 497             /*
V 498              * first update the "update-database"
499              */
500             shell_exec('apt-get update');
716255 501
36d307 502             /*
V 503              * Then test the upgrade.
504              * if there is any output, then there is a needed update
505              */
506             $aptData = shell_exec('apt-get -s -qq dist-upgrade');
507             if ($aptData == '')
508             {
509                 /* There is nothing to update! */
510                 $state = 'ok';
511             }
512             else
513             {
514                 /* There is something to update! */
515                 $state = 'warning';
516             }
517
518             /*
519              * Fetch the output
520              */
521             $data['output'] = shell_exec('apt-get -s -q dist-upgrade');
522         }
523         else {
524             /*
525              * It is not debian/Ubuntu, so there is no data and no state
526              *
527              * no_state, NOT unknown, because "unknown" is shown as state
528              * inside the GUI. no_state is hidden.
529              *
530              * We have to write NO DATA inside the DB, because the GUI
531              * could not know, if there is any dat, or not...
532              */
533             $state = 'no_state';
534             $data['output']= '';
535         }
716255 536
V 537         /*
538          * Insert the data into the database
539          */
540         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
541             "VALUES (".
542         $server_id . ", " .
273547 543             "'" . $app->dbmaster->quote($type) . "', " .
716255 544         time() . ", " .
273547 545             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
716255 546             "'" . $state . "'" .
V 547             ")";
bfbabf 548         $app->dbmaster->query($sql);
fb4c27 549
V 550         /* The new data is written, now we can delete the old one */
551         $this->_delOldRecords($type, 0, 2);
716255 552     }
V 553
554     function monitorMailQueue(){
555         global $app;
556         global $conf;
557
558         /* the id of the server as int */
559         $server_id = intval($conf["server_id"]);
560
561         /** The type of the data */
562         $type = 'mailq';
563
564         /* Get the data from the mailq */
565         $data['output'] = shell_exec('mailq');
566
567         /*
568          *  The last line has more informations
569          */
570         $tmp = explode("\n", $data['output']);
571         $more = $tmp[sizeof($tmp) - 1];
572         $this->_getIntArray($more);
573         $data['bytes'] = $res[0];
574         $data['requests'] = $res[1];
575
576         /** The state of the mailq. */
577         $state = 'ok';
578         if ($data['requests'] > 2000 ) $state = 'info';
579         if ($data['requests'] > 5000 ) $state = 'warning';
580         if ($data['requests'] > 8000 ) $state = 'critical';
581         if ($data['requests'] > 10000 ) $state = 'error';
582
583         /*
584          * Insert the data into the database
585          */
586         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
587             "VALUES (".
588         $server_id . ", " .
273547 589             "'" . $app->dbmaster->quote($type) . "', " .
716255 590         time() . ", " .
273547 591             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
716255 592             "'" . $state . "'" .
V 593             ")";
bfbabf 594         $app->dbmaster->query($sql);
fb4c27 595
V 596         /* The new data is written, now we can delete the old one */
597         $this->_delOldRecords($type, 10);
716255 598     }
V 599
36d307 600
V 601     function monitorRaid(){
602         global $app;
603         global $conf;
604
605         /* the id of the server as int */
606         $server_id = intval($conf["server_id"]);
607
608         /** The type of the data */
609         $type = 'raid_state';
610
611         /* This monitoring is only available if mdadm is installed */
9dbd28 612         $location = system('which mdadm', $retval);
F 613         if($retval === 0){
36d307 614             /*
V 615              * Fetch the output
616              */
617             $data['output'] = shell_exec('cat /proc/mdstat');
618
619             /*
620              * Then calc the state.
621              */
622             $tmp = explode("\n", $data['output']);
623             $state = 'ok';
fb4c27 624             for ($i = 0; $i < sizeof($tmp); $i++){
V 625                 /* fetch the next line */
626                 $line = $tmp[$i];
627
628                 if ((strpos($line, '[U_]') !== false) || (strpos($line, '[_U]') !== false))
36d307 629                 {
fb4c27 630                     /* One Disk is not working.
V 631                      * if the next line starts with "[>" or "[=" then
632                      * recovery (resync) is in state and the state is
633                      * information instead of critical
634                      */
635                     $nextLine = $tmp[$i+1];
636                     if ((strpos($nextLine, '[>') === false) && (strpos($nextLine, '[=') === false)) {
637                         $state = $this->_setState($state, 'critical');
638                     }
639                     else
640                     {
641                         $state = $this->_setState($state, 'info');
642                     }
36d307 643                 }
fb4c27 644                 if (strpos($line, '[__]') !== false)
36d307 645                 {
V 646                     /* both Disk are not working */
647                     $state = $this->_setState($state, 'error');
648                 }
abc09d 649                 if (strpos($line, '[UU]') !== false)
V 650                 {
651                     /* The disks are OK.
652                      * if the next line starts with "[>" or "[=" then
653                      * recovery (resync) is in state and the state is
654                      * information instead of ok
655                      */
656                     $nextLine = $tmp[$i+1];
657                     if ((strpos($nextLine, '[>') === false) && (strpos($nextLine, '[=') === false)) {
658                         $state = $this->_setState($state, 'ok');
659                     }
660                     else
661                     {
662                         $state = $this->_setState($state, 'info');
663                     }
664                 }
36d307 665             }
V 666
667         }
668         else {
669             /*
670              * mdadm is not installed, so there is no data and no state
671              *
672              * no_state, NOT unknown, because "unknown" is shown as state
673              * inside the GUI. no_state is hidden.
674              *
675              * We have to write NO DATA inside the DB, because the GUI
676              * could not know, if there is any dat, or not...
677              */
678             $state = 'no_state';
679             $data['output']= '';
680         }
681
682         /*
683          * Insert the data into the database
684          */
685         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
686             "VALUES (".
687         $server_id . ", " .
273547 688             "'" . $app->dbmaster->quote($type) . "', " .
36d307 689         time() . ", " .
273547 690             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
36d307 691             "'" . $state . "'" .
V 692             ")";
bfbabf 693         $app->dbmaster->query($sql);
fb4c27 694
V 695         /* The new data is written, now we can delete the old one */
696         $this->_delOldRecords($type, 10);
36d307 697     }
V 698
699     function monitorRkHunter(){
fb4c27 700         /*
8c4aa3 701          *  This monitoring is expensive, so do it only once a day
fb4c27 702          */
V 703         $min = date('i');
24854c 704         $hour = date('H');
542146 705         if (!($min == 0 && $hour == 23)) return;
fb4c27 706
V 707         global $app;
708         global $conf;
709
710         /* the id of the server as int */
711         $server_id = intval($conf["server_id"]);
712
713         /** The type of the data */
714         $type = 'rkhunter';
715
716         /* This monitoring is only available if rkhunter is installed */
9dbd28 717         $location = system('which rkhunter', $retval);
F 718         if($retval === 0){
fb4c27 719             /*
V 720              * Fetch the output
721              */
179c91 722             $data['output'] = shell_exec('rkhunter --update --checkall --nocolors --skip-keypress');
fb4c27 723
V 724             /*
725              * At this moment, there is no state (maybe later)
726              */
727             $state = 'no_state';
728         }
729         else {
730             /*
731              * rkhunter is not installed, so there is no data and no state
732              *
733              * no_state, NOT unknown, because "unknown" is shown as state
734              * inside the GUI. no_state is hidden.
735              *
736              * We have to write NO DATA inside the DB, because the GUI
737              * could not know, if there is any dat, or not...
738              */
739             $state = 'no_state';
740             $data['output']= '';
741         }
742
743         /*
744          * Insert the data into the database
745          */
746         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
747             "VALUES (".
748         $server_id . ", " .
273547 749             "'" . $app->dbmaster->quote($type) . "', " .
fb4c27 750         time() . ", " .
273547 751             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
fb4c27 752             "'" . $state . "'" .
V 753             ")";
bfbabf 754         $app->dbmaster->query($sql);
fb4c27 755
V 756         /* The new data is written, now we can delete the old one */
757         $this->_delOldRecords($type, 0, 2);
36d307 758     }
8793b3 759
476a60 760     function monitorFail2ban(){
V 761         global $app;
762         global $conf;
763
764         /* the id of the server as int */
765         $server_id = intval($conf["server_id"]);
766
767         /** The type of the data */
768         $type = 'log_fail2ban';
769
770         /* This monitoring is only available if fail2ban is installed */
65bfb9 771         $location = system('which fail2ban-client', $retval); // Debian, Ubuntu, Fedora
F 772         if($retval !== 0) $location = system('which fail2ban', $retval); // CentOS
9dbd28 773         if($retval === 0){
476a60 774             /*  Get the data of the log */
V 775             $data = $this->_getLogData($type);
776
777             /*
778              * At this moment, there is no state (maybe later)
779              */
780             $state = 'no_state';
781         }
782         else {
783             /*
784              * fail2ban is not installed, so there is no data and no state
785              *
786              * no_state, NOT unknown, because "unknown" is shown as state
787              * inside the GUI. no_state is hidden.
788              *
789              * We have to write NO DATA inside the DB, because the GUI
790              * could not know, if there is any dat, or not...
791              */
792             $state = 'no_state';
793             $data = '';
794         }
795
796         /*
797          * Insert the data into the database
798          */
799         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
800             "VALUES (".
801         $server_id . ", " .
802             "'" . $app->dbmaster->quote($type) . "', " .
803         time() . ", " .
804             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
805             "'" . $state . "'" .
806             ")";
807         $app->dbmaster->query($sql);
808
809         /* The new data is written, now we can delete the old one */
810         $this->_delOldRecords($type, 10);
811     }
812
671a41 813     function monitorSysLog(){
V 814         global $app;
815         global $conf;
816
817         /* the id of the server as int */
818         $server_id = intval($conf["server_id"]);
819
820         /** The type of the data */
821         $type = 'sys_log';
822
476a60 823         /*
V 824          * is there any warning or error for this server?
825          */
826         $state = 'ok';
671a41 827         $dbData = $app->dbmaster->queryAllRecords("SELECT loglevel FROM sys_log WHERE server_id = " . $server_id . " AND loglevel > 0");
476a60 828         if (is_array($dbData)) {
V 829             foreach($dbData as $item){
830             if ($item['loglevel'] == 1) $state = $this->_setState($state, 'warning');
831             if ($item['loglevel'] == 2) $state = $this->_setState($state, 'error');
832             }
833         }
671a41 834
476a60 835         /** There is no monitor-data because the data is in the sys_log table */
671a41 836         $data['output']= '';
V 837
838         /*
839          * Insert the data into the database
840          */
841         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
842             "VALUES (".
843         $server_id . ", " .
844             "'" . $app->dbmaster->quote($type) . "', " .
845         time() . ", " .
846             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
847             "'" . $state . "'" .
848             ")";
849         $app->dbmaster->query($sql);
850
851         /* The new data is written, now we can delete the old one */
852         $this->_delOldRecords($type, 10);
853     }
854
476a60 855     function monitorMailLog()
8793b3 856     {
V 857         global $app;
858         global $conf;
859
860         /* the id of the server as int */
861         $server_id = intval($conf["server_id"]);
862
863         /** The type of the data */
864         $type = 'log_mail';
865
866         /* Get the data of the log */
867         $data = $this->_getLogData($type);
868
869         /*
870          * actually this info has no state.
871          * maybe someone knows better...???...
872          */
873         $state = 'no_state';
874
875         /*
876         Insert the data into the database
877         */
878         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
879             "VALUES (".
880         $server_id . ", " .
273547 881             "'" . $app->dbmaster->quote($type) . "', " .
8793b3 882         time() . ", " .
273547 883             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
8793b3 884             "'" . $state . "'" .
V 885             ")";
bfbabf 886         $app->dbmaster->query($sql);
fb4c27 887
V 888         /* The new data is written, now we can delete the old one */
889         $this->_delOldRecords($type, 10);
8793b3 890     }
V 891
892     function monitorMailWarnLog()
893     {
894         global $app;
895         global $conf;
896
897         /* the id of the server as int */
898         $server_id = intval($conf["server_id"]);
899
900         /** The type of the data */
901         $type = 'log_mail_warn';
902
903         /* Get the data of the log */
904         $data = $this->_getLogData($type);
905
906         /*
907          * actually this info has no state.
908          * maybe someone knows better...???...
909          */
910         $state = 'no_state';
911
912         /*
913         Insert the data into the database
914         */
915         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
916             "VALUES (".
917         $server_id . ", " .
273547 918             "'" . $app->dbmaster->quote($type) . "', " .
8793b3 919         time() . ", " .
273547 920             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
8793b3 921             "'" . $state . "'" .
V 922             ")";
bfbabf 923         $app->dbmaster->query($sql);
fb4c27 924
V 925         /* The new data is written, now we can delete the old one */
926         $this->_delOldRecords($type, 10);
8793b3 927     }
V 928
929     function monitorMailErrLog()
930     {
931         global $app;
932         global $conf;
933
934         /* the id of the server as int */
935         $server_id = intval($conf["server_id"]);
936
937         /** The type of the data */
938         $type = 'log_mail_err';
939
940         /* Get the data of the log */
941         $data = $this->_getLogData($type);
942
943         /*
944          * actually this info has no state.
945          * maybe someone knows better...???...
946          */
947         $state = 'no_state';
948
949         /*
950         Insert the data into the database
951         */
952         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
953             "VALUES (".
954         $server_id . ", " .
273547 955             "'" . $app->dbmaster->quote($type) . "', " .
8793b3 956         time() . ", " .
273547 957             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
8793b3 958             "'" . $state . "'" .
V 959             ")";
bfbabf 960         $app->dbmaster->query($sql);
fb4c27 961
V 962         /* The new data is written, now we can delete the old one */
963         $this->_delOldRecords($type, 10);
8793b3 964     }
V 965
966
967     function monitorMessagesLog()
968     {
969         global $app;
970         global $conf;
971
972         /* the id of the server as int */
973         $server_id = intval($conf["server_id"]);
974
975         /** The type of the data */
976         $type = 'log_messages';
977
978         /* Get the data of the log */
979         $data = $this->_getLogData($type);
980
981         /*
982          * actually this info has no state.
983          * maybe someone knows better...???...
984          */
985         $state = 'no_state';
986
987         /*
988         Insert the data into the database
989         */
990         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
991             "VALUES (".
992         $server_id . ", " .
273547 993             "'" . $app->dbmaster->quote($type) . "', " .
8793b3 994         time() . ", " .
273547 995             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
8793b3 996             "'" . $state . "'" .
V 997             ")";
bfbabf 998         $app->dbmaster->query($sql);
fb4c27 999
V 1000         /* The new data is written, now we can delete the old one */
1001         $this->_delOldRecords($type, 10);
8793b3 1002     }
V 1003
641cb3 1004     function monitorISPCCronLog()
R 1005     {
1006         global $app;
1007         global $conf;
1008
1009         /* the id of the server as int */
1010         $server_id = intval($conf["server_id"]);
1011
1012         /** The type of the data */
1013         $type = 'log_ispc_cron';
1014
1015         /* Get the data of the log */
1016         $data = $this->_getLogData($type);
1017
1018         /*
1019          * actually this info has no state.
1020          * maybe someone knows better...???...
1021          */
1022         $state = 'no_state';
1023
1024         /*
1025         Insert the data into the database
1026         */
1027         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
1028             "VALUES (".
1029         $server_id . ", " .
1030             "'" . $app->dbmaster->quote($type) . "', " .
1031         time() . ", " .
1032             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
1033             "'" . $state . "'" .
1034             ")";
1035         $app->dbmaster->query($sql);
1036
1037         /* The new data is written, now we can delete the old one */
1038         $this->_delOldRecords($type, 10);
1039     }
1040     
8793b3 1041     function monitorFreshClamLog()
V 1042     {
1043         global $app;
1044         global $conf;
1045
1046         /* the id of the server as int */
1047         $server_id = intval($conf["server_id"]);
1048
1049         /** The type of the data */
1050         $type = 'log_freshclam';
1051
1052         /* Get the data of the log */
1053         $data = $this->_getLogData($type);
1054
fb4c27 1055         /* Get the data from the LAST log-Entry.
V 1056          * if there can be found:
1057          * WARNING: Your ClamAV installation is OUTDATED!
1058          * then the clamav is outdated. This is a warning!
1059          */
8793b3 1060         $state = 'ok';
fb4c27 1061
V 1062         $tmp = explode("\n", $data);
1063         $lastLog = array();
1064         if ($tmp[sizeof($tmp)-1] == "")
1065         {
1066             /* the log ends with an empty line remove this */
1067             array_pop($tmp);
1068         }
1069         if (strpos($tmp[sizeof($tmp)-1], "-------------") !== false)
1070         {
1071             /* the log ends with "-----..." remove this */
1072             array_pop($tmp);
1073         }
1074         for ($i = sizeof($tmp) -1; $i > 0; $i--){
1075             if (strpos($tmp[$i], "---------") === false){
1076                 /* no delimiter found, so add this to the last-log */
1077                 $lastLog[] = $tmp[$i];
1078             }
1079             else
1080             {
1081                 /* delimiter found, so there is no more line left! */
1082                 break;
1083             }
1084         }
1085
1086         /*
1087          * Now we have the last log in the array.
1088          * Check if the outdated-string is found...
1089          */
1090         foreach($lastLog as $line){
1091             if (strpos(strtolower($line), "outdated") !== false) {
1092                  $state = $this->_setState($state, 'warning');
1093             }
1094         }
8793b3 1095
V 1096         /*
1097         Insert the data into the database
1098         */
1099         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
1100             "VALUES (".
1101         $server_id . ", " .
273547 1102             "'" . $app->dbmaster->quote($type) . "', " .
8793b3 1103         time() . ", " .
273547 1104             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
8793b3 1105             "'" . $state . "'" .
V 1106             ")";
bfbabf 1107         $app->dbmaster->query($sql);
fb4c27 1108
V 1109         /* The new data is written, now we can delete the old one */
1110         $this->_delOldRecords($type, 10);
8793b3 1111     }
V 1112
1113     function monitorClamAvLog()
1114     {
1115         global $app;
1116         global $conf;
1117
1118         /* the id of the server as int */
1119         $server_id = intval($conf["server_id"]);
1120
1121         /** The type of the data */
1122         $type = 'log_clamav';
1123
1124         /* Get the data of the log */
1125         $data = $this->_getLogData($type);
1126
1127         // Todo: the state should be calculated.
1128         $state = 'ok';
1129
1130         /*
1131         Insert the data into the database
1132         */
1133         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
1134             "VALUES (".
1135         $server_id . ", " .
273547 1136             "'" . $app->dbmaster->quote($type) . "', " .
8793b3 1137         time() . ", " .
273547 1138             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
8793b3 1139             "'" . $state . "'" .
V 1140             ")";
bfbabf 1141         $app->dbmaster->query($sql);
36d307 1142
fb4c27 1143         /* The new data is written, now we can delete the old one */
V 1144         $this->_delOldRecords($type, 10);
8793b3 1145     }
V 1146
1147     function monitorIspConfigLog()
1148     {
1149         global $app;
1150         global $conf;
1151
1152         /* the id of the server as int */
1153         $server_id = intval($conf["server_id"]);
1154
1155         /** The type of the data */
1156         $type = 'log_ispconfig';
1157
1158         /* Get the data of the log */
1159         $data = $this->_getLogData($type);
1160
1161         // Todo: the state should be calculated.
1162         $state = 'ok';
1163
1164         /*
1165         Insert the data into the database
1166         */
1167         $sql = "INSERT INTO monitor_data (server_id, type, created, data, state) " .
1168             "VALUES (".
1169         $server_id . ", " .
273547 1170             "'" . $app->dbmaster->quote($type) . "', " .
8793b3 1171         time() . ", " .
273547 1172             "'" . $app->dbmaster->quote(serialize($data)) . "', " .
8793b3 1173             "'" . $state . "'" .
V 1174             ")";
bfbabf 1175         $app->dbmaster->query($sql);
fb4c27 1176
V 1177         /* The new data is written, now we can delete the old one */
1178         $this->_delOldRecords($type, 10);
8793b3 1179     }
V 1180
1181
1182     function _getLogData($log){
ad9356 1183         
T 1184         $dist = '';
1185         $logfile = '';
1186         
1187         if(@is_file('/etc/debian_version')) $dist = 'debian';
1188         if(@is_file('/etc/redhat-release')) $dist = 'redhat';
1054a3 1189         if(@is_file('/etc/SuSE-release')) $dist = 'suse';
ad9356 1190         
T 1191         switch($log) {
8793b3 1192             case 'log_mail':
ad9356 1193                 if($dist == 'debian') $logfile = '/var/log/mail.log';
T 1194                 if($dist == 'redhat') $logfile = '/var/log/maillog';
1054a3 1195                 if($dist == 'suse') $logfile = '/var/log/mail.info';
8793b3 1196                 break;
V 1197             case 'log_mail_warn':
ad9356 1198                 if($dist == 'debian') $logfile = '/var/log/mail.warn';
T 1199                 if($dist == 'redhat') $logfile = '/var/log/maillog';
1054a3 1200                 if($dist == 'suse') $logfile = '/var/log/mail.warn';
8793b3 1201                 break;
V 1202             case 'log_mail_err':
ad9356 1203                 if($dist == 'debian') $logfile = '/var/log/mail.err';
T 1204                 if($dist == 'redhat') $logfile = '/var/log/maillog';
1054a3 1205                 if($dist == 'suse') $logfile = '/var/log/mail.err';
8793b3 1206                 break;
V 1207             case 'log_messages':
ad9356 1208                 if($dist == 'debian') $logfile = '/var/log/messages';
T 1209                 if($dist == 'redhat') $logfile = '/var/log/messages';
8418bd 1210                 if($dist == 'suse') $logfile = '/var/log/messages';
8793b3 1211                 break;
641cb3 1212             case 'log_ispc_cron':
ad9356 1213                 if($dist == 'debian') $logfile = '/var/log/ispconfig/cron.log';
T 1214                 if($dist == 'redhat') $logfile = '/var/log/ispconfig/cron.log';
1054a3 1215                 if($dist == 'suse') $logfile = '/var/log/ispconfig/cron.log';
641cb3 1216                 break;
8793b3 1217             case 'log_freshclam':
ad9356 1218                 if($dist == 'debian') $logfile = '/var/log/clamav/freshclam.log';
948245 1219                 if($dist == 'redhat') $logfile = (is_file('/var/log/clamav/freshclam.log') ? '/var/log/clamav/freshclam.log' : '/var/log/freshclam.log');
1054a3 1220                 if($dist == 'suse') $logfile = '';
T 1221                 break;
8793b3 1222             case 'log_clamav':
ad9356 1223                 if($dist == 'debian') $logfile = '/var/log/clamav/clamav.log';
948245 1224                 if($dist == 'redhat') $logfile = (is_file('/var/log/clamav/clamd.log') ? '/var/log/clamav/clamd.log' : '/var/log/maillog');
1054a3 1225                 if($dist == 'suse') $logfile = '';
8793b3 1226                 break;
476a60 1227             case 'log_fail2ban':
ad9356 1228                 if($dist == 'debian') $logfile = '/var/log/fail2ban.log';
T 1229                 if($dist == 'redhat') $logfile = '/var/log/fail2ban.log';
1054a3 1230                 if($dist == 'suse') $logfile = '/var/log/fail2ban.log';
476a60 1231                 break;
8793b3 1232             case 'log_ispconfig':
ad9356 1233                 if($dist == 'debian') $logfile = '/var/log/ispconfig/ispconfig.log';
T 1234                 if($dist == 'redhat') $logfile = '/var/log/ispconfig/ispconfig.log';
1054a3 1235                 if($dist == 'suse') $logfile = '/var/log/ispconfig/ispconfig.log';
8793b3 1236                 break;
V 1237             default:
1238                 $logfile = '';
1239                 break;
1240         }
1241
1242         // Getting the logfile content
1243         if($logfile != '') {
1244             $logfile = escapeshellcmd($logfile);
130cd4 1245             if(stristr($logfile, ';') or substr($logfile,0,9) != '/var/log/' or stristr($logfile, '..')) {
8793b3 1246                 $log = 'Logfile path error.';
V 1247             }
1248             else
1249             {
1250                 $log = '';
1251                 if(is_readable($logfile)) {
1252                     if($fd = popen("tail -n 100 $logfile", 'r')) {
1253                         while (!feof($fd)) {
1254                             $log .= fgets($fd, 4096);
1255                             $n++;
1256                             if($n > 1000) break;
1257                         }
1258                         fclose($fd);
1259                     }
1260                 } else {
1261                     $log = 'Unable to read '.$logfile;
1262                 }
1263             }
1264         }
1265
1266         return $log;
1267     }
1268
1269     function _checkTcp ($host,$port) {
1270
79d37f 1271         $fp = @fsockopen ($host, $port, $errno, $errstr, 2);
8793b3 1272
V 1273         if ($fp) {
1274             fclose($fp);
1275             return true;
1276         } else {
1277             return false;
1278         }
1279     }
1280
1281     function _checkUdp ($host,$port) {
1282
79d37f 1283         $fp = @fsockopen ('udp://'.$host, $port, $errno, $errstr, 2);
8793b3 1284
V 1285         if ($fp) {
1286             fclose($fp);
1287             return true;
1288         } else {
1289             return false;
1290         }
1291     }
1292
1293     function _checkFtp ($host,$port){
1294
1295         $conn_id = @ftp_connect($host, $port);
1296
1297         if($conn_id){
1298             @ftp_close($conn_id);
1299             return true;
1300         } else {
1301             return false;
1302         }
1303     }
1304
1305     /*
1306      Deletes Records older than n.
1307     */
1308     function _delOldRecords($type, $min, $hour=0, $days=0) {
1309         global $app;
1310
1311         $now = time();
1312         $old = $now - ($min * 60) - ($hour * 60 * 60) - ($days * 24 * 60 * 60);
1313         $sql = "DELETE FROM monitor_data " .
1314             "WHERE " .
273547 1315             "type =" . "'" . $app->dbmaster->quote($type) . "' " .
8793b3 1316             "AND " .
V 1317             "created < " . $old;
bfbabf 1318         $app->dbmaster->query($sql);
8793b3 1319     }
V 1320
1321     /*
1322      * Set the state to the given level (or higher, but not lesser).
1323      * * If the actual state is critical and you call the method with ok,
1324      *   then the state is critical.
1325      *
1326      * * If the actual state is critical and you call the method with error,
1327      *   then the state is error.
1328      */
1329     function _setState($oldState, $newState)
1330     {
1331         /*
1332          * Calculate the weight of the old state
1333          */
1334         switch ($oldState) {
1335             case 'no_state': $oldInt = 0;
1336                 break;
1337             case 'ok': $oldInt = 1;
1338                 break;
1339             case 'unknown': $oldInt = 2;
1340                 break;
1341             case 'info': $oldInt = 3;
1342                 break;
1343             case 'warning': $oldInt = 4;
1344                 break;
1345             case 'critical': $oldInt = 5;
1346                 break;
1347             case 'error': $oldInt = 6;
1348                 break;
1349         }
1350         /*
1351          * Calculate the weight of the new state
1352          */
1353         switch ($newState) {
1354             case 'no_state': $newInt = 0 ;
1355                 break;
a2e689 1356             case 'ok': $newInt = 1 ;
8793b3 1357                 break;
a2e689 1358             case 'unknown': $newInt = 2 ;
8793b3 1359                 break;
V 1360             case 'info': $newInt = 3 ;
1361                 break;
1362             case 'warning': $newInt = 4 ;
1363                 break;
1364             case 'critical': $newInt = 5 ;
1365                 break;
1366             case 'error': $newInt = 6 ;
1367                 break;
1368         }
1369
1370         /*
1371          * Set to the higher level
1372          */
1373         if ($newInt > $oldInt){
1374             return $newState;
1375         }
1376         else
1377         {
1378             return $oldState;
1379         }
1380     }
1381
716255 1382     function _getIntArray($line){
V 1383         /** The array of float found */
1384         $res = array();
1385         /* First build a array from the line */
1386         $data = explode(' ', $line);
1387         /* then check if any item is a float */
1388         foreach ($data as $item) {
1389             if ($item . '' == (int)$item . ''){
1390                 $res[] = $item;
1391             }
1392         }
1393         return $res;
1394     }
1395
8793b3 1396
0d0cd9 1397 } // end class
V 1398
e403c9 1399 ?>