Completed
Push — master ( 2f676f...ba4b05 )
by Patrick
02:03
created

Trap::getTrapApi()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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