Passed
Push — master ( 300cc7...278791 )
by Patrick
01:59
created

Trap::eval_cleanup()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 7
nop 1
dl 0
loc 27
rs 8.8333
c 0
b 0
f 0
1
<?php
2
3
4
//use FontLib\EOT\File;
5
6
include (dirname(__DIR__).'/library/Trapdirector/Icinga2Api.php');
7
include (dirname(__DIR__).'/library/Trapdirector/TrapsProcess/Logging.php');
8
include (dirname(__DIR__).'/library/Trapdirector/TrapsProcess/Database.php');
9
include (dirname(__DIR__).'/library/Trapdirector/TrapsProcess/Mib.php');
10
include (dirname(__DIR__).'/library/Trapdirector/TrapsProcess/Rule.php');
11
12
use Icinga\Module\Trapdirector\Icinga2API;
13
use Trapdirector\Logging;
14
use Trapdirector\Database;
15
use Trapdirector\Mib;
16
use Trapdirector\Rule;
17
18
class Trap
19
{
20
	// Configuration files and dirs
21
	protected $icingaweb2_etc; //< Icinga etc path	
22
	protected $trap_module_config; //< config.ini of module	
23
	protected $icingaweb2_ressources; //< resources.ini of icingaweb2
24
	// Options from config.ini 
25
	protected $snmptranslate='/usr/bin/snmptranslate';
26
	protected $snmptranslate_dirs='/usr/share/icingaweb2/modules/trapdirector/mibs';
27
	protected $icinga2cmd='/var/run/icinga2/cmd/icinga2.cmd';
28
	protected $db_prefix='traps_';
29
30
	// API
31
	protected $api_use=false;
32
	protected $icinga2api=null;
33
	protected $api_hostname='';
34
	protected $api_port=0;
35
	protected $api_username='';
36
	protected $api_password='';
37
38
	// Logs 
39
	protected $logging;    //< Logging class.
40
	protected $logSetup;   //< bool true if log was setup in constructor
41
	
42
	// Databases
43
	public $trapsDB; //< Database class
44
	
45
	// Trap received data
46
	protected $receivingHost;
47
	public $trap_data=array(); //< Main trap data (oid, source...)
48
	public $trap_data_ext=array(); //< Additional trap data objects (oid/value).
49
	public $trap_id=null; //< trap_id after sql insert
50
	public $trap_action=null; //< trap action for final write
51
	protected $trap_to_db=true; //< log trap to DB
52
	
53
	// Mib update data
54
	public $mibClass; //< Mib class
55
	
56
	// Rule evaluation 
57
	public $ruleClass; // Rule class
58
	
59
	function __construct($etc_dir='/etc/icingaweb2',$baseLogLevel=null,$baseLogMode='syslog',$baseLogFile='')
60
	{
61
	    // Paths of ini files
62
		$this->icingaweb2_etc=$etc_dir;
63
		$this->trap_module_config=$this->icingaweb2_etc."/modules/trapdirector/config.ini";		
64
		$this->icingaweb2_ressources=$this->icingaweb2_etc."/resources.ini";
65
66
		// Setup logging
67
		$this->logging = new Logging();
68
		if ($baseLogLevel != null)
69
		{
70
		    $this->logging->setLogging($baseLogLevel, $baseLogMode,$baseLogFile);
71
		    $this->logSetup=true;
72
		}
73
		else
74
		    $this->logSetup=false;
75
		$this->logging->log('Loggin started', INFO);
76
77
		// Get options from ini files
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
		}
83
		$this->getMainOptions($trapConfig); // Get main options from ini file
84
		$this->setupDatabase($trapConfig); // Setup database class
85
		
86
		$this->getDatabaseOptions(); // Get options in database
87
		if ($this->api_use === true) $this->getAPI(); // Setup API
88
		
89
		$this->mibClass = new Mib($this->logging,$this->trapsDB,$this->snmptranslate,$this->snmptranslate_dirs); // Create Mib class
90
		
91
		$this->ruleClass = new Rule($this->logging); //< Create Rule class
92
		
93
		$this->trap_data=array(
94
			'source_ip'	=> 'unknown',
95
			'source_port'	=> 'unknown',
96
			'destination_ip'	=> 'unknown',
97
			'destination_port'	=> 'unknown',
98
			'trap_oid'	=> 'unknown',
99
		);
100
		
101
	}
102
	
103
	/**
104
	 * Get option from array of ini file, send message if empty
105
	 * @param string $option_array Array of ini file
106
	 * @param string $option_category category in ini file
107
	 * @param string $option_name name of option in category
108
	 * @param resource $option_var variable to fill if found, left untouched if not found
109
	 * @param integer $log_level default 2 (warning)
110
	 * @param string $message warning message if not found
111
	 * @return boolean true if found, or false
112
	 */
113
	protected function getOptionIfSet($option_array,$option_category,$option_name, &$option_var, $log_level = 2, $message = null)
114
	{
115
	    if (!isset($option_array[$option_category][$option_name]))
116
	    {
117
	        if ($message === null)
118
	        {
119
	            $message='No ' . $option_name . ' in config file: '. $this->trap_module_config;
120
	        }
121
	        $this->logging->log($message,$log_level,'syslog');
122
	        return false;
123
	    }
124
	    else
125
	    {
126
	        $option_var=$option_array[$option_category][$option_name];
127
	        return true;
128
	    }
129
	}
130
	
131
	/** 
132
	 * Get options from ini file
133
	 * @param array $trap_config : ini file array
134
	*/
135
	protected function getMainOptions($trapConfig)
136
	{
137
138
		// Snmptranslate binary path
139
		$this->getOptionIfSet($trapConfig,'config','snmptranslate', $this->snmptranslate);
140
141
		// mibs path
142
		$this->getOptionIfSet($trapConfig,'config','snmptranslate_dirs', $this->snmptranslate_dirs);
143
144
		// icinga2cmd path
145
		$this->getOptionIfSet($trapConfig,'config','icingacmd', $this->icinga2cmd);
146
		
147
		// table prefix
148
		$this->getOptionIfSet($trapConfig,'config','database_prefix', $this->db_prefix);
149
150
		// API options
151
		if ($this->getOptionIfSet($trapConfig,'config','icingaAPI_host', $this->api_hostname))
152
		{
153
		    $this->api_use=true;
154
		    $this->getOptionIfSet($trapConfig,'config','icingaAPI_port', $this->api_port);
0 ignored issues
show
Bug introduced by
$this->api_port of type integer is incompatible with the type resource expected by parameter $option_var of Trap::getOptionIfSet(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

154
		    $this->getOptionIfSet($trapConfig,'config','icingaAPI_port', /** @scrutinizer ignore-type */ $this->api_port);
Loading history...
155
		    $this->getOptionIfSet($trapConfig,'config','icingaAPI_user', $this->api_username);
0 ignored issues
show
Bug introduced by
$this->api_username of type string is incompatible with the type resource expected by parameter $option_var of Trap::getOptionIfSet(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

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

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...