Trap::writeTrapToDB()   F
last analyzed

Complexity

Conditions 18
Paths 736

Size

Total Lines 92
Code Lines 58

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 18
eloc 58
c 3
b 0
f 0
nc 736
nop 0
dl 0
loc 92
rs 1.0666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
                continue;
258
            }
259
            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'))
260
            {
261
                $this->trapData['trap_oid']=$matches[2];
262
                continue;
263
            }
264
            if ( $this->useSnmpTrapAddess === TRUE &&  preg_match('/'.$this->snmpTrapAddressOID.'/', $matches[1]) == 1)
265
            {
266
                $this->logging->log('Found relayed trap from ' . $matches[2] . ' relayed by ' .$this->trapData['source_ip'],DEBUG);
267
                if (preg_match('/^[0-9\.]+$/',$matches[2]) == 0 && preg_match('/^[0-9a-fA-F:]+$/',$matches[2]) == 0)
268
                {
269
                    $this->logging->log('Value of SnmpTrapAddess ('.$this->snmpTrapAddressOID.') is not IP : ' .$matches[2],WARN,'');
270
                    continue;
271
                }
272
                $this->trapData['source_ip'] = $matches[2];
273
                continue;
274
            }
275
            $object= new stdClass;
276
            $object->oid =$matches[1];
277
            $object->value = $matches[2];
278
            array_push($this->trapDataExt,$object);
279
        }
280
        
281
        if ($this->trapData['trap_oid']=='unknown')
282
        {
283
            $this->writeTrapErrorToDB("No trap oid found : check snmptrapd configuration (code 3/OID)",$this->trapData['source_ip']);
284
            $this->logging->log('no trap oid found',ERROR,'');
285
        }
286
        
287
        // Translate oids.
288
        
289
        $retArray=$this->translateOID($this->trapData['trap_oid']);
290
        if ($retArray != null)
291
        {
292
            $this->trapData['trap_name']=$retArray['trap_name'];
293
            $this->trapData['trap_name_mib']=$retArray['trap_name_mib'];
294
        }
295
        foreach ($this->trapDataExt as $key => $val)
296
        {
297
            $retArray=$this->translateOID($val->oid);
298
            if ($retArray != null)
299
            {
300
                $this->trapDataExt[$key]->oid_name=$retArray['trap_name'];
301
                $this->trapDataExt[$key]->oid_name_mib=$retArray['trap_name_mib'];
302
            }
303
        }
304
        
305
        
306
        $this->trapData['status']= 'waiting';
307
        
308
        return $this->trapData;
309
    }
310
    
311
    /**
312
     * Translate oid into array(MIB,Name)
313
     * @param $oid string oid to translate
314
     * @return mixed : null if not found or array(MIB,Name)
315
     */
316
    public function translateOID($oid)
317
    {
318
        // try from database
319
        $db_conn=$this->trapsDB->db_connect_trap();
320
        
321
        $sql='SELECT mib,name from '.$this->dbPrefix.'mib_cache WHERE oid=\''.$oid.'\';';
322
        $this->logging->log('SQL query : '.$sql,DEBUG );
323
        if (($ret_code=$db_conn->query($sql)) === false) {
324
            $this->logging->log('No result in query : ' . $sql,ERROR,'');
325
        }
326
        $name=$ret_code->fetch();
327
        if ($name['name'] != null)
328
        {
329
            return array('trap_name_mib'=>$name['mib'],'trap_name'=>$name['name']);
330
        }
331
        
332
        // Also check if it is an instance of OID
333
        $oid_instance=preg_replace('/\.[0-9]+$/','',$oid);
334
        
335
        $sql='SELECT mib,name from '.$this->dbPrefix.'mib_cache WHERE oid=\''.$oid_instance.'\';';
336
        $this->logging->log('SQL query : '.$sql,DEBUG );
337
        if (($ret_code=$db_conn->query($sql)) === false) {
338
            $this->logging->log('No result in query : ' . $sql,ERROR,'');
339
        }
340
        $name=$ret_code->fetch();
341
        if ($name['name'] != null)
342
        {
343
            return array('trap_name_mib'=>$name['mib'],'trap_name'=>$name['name']);
344
        }
345
        
346
        // Try to get oid name from snmptranslate
347
        $translate=exec($this->snmptranslate . ' -m ALL -M +'.$this->snmptranslate_dirs.
348
            ' '.$oid);
349
        $matches=array();
350
        $ret_code=preg_match('/(.*)::(.*)/',$translate,$matches);
351
        if ($ret_code===0 || $ret_code === false) {
352
            return NULL;
353
        } else {
354
            $this->logging->log('Found name with snmptrapd and not in DB for oid='.$oid,INFO);
355
            return array('trap_name_mib'=>$matches[1],'trap_name'=>$matches[2]);
356
        }
357
    }
358
    
359
    /**
360
     * Erase old trap records
361
     *	@param integer $days : erase traps when more than $days old
362
     *	@return integer : number of lines deleted
363
     **/
364
    public function eraseOldTraps($days=0)
365
    {
366
        if ($days==0)
367
        {
368
            if (($days=$this->getDBConfig('db_remove_days')) == null)
369
            {
370
                $this->logging->log('No days specified & no db value : no tap erase' ,WARN,'');
371
                return;
372
            }
373
        }
374
        $db_conn=$this->trapsDB->db_connect_trap();
375
        $daysago = strtotime("-".$days." day");
376
        $sql= 'delete from '.$this->dbPrefix.'received where date_received < \''.date("Y-m-d H:i:s",$daysago).'\';';
377
        if ($db_conn->query($sql) === false) {
378
            $this->logging->log('Error erasing traps : '.$sql,ERROR,'');
379
        }
380
        $this->logging->log('Erased traps older than '.$days.' day(s) : '.$sql,INFO);
381
    }
382
    
383
    /** Write error to received trap database
384
     */
385
    public function writeTrapErrorToDB($message,$sourceIP=null,$trapoid=null)
386
    {
387
        
388
        $db_conn=$this->trapsDB->db_connect_trap();
389
        
390
        // add date time
391
        $insert_col ='date_received,status';
392
        $insert_val = "'" . date("Y-m-d H:i:s")."','error'";
393
        
394
        if ($sourceIP !=null)
395
        {
396
            $insert_col .=',source_ip';
397
            $insert_val .=",'". $sourceIP ."'";
398
        }
399
        if ($trapoid !=null)
400
        {
401
            $insert_col .=',trap_oid';
402
            $insert_val .=",'". $trapoid ."'";
403
        }
404
        $insert_col .=',status_detail';
405
        $insert_val .=",'". $message ."'";
406
        
407
        $sql= 'INSERT INTO '.$this->dbPrefix.'received (' . $insert_col . ') VALUES ('.$insert_val.')';
408
        
409
        switch ($this->trapsDB->trapDBType)
410
        {
411
            case 'pgsql':
412
                $sql .= ' RETURNING id;';
413
                $this->logging->log('sql : '.$sql,INFO);
414
                if (($ret_code=$db_conn->query($sql)) === false) {
415
                    $this->logging->log('Error SQL insert : '.$sql,1,'');
416
                }
417
                $this->logging->log('SQL insertion OK',INFO );
418
                // Get last id to insert oid/values in secondary table
419
                if (($inserted_id_ret=$ret_code->fetch(PDO::FETCH_ASSOC)) === false) {
420
                    
421
                    $this->logging->log('Erreur recuperation id',1,'');
422
                }
423
                if (! isset($inserted_id_ret['id'])) {
424
                    $this->logging->log('Error getting id',1,'');
425
                }
426
                $this->trapId=$inserted_id_ret['id'];
427
                break;
428
            case 'mysql':
429
                $sql .= ';';
430
                $this->logging->log('sql : '.$sql,INFO );
431
                if ($db_conn->query($sql) === false) {
432
                    $this->logging->log('Error SQL insert : '.$sql,1,'');
433
                }
434
                $this->logging->log('SQL insertion OK',INFO );
435
                // Get last id to insert oid/values in secondary table
436
                $sql='SELECT LAST_INSERT_ID();';
437
                if (($ret_code=$db_conn->query($sql)) === false) {
438
                    $this->logging->log('Erreur recuperation id',1,'');
439
                }
440
                
441
                $inserted_id=$ret_code->fetch(PDO::FETCH_ASSOC)['LAST_INSERT_ID()'];
442
                if ($inserted_id==false) throw new Exception("Weird SQL error : last_insert_id returned false : open issue");
443
                $this->trapId=$inserted_id;
444
                break;
445
            default:
446
                $this->logging->log('Error SQL type unknown  : '.$this->trapsDB->trapDBType,1,'');
447
        }
448
        
449
        $this->logging->log('id found: '. $this->trapId,INFO );
450
    }
451
    
452
    /** Write trap data to trap database
453
     */
454
    public function writeTrapToDB()
455
    {
456
        
457
        // If action is ignore -> don't send t DB
458
        if ($this->trapToDb === false) return;
459
        
460
        
461
        $db_conn=$this->trapsDB->db_connect_trap();
462
        
463
        $insert_col='';
464
        $insert_val='';
465
        // add date time
466
        $this->trapData['date_received'] = date("Y-m-d H:i:s");
467
        
468
        $firstcol=1;
469
        foreach ($this->trapData as $col => $val)
470
        {
471
            if ($firstcol==0)
472
            {
473
                $insert_col .=',';
474
                $insert_val .=',';
475
            }
476
            $insert_col .= $col ;
477
            $insert_val .= ($val==null)? 'NULL' : $db_conn->quote($val);
478
            $firstcol=0;
479
        }
480
        
481
        $sql= 'INSERT INTO '.$this->dbPrefix.'received (' . $insert_col . ') VALUES ('.$insert_val.')';
482
        switch ($this->trapsDB->trapDBType)
483
        {
484
            case 'pgsql':
485
                $sql .= ' RETURNING id;';
486
                $this->logging->log('sql : '.$sql,INFO );
487
                if (($ret_code=$db_conn->query($sql)) === false) {
488
                    $this->logging->log('Error SQL insert : '.$sql,ERROR,'');
489
                }
490
                $this->logging->log('SQL insertion OK',INFO );
491
                // Get last id to insert oid/values in secondary table
492
                if (($inserted_id_ret=$ret_code->fetch(PDO::FETCH_ASSOC)) === false) {
493
                    
494
                    $this->logging->log('Erreur recuperation id',ERROR,'');
495
                }
496
                if (! isset($inserted_id_ret['id'])) {
497
                    $this->logging->log('Error getting id',ERROR,'');
498
                }
499
                $this->trapId=$inserted_id_ret['id'];
500
                break;
501
            case 'mysql':
502
                $sql .= ';';
503
                $this->logging->log('sql : '.$sql,INFO );
504
                if ($db_conn->query($sql) === false) {
505
                    $this->logging->log('Error SQL insert : '.$sql,ERROR,'');
506
                }
507
                $this->logging->log('SQL insertion OK',INFO );
508
                // Get last id to insert oid/values in secondary table
509
                $sql='SELECT LAST_INSERT_ID();';
510
                if (($ret_code=$db_conn->query($sql)) === false) {
511
                    $this->logging->log('Erreur recuperation id',ERROR,'');
512
                }
513
                
514
                $inserted_id=$ret_code->fetch(PDO::FETCH_ASSOC)['LAST_INSERT_ID()'];
515
                if ($inserted_id==false) throw new Exception("Weird SQL error : last_insert_id returned false : open issue");
516
                $this->trapId=$inserted_id;
517
                break;
518
            default:
519
                $this->logging->log('Error SQL type unknown : '.$this->trapsDB->trapDBType,ERROR,'');
520
        }
521
        $this->logging->log('id found: '.$this->trapId,INFO );
522
        
523
        // Fill trap extended data table
524
        foreach ($this->trapDataExt as $value) {
525
            // TODO : detect if trap value is encoded and decode it to UTF-8 for database
526
            $firstcol=1;
527
            $value->trap_id = $this->trapId;
528
            $insert_col='';
529
            $insert_val='';
530
            foreach ($value as $col => $val)
531
            {
532
                if ($firstcol==0)
533
                {
534
                    $insert_col .=',';
535
                    $insert_val .=',';
536
                }
537
                $insert_col .= $col;
538
                $insert_val .= ($val==null)? 'NULL' : $db_conn->quote($val);
539
                $firstcol=0;
540
            }
541
            
542
            $sql= 'INSERT INTO '.$this->dbPrefix.'received_data (' . $insert_col . ') VALUES ('.$insert_val.');';
543
            
544
            if ($db_conn->query($sql) === false) {
545
                $this->logging->log('Erreur insertion data : ' . $sql,WARN,'');
546
            }
547
        }
548
    }
549
    
550
    /** Get rules from rule database with ip and oid
551
     *	@param $ip string ipv4 or ipv6
552
     *	@param $oid string oid in numeric
553
     *	@return mixed|boolean : PDO object or false
554
     */
555
    protected function getRules($ip,$oid)
556
    {
557
        $db_conn=$this->trapsDB->db_connect_trap();
558
        // fetch rules based on IP in rule and OID
559
        $sql='SELECT * from '.$this->dbPrefix.'rules WHERE trap_oid=\''.$oid.'\' ';
560
        $this->logging->log('SQL query : '.$sql,DEBUG );
561
        if (($ret_code=$db_conn->query($sql)) === false) {
562
            $this->logging->log('No result in query : ' . $sql,WARN,'');
563
            return false;
564
        }
565
        $rules_all=$ret_code->fetchAll();
566
        //echo "rule all :\n";print_r($rules_all);echo "\n";
567
        $rules_ret=array();
568
        $rule_ret_key=0;
569
        foreach ($rules_all as $key => $rule)
570
        {
571
            if ($rule['ip4']==$ip || $rule['ip6']==$ip)
572
            {
573
                $rules_ret[$rule_ret_key]=$rules_all[$key];
574
                //TODO : get host name by API (and check if correct in rule).
575
                $rule_ret_key++;
576
                continue;
577
            }
578
            // TODO : get hosts IP by API
579
            if (isset($rule['host_group_name']) && $rule['host_group_name']!=null)
580
            { // get ips of group members by oid
581
                $db_conn2=$this->trapsDB->db_connect_ido();
582
                $sql="SELECT m.host_object_id, a.address as ip4, a.address6 as ip6, b.name1 as host_name
583
						FROM icinga_objects as o
584
						LEFT JOIN icinga_hostgroups as h ON o.object_id=h.hostgroup_object_id
585
						LEFT JOIN icinga_hostgroup_members as m ON h.hostgroup_id=m.hostgroup_id
586
						LEFT JOIN icinga_hosts as a ON a.host_object_id = m.host_object_id
587
						LEFT JOIN icinga_objects as b ON b.object_id = a.host_object_id
588
						WHERE o.name1='".$rule['host_group_name']."';";
589
                if (($ret_code2=$db_conn2->query($sql)) === false) {
590
                    $this->logging->log('No result in query : ' . $sql,WARN,'');
591
                    continue;
592
                }
593
                $grouphosts=$ret_code2->fetchAll();
594
                //echo "rule grp :\n";print_r($grouphosts);echo "\n";
595
                foreach ( $grouphosts as $host)
596
                {
597
                    //echo $host['ip4']."\n";
598
                    if ($host['ip4']==$ip || $host['ip6']==$ip)
599
                    {
600
                        //echo "Rule added \n";
601
                        $rules_ret[$rule_ret_key]=$rules_all[$key];
602
                        $rules_ret[$rule_ret_key]['host_name']=$host['host_name'];
603
                        $rule_ret_key++;
604
                    }
605
                }
606
            }
607
        }
608
        //echo "rule rest :\n";print_r($rules_ret);echo "\n";exit(0);
609
        return $rules_ret;
610
    }
611
    
612
    /** Add rule match to rule
613
     *	@param id int : rule id
614
     *   @param set int : value to set
615
     */
616
    protected function add_rule_match($id, $set)
617
    {
618
        $db_conn=$this->trapsDB->db_connect_trap();
619
        $sql="UPDATE ".$this->dbPrefix."rules SET num_match = '".$set."' WHERE (id = '".$id."');";
620
        if ($db_conn->query($sql) === false) {
621
            $this->logging->log('Error in update query : ' . $sql,WARN,'');
622
        }
623
    }
624
    
625
    /** Send SERVICE_CHECK_RESULT with icinga2cmd or API
626
     *
627
     * @param string $host
628
     * @param string $service
629
     * @param integer $state numerical staus
630
     * @param string $display
631
     * @returnn bool true is service check was sent without error
632
     */
633
    public function serviceCheckResult($host,$service,$state,$display)
634
    {
635
        if ($this->apiUse === false)
636
        {
637
            $send = '[' . date('U') .'] PROCESS_SERVICE_CHECK_RESULT;' .
638
                $host.';' .$service .';' . $state . ';'.$display;
639
                $this->logging->log( $send." : to : " .$this->icinga2cmd,INFO );
640
                
641
                // TODO : file_put_contents & fopen (,'w' or 'a') does not work. See why. Or not as using API will be by default....
642
                exec('echo "'.$send.'" > ' .$this->icinga2cmd);
643
                return true;
644
        }
645
        else
646
        {
647
            // Get perfdata if found
648
            $matches=array();
649
            if (preg_match('/(.*)\|(.*)/',$display,$matches) == 1)
650
            {
651
                $display=$matches[1];
652
                $perfdata=$matches[2];
653
            }
654
            else
655
            {
656
                $perfdata='';
657
            }
658
            
659
            $api = $this->getAPI();
660
            $api->setCredentials($this->apiUsername, $this->apiPassword);
661
            list($retcode,$retmessage)=$api->serviceCheckResult($host,$service,$state,$display,$perfdata);
662
            if ($retcode == false)
663
            {
664
                $this->logging->log( "Error sending result : " .$retmessage,WARN,'');
665
                return false;
666
            }
667
            else
668
            {
669
                $this->logging->log( "Sent result : " .$retmessage,INFO );
670
                return true;
671
            }
672
        }
673
    }
674
    
675
    public function getHostByIP($ip)
676
    {
677
        $api = $this->getAPI();
678
        $api->setCredentials($this->apiUsername, $this->apiPassword);
679
        return $api->getHostByIP($ip);
680
    }
681
    
682
    /** Resolve display.
683
     *	Changes _OID(<oid>) to value if found or text "<not in trap>"
684
     *	@param $display string
685
     *	@return string display
686
     */
687
    protected function applyDisplay($display)
688
    {
689
        $matches=array();
690
        while (preg_match('/_OID\(([0-9\.\*]+)\)/',$display,$matches) == 1)
691
        {
692
            $oid=$matches[1];
693
            $found=0;
694
            // Test and transform regexp
695
            $oidR = $this->ruleClass->regexp_eval($oid);
696
            
697
            foreach($this->trapDataExt as $val)
698
            {
699
                if (preg_match("/^$oidR$/",$val->oid) == 1)
700
                {
701
                    $val->value=preg_replace('/"/','',$val->value);
702
                    $rep=0;
703
                    $display=preg_replace('/_OID\('.$oid.'\)/',$val->value,$display,-1,$rep);
704
                    if ($rep==0)
705
                    {
706
                        $this->logging->log("Error in display",WARN,'');
707
                        return $display;
708
                    }
709
                    $found=1;
710
                    break;
711
                }
712
            }
713
            if ($found==0)
714
            {
715
                $display=preg_replace('/_OID\('.$oid.'\)/','<not in trap>',$display,-1,$rep);
716
                if ($rep==0)
717
                {
718
                    $this->logging->log("Error in display",WARN,'');
719
                    return $display;
720
                }
721
            }
722
        }
723
        return $display;
724
    }
725
    
726
    /** Match rules for current trap and do action
727
     */
728
    public function applyRules()
729
    {
730
        $rules = $this->getRules($this->trapData['source_ip'],$this->trapData['trap_oid']);
731
        
732
        if ($rules===false || count($rules)==0)
0 ignored issues
show
introduced by
The condition $rules === false is always true.
Loading history...
733
        {
734
            $this->logging->log('No rules found for this trap',INFO );
735
            $this->trapData['status']='unknown';
736
            $this->trapToDb=true;
737
            return;
738
        }
739
        //print_r($rules);
740
        // Evaluate all rules in sequence
741
        $this->trapAction=null;
742
        foreach ($rules as $rule)
743
        {
744
            
745
            $host_name=$rule['host_name'];
746
            $service_name=$rule['service_name'];
747
            
748
            $display=$this->applyDisplay($rule['display']);
749
            $this->trapAction = ($this->trapAction==null)? '' : $this->trapAction . ', ';
750
            try
751
            {
752
                $this->logging->log('Rule to eval : '.$rule['rule'],INFO );
753
                $evalr=$this->ruleClass->eval_rule($rule['rule'], $this->trapDataExt) ;
754
                //->eval_rule($rule['rule']);
755
                
756
                if ($evalr == true)
757
                {
758
                    //$this->logging->log('rules OOK: '.print_r($rule),INFO );
759
                    $action=$rule['action_match'];
760
                    $this->logging->log('action OK : '.$action,INFO );
761
                    if ($action >= 0)
762
                    {
763
                        if ($this->serviceCheckResult($host_name,$service_name,$action,$display) == false)
764
                        {
765
                            $this->trapAction.='Error sending status : check cmd/API';
766
                        }
767
                        else
768
                        {
769
                            $this->add_rule_match($rule['id'],$rule['num_match']+1);
770
                            $this->trapAction.='Status '.$action.' to '.$host_name.'/'.$service_name;
771
                        }
772
                    }
773
                    else
774
                    {
775
                        $this->add_rule_match($rule['id'],$rule['num_match']+1);
776
                    }
777
                    $this->trapToDb=($action==-2)?false:true;
778
                }
779
                else
780
                {
781
                    //$this->logging->log('rules KOO : '.print_r($rule),INFO );
782
                    
783
                    $action=$rule['action_nomatch'];
784
                    $this->logging->log('action NOK : '.$action,INFO );
785
                    if ($action >= 0)
786
                    {
787
                        if ($this->serviceCheckResult($host_name,$service_name,$action,$display)==false)
788
                        {
789
                            $this->trapAction.='Error sending status : check cmd/API';
790
                        }
791
                        else
792
                        {
793
                            $this->add_rule_match($rule['id'],$rule['num_match']+1);
794
                            $this->trapAction.='Status '.$action.' to '.$host_name.'/'.$service_name;
795
                        }
796
                    }
797
                    else
798
                    {
799
                        $this->add_rule_match($rule['id'],$rule['num_match']+1);
800
                    }
801
                    $this->trapToDb=($action==-2)?false:true;
802
                }
803
                // Put name in source_name
804
                if (!isset($this->trapData['source_name']))
805
                {
806
                    $this->trapData['source_name']=$rule['host_name'];
807
                }
808
                else
809
                {
810
                    if (!preg_match('/'.$rule['host_name'].'/',$this->trapData['source_name']))
811
                    { // only add if not present
812
                        $this->trapData['source_name'].=','.$rule['host_name'];
813
                    }
814
                }
815
            }
816
            catch (Exception $e)
817
            {
818
                $this->logging->log('Error in rule eval : '.$e->getMessage(),WARN,'');
819
                $this->trapAction.=' ERR : '.$e->getMessage();
820
                $this->trapData['status']='error';
821
            }
822
            
823
        }
824
        if ($this->trapData['status']=='error')
825
        {
826
            $this->trapToDb=true; // Always put errors in DB for the use can see
827
        }
828
        else
829
        {
830
            $this->trapData['status']='done';
831
        }
832
    }
833
    
834
    /** Add Time a action to rule
835
     *	@param string $time : time to process to insert in SQL
836
     */
837
    public function add_rule_final($time)
838
    {
839
        $db_conn=$this->trapsDB->db_connect_trap();
840
        if ($this->trapAction==null)
841
        {
842
            $this->trapAction='No action';
843
        }
844
        $sql="UPDATE ".$this->dbPrefix."received SET process_time = '".$time."' , status_detail='".$this->trapAction."'  WHERE (id = '".$this->trapId."');";
845
        if ($db_conn->query($sql) === false) {
846
            $this->logging->log('Error in update query : ' . $sql,WARN,'');
847
        }
848
    }
849
    
850
    /*********** UTILITIES *********************/
851
    
852
    /** reset service to OK after time defined in rule
853
     *	TODO logic is : get all service in error + all rules, see if getting all rules then select services is better
854
     *	@return integer : not in use
855
     **/
856
    public function reset_services()
857
    {
858
        // Get all services not in 'ok' state
859
        $sql_query="SELECT s.service_object_id,
860
	 UNIX_TIMESTAMP(s.last_check) AS last_check,
861
	s.current_state as state,
862
	v.name1 as host_name,
863
    v.name2 as service_name
864
	FROM icinga_servicestatus AS s
865
    LEFT JOIN icinga_objects as v ON s.service_object_id=v.object_id
866
    WHERE s.current_state != 0;";
867
        $db_conn=$this->trapsDB->db_connect_ido();
868
        if (($services_db=$db_conn->query($sql_query)) === false) { // set err to 1 to throw exception.
869
            $this->logging->log('No result in query : ' . $sql_query,ERROR,'');
870
            return 0;
871
        }
872
        $services=$services_db->fetchAll();
873
        
874
        // Get all rules
875
        $sql_query="SELECT host_name, service_name, revert_ok FROM ".$this->dbPrefix."rules where revert_ok != 0;";
876
        $db_conn2=$this->trapsDB->db_connect_trap();
877
        if (($rules_db=$db_conn2->query($sql_query)) === false) {
878
            $this->logging->log('No result in query : ' . $sql_query,ERROR,'');
879
            return 0;
880
        }
881
        $rules=$rules_db->fetchAll();
882
        
883
        $now=date('U');
884
        
885
        $numreset=0;
886
        foreach ($rules as $rule)
887
        {
888
            foreach ($services as $service)
889
            {
890
                if ($service['service_name'] == $rule['service_name'] &&
891
                    $service['host_name'] == $rule['host_name'] &&
892
                    ($service['last_check'] + $rule['revert_ok']) < $now)
893
                {
894
                    $this->serviceCheckResult($service['host_name'],$service['service_name'],0,'Reset service to OK after '.$rule['revert_ok'].' seconds');
895
                    $numreset++;
896
                }
897
            }
898
        }
899
        echo "\n";
900
        echo $numreset . " service(s) reset to OK\n";
901
        return 0;
902
        
903
    }
904
    
905
    
906
}