Passed
Push — master ( 6ce43c...1031ec )
by Patrick
01:53
created

Trap::trapLog()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 2
b 0
f 0
nc 1
nop 3
dl 0
loc 4
rs 10
1
<?php
2
3
namespace Trapdirector;
4
5
use Icinga\Module\Trapdirector\Icinga2API;
6
use Exception;
7
use stdClass as stdClass;
8
use PDO;
9
10
/**
11
 * Main Trapdirector trap manager 
12
 * 
13
 * @license GPL
14
 * @author Patrick Proy
15
 * @package Trapdirector
16
 * @subpackage Processing
17
 */
18
class Trap
19
{
20
    use TrapConfig;
0 ignored issues
show
introduced by
The trait Trapdirector\TrapConfig requires some properties which are not provided by Trapdirector\Trap: $outputMode, $debugLevel, $outputFile
Loading history...
21
    
22
    // Configuration files and dirs
23
    /** @var string Icinga etc path */
24
    protected $icingaweb2Etc;
25
    /** @var string $trapModuleConfig config.ini of module */
26
    protected $trapModuleConfig;
27
    /** @var string $icingaweb2Ressources resources.ini of icingaweb2 */
28
    protected $icingaweb2Ressources;
29
    // Options from config.ini (default values)
30
    /** @var string $snmptranslate */
31
    protected $snmptranslate='/usr/bin/snmptranslate';
32
    /** @var string $snmptranslate_dirs */
33
    protected $snmptranslate_dirs='/usr/share/icingaweb2/modules/trapdirector/mibs';
34
    /** @var string $icinga2cmd */
35
    protected $icinga2cmd='/var/run/icinga2/cmd/icinga2.cmd';
36
    /** @var string $dbPrefix */
37
    protected $dbPrefix='traps_';
38
    
39
    // API
40
    /** @var boolean $apiUse */
41
    protected $apiUse=false;
42
    /** @var Icinga2API $icinga2api */
43
    protected $icinga2api=null;
44
    /** @var string $apiHostname */
45
    protected $apiHostname='';
46
    /** @var integer $apiPort */
47
    protected $apiPort=0;
48
    /** @var string $apiUsername */
49
    protected $apiUsername='';
50
    /** @var string $apiPassword */
51
    protected $apiPassword='';
52
    
53
    // Logs
54
    /** @var Logging Logging class. */
55
    public $logging;    //< Logging class.
56
    /** @var bool true if log was setup in constructor */
57
    protected $logSetup;   //< bool true if log was setup in constructor
58
    
59
    // Databases
60
    /** @var Database $trapsDB  Database class*/
61
    public $trapsDB = null;
62
    
63
    // Trap received data
64
    protected $receivingHost;
65
    /** @var array	Main trap data (oid, source...) */
66
    public $trapData=array();
67
    /** @var array $trapDataExt Additional trap data objects (oid/value).*/
68
    public $trapDataExt=array(); 
69
    /** @var int $trapId trap_id after sql insert*/
70
    public $trapId=null;
71
    /** @var string $trapAction trap action for final write*/
72
    public $trapAction=null;
73
    /** @var boolean $trapToDb log trap to DB */
74
    protected $trapToDb=true;
75
    
76
    /** @var Mib mib class */
77
    public $mibClass = null;
78
    
79
    /** @var Rule rule class */
80
    public $ruleClass = null;
81
    
82
    /** @var Plugins plugins manager **/
83
    public $pluginClass = null;
84
    
85
    function __construct($etcDir='/etc/icingaweb2',$baseLogLevel=null,$baseLogMode='syslog',$baseLogFile='')
86
    {
87
        // Paths of ini files
88
        $this->icingaweb2Etc=$etcDir;
89
        $this->trapModuleConfig=$this->icingaweb2Etc."/modules/trapdirector/config.ini";
90
        $this->icingaweb2Ressources=$this->icingaweb2Etc."/resources.ini";
91
        
92
        //************* Setup logging
93
        $this->logging = new Logging();
94
        if ($baseLogLevel != null)
95
        {
96
            $this->logging->setLogging($baseLogLevel, $baseLogMode,$baseLogFile);
97
            $this->logSetup=true;
98
        }
99
        else
100
        {
101
            $this->logSetup=false;
102
        }
103
        $this->logging->log('Loggin started', INFO);
104
        
105
        //*************** Get options from ini files
106
        if (! is_file($this->trapModuleConfig))
107
        {
108
            throw new Exception("Ini file ".$this->trapModuleConfig." does not exists");
109
        }
110
        $trapConfig=parse_ini_file($this->trapModuleConfig,true);
111
        if ($trapConfig == false)
112
        {
113
            $this->logging->log("Error reading ini file : ".$this->trapModuleConfig,ERROR,'syslog');
114
            throw new Exception("Error reading ini file : ".$this->trapModuleConfig);
115
        }
116
        $this->getMainOptions($trapConfig); // Get main options from ini file
117
        
118
        //*************** Setup database class & get options
119
        $this->setupDatabase($trapConfig);
120
        
121
        $this->getDatabaseOptions(); // Get options in database
122
        
123
        //*************** Setup API
124
        if ($this->apiUse === true) $this->getAPI(); // Setup API
125
        
126
        //*************** Setup MIB
127
        $this->mibClass = new Mib($this->logging,$this->trapsDB,$this->snmptranslate,$this->snmptranslate_dirs); // Create Mib class
128
        
129
        //*************** Setup Rule
130
        $this->ruleClass = new Rule($this); //< Create Rule class
131
        
132
        $this->trapData=array(  // TODO : put this in a reset function (DAEMON_MODE)
133
            'source_ip'	=> 'unknown',
134
            'source_port'	=> 'unknown',
135
            'destination_ip'	=> 'unknown',
136
            'destination_port'	=> 'unknown',
137
            'trap_oid'	=> 'unknown'
138
        );
139
        
140
        //*************** Setup Plugins
141
        //Create plugin class. Plugins are not loaded here, but by calling registerAllPlugins
142
        $this->pluginClass = new Plugins($this);
143
            
144
            
145
    }
146
147
    /** @return \Trapdirector\Logging   */
148
    public function getLogging()
149
    {
150
        return $this->logging;
151
    }
152
    
153
    /** @return \Trapdirector\Database */
154
    public function getTrapsDB()
155
    {
156
        return $this->trapsDB;
157
    }
158
    
159
    /** OBSOLETE Send log. Throws exception on critical error
160
     *	@param	string $message Message to log
161
     *	@param	int $level 1=critical 2=warning 3=trace 4=debug
162
     *	@param  string $destination file/syslog/display
163
     *	@return void
164
     **/
165
    public function trapLog( $message, $level, $destination ='') // OBSOLETE
166
    {
167
        // TODO : replace ref with $this->logging->log
168
        $this->logging->log($message, $level, $destination);
169
    }
170
    
171
    public function setLogging($debugLvl,$outputType,$outputOption=null)  // OBSOLETE
172
    {
173
        $this->logging->setLogging($debugLvl, $outputType,$outputOption);
174
    }
175
    
176
    /**
177
     * Returns or create new IcingaAPI object
178
     * @return \Icinga\Module\Trapdirector\Icinga2API
179
     */
180
    protected function getAPI()
181
    {
182
        if ($this->icinga2api == null)
183
        {
184
            $this->icinga2api = new Icinga2API($this->apiHostname,$this->apiPort);
185
        }
186
        return $this->icinga2api;
187
    }
188
    
189
    
190
    /**
191
     * read data from stream
192
     *	@param $stream string input stream, defaults to "php://stdin"
193
     *	@return mixed array trap data or exception with error
194
     */
195
    public function read_trap($stream='php://stdin')
196
    {
197
        //Read data from snmptrapd from stdin
198
        $input_stream=fopen($stream, 'r');
199
        
200
        if ($input_stream === false)
201
        {
202
            $this->writeTrapErrorToDB("Error reading trap (code 1/Stdin)");
203
            $this->logging->log("Error reading stdin !",ERROR,'');
204
            return null; // note : exception thrown by logging
205
        }
206
        
207
        // line 1 : host
208
        $this->receivingHost=chop(fgets($input_stream));
209
        if ($this->receivingHost === false)
210
        {
211
            $this->writeTrapErrorToDB("Error reading trap (code 1/Line Host)");
212
            $this->logging->log("Error reading Host !",ERROR,'');
213
        }
214
        // line 2 IP:port=>IP:port
215
        $IP=chop(fgets($input_stream));
216
        if ($IP === false)
217
        {
218
            $this->writeTrapErrorToDB("Error reading trap (code 1/Line IP)");
219
            $this->logging->log("Error reading IP !",ERROR,'');
220
        }
221
        $matches=array();
222
        $ret_code=preg_match('/.DP: \[(.*)\]:(.*)->\[(.*)\]:(.*)/',$IP,$matches);
223
        if ($ret_code===0 || $ret_code===false)
224
        {
225
            $this->writeTrapErrorToDB("Error parsing trap (code 2/IP)");
226
            $this->logging->log('Error parsing IP : '.$IP,ERROR,'');
227
        }
228
        else
229
        {
230
            $this->trapData['source_ip']=$matches[1];
231
            $this->trapData['destination_ip']=$matches[3];
232
            $this->trapData['source_port']=$matches[2];
233
            $this->trapData['destination_port']=$matches[4];
234
        }
235
        
236
        while (($vars=fgets($input_stream)) !==false)
237
        {
238
            $vars=chop($vars);
239
            $ret_code=preg_match('/^([^ ]+) (.*)$/',$vars,$matches);
240
            if ($ret_code===0 || $ret_code===false)
241
            {
242
                $this->logging->log('No match on trap data : '.$vars,WARN,'');
243
            }
244
            else
245
            {
246
                if (($matches[1]=='.1.3.6.1.6.3.1.1.4.1.0') || ($matches[1]=='.1.3.6.1.6.3.1.1.4.1'))
247
                {
248
                    $this->trapData['trap_oid']=$matches[2];
249
                }
250
                else
251
                {
252
                    $object= new stdClass;
253
                    $object->oid =$matches[1];
254
                    $object->value = $matches[2];
255
                    array_push($this->trapDataExt,$object);
256
                }
257
            }
258
        }
259
        
260
        if ($this->trapData['trap_oid']=='unknown')
261
        {
262
            $this->writeTrapErrorToDB("No trap oid found : check snmptrapd configuration (code 3/OID)",$this->trapData['source_ip']);
263
            $this->logging->log('no trap oid found',ERROR,'');
264
        }
265
        
266
        // Translate oids.
267
        
268
        $retArray=$this->translateOID($this->trapData['trap_oid']);
269
        if ($retArray != null)
270
        {
271
            $this->trapData['trap_name']=$retArray['trap_name'];
272
            $this->trapData['trap_name_mib']=$retArray['trap_name_mib'];
273
        }
274
        foreach ($this->trapDataExt as $key => $val)
275
        {
276
            $retArray=$this->translateOID($val->oid);
277
            if ($retArray != null)
278
            {
279
                $this->trapDataExt[$key]->oid_name=$retArray['trap_name'];
280
                $this->trapDataExt[$key]->oid_name_mib=$retArray['trap_name_mib'];
281
            }
282
        }
283
        
284
        
285
        $this->trapData['status']= 'waiting';
286
        
287
        return $this->trapData;
288
    }
289
    
290
    /**
291
     * Translate oid into array(MIB,Name)
292
     * @param $oid string oid to translate
293
     * @return mixed : null if not found or array(MIB,Name)
294
     */
295
    public function translateOID($oid)
296
    {
297
        // try from database
298
        $db_conn=$this->trapsDB->db_connect_trap();
299
        
300
        $sql='SELECT mib,name from '.$this->dbPrefix.'mib_cache WHERE oid=\''.$oid.'\';';
301
        $this->logging->log('SQL query : '.$sql,DEBUG );
302
        if (($ret_code=$db_conn->query($sql)) === false) {
303
            $this->logging->log('No result in query : ' . $sql,ERROR,'');
304
        }
305
        $name=$ret_code->fetch();
306
        if ($name['name'] != null)
307
        {
308
            return array('trap_name_mib'=>$name['mib'],'trap_name'=>$name['name']);
309
        }
310
        
311
        // Also check if it is an instance of OID
312
        $oid_instance=preg_replace('/\.[0-9]+$/','',$oid);
313
        
314
        $sql='SELECT mib,name from '.$this->dbPrefix.'mib_cache WHERE oid=\''.$oid_instance.'\';';
315
        $this->logging->log('SQL query : '.$sql,DEBUG );
316
        if (($ret_code=$db_conn->query($sql)) === false) {
317
            $this->logging->log('No result in query : ' . $sql,ERROR,'');
318
        }
319
        $name=$ret_code->fetch();
320
        if ($name['name'] != null)
321
        {
322
            return array('trap_name_mib'=>$name['mib'],'trap_name'=>$name['name']);
323
        }
324
        
325
        // Try to get oid name from snmptranslate
326
        $translate=exec($this->snmptranslate . ' -m ALL -M +'.$this->snmptranslate_dirs.
327
            ' '.$oid);
328
        $matches=array();
329
        $ret_code=preg_match('/(.*)::(.*)/',$translate,$matches);
330
        if ($ret_code===0 || $ret_code === false) {
331
            return NULL;
332
        } else {
333
            $this->logging->log('Found name with snmptrapd and not in DB for oid='.$oid,INFO);
334
            return array('trap_name_mib'=>$matches[1],'trap_name'=>$matches[2]);
335
        }
336
    }
337
    
338
    /**
339
     * Erase old trap records
340
     *	@param integer $days : erase traps when more than $days old
341
     *	@return integer : number of lines deleted
342
     **/
343
    public function eraseOldTraps($days=0)
344
    {
345
        if ($days==0)
346
        {
347
            if (($days=$this->getDBConfig('db_remove_days')) == null)
348
            {
349
                $this->logging->log('No days specified & no db value : no tap erase' ,WARN,'');
350
                return;
351
            }
352
        }
353
        $db_conn=$this->trapsDB->db_connect_trap();
354
        $daysago = strtotime("-".$days." day");
355
        $sql= 'delete from '.$this->dbPrefix.'received where date_received < \''.date("Y-m-d H:i:s",$daysago).'\';';
356
        if ($db_conn->query($sql) === false) {
357
            $this->logging->log('Error erasing traps : '.$sql,ERROR,'');
358
        }
359
        $this->logging->log('Erased traps older than '.$days.' day(s) : '.$sql,INFO);
360
    }
361
    
362
    /** Write error to received trap database
363
     */
364
    public function writeTrapErrorToDB($message,$sourceIP=null,$trapoid=null)
365
    {
366
        
367
        $db_conn=$this->trapsDB->db_connect_trap();
368
        
369
        // add date time
370
        $insert_col ='date_received,status';
371
        $insert_val = "'" . date("Y-m-d H:i:s")."','error'";
372
        
373
        if ($sourceIP !=null)
374
        {
375
            $insert_col .=',source_ip';
376
            $insert_val .=",'". $sourceIP ."'";
377
        }
378
        if ($trapoid !=null)
379
        {
380
            $insert_col .=',trap_oid';
381
            $insert_val .=",'". $trapoid ."'";
382
        }
383
        $insert_col .=',status_detail';
384
        $insert_val .=",'". $message ."'";
385
        
386
        $sql= 'INSERT INTO '.$this->dbPrefix.'received (' . $insert_col . ') VALUES ('.$insert_val.')';
387
        
388
        switch ($this->trapsDB->trapDBType)
389
        {
390
            case 'pgsql':
391
                $sql .= ' RETURNING id;';
392
                $this->logging->log('sql : '.$sql,INFO);
393
                if (($ret_code=$db_conn->query($sql)) === false) {
394
                    $this->logging->log('Error SQL insert : '.$sql,1,'');
395
                }
396
                $this->logging->log('SQL insertion OK',INFO );
397
                // Get last id to insert oid/values in secondary table
398
                if (($inserted_id_ret=$ret_code->fetch(PDO::FETCH_ASSOC)) === false) {
399
                    
400
                    $this->logging->log('Erreur recuperation id',1,'');
401
                }
402
                if (! isset($inserted_id_ret['id'])) {
403
                    $this->logging->log('Error getting id',1,'');
404
                }
405
                $this->trapId=$inserted_id_ret['id'];
406
                break;
407
            case 'mysql':
408
                $sql .= ';';
409
                $this->logging->log('sql : '.$sql,INFO );
410
                if ($db_conn->query($sql) === false) {
411
                    $this->logging->log('Error SQL insert : '.$sql,1,'');
412
                }
413
                $this->logging->log('SQL insertion OK',INFO );
414
                // Get last id to insert oid/values in secondary table
415
                $sql='SELECT LAST_INSERT_ID();';
416
                if (($ret_code=$db_conn->query($sql)) === false) {
417
                    $this->logging->log('Erreur recuperation id',1,'');
418
                }
419
                
420
                $inserted_id=$ret_code->fetch(PDO::FETCH_ASSOC)['LAST_INSERT_ID()'];
421
                if ($inserted_id==false) throw new Exception("Weird SQL error : last_insert_id returned false : open issue");
422
                $this->trapId=$inserted_id;
423
                break;
424
            default:
425
                $this->logging->log('Error SQL type unknown  : '.$this->trapsDB->trapDBType,1,'');
426
        }
427
        
428
        $this->logging->log('id found: '. $this->trapId,INFO );
429
    }
430
    
431
    /** Write trap data to trap database
432
     */
433
    public function writeTrapToDB()
434
    {
435
        
436
        // If action is ignore -> don't send t DB
437
        if ($this->trapToDb === false) return;
438
        
439
        
440
        $db_conn=$this->trapsDB->db_connect_trap();
441
        
442
        $insert_col='';
443
        $insert_val='';
444
        // add date time
445
        $this->trapData['date_received'] = date("Y-m-d H:i:s");
446
        
447
        $firstcol=1;
448
        foreach ($this->trapData as $col => $val)
449
        {
450
            if ($firstcol==0)
451
            {
452
                $insert_col .=',';
453
                $insert_val .=',';
454
            }
455
            $insert_col .= $col ;
456
            $insert_val .= ($val==null)? 'NULL' : $db_conn->quote($val);
457
            $firstcol=0;
458
        }
459
        
460
        $sql= 'INSERT INTO '.$this->dbPrefix.'received (' . $insert_col . ') VALUES ('.$insert_val.')';
461
        switch ($this->trapsDB->trapDBType)
462
        {
463
            case 'pgsql':
464
                $sql .= ' RETURNING id;';
465
                $this->logging->log('sql : '.$sql,INFO );
466
                if (($ret_code=$db_conn->query($sql)) === false) {
467
                    $this->logging->log('Error SQL insert : '.$sql,ERROR,'');
468
                }
469
                $this->logging->log('SQL insertion OK',INFO );
470
                // Get last id to insert oid/values in secondary table
471
                if (($inserted_id_ret=$ret_code->fetch(PDO::FETCH_ASSOC)) === false) {
472
                    
473
                    $this->logging->log('Erreur recuperation id',ERROR,'');
474
                }
475
                if (! isset($inserted_id_ret['id'])) {
476
                    $this->logging->log('Error getting id',ERROR,'');
477
                }
478
                $this->trapId=$inserted_id_ret['id'];
479
                break;
480
            case 'mysql':
481
                $sql .= ';';
482
                $this->logging->log('sql : '.$sql,INFO );
483
                if ($db_conn->query($sql) === false) {
484
                    $this->logging->log('Error SQL insert : '.$sql,ERROR,'');
485
                }
486
                $this->logging->log('SQL insertion OK',INFO );
487
                // Get last id to insert oid/values in secondary table
488
                $sql='SELECT LAST_INSERT_ID();';
489
                if (($ret_code=$db_conn->query($sql)) === false) {
490
                    $this->logging->log('Erreur recuperation id',ERROR,'');
491
                }
492
                
493
                $inserted_id=$ret_code->fetch(PDO::FETCH_ASSOC)['LAST_INSERT_ID()'];
494
                if ($inserted_id==false) throw new Exception("Weird SQL error : last_insert_id returned false : open issue");
495
                $this->trapId=$inserted_id;
496
                break;
497
            default:
498
                $this->logging->log('Error SQL type unknown : '.$this->trapsDB->trapDBType,ERROR,'');
499
        }
500
        $this->logging->log('id found: '.$this->trapId,INFO );
501
        
502
        // Fill trap extended data table
503
        foreach ($this->trapDataExt as $value) {
504
            // TODO : detect if trap value is encoded and decode it to UTF-8 for database
505
            $firstcol=1;
506
            $value->trap_id = $this->trapId;
507
            $insert_col='';
508
            $insert_val='';
509
            foreach ($value as $col => $val)
510
            {
511
                if ($firstcol==0)
512
                {
513
                    $insert_col .=',';
514
                    $insert_val .=',';
515
                }
516
                $insert_col .= $col;
517
                $insert_val .= ($val==null)? 'NULL' : $db_conn->quote($val);
518
                $firstcol=0;
519
            }
520
            
521
            $sql= 'INSERT INTO '.$this->dbPrefix.'received_data (' . $insert_col . ') VALUES ('.$insert_val.');';
522
            
523
            if ($db_conn->query($sql) === false) {
524
                $this->logging->log('Erreur insertion data : ' . $sql,WARN,'');
525
            }
526
        }
527
    }
528
    
529
    /** Get rules from rule database with ip and oid
530
     *	@param $ip string ipv4 or ipv6
531
     *	@param $oid string oid in numeric
532
     *	@return mixed|boolean : PDO object or false
533
     */
534
    protected function getRules($ip,$oid)
535
    {
536
        $db_conn=$this->trapsDB->db_connect_trap();
537
        // fetch rules based on IP in rule and OID
538
        $sql='SELECT * from '.$this->dbPrefix.'rules WHERE trap_oid=\''.$oid.'\' ';
539
        $this->logging->log('SQL query : '.$sql,DEBUG );
540
        if (($ret_code=$db_conn->query($sql)) === false) {
541
            $this->logging->log('No result in query : ' . $sql,WARN,'');
542
            return false;
543
        }
544
        $rules_all=$ret_code->fetchAll();
545
        //echo "rule all :\n";print_r($rules_all);echo "\n";
546
        $rules_ret=array();
547
        $rule_ret_key=0;
548
        foreach ($rules_all as $key => $rule)
549
        {
550
            if ($rule['ip4']==$ip || $rule['ip6']==$ip)
551
            {
552
                $rules_ret[$rule_ret_key]=$rules_all[$key];
553
                //TODO : get host name by API (and check if correct in rule).
554
                $rule_ret_key++;
555
                continue;
556
            }
557
            // TODO : get hosts IP by API
558
            if (isset($rule['host_group_name']) && $rule['host_group_name']!=null)
559
            { // get ips of group members by oid
560
                $db_conn2=$this->trapsDB->db_connect_ido();
561
                $sql="SELECT m.host_object_id, a.address as ip4, a.address6 as ip6, b.name1 as host_name
562
						FROM icinga_objects as o
563
						LEFT JOIN icinga_hostgroups as h ON o.object_id=h.hostgroup_object_id
564
						LEFT JOIN icinga_hostgroup_members as m ON h.hostgroup_id=m.hostgroup_id
565
						LEFT JOIN icinga_hosts as a ON a.host_object_id = m.host_object_id
566
						LEFT JOIN icinga_objects as b ON b.object_id = a.host_object_id
567
						WHERE o.name1='".$rule['host_group_name']."';";
568
                if (($ret_code2=$db_conn2->query($sql)) === false) {
569
                    $this->logging->log('No result in query : ' . $sql,WARN,'');
570
                    continue;
571
                }
572
                $grouphosts=$ret_code2->fetchAll();
573
                //echo "rule grp :\n";print_r($grouphosts);echo "\n";
574
                foreach ( $grouphosts as $host)
575
                {
576
                    //echo $host['ip4']."\n";
577
                    if ($host['ip4']==$ip || $host['ip6']==$ip)
578
                    {
579
                        //echo "Rule added \n";
580
                        $rules_ret[$rule_ret_key]=$rules_all[$key];
581
                        $rules_ret[$rule_ret_key]['host_name']=$host['host_name'];
582
                        $rule_ret_key++;
583
                    }
584
                }
585
            }
586
        }
587
        //echo "rule rest :\n";print_r($rules_ret);echo "\n";exit(0);
588
        return $rules_ret;
589
    }
590
    
591
    /** Add rule match to rule
592
     *	@param id int : rule id
593
     *   @param set int : value to set
594
     */
595
    protected function add_rule_match($id, $set)
596
    {
597
        $db_conn=$this->trapsDB->db_connect_trap();
598
        $sql="UPDATE ".$this->dbPrefix."rules SET num_match = '".$set."' WHERE (id = '".$id."');";
599
        if ($db_conn->query($sql) === false) {
600
            $this->logging->log('Error in update query : ' . $sql,WARN,'');
601
        }
602
    }
603
    
604
    /** Send SERVICE_CHECK_RESULT with icinga2cmd or API
605
     *
606
     * @param string $host
607
     * @param string $service
608
     * @param integer $state numerical staus
609
     * @param string $display
610
     * @returnn bool true is service check was sent without error
611
     */
612
    public function serviceCheckResult($host,$service,$state,$display)
613
    {
614
        if ($this->apiUse === false)
615
        {
616
            $send = '[' . date('U') .'] PROCESS_SERVICE_CHECK_RESULT;' .
617
                $host.';' .$service .';' . $state . ';'.$display;
618
                $this->logging->log( $send." : to : " .$this->icinga2cmd,INFO );
619
                
620
                // TODO : file_put_contents & fopen (,'w' or 'a') does not work. See why. Or not as using API will be by default....
621
                exec('echo "'.$send.'" > ' .$this->icinga2cmd);
622
                return true;
623
        }
624
        else
625
        {
626
            // Get perfdata if found
627
            $matches=array();
628
            if (preg_match('/(.*)\|(.*)/',$display,$matches) == 1)
629
            {
630
                $display=$matches[1];
631
                $perfdata=$matches[2];
632
            }
633
            else
634
            {
635
                $perfdata='';
636
            }
637
            
638
            $api = $this->getAPI();
639
            $api->setCredentials($this->apiUsername, $this->apiPassword);
640
            list($retcode,$retmessage)=$api->serviceCheckResult($host,$service,$state,$display,$perfdata);
641
            if ($retcode == false)
642
            {
643
                $this->logging->log( "Error sending result : " .$retmessage,WARN,'');
644
                return false;
645
            }
646
            else
647
            {
648
                $this->logging->log( "Sent result : " .$retmessage,INFO );
649
                return true;
650
            }
651
        }
652
    }
653
    
654
    public function getHostByIP($ip)
655
    {
656
        $api = $this->getAPI();
657
        $api->setCredentials($this->apiUsername, $this->apiPassword);
658
        return $api->getHostByIP($ip);
659
    }
660
    
661
    /** Resolve display.
662
     *	Changes _OID(<oid>) to value if found or text "<not in trap>"
663
     *	@param $display string
664
     *	@return string display
665
     */
666
    protected function applyDisplay($display)
667
    {
668
        $matches=array();
669
        while (preg_match('/_OID\(([0-9\.\*]+)\)/',$display,$matches) == 1)
670
        {
671
            $oid=$matches[1];
672
            $found=0;
673
            // Test and transform regexp
674
            $oidR = $this->ruleClass->regexp_eval($oid);
675
            
676
            foreach($this->trapDataExt as $val)
677
            {
678
                if (preg_match("/^$oidR$/",$val->oid) == 1)
679
                {
680
                    $val->value=preg_replace('/"/','',$val->value);
681
                    $rep=0;
682
                    $display=preg_replace('/_OID\('.$oid.'\)/',$val->value,$display,-1,$rep);
683
                    if ($rep==0)
684
                    {
685
                        $this->logging->log("Error in display",WARN,'');
686
                        return $display;
687
                    }
688
                    $found=1;
689
                    break;
690
                }
691
            }
692
            if ($found==0)
693
            {
694
                $display=preg_replace('/_OID\('.$oid.'\)/','<not in trap>',$display,-1,$rep);
695
                if ($rep==0)
696
                {
697
                    $this->logging->log("Error in display",WARN,'');
698
                    return $display;
699
                }
700
            }
701
        }
702
        return $display;
703
    }
704
    
705
    /** Match rules for current trap and do action
706
     */
707
    public function applyRules()
708
    {
709
        $rules = $this->getRules($this->trapData['source_ip'],$this->trapData['trap_oid']);
710
        
711
        if ($rules===false || count($rules)==0)
0 ignored issues
show
introduced by
The condition $rules === false is always true.
Loading history...
712
        {
713
            $this->logging->log('No rules found for this trap',INFO );
714
            $this->trapData['status']='unknown';
715
            $this->trapToDb=true;
716
            return;
717
        }
718
        //print_r($rules);
719
        // Evaluate all rules in sequence
720
        $this->trapAction=null;
721
        foreach ($rules as $rule)
722
        {
723
            
724
            $host_name=$rule['host_name'];
725
            $service_name=$rule['service_name'];
726
            
727
            $display=$this->applyDisplay($rule['display']);
728
            $this->trapAction = ($this->trapAction==null)? '' : $this->trapAction . ', ';
729
            try
730
            {
731
                $this->logging->log('Rule to eval : '.$rule['rule'],INFO );
732
                $evalr=$this->ruleClass->eval_rule($rule['rule'], $this->trapDataExt) ;
733
                //->eval_rule($rule['rule']);
734
                
735
                if ($evalr == true)
736
                {
737
                    //$this->logging->log('rules OOK: '.print_r($rule),INFO );
738
                    $action=$rule['action_match'];
739
                    $this->logging->log('action OK : '.$action,INFO );
740
                    if ($action >= 0)
741
                    {
742
                        if ($this->serviceCheckResult($host_name,$service_name,$action,$display) == false)
743
                        {
744
                            $this->trapAction.='Error sending status : check cmd/API';
745
                        }
746
                        else
747
                        {
748
                            $this->add_rule_match($rule['id'],$rule['num_match']+1);
749
                            $this->trapAction.='Status '.$action.' to '.$host_name.'/'.$service_name;
750
                        }
751
                    }
752
                    else
753
                    {
754
                        $this->add_rule_match($rule['id'],$rule['num_match']+1);
755
                    }
756
                    $this->trapToDb=($action==-2)?false:true;
757
                }
758
                else
759
                {
760
                    //$this->logging->log('rules KOO : '.print_r($rule),INFO );
761
                    
762
                    $action=$rule['action_nomatch'];
763
                    $this->logging->log('action NOK : '.$action,INFO );
764
                    if ($action >= 0)
765
                    {
766
                        if ($this->serviceCheckResult($host_name,$service_name,$action,$display)==false)
767
                        {
768
                            $this->trapAction.='Error sending status : check cmd/API';
769
                        }
770
                        else
771
                        {
772
                            $this->add_rule_match($rule['id'],$rule['num_match']+1);
773
                            $this->trapAction.='Status '.$action.' to '.$host_name.'/'.$service_name;
774
                        }
775
                    }
776
                    else
777
                    {
778
                        $this->add_rule_match($rule['id'],$rule['num_match']+1);
779
                    }
780
                    $this->trapToDb=($action==-2)?false:true;
781
                }
782
                // Put name in source_name
783
                if (!isset($this->trapData['source_name']))
784
                {
785
                    $this->trapData['source_name']=$rule['host_name'];
786
                }
787
                else
788
                {
789
                    if (!preg_match('/'.$rule['host_name'].'/',$this->trapData['source_name']))
790
                    { // only add if not present
791
                        $this->trapData['source_name'].=','.$rule['host_name'];
792
                    }
793
                }
794
            }
795
            catch (Exception $e)
796
            {
797
                $this->logging->log('Error in rule eval : '.$e->getMessage(),WARN,'');
798
                $this->trapAction.=' ERR : '.$e->getMessage();
799
                $this->trapData['status']='error';
800
            }
801
            
802
        }
803
        if ($this->trapData['status']=='error')
804
        {
805
            $this->trapToDb=true; // Always put errors in DB for the use can see
806
        }
807
        else
808
        {
809
            $this->trapData['status']='done';
810
        }
811
    }
812
    
813
    /** Add Time a action to rule
814
     *	@param string $time : time to process to insert in SQL
815
     */
816
    public function add_rule_final($time)
817
    {
818
        $db_conn=$this->trapsDB->db_connect_trap();
819
        if ($this->trapAction==null)
820
        {
821
            $this->trapAction='No action';
822
        }
823
        $sql="UPDATE ".$this->dbPrefix."received SET process_time = '".$time."' , status_detail='".$this->trapAction."'  WHERE (id = '".$this->trapId."');";
824
        if ($db_conn->query($sql) === false) {
825
            $this->logging->log('Error in update query : ' . $sql,WARN,'');
826
        }
827
    }
828
    
829
    /*********** UTILITIES *********************/
830
    
831
    /** reset service to OK after time defined in rule
832
     *	TODO logic is : get all service in error + all rules, see if getting all rules then select services is better
833
     *	@return integer : not in use
834
     **/
835
    public function reset_services()
836
    {
837
        // Get all services not in 'ok' state
838
        $sql_query="SELECT s.service_object_id,
839
	 UNIX_TIMESTAMP(s.last_check) AS last_check,
840
	s.current_state as state,
841
	v.name1 as host_name,
842
    v.name2 as service_name
843
	FROM icinga_servicestatus AS s
844
    LEFT JOIN icinga_objects as v ON s.service_object_id=v.object_id
845
    WHERE s.current_state != 0;";
846
        $db_conn=$this->trapsDB->db_connect_ido();
847
        if (($services_db=$db_conn->query($sql_query)) === false) { // set err to 1 to throw exception.
848
            $this->logging->log('No result in query : ' . $sql_query,ERROR,'');
849
            return 0;
850
        }
851
        $services=$services_db->fetchAll();
852
        
853
        // Get all rules
854
        $sql_query="SELECT host_name, service_name, revert_ok FROM ".$this->dbPrefix."rules where revert_ok != 0;";
855
        $db_conn2=$this->trapsDB->db_connect_trap();
856
        if (($rules_db=$db_conn2->query($sql_query)) === false) {
857
            $this->logging->log('No result in query : ' . $sql_query,ERROR,'');
858
            return 0;
859
        }
860
        $rules=$rules_db->fetchAll();
861
        
862
        $now=date('U');
863
        
864
        $numreset=0;
865
        foreach ($rules as $rule)
866
        {
867
            foreach ($services as $service)
868
            {
869
                if ($service['service_name'] == $rule['service_name'] &&
870
                    $service['host_name'] == $rule['host_name'] &&
871
                    ($service['last_check'] + $rule['revert_ok']) < $now)
872
                {
873
                    $this->serviceCheckResult($service['host_name'],$service['service_name'],0,'Reset service to OK after '.$rule['revert_ok'].' seconds');
874
                    $numreset++;
875
                }
876
            }
877
        }
878
        echo "\n";
879
        echo $numreset . " service(s) reset to OK\n";
880
        return 0;
881
        
882
    }
883
    
884
    
885
}