Passed
Push — master ( 185cb1...b3870e )
by Patrick
01:50
created

Trap::getDBConfigIfSet()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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