Passed
Push — master ( 27233f...bd4945 )
by Patrick
02:03
created

Trap::create_schema()   B

Complexity

Conditions 8
Paths 19

Size

Total Lines 45
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

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

151
		    $this->getOptionIfSet($trapConfig,'config','icingaAPI_port', /** @scrutinizer ignore-type */ $this->api_port);
Loading history...
152
		    $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

152
		    $this->getOptionIfSet($trapConfig,'config','icingaAPI_user', /** @scrutinizer ignore-type */ $this->api_username);
Loading history...
153
		    $this->getOptionIfSet($trapConfig,'config','icingaAPI_password', $this->api_password);
154
		}
155
	}
156
	
157
	/**
158
	 * Create and setup database class for trap & ido (if no api) db
159
	 * @param array $trap_config : ini file array
160
	 */
161
	protected function setupDatabase($trapConfig)
162
	{
163
	    // Trap database
164
	    if (!array_key_exists('database',$trapConfig['config']))
165
        {
166
            $this->logging->log("No database in config file: ".$this->trap_module_config,ERROR,'');
167
            return;
168
        }
169
        $dbTrapName=$trapConfig['config']['database'];
170
        $this->logging->log("Found database in config file: ".$dbTrapName,INFO );
171
	    
172
	   if ( ($dbConfig=parse_ini_file($this->icingaweb2_ressources,true)) === false)
173
	    {
174
	        $this->logging->log("Error reading ini file : ".$this->icingaweb2_ressources,ERROR,'');
175
	        return;
176
	    }
177
	    if (!array_key_exists($dbTrapName,$dbConfig))
178
	    {
179
	        $this->logging->log("No database '.$dbTrapName.' in config file: ".$this->icingaweb2_ressources,ERROR,'');
180
	        return;
181
	    }
182
	    
183
        $this->trapsDB = new Database($this->logging,$dbConfig[$dbTrapName]);
184
	    
185
	    if ($this->api_use === true) return; // In case of API use, no IDO is necessary
186
        
187
	    // IDO Database
188
	    if (!array_key_exists('IDOdatabase',$trapConfig['config']))
189
	    {
190
	        $this->logging->log("No IDOdatabase in config file: ".$this->trap_module_config,ERROR,'');
191
	    }
192
	    $dbIdoName=$trapConfig['config']['IDOdatabase'];		
193
194
	    $this->logging->log("Found IDO database in config file: ".$dbIdoName,INFO );
195
        if (!array_key_exists($dbIdoName,$dbConfig))
196
	    {
197
	        $this->logging->log("No database '.$dbIdoName.' in config file: ".$this->icingaweb2_ressources,ERROR,'');
198
	        return;
199
	    }
200
	    
201
	    $this->trapsDB->setupIDO($dbConfig[$dbIdoName]);
202
	}
203
	
204
	/**
205
	 * Get options in database
206
	 */
207
	protected function getDatabaseOptions()
208
	{
209
		// Database options
210
		if ($this->logSetup === false) // Only if logging was no setup in constructor
211
		{
212
    		$this->getDBConfigIfSet('log_level',$this->logging->debugLevel);
213
    		$this->getDBConfigIfSet('log_destination',$this->logging->outputMode);
214
    		$this->getDBConfigIfSet('log_file',$this->logging->outputFile);
215
		}
216
	}
217
218
	protected function getDBConfigIfSet($element,&$variable)
219
	{
220
		$value=$this->getDBConfig($element);
221
		if ($value != 'null') $variable=$value;
222
	}
223
	
224
	/** 
225
	*   Get data from db_config
226
	*	@param $element string name of param
227
	*	@return mixed : value (or null)
228
	*/	
229
	protected function getDBConfig($element)
230
	{
231
		$db_conn=$this->trapsDB->db_connect_trap();
232
		$sql='SELECT value from '.$this->db_prefix.'db_config WHERE ( name=\''.$element.'\' )';
233
		if (($ret_code=$db_conn->query($sql)) === false) {
234
			$this->logging->log('No result in query : ' . $sql,WARN,'');
235
			return null;
236
		}
237
		$value=$ret_code->fetch();
238
		if ($value != null && isset($value['value']))
239
		{
240
			return $value['value'];
241
		}
242
		return null;
243
	}
244
	
245
	/** OBSOLETE Send log. Throws exception on critical error
246
	*	@param	string $message Message to log
247
	*	@param	int $level 1=critical 2=warning 3=trace 4=debug
248
	*	@param  string $destination file/syslog/display
249
	*	@return void
250
	**/	
251
	public function trapLog( $message, $level, $destination ='') // OBSOLETE
252
	{	
253
		// TODO : replace ref with $this->logging->log 
254
	    $this->logging->log($message, $level, $destination);
255
	}
256
	
257
	public function setLogging($debugLvl,$outputType,$outputOption=null)  // OBSOLETE
258
	{
259
		$this->logging->setLogging($debugLvl, $outputType,$outputOption);
260
	}
261
	
262
	protected function getAPI()
263
	{
264
	    if ($this->icinga2api == null)
265
	    {
266
	        $this->icinga2api = new Icinga2API($this->api_hostname,$this->api_port);
267
	    }
268
	    return $this->icinga2api;
269
	}
270
	
271
	
272
	/** 
273
	 * read data from stream
274
	*	@param $stream string input stream, defaults to "php://stdin"
275
	*	@return mixed array trap data or exception with error
276
	*/
277
	public function read_trap($stream='php://stdin')
278
	{
279
		//Read data from snmptrapd from stdin
280
		$input_stream=fopen($stream, 'r');
281
282
		if ($input_stream === false)
283
		{
284
		    $this->writeTrapErrorToDB("Error reading trap (code 1/Stdin)");
285
			$this->logging->log("Error reading stdin !",ERROR,'');
286
			return null; // note : exception thrown by logging
287
		}
288
289
		// line 1 : host
290
		$this->receivingHost=chop(fgets($input_stream));
291
		if ($this->receivingHost === false)
292
		{
293
		    $this->writeTrapErrorToDB("Error reading trap (code 1/Line Host)");
294
			$this->logging->log("Error reading Host !",ERROR,''); 
295
		}
296
		// line 2 IP:port=>IP:port
297
		$IP=chop(fgets($input_stream));
298
		if ($IP === false)
299
		{
300
		    $this->writeTrapErrorToDB("Error reading trap (code 1/Line IP)");
301
			$this->logging->log("Error reading IP !",ERROR,''); 
302
		}
303
		$matches=array();
304
		$ret_code=preg_match('/.DP: \[(.*)\]:(.*)->\[(.*)\]:(.*)/',$IP,$matches);
305
		if ($ret_code===0 || $ret_code===false) 
306
		{
307
		    $this->writeTrapErrorToDB("Error parsing trap (code 2/IP)");
308
			$this->logging->log('Error parsing IP : '.$IP,ERROR,'');
309
		} 
310
		else 
311
		{		
312
			$this->trap_data['source_ip']=$matches[1];
313
			$this->trap_data['destination_ip']=$matches[3];
314
			$this->trap_data['source_port']=$matches[2];
315
			$this->trap_data['destination_port']=$matches[4];
316
		}
317
318
		while (($vars=fgets($input_stream)) !==false)
319
		{
320
			$vars=chop($vars);
321
			$ret_code=preg_match('/^([^ ]+) (.*)$/',$vars,$matches);
322
			if ($ret_code===0 || $ret_code===false) 
323
			{
324
				$this->logging->log('No match on trap data : '.$vars,WARN,'');
325
			}
326
			else 
327
			{
328
			    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'))
329
				{
330
					$this->trap_data['trap_oid']=$matches[2];				
331
				}
332
				else
333
				{
334
					$object= new stdClass;
335
					$object->oid =$matches[1];
336
					$object->value = $matches[2];
337
					array_push($this->trap_data_ext,$object);
338
				}
339
			}
340
		}
341
342
		if ($this->trap_data['trap_oid']=='unknown') 
343
		{
344
		    $this->writeTrapErrorToDB("No trap oid found : check snmptrapd configuration (code 3/OID)",$this->trap_data['source_ip']);
345
			$this->logging->log('no trap oid found',ERROR,'');
346
		} 
347
348
		// Translate oids.
349
		
350
		$retArray=$this->translateOID($this->trap_data['trap_oid']);
351
		if ($retArray != null)
352
		{
353
			$this->trap_data['trap_name']=$retArray['trap_name'];
354
			$this->trap_data['trap_name_mib']=$retArray['trap_name_mib'];
355
		}
356
		foreach ($this->trap_data_ext as $key => $val)
357
		{
358
			$retArray=$this->translateOID($val->oid);
359
			if ($retArray != null)
360
			{
361
				$this->trap_data_ext[$key]->oid_name=$retArray['trap_name'];
362
				$this->trap_data_ext[$key]->oid_name_mib=$retArray['trap_name_mib'];
363
			}			
364
		}
365
		
366
367
		$this->trap_data['status']= 'waiting';
368
		
369
		return $this->trap_data;
370
	}
371
372
	/** 
373
	 * Translate oid into array(MIB,Name)
374
	* @param $oid string oid to translate
375
	* @return mixed : null if not found or array(MIB,Name)
376
	*/
377
	public function translateOID($oid)
378
	{
379
		// try from database
380
		$db_conn=$this->trapsDB->db_connect_trap();
381
		
382
		$sql='SELECT mib,name from '.$this->db_prefix.'mib_cache WHERE oid=\''.$oid.'\';';
383
		$this->logging->log('SQL query : '.$sql,DEBUG );
384
		if (($ret_code=$db_conn->query($sql)) === false) {
385
			$this->logging->log('No result in query : ' . $sql,ERROR,'');
386
		}
387
		$name=$ret_code->fetch();
388
		if ($name['name'] != null)
389
		{
390
			return array('trap_name_mib'=>$name['mib'],'trap_name'=>$name['name']);
391
		}
392
		
393
		// Also check if it is an instance of OID
394
		$oid_instance=preg_replace('/\.[0-9]+$/','',$oid);
395
		
396
		$sql='SELECT mib,name from '.$this->db_prefix.'mib_cache WHERE oid=\''.$oid_instance.'\';';
397
		$this->logging->log('SQL query : '.$sql,DEBUG );
398
		if (($ret_code=$db_conn->query($sql)) === false) {
399
			$this->logging->log('No result in query : ' . $sql,ERROR,'');
400
		}
401
		$name=$ret_code->fetch();
402
		if ($name['name'] != null)
403
		{
404
			return array('trap_name_mib'=>$name['mib'],'trap_name'=>$name['name']);
405
		}
406
		
407
		// Try to get oid name from snmptranslate
408
		$translate=exec($this->snmptranslate . ' -m ALL -M +'.$this->snmptranslate_dirs.
409
		    ' '.$oid);
410
		$matches=array();
411
		$ret_code=preg_match('/(.*)::(.*)/',$translate,$matches);
412
		if ($ret_code===0 || $ret_code === false) {
413
			return NULL;
414
		} else {
415
			$this->logging->log('Found name with snmptrapd and not in DB for oid='.$oid,INFO);
416
			return array('trap_name_mib'=>$matches[1],'trap_name'=>$matches[2]);
417
		}	
418
	}
419
	
420
	/** 
421
	 * Erase old trap records 
422
	*	@param integer $days : erase traps when more than $days old
423
	*	@return integer : number of lines deleted
424
	**/
425
	public function eraseOldTraps($days=0)
426
	{
427
		if ($days==0)
428
		{
429
			if (($days=$this->getDBConfig('db_remove_days')) == null)
430
			{
431
				$this->logging->log('No days specified & no db value : no tap erase' ,WARN,'');
432
				return;
433
			}
434
		}
435
		$db_conn=$this->trapsDB->db_connect_trap();
436
		$daysago = strtotime("-".$days." day");
437
		$sql= 'delete from '.$this->db_prefix.'received where date_received < \''.date("Y-m-d H:i:s",$daysago).'\';';
438
		if ($db_conn->query($sql) === false) {
439
			$this->logging->log('Error erasing traps : '.$sql,ERROR,'');
440
		}
441
		$this->logging->log('Erased traps older than '.$days.' day(s) : '.$sql,INFO);
442
	}
443
444
	/** Write error to received trap database
445
	 */
446
	public function writeTrapErrorToDB($message,$sourceIP=null,$trapoid=null)
447
	{
448
	    
449
	    $db_conn=$this->trapsDB->db_connect_trap();
450
	    
451
	    // add date time
452
	    $insert_col ='date_received,status';
453
	    $insert_val = "'" . date("Y-m-d H:i:s")."','error'";
454
        
455
	    if ($sourceIP !=null)
456
	    {
457
	        $insert_col .=',source_ip';
458
	        $insert_val .=",'". $sourceIP ."'";
459
	    }
460
	    if ($trapoid !=null)
461
	    {
462
	        $insert_col .=',trap_oid';
463
	        $insert_val .=",'". $trapoid ."'";
464
	    }
465
	    $insert_col .=',status_detail';
466
	    $insert_val .=",'". $message ."'";
467
	    
468
	    $sql= 'INSERT INTO '.$this->db_prefix.'received (' . $insert_col . ') VALUES ('.$insert_val.')';
469
	    
470
	    switch ($this->trapsDB->trapDBType)
471
	    {
472
	        case 'pgsql':
473
	            $sql .= ' RETURNING id;';
474
	            $this->logging->log('sql : '.$sql,INFO);
475
	            if (($ret_code=$db_conn->query($sql)) === false) {
476
	                $this->logging->log('Error SQL insert : '.$sql,1,'');
477
	            }
478
	            $this->logging->log('SQL insertion OK',INFO );
479
	            // Get last id to insert oid/values in secondary table
480
	            if (($inserted_id_ret=$ret_code->fetch(PDO::FETCH_ASSOC)) === false) {
481
	                
482
	                $this->logging->log('Erreur recuperation id',1,'');
483
	            }
484
	            if (! isset($inserted_id_ret['id'])) {
485
	                $this->logging->log('Error getting id',1,'');
486
	            }
487
	            $this->trap_id=$inserted_id_ret['id'];
488
	            break;
489
	        case 'mysql':
490
	            $sql .= ';';
491
	            $this->logging->log('sql : '.$sql,INFO );
492
	            if ($db_conn->query($sql) === false) {
493
	                $this->logging->log('Error SQL insert : '.$sql,1,'');
494
	            }
495
	            $this->logging->log('SQL insertion OK',INFO );
496
	            // Get last id to insert oid/values in secondary table
497
	            $sql='SELECT LAST_INSERT_ID();';
498
	            if (($ret_code=$db_conn->query($sql)) === false) {
499
	                $this->logging->log('Erreur recuperation id',1,'');
500
	            }
501
	            
502
	            $inserted_id=$ret_code->fetch(PDO::FETCH_ASSOC)['LAST_INSERT_ID()'];
503
	            if ($inserted_id==false) throw new Exception("Weird SQL error : last_insert_id returned false : open issue");
504
	            $this->trap_id=$inserted_id;
505
	            break;
506
	        default:
507
	            $this->logging->log('Error SQL type unknown  : '.$this->trapsDB->trapDBType,1,'');
508
	    }
509
	    
510
	    $this->logging->log('id found: '. $this->trap_id,INFO );    
511
	}
512
	
513
	/** Write trap data to trap database
514
	*/
515
	public function writeTrapToDB()
516
	{
517
		
518
		// If action is ignore -> don't send t DB
519
		if ($this->trap_to_db === false) return;
520
		
521
		
522
		$db_conn=$this->trapsDB->db_connect_trap();
523
		
524
		$insert_col='';
525
		$insert_val='';
526
		// add date time
527
		$this->trap_data['date_received'] = date("Y-m-d H:i:s");
528
529
		$firstcol=1;
530
		foreach ($this->trap_data 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->db_prefix.'received (' . $insert_col . ') VALUES ('.$insert_val.')';
543
		switch ($this->trapsDB->trapDBType)
544
		{
545
			case 'pgsql': 
546
				$sql .= ' RETURNING id;';
547
				$this->logging->log('sql : '.$sql,INFO );
548
				if (($ret_code=$db_conn->query($sql)) === false) {
549
					$this->logging->log('Error SQL insert : '.$sql,ERROR,'');
550
				}
551
				$this->logging->log('SQL insertion OK',INFO );
552
				// Get last id to insert oid/values in secondary table
553
				if (($inserted_id_ret=$ret_code->fetch(PDO::FETCH_ASSOC)) === false) {
554
														   
555
					$this->logging->log('Erreur recuperation id',ERROR,'');
556
				}
557
				if (! isset($inserted_id_ret['id'])) {
558
					$this->logging->log('Error getting id',ERROR,'');
559
				}
560
				$this->trap_id=$inserted_id_ret['id'];
561
			break;
562
			case 'mysql': 
563
				$sql .= ';';
564
				$this->logging->log('sql : '.$sql,INFO );
565
				if ($db_conn->query($sql) === false) {
566
					$this->logging->log('Error SQL insert : '.$sql,ERROR,'');
567
				}
568
				$this->logging->log('SQL insertion OK',INFO );
569
				// Get last id to insert oid/values in secondary table
570
				$sql='SELECT LAST_INSERT_ID();';
571
				if (($ret_code=$db_conn->query($sql)) === false) {
572
					$this->logging->log('Erreur recuperation id',ERROR,'');
573
				}
574
575
				$inserted_id=$ret_code->fetch(PDO::FETCH_ASSOC)['LAST_INSERT_ID()'];
576
				if ($inserted_id==false) throw new Exception("Weird SQL error : last_insert_id returned false : open issue");
577
				$this->trap_id=$inserted_id;
578
			break;
579
			default: 
580
				$this->logging->log('Error SQL type unknown : '.$this->trapsDB->trapDBType,ERROR,'');
581
		}
582
		$this->logging->log('id found: '.$this->trap_id,INFO );
583
		
584
		// Fill trap extended data table
585
		foreach ($this->trap_data_ext as $value) {			
586
			// TODO : detect if trap value is encoded and decode it to UTF-8 for database
587
			$firstcol=1;
588
			$value->trap_id = $this->trap_id;
589
			$insert_col='';
590
			$insert_val='';
591
			foreach ($value as $col => $val)
592
			{
593
				if ($firstcol==0) 
594
				{
595
					$insert_col .=',';
596
					$insert_val .=',';
597
				}
598
				$insert_col .= $col;
599
				$insert_val .= ($val==null)? 'NULL' : $db_conn->quote($val);
600
				$firstcol=0;
601
			}
602
603
			$sql= 'INSERT INTO '.$this->db_prefix.'received_data (' . $insert_col . ') VALUES ('.$insert_val.');';			
604
605
			if ($db_conn->query($sql) === false) {
606
				$this->logging->log('Erreur insertion data : ' . $sql,WARN,'');
607
			}	
608
		}	
609
	}
610
611
	/** Get rules from rule database with ip and oid
612
	*	@param $ip string ipv4 or ipv6
613
	*	@param $oid string oid in numeric
614
	*	@return mixed : PDO object or false
615
	*/	
616
	protected function getRules($ip,$oid)
617
	{
618
		$db_conn=$this->trapsDB->db_connect_trap();
619
		// fetch rules based on IP in rule and OID
620
		$sql='SELECT * from '.$this->db_prefix.'rules WHERE trap_oid=\''.$oid.'\' ';
621
		$this->logging->log('SQL query : '.$sql,DEBUG );
622
		if (($ret_code=$db_conn->query($sql)) === false) {
623
			$this->logging->log('No result in query : ' . $sql,WARN,'');
624
			return false;
625
		}
626
		$rules_all=$ret_code->fetchAll();
627
		//echo "rule all :\n";print_r($rules_all);echo "\n";
628
		$rules_ret=array();
629
		$rule_ret_key=0;
630
		foreach ($rules_all as $key => $rule)
631
		{
632
			if ($rule['ip4']==$ip || $rule['ip6']==$ip)
633
			{
634
				$rules_ret[$rule_ret_key]=$rules_all[$key];
635
				//TODO : get host name by API (and check if correct in rule).
636
				$rule_ret_key++;
637
				continue;
638
			}
639
			// TODO : get hosts IP by API
640
			if (isset($rule['host_group_name']) && $rule['host_group_name']!=null)
641
			{ // get ips of group members by oid
642
				$db_conn2=$this->trapsDB->db_connect_ido();
643
				$sql="SELECT m.host_object_id, a.address as ip4, a.address6 as ip6, b.name1 as host_name
644
						FROM icinga_objects as o
645
						LEFT JOIN icinga_hostgroups as h ON o.object_id=h.hostgroup_object_id
646
						LEFT JOIN icinga_hostgroup_members as m ON h.hostgroup_id=m.hostgroup_id
647
						LEFT JOIN icinga_hosts as a ON a.host_object_id = m.host_object_id
648
						LEFT JOIN icinga_objects as b ON b.object_id = a.host_object_id
649
						WHERE o.name1='".$rule['host_group_name']."';";
650
				if (($ret_code2=$db_conn2->query($sql)) === false) {
651
					$this->logging->log('No result in query : ' . $sql,WARN,'');
652
					continue;
653
				}
654
				$grouphosts=$ret_code2->fetchAll();
655
				//echo "rule grp :\n";print_r($grouphosts);echo "\n";
656
				foreach ( $grouphosts as $host)
657
				{
658
					//echo $host['ip4']."\n";
659
					if ($host['ip4']==$ip || $host['ip6']==$ip)
660
					{
661
						//echo "Rule added \n";
662
						$rules_ret[$rule_ret_key]=$rules_all[$key];
663
						$rules_ret[$rule_ret_key]['host_name']=$host['host_name'];
664
						$rule_ret_key++;
665
					}	
666
				}
667
			}
668
		}
669
		//echo "rule rest :\n";print_r($rules_ret);echo "\n";exit(0);
670
		return $rules_ret;
671
	}
672
673
	/** Add rule match to rule
674
	*	@param id int : rule id
675
	*   @param set int : value to set
676
	*/
677
	protected function add_rule_match($id, $set)
678
	{
679
		$db_conn=$this->trapsDB->db_connect_trap();
680
		$sql="UPDATE ".$this->db_prefix."rules SET num_match = '".$set."' WHERE (id = '".$id."');";
681
		if ($db_conn->query($sql) === false) {
682
			$this->logging->log('Error in update query : ' . $sql,WARN,'');
683
		}
684
	}
685
	
686
	/** Send SERVICE_CHECK_RESULT with icinga2cmd or API
687
	 * 
688
	 * @param string $host
689
	 * @param string $service
690
	 * @param integer $state numerical staus 
691
	 * @param string $display
692
	 * @returnn bool true is service check was sent without error
693
	*/
694
	public function serviceCheckResult($host,$service,$state,$display)
695
	{
696
	    if ($this->api_use === false)
697
	    {
698
    		$send = '[' . date('U') .'] PROCESS_SERVICE_CHECK_RESULT;' .
699
    			$host.';' .$service .';' . $state . ';'.$display;
700
    		$this->logging->log( $send." : to : " .$this->icinga2cmd,INFO );
701
    		
702
    		// TODO : file_put_contents & fopen (,'w' or 'a') does not work. See why. Or not as using API will be by default....
703
    		exec('echo "'.$send.'" > ' .$this->icinga2cmd);
704
    		return true;
705
	    }
706
	    else
707
	    {
708
	        $api = $this->getAPI();
709
	        $api->setCredentials($this->api_username, $this->api_password);
710
	        list($retcode,$retmessage)=$api->serviceCheckResult($host,$service,$state,$display);
711
	        if ($retcode == false)
712
	        {
713
	            $this->logging->log( "Error sending result : " .$retmessage,WARN,'');
714
	            return false;
715
	        }
716
	        else 
717
	        {
718
	            $this->logging->log( "Sent result : " .$retmessage,INFO );
719
	            return true;
720
	        }
721
	    }
722
	}
723
	
724
	public function getHostByIP($ip)
725
	{
726
	    $api = $this->getAPI();
727
	    $api->setCredentials($this->api_username, $this->api_password);
728
	    return $api->getHostByIP($ip);
729
	}
730
	
731
	/** Resolve display. 
732
	*	Changes OID(<oid>) to value if found or text "<not in trap>"
733
	*	@param $display string
734
	*	@return string display
735
	*/
736
	protected function applyDisplay($display)
737
	{
738
	    $matches=array();
739
	    while (preg_match('/_OID\(([0-9\.]+)\)/',$display,$matches) == 1)
740
		{
741
			$oid=$matches[1];
742
			$found=0;
743
			foreach($this->trap_data_ext as $val)
744
			{
745
				if ($oid == $val->oid)
746
				{
747
					$val->value=preg_replace('/"/','',$val->value);
748
					$rep=0;
749
					$display=preg_replace('/_OID\('.$oid.'\)/',$val->value,$display,-1,$rep);
750
					if ($rep==0)
751
					{
752
						$this->logging->log("Error in display",WARN,'');
753
						return $display;
754
					}
755
					$found=1;
756
					break;
757
				}
758
			}
759
			if ($found==0)
760
			{
761
				$display=preg_replace('/_OID\('.$oid.'\)/','<not in trap>',$display,-1,$rep);
762
				if ($rep==0)
763
				{
764
					$this->logging->log("Error in display",WARN,'');
765
					return $display;
766
				}				
767
			}
768
		}
769
		return $display;
770
	}
771
772
	
773
	/***************** Eval & tokenizer functions ****************/
774
	protected function eval_getElement($rule,&$item)
775
	{
776
		while ($rule[$item]==' ') $item++;
777
		if (preg_match('/[0-9\.]/',$rule[$item]))
778
		{ // number
779
	
780
			$item2=$item+1; 
781
			while (($item2!=strlen($rule)) && (preg_match('/[0-9\.]/',$rule[$item2]))) { $item2++ ;}
782
			$val=substr($rule,$item,$item2-$item);
783
			$item=$item2;
784
			//echo "number ".$val."\n";
785
			return array(0,$val);
786
		}
787
		if ($rule[$item] == '"')
788
		{ // string
789
			$item++;
790
			$item2=$this->eval_getNext($rule,$item,'"');
791
			$val=substr($rule,$item,$item2-$item-1);
792
			$item=$item2;
793
			//echo "string : ".$val."\n";
794
			return array(1,$val);
795
		}
796
		
797
		if ($rule[$item] == '(')
798
		{ // grouping
799
		    $item++;
800
			$start=$item;
801
			$parenthesis_count=0; 
802
			while (($item < strlen($rule)) // Not end of string AND
803
			      && ( ($rule[$item] != ')' ) || $parenthesis_count > 0) ) // Closing ')' or embeded ()
804
			{ 
805
				if ($rule[$item] == '"' )
806
				{ // pass through string
807
					$item++;
808
					$item=$this->eval_getNext($rule,$item,'"');
809
				} 
810
				else{
811
				    if ($rule[$item] == '(')
812
				    {
813
				        $parenthesis_count++;
814
				    }
815
				    if ($rule[$item] == ')')
816
				    {
817
				        $parenthesis_count--;
818
				    }
819
					$item++;
820
				}
821
			}
822
			
823
			if ($item==strlen($rule)) {throw new Exception("no closing () in ".$rule ." at " .$item);}
824
			$val=substr($rule,$start,$item-$start);
825
			$item++;
826
			$start=0;
827
			//echo "group : ".$val."\n";
828
			// returns evaluation of group as type 2 (boolean)
829
			return array(2,$this->evaluation($val,$start));		
830
		}
831
		throw new Exception("number/string not found in ".$rule ." at " .$item . ' : ' .$rule[$item]);
832
		
833
	}
834
	
835
	protected function eval_getNext($rule,$item,$tok)
836
	{
837
		while (($rule[$item] != $tok ) && ($item < strlen($rule))) { $item++;}
838
		if ($item==strlen($rule)) throw new Exception("closing '".$tok."' not found in ".$rule ." at " .$item);
839
		return $item+1;
840
	}
841
	
842
	protected function eval_getOper($rule,&$item)
843
	{
844
		while ($rule[$item]==' ') $item++;
845
		switch ($rule[$item])
846
		{
847
			case '<':
848
				if ($rule[$item+1]=='=') { $item+=2; return array(0,"<=");}
849
				$item++; return array(0,"<");
850
			case '>':
851
				if ($rule[$item+1]=='=') { $item+=2; return array(0,">=");}
852
				$item++; return array(0,">");
853
			case '=':
854
				$item++; return array(0,"=");	
855
			case '!':
856
				if ($rule[$item+1]=='=') { $item+=2; return array(0,"!=");}
857
				throw new Exception("Erreur in expr - incorrect operator '!'  found in ".$rule ." at " .$item);
858
			case '~':
859
				$item++; return array(0,"~");	
860
			case '|':
861
				$item++; return array(1,"|");	
862
			case '&':
863
				$item++; return array(1,"&");
864
			default	:
865
				throw new Exception("Erreur in expr - operator not found in ".$rule ." at " .$item);
866
		}
867
	}
868
	
869
	/** Evaluation : makes token and evaluate. 
870
	*	Public function for expressions testing
871
	*	accepts : < > = <= >= !=  (typec = 0)
872
	*	operators : & | (typec=1)
873
	*	with : integers/float  (type 0) or strings "" (type 1) or results (type 2)
874
	*   comparison int vs strings will return null (error)
875
	*	return : bool or null on error
876
	*/
877
	public function evaluation($rule,&$item)
878
	{
879
	    //echo "Evaluation of ".substr($rule,$item)."\n";
880
		if ( $rule[$item] == '!') // If '!' found, negate next expression.
881
		{
882
		    $negate=true;
883
		    $item++;
884
		}
885
		else
886
		{
887
		    $negate=false;
888
		}
889
		// First element : number, string or ()
890
		list($type1,$val1) = $this->eval_getElement($rule,$item);
891
		//echo "Elmt1: ".$val1."/".$type1." : ".substr($rule,$item)."\n";
892
		
893
		if ($item==strlen($rule)) // If only element, return value, but only boolean
894
		{
895
		  if ($type1 != 2) throw new Exception("Cannot use num/string as boolean : ".$rule);
896
		  if ($negate === true) $val1= ! $val1;
897
		  return $val1;
898
		}  
899
		
900
		// Second element : operator
901
		list($typec,$comp) = $this->eval_getOper($rule,$item);
902
		//echo "Comp : ".$comp." : ".substr($rule,$item)."\n";
903
        
904
		// Third element : number, string or ()
905
		if ( $rule[$item] == '!') // starts with a ! so evaluate whats next
906
		{
907
		    $item++;
908
		    if ($typec != 1) throw new Exception("Mixing boolean and comparison : ".$rule);
909
		    $val2= ! $this->evaluation($rule,$item);
910
		    $type2=2; // result is a boolean 
911
		}
912
		else 
913
		{
914
		    list($type2,$val2) = $this->eval_getElement($rule,$item);
915
		}
916
		//echo "Elmt2: ".$val2."/".$type2." : ".substr($rule,$item)."\n";
917
		
918
		if ($type1!=$type2)  // cannot compare different types
919
		{ 
920
		    throw new Exception("Cannot compare string & number : ".$rule);
921
		}
922
		if ($typec==1 && $type1 !=2) // cannot use & or | with string/number
923
		{
924
		    throw new Exception("Cannot use boolean operators with string & number : ".$rule);
925
		}
926
		
927
		switch ($comp){
928
			case '<':	$retVal= ($val1 < $val2); break;
929
			case '<=':	$retVal= ($val1 <= $val2); break;
930
			case '>':	$retVal= ($val1 > $val2); break;
931
			case '>=':	$retVal= ($val1 >= $val2); break;
932
			case '=':	$retVal= ($val1 == $val2); break;
933
			case '!=':	$retVal= ($val1 != $val2); break;
934
			case '~':	$retVal= (preg_match('/'.preg_replace('/"/','',$val2).'/',$val1)); break;
935
			case '|':	$retVal= ($val1 || $val2); break;
936
			case '&':	$retVal= ($val1 && $val2); break;
937
			default:  throw new Exception("Error in expression - unknown comp : ".$comp);
938
		}
939
		if ($negate === true) $retVal = ! $retVal; // Inverse result if negate before expression
940
		
941
		if ($item==strlen($rule)) return $retVal; // End of string : return evaluation
942
		// check for logical operator :
943
		switch ($rule[$item])
944
		{
945
			case '|':	$item++; return ($retVal || $this->evaluation($rule,$item) );
946
			case '&':	$item++; return ($retVal && $this->evaluation($rule,$item) );
947
			
948
			default:  throw new Exception("Erreur in expr - garbadge at end of expression : ".$rule[$item]);
949
		}
950
	}
951
	// Remove all whitespaces (when not quoted)
952
	public function eval_cleanup($rule)
953
	{
954
		$item=0;
955
		$rule2='';
956
		while ($item < strlen($rule))
957
		{
958
			if ($rule[$item]==' ') { $item++; continue; }
959
			if ($rule[$item]=='"')
960
			{
961
				$rule2.=$rule[$item];
962
				$item++;
963
				while (($rule[$item]!='"') && ($item < strlen($rule)))
964
				{
965
					$rule2.=$rule[$item];
966
					$item++;
967
				}
968
				if ($item == strlen ($rule)) throw new Exception("closing '\"' not found in ".$rule ." at " .$item);
969
				$rule2.=$rule[$item];
970
				$item++;
971
				continue;
972
			}
973
			
974
			$rule2.=$rule[$item];
975
			$item++;		
976
		}
977
		
978
		return $rule2;		
979
	}		
980
	
981
	/** Evaluation rule (uses eval_* functions recursively)
982
	*	@param $rule string rule ( _OID(.1.3.6.1.4.1.8072.2.3.2.1)=_OID(.1.3.6.1.2.1.1.3.0) )
983
	*	@return bool : true : rule match, false : rule don't match , throw exception on error.
984
	*/
985
	
986
	protected function eval_rule($rule)
987
	{
988
		if ($rule==null || $rule == '') // Empty rule is always true
989
		{
990
			return true;
991
		}
992
		$matches=array();
993
		while (preg_match('/_OID\(([0-9\.\*]+)\)/',$rule,$matches) == 1)
994
		{
995
			$oid=$matches[1];
996
			$found=0;
997
			// ** replaced by .*
998
			$oidR=preg_replace('/\*\*/', '.*', $oid);
999
			// * replaced by [^.]*  
1000
			$oidR=preg_replace('/\*/', '[0-9]+', $oidR);
1001
			
1002
			// replace * with \* in oid for preg_replace
1003
			$oid=preg_replace('/\*/', '\*', $oid);
1004
			
1005
			$this->logging->log('OID in rule : '.$oid.' / '.$oidR,DEBUG );
1006
			
1007
			foreach($this->trap_data_ext as $val)
1008
			{
1009
				if (preg_match("/^$oidR$/",$val->oid) == 1)
1010
				{
1011
					if (!preg_match('/^[0-9]*\.?[0-9]+$/',$val->value))
1012
					{ // If not a number, change " to ' and put " around it
1013
						$val->value=preg_replace('/"/',"'",$val->value);
1014
						$val->value='"'.$val->value.'"';
1015
					}
1016
					$rep=0;
1017
					$rule=preg_replace('/_OID\('.$oid.'\)/',$val->value,$rule,-1,$rep);
1018
					if ($rep==0)
1019
					{
1020
						$this->logging->log("Error in rule_eval",WARN,'');
1021
						return false;
1022
					}
1023
					$found=1;
1024
					break;
1025
				}
1026
			}
1027
			if ($found==0)
1028
			{	// OID not found : throw error
1029
			    throw new Exception('OID '.$oid.' not found in trap');
1030
			}
1031
		}
1032
		$item=0;
1033
		$rule=$this->eval_cleanup($rule);
1034
		$this->logging->log('Rule after clenup: '.$rule,INFO );
1035
		
1036
		return  $this->evaluation($rule,$item);
1037
	}
1038
	
1039
	/** Match rules for current trap and do action
1040
	*/
1041
	public function applyRules()
1042
	{
1043
		$rules = $this->getRules($this->trap_data['source_ip'],$this->trap_data['trap_oid']);
1044
		
1045
		if ($rules===false || count($rules)==0)
0 ignored issues
show
introduced by
The condition $rules === false is always true.
Loading history...
1046
		{
1047
			$this->logging->log('No rules found for this trap',INFO );
1048
			$this->trap_data['status']='unknown';
1049
			$this->trap_to_db=true;
1050
			return;
1051
		}
1052
		//print_r($rules);
1053
		// Evaluate all rules in sequence
1054
		$this->trap_action=null;
1055
		foreach ($rules as $rule)
1056
		{
1057
			
1058
			$host_name=$rule['host_name'];
1059
			$service_name=$rule['service_name'];
1060
			
1061
			$display=$this->applyDisplay($rule['display']);
1062
			$this->trap_action = ($this->trap_action==null)? '' : $this->trap_action . ', ';
1063
			try
1064
			{
1065
				$this->logging->log('Rule to eval : '.$rule['rule'],INFO );
1066
				$evalr=$this->eval_rule($rule['rule']);
1067
				
1068
				if ($evalr == true)
1069
				{
1070
					//$this->logging->log('rules OOK: '.print_r($rule),INFO );
1071
					$action=$rule['action_match'];
1072
					$this->logging->log('action OK : '.$action,INFO );
1073
					if ($action >= 0)
1074
					{
1075
						if ($this->serviceCheckResult($host_name,$service_name,$action,$display) == false)
1076
						{
1077
						    $this->trap_action.='Error sending status : check cmd/API';
1078
						}
1079
						else
1080
						{
1081
						    $this->add_rule_match($rule['id'],$rule['num_match']+1);
1082
						    $this->trap_action.='Status '.$action.' to '.$host_name.'/'.$service_name;
1083
						}
1084
					}
1085
					else
1086
					{
1087
						$this->add_rule_match($rule['id'],$rule['num_match']+1);
1088
					}
1089
					$this->trap_to_db=($action==-2)?false:true;
1090
				}
1091
				else
1092
				{
1093
					//$this->logging->log('rules KOO : '.print_r($rule),INFO );
1094
					
1095
					$action=$rule['action_nomatch'];
1096
					$this->logging->log('action NOK : '.$action,INFO );
1097
					if ($action >= 0)
1098
					{
1099
					    if ($this->serviceCheckResult($host_name,$service_name,$action,$display)==false)
1100
					    {
1101
					        $this->trap_action.='Error sending status : check cmd/API';
1102
					    }
1103
					    else
1104
					    {
1105
    						$this->add_rule_match($rule['id'],$rule['num_match']+1);
1106
    						$this->trap_action.='Status '.$action.' to '.$host_name.'/'.$service_name;
1107
					    }
1108
					}
1109
					else
1110
					{
1111
						$this->add_rule_match($rule['id'],$rule['num_match']+1);
1112
					}
1113
					$this->trap_to_db=($action==-2)?false:true;					
1114
				}
1115
				// Put name in source_name
1116
				if (!isset($this->trap_data['source_name']))
1117
				{
1118
					$this->trap_data['source_name']=$rule['host_name'];
1119
				}
1120
				else
1121
				{
1122
					if (!preg_match('/'.$rule['host_name'].'/',$this->trap_data['source_name']))
1123
					{ // only add if not present
1124
						$this->trap_data['source_name'].=','.$rule['host_name'];
1125
					}
1126
				}
1127
			}
1128
			catch (Exception $e) 
1129
			{ 
1130
			    $this->logging->log('Error in rule eval : '.$e->getMessage(),WARN,'');
1131
			    $this->trap_action.=' ERR : '.$e->getMessage();
1132
			    $this->trap_data['status']='error';
1133
			}
1134
			
1135
		}
1136
		if ($this->trap_data['status']=='error')
1137
		{
1138
		  $this->trap_to_db=true; // Always put errors in DB for the use can see
1139
		}
1140
		else
1141
		{
1142
		  $this->trap_data['status']='done';
1143
		}
1144
	}
1145
1146
	/** Add Time a action to rule
1147
	*	@param string $time : time to process to insert in SQL
1148
	*/
1149
	public function add_rule_final($time)
1150
	{
1151
		$db_conn=$this->trapsDB->db_connect_trap();
1152
		if ($this->trap_action==null) 
1153
		{
1154
			$this->trap_action='No action';
1155
		}
1156
		$sql="UPDATE ".$this->db_prefix."received SET process_time = '".$time."' , status_detail='".$this->trap_action."'  WHERE (id = '".$this->trap_id."');";
1157
		if ($db_conn->query($sql) === false) {
1158
			$this->logging->log('Error in update query : ' . $sql,WARN,'');
1159
		}
1160
	}
1161
	
1162
	/*********** UTILITIES *********************/
1163
	
1164
	/** reset service to OK after time defined in rule
1165
	*	TODO logic is : get all service in error + all rules, see if getting all rules then select services is better 
1166
	*	@return integer : not in use
1167
	**/
1168
	public function reset_services()
1169
	{
1170
		// Get all services not in 'ok' state
1171
		$sql_query="SELECT s.service_object_id,
1172
	 UNIX_TIMESTAMP(s.last_check) AS last_check,
1173
	s.current_state as state,
1174
	v.name1 as host_name,
1175
    v.name2 as service_name
1176
	FROM icinga_servicestatus AS s 
1177
    LEFT JOIN icinga_objects as v ON s.service_object_id=v.object_id
1178
    WHERE s.current_state != 0;";
1179
		$db_conn=$this->trapsDB->db_connect_ido();
1180
		if (($services_db=$db_conn->query($sql_query)) === false) { // set err to 1 to throw exception.
1181
			$this->logging->log('No result in query : ' . $sql_query,ERROR,'');
1182
			return 0;
1183
		}
1184
		$services=$services_db->fetchAll();
1185
		
1186
		// Get all rules
1187
		$sql_query="SELECT host_name, service_name, revert_ok FROM ".$this->db_prefix."rules where revert_ok != 0;";
1188
		$db_conn2=$this->trapsDB->db_connect_trap();
1189
		if (($rules_db=$db_conn2->query($sql_query)) === false) {
1190
			$this->logging->log('No result in query : ' . $sql_query,ERROR,'');
1191
			return 0;
1192
		}
1193
		$rules=$rules_db->fetchAll();
1194
		
1195
		$now=date('U');
1196
		
1197
		$numreset=0;
1198
		foreach ($rules as $rule)
1199
		{
1200
			foreach ($services as $service)
1201
			{
1202
				if ($service['service_name'] == $rule['service_name'] &&
1203
					$service['host_name'] == $rule['host_name'] &&
1204
					($service['last_check'] + $rule['revert_ok']) < $now)
1205
				{
1206
					$this->serviceCheckResult($service['host_name'],$service['service_name'],0,'Reset service to OK after '.$rule['revert_ok'].' seconds');
1207
					$numreset++;
1208
				}
1209
			}
1210
		}
1211
		echo "\n";
1212
		echo $numreset . " service(s) reset to OK\n";
1213
		return 0;
1214
		
1215
	}
1216
1217
	
1218
	/*********** MIB cache update functions *********************/
1219
	
1220
	/**
1221
	 * Update or add an OID to database uses $this->dbOidIndex for mem cache
1222
	 * @param string $oid
1223
	 * @param string $mib
1224
	 * @param string $name
1225
	 * @param string $type
1226
	 * @param string $textConv
1227
	 * @param string $dispHint
1228
	 * @param string $syntax
1229
	 * @param string $type_enum
1230
	 * @param string $description
1231
	 * @return number : 0=unchanged, 1 = changed, 2=created
1232
	 */
1233
	public function update_oid($oid,$mib,$name,$type,$textConv,$dispHint,$syntax,$type_enum,$description=NULL)
1234
	{
1235
		$db_conn=$this->trapsDB->db_connect_trap();
1236
		$description=$db_conn->quote($description);
1237
		if (isset($this->dbOidIndex[$oid]))
1238
		{
1239
		    if ($this->dbOidIndex[$oid]['key'] == -1)
1240
		    { // newly created.
1241
		        return 0;
1242
		    }
1243
			if ( $name != $this->dbOidAll[$this->dbOidIndex[$oid]['key']]['name'] ||
1244
			    $mib != $this->dbOidAll[$this->dbOidIndex[$oid]['key']]['mib'] ||
1245
			    $type != $this->dbOidAll[$this->dbOidIndex[$oid]['key']]['type'] //||
1246
			    //$textConv != $this->dbOidAll[$this->dbOidIndex[$oid]['key']]['textual_convention'] //||
1247
			    //$dispHint != $this->dbOidAll[$this->dbOidIndex[$oid]['key']]['display_hint'] ||
1248
			    //$syntax != $this->dbOidAll[$this->dbOidIndex[$oid]['key']]['syntax'] ||
1249
			    //$type_enum != $this->dbOidAll[$this->dbOidIndex[$oid]['key']]['type_enum'] ||
1250
			    //$description != $this->dbOidAll[$this->dbOidIndex[$oid]['key']]['description']
1251
			    )
1252
			{ // Do update
1253
			    $sql='UPDATE '.$this->db_prefix.'mib_cache SET '.
1254
 			    'name = :name , type = :type , mib = :mib , textual_convention = :tc , display_hint = :display_hint'. 
1255
 			    ', syntax = :syntax, type_enum = :type_enum, description = :description '.
1256
 			    ' WHERE id= :id';
1257
			    $sqlQuery=$db_conn->prepare($sql);
1258
			    
1259
			    $sqlParam=array(
1260
			        ':name' => $name,
1261
			        ':type' => $type, 
1262
			        ':mib' => $mib, 
1263
			        ':tc' =>  ($textConv==null)?'null':$textConv , 
1264
			        ':display_hint' => ($dispHint==null)?'null':$dispHint ,
1265
			        ':syntax' => ($syntax==null)?'null':$syntax,
1266
			        ':type_enum' => ($type_enum==null)?'null':$type_enum, 
1267
			        ':description' => ($description==null)?'null':$description,
1268
			        ':id' => $this->dbOidAll[$this->dbOidIndex[$oid]['id']]
1269
			    );
1270
			    
1271
			    if ($sqlQuery->execute($sqlParam) === false) {
1272
			        $this->logging->log('Error in query : ' . $sql,ERROR,'');
1273
			    }
1274
			    $this->logging->log('Trap updated : '.$name . ' / OID : '.$oid,DEBUG );
1275
				return 1;
1276
			}
1277
			else
1278
			{
1279
			    $this->logging->log('Trap unchanged : '.$name . ' / OID : '.$oid,DEBUG );
1280
			    return 0;
1281
			}
1282
		}
1283
        // create new OID.
1284
			
1285
		// Insert data
1286
1287
		$sql='INSERT INTO '.$this->db_prefix.'mib_cache '.
1288
		      '(oid, name, type , mib, textual_convention, display_hint '.
1289
              ', syntax, type_enum , description ) ' . 
1290
              'values (:oid, :name , :type ,:mib ,:tc , :display_hint'.
1291
              ', :syntax, :type_enum, :description )';
1292
        
1293
		if ($this->trapsDB->trapDBType == 'pgsql') $sql .= 'RETURNING id';
1294
		
1295
		$sqlQuery=$db_conn->prepare($sql);
1296
		
1297
		$sqlParam=array(
1298
		    ':oid' => $oid,
1299
		    ':name' => $name,
1300
		    ':type' => $type,
1301
		    ':mib' => $mib,
1302
		    ':tc' =>  ($textConv==null)?'null':$textConv ,
1303
		    ':display_hint' => ($dispHint==null)?'null':$dispHint ,
1304
		    ':syntax' => ($syntax==null)?'null':$syntax,
1305
		    ':type_enum' => ($type_enum==null)?'null':$type_enum,
1306
		    ':description' => ($description==null)?'null':$description
1307
		);
1308
		
1309
		if ($sqlQuery->execute($sqlParam) === false) {
1310
		    $this->logging->log('Error in query : ' . $sql,1,'');
1311
		}
1312
		
1313
		switch ($this->trapsDB->trapDBType)
1314
		{
1315
		    case 'pgsql':
1316
		        // Get last id to insert oid/values in secondary table
1317
		        if (($inserted_id_ret=$sqlQuery->fetch(PDO::FETCH_ASSOC)) === false) {		            
1318
		            $this->logging->log('Error getting id - pgsql - ',1,'');
1319
		        }
1320
		        if (! isset($inserted_id_ret['id'])) {
1321
		            $this->logging->log('Error getting id - pgsql - empty.',1,'');
1322
		        }
1323
		        $this->dbOidIndex[$oid]['id']=$inserted_id_ret['id'];
1324
		        break;
1325
		    case 'mysql':
1326
		        // Get last id to insert oid/values in secondary table
1327
		        $sql='SELECT LAST_INSERT_ID();';
1328
		        if (($ret_code=$db_conn->query($sql)) === false) {
1329
		            $this->logging->log('Erreur getting id - mysql - ',1,'');
1330
		        }
1331
		        
1332
		        $inserted_id=$ret_code->fetch(PDO::FETCH_ASSOC)['LAST_INSERT_ID()'];
1333
		        if ($inserted_id==false) throw new Exception("Weird SQL error : last_insert_id returned false : open issue");
1334
		        $this->dbOidIndex[$oid]['id']=$inserted_id;
1335
		        break;
1336
		    default:
1337
		        $this->logging->log('Error SQL type Unknown : '.$this->trapsDB->trapDBType,1,'');
1338
		}
1339
1340
		// Set as newly created.
1341
		$this->dbOidIndex[$oid]['key']=-1;
1342
		return 2;
1343
	}
1344
1345
    /**
1346
     * create or update (with check_existing = true) objects of trap
1347
     * @param string $trapOID : trap oid
1348
     * @param string $trapmib : mib of trap
1349
     * @param array $objects : array of objects name (without MIB)
1350
     * @param bool $check_existing : check instead of create
1351
     */
1352
	public function trap_objects($trapOID,$trapmib,$objects,$check_existing)
1353
	{
1354
	    $dbObjects=null; // cache of objects for trap in db
1355
	    $db_conn=$this->trapsDB->db_connect_trap();
1356
	    
1357
	    // Get id of trapmib.
1358
1359
	    $trapId = $this->dbOidIndex[$trapOID]['id'];
1360
	    if ($check_existing === true)
1361
	    {
1362
	        // Get all objects
1363
	        $sql='SELECT * FROM '.$this->db_prefix.'mib_cache_trap_object where trap_id='.$trapId.';';
1364
	        $this->logging->log('SQL query get all traps: '.$sql,DEBUG );
1365
	        if (($ret_code=$db_conn->query($sql)) === false) {
1366
	            $this->logging->log('No result in query : ' . $sql,1,'');
1367
	        }
1368
	        $dbObjectsRaw=$ret_code->fetchAll();
1369
	        
1370
	        foreach ($dbObjectsRaw as $val)
1371
	        {
1372
	            $dbObjects[$val['object_id']]=1;
1373
	        }
1374
	    }
1375
	    foreach ($objects as $object)
1376
	    {
1377
	        $match=$snmptrans=array();
1378
	        $retVal=0;
1379
	        $objOid=$objTc=$objDispHint=$objSyntax=$objDesc=$objEnum=NULL;
1380
	        $tmpdesc='';$indesc=false;
1381
	        
1382
	        $objMib=$trapmib;
1383
	        exec($this->snmptranslate . ' -m ALL -M +'.$this->snmptranslate_dirs.
1384
	            ' -On -Td '.$objMib.'::'.$object . ' 2>/dev/null',$snmptrans,$retVal);
1385
	        if ($retVal!=0)
1386
	        {
1387
	            // Maybe not trap mib, search with IR
1388
	            exec($this->snmptranslate . ' -m ALL -M +'.$this->snmptranslate_dirs.
1389
	                ' -IR '.$object . ' 2>/dev/null',$snmptrans,$retVal);
1390
	            if ($retVal != 0 || !preg_match('/(.*)::(.*)/',$snmptrans[0],$match))
1391
	            { // Not found -> continue with warning
1392
	               $this->logging->log('Error finding trap object : '.$trapmib.'::'.$object,2,'');
1393
	               continue;
1394
	            }
1395
	            $objMib=$match[1];
1396
	            
1397
	            // Do the snmptranslate again.
1398
	            exec($this->snmptranslate . ' -m ALL -M +'.$this->snmptranslate_dirs.
1399
	                ' -On -Td '.$objMib.'::'.$object,$snmptrans,$retVal);
1400
	            if ($retVal!=0) {
1401
	                $this->logging->log('Error finding trap object : '.$objMib.'::'.$object,2,'');
1402
	            }
1403
	            
1404
	        }
1405
	        foreach ($snmptrans as $line)
1406
	        {
1407
	            if ($indesc===true)
1408
	            {
1409
	                $line=preg_replace('/[\t ]+/',' ',$line);
1410
	                if (preg_match('/(.*)"$/', $line,$match))
1411
	                {
1412
	                    $objDesc = $tmpdesc . $match[1];
1413
	                    $indesc=false;
1414
	                }
1415
	                $tmpdesc.=$line;
1416
	                continue;
1417
	            }
1418
	            if (preg_match('/^\.[0-9\.]+$/', $line))
1419
	            {
1420
	                $objOid=$line;
1421
	                continue;
1422
	            }
1423
	            if (preg_match('/^[\t ]+SYNTAX[\t ]+([^{]*) \{(.*)\}/',$line,$match))
1424
	            {
1425
	                $objSyntax=$match[1];
1426
                    $objEnum=$match[2];
1427
	                continue;
1428
	            }
1429
	            if (preg_match('/^[\t ]+SYNTAX[\t ]+(.*)/',$line,$match))
1430
	            {
1431
	                $objSyntax=$match[1];
1432
	                continue;
1433
	            }
1434
	            if (preg_match('/^[\t ]+DISPLAY-HINT[\t ]+"(.*)"/',$line,$match))
1435
	            {
1436
	                $objDispHint=$match[1];
1437
	                continue;
1438
	            }
1439
	            if (preg_match('/^[\t ]+DESCRIPTION[\t ]+"(.*)"/',$line,$match))
1440
	            {
1441
	                $objDesc=$match[1];
1442
	                continue;
1443
	            }
1444
	            if (preg_match('/^[\t ]+DESCRIPTION[\t ]+"(.*)/',$line,$match))
1445
	            {
1446
	                $tmpdesc=$match[1];
1447
	                $indesc=true;
1448
	                continue;
1449
	            }
1450
	            if (preg_match('/^[\t ]+-- TEXTUAL CONVENTION[\t ]+(.*)/',$line,$match))
1451
	            {
1452
	                $objTc=$match[1];
1453
	                continue;
1454
	            }
1455
	        }
1456
	        $this->logging->log("Adding trap $object : $objOid / $objSyntax / $objEnum / $objDispHint / $objTc",DEBUG );
1457
	        //echo "$object : $objOid / $objSyntax / $objEnum / $objDispHint / $objTc / $objDesc\n";
1458
	        // Update 
1459
	        $this->update_oid($objOid, $objMib, $object, '3', $objTc, $objDispHint, $objSyntax, $objEnum,$objDesc);
1460
            
1461
	        if (isset($dbObjects[$this->dbOidIndex[$objOid]['id']]))
1462
	        {   // if link exists, continue
1463
	            $dbObjects[$this->dbOidIndex[$objOid]['id']]=2;
1464
	            continue;
1465
	        }
1466
	        if ($check_existing === true) 
1467
	        {
1468
	            // TODO : check link trap - objects exists, mark them.
1469
	        }
1470
	        // Associate in object table
1471
	        $sql='INSERT INTO '.$this->db_prefix.'mib_cache_trap_object (trap_id,object_id) '.
1472
	   	        'values (:trap_id, :object_id)';	        
1473
	        $sqlQuery=$db_conn->prepare($sql);	        
1474
	        $sqlParam=array(
1475
	            ':trap_id' => $trapId,
1476
	            ':object_id' => $this->dbOidIndex[$objOid]['id'],
1477
	        );
1478
	        
1479
	        if ($sqlQuery->execute($sqlParam) === false) {
1480
	            $this->logging->log('Error adding trap object : ' . $sql . ' / ' . $trapId . '/'. $this->dbOidIndex[$objOid]['id'] ,1,'');
1481
	        }
1482
	    }
1483
	    if ($check_existing === true)
1484
	    {
1485
	        // TODO : remove link trap - objects that wasn't marked.
1486
	    }
1487
	    
1488
	}
1489
	
1490
	/** 
1491
	 * Cache mib in database
1492
	 * @param boolean $display_progress : Display progress on standard output
1493
	 * @param boolean $check_change : Force check of trap params & objects
1494
	 * @param boolean $onlyTraps : only cache traps and objects (true) or all (false)
1495
	 * @param string $startOID : only cache under startOID (NOT IMPLEMENTED)
1496
	*/	
1497
	public function update_mib_database($display_progress=false,$check_change=false,$onlyTraps=true,$startOID='.1')
0 ignored issues
show
Unused Code introduced by
The parameter $startOID is not used and could be removed. ( Ignorable by Annotation )

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

1497
	public function update_mib_database($display_progress=false,$check_change=false,$onlyTraps=true,/** @scrutinizer ignore-unused */ $startOID='.1')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1498
	{
1499
		// Timing 
1500
		$timeTaken = microtime(true);
1501
		$retVal=0;
1502
		// Get all mib objects from all mibs
1503
		$snmpCommand=$this->snmptranslate . ' -m ALL -M +'.$this->snmptranslate_dirs.' -On -Tto 2>/dev/null';
1504
		$this->logging->log('Getting all traps : '.$snmpCommand,DEBUG );
1505
		unset($this->objectsAll);
1506
		exec($snmpCommand,$this->objectsAll,$retVal);		
1507
		if ($retVal!=0)
1508
		{
1509
			$this->logging->log('error executing snmptranslate',ERROR,'');
1510
		}
1511
		
1512
		// Get all mibs from databse to have a memory index
1513
		
1514
		$db_conn=$this->trapsDB->db_connect_trap();
1515
		
1516
		$sql='SELECT * from '.$this->db_prefix.'mib_cache;';
1517
		$this->logging->log('SQL query : '.$sql,DEBUG );
1518
		if (($ret_code=$db_conn->query($sql)) === false) {
1519
			$this->logging->log('No result in query : ' . $sql,ERROR,'');
1520
		}
1521
		$this->dbOidAll=$ret_code->fetchAll();
1522
		$this->dbOidIndex=array();
1523
		// Create the index for db;
1524
		foreach($this->dbOidAll as $key=>$val)
1525
		{
1526
			$this->dbOidIndex[$val['oid']]['key']=$key;
1527
			$this->dbOidIndex[$val['oid']]['id']=$val['id'];
1528
		}
1529
		
1530
		// Count elements to show progress
1531
		$numElements=count($this->objectsAll);
1532
		$this->logging->log('Total snmp objects returned by snmptranslate : '.$numElements,INFO );
1533
		
1534
		$step=$basestep=$numElements/10; // output display of % done
1535
		$num_step=0;
1536
		$timeFiveSec = microtime(true); // Used for display a '.' every <n> seconds
1537
		
1538
		// Create index for trap objects
1539
		$this->trapObjectsIndex=array();
1540
		
1541
		// detailed timing (time_* vars)
1542
		$time_parse1=$time_check1=$time_check2=$time_check3=$time_update=$time_objects=0;
1543
		$time_parse1N=$time_check1N=$time_check2N=$time_check3N=$time_updateN=$time_objectsN=0;
1544
		$time_num_traps=0;
1545
		
1546
		for ($curElement=0;$curElement < $numElements;$curElement++)
1547
		{
1548
		    $time_1= microtime(true);
1549
			if ((microtime(true)-$timeFiveSec) > 2 && $display_progress)
1550
			{ // echo a . every 2 sec
1551
				echo '.';
1552
				$timeFiveSec = microtime(true);
1553
			}
1554
			if ($curElement>$step) 
1555
			{ // display progress
1556
				$num_step++;
1557
				$step+=$basestep;
1558
				if ($display_progress)
1559
				{				
1560
					echo "\n" . ($num_step*10). '% : ';
1561
				}
1562
			}
1563
			// Get oid or pass if not found
1564
			if (!preg_match('/^\.[0-9\.]+$/',$this->objectsAll[$curElement]))
1565
			{
1566
			    $time_parse1 += microtime(true) - $time_1;
1567
			    $time_parse1N ++;
1568
				continue;
1569
			}
1570
			$oid=$this->objectsAll[$curElement];
1571
			
1572
			// get next line 
1573
			$curElement++;
1574
			$match=$snmptrans=array();
1575
			if (!preg_match('/ +([^\(]+)\(.+\) type=([0-9]+)( tc=([0-9]+))?( hint=(.+))?/',
1576
						$this->objectsAll[$curElement],$match))
1577
			{
1578
			    $time_check1 += microtime(true) - $time_1;
1579
				$time_check1N++;
1580
				continue;
1581
			}
1582
			
1583
			$name=$match[1]; // Name 
1584
			$type=$match[2]; // type (21=trap, 0: may be trap, else : not trap
1585
			
1586
			if ($type==0) // object type=0 : check if v1 trap
1587
			{
1588
				// Check if next is suboid -> in that case is cannot be a trap
1589
				if (preg_match("/^$oid/",$this->objectsAll[$curElement+1]))
1590
				{
1591
				    $time_check2 += microtime(true) - $time_1;
1592
				    $time_check2N++;
1593
					continue;
1594
				}		
1595
				unset($snmptrans);
1596
				exec($this->snmptranslate . ' -m ALL -M +'.$this->snmptranslate_dirs.
1597
					' -Td '.$oid . ' | grep OBJECTS ',$snmptrans,$retVal);
1598
				if ($retVal!=0)
1599
				{
1600
				    $time_check2 += microtime(true) - $time_1;
1601
				    $time_check2N++;
1602
					continue;
1603
				}
1604
				//echo "\n v1 trap found : $oid \n";
1605
				// Force as trap.
1606
				$type=21;
1607
			}
1608
			if ($onlyTraps===true && $type!=21) // if only traps and not a trap, continue
1609
			{
1610
			    $time_check3 += microtime(true) - $time_1;
1611
				$time_check3N++;
1612
				continue;
1613
			}
1614
			
1615
			$time_num_traps++;
1616
			
1617
			$this->logging->log('Found trap : '.$match[1] . ' / OID : '.$oid,INFO );
1618
			if ($display_progress) echo '#'; // echo a # when trap found
1619
				
1620
			// get trap objects & source MIB
1621
			unset($snmptrans);
1622
			exec($this->snmptranslate . ' -m ALL -M +'.$this->snmptranslate_dirs.
1623
					' -Td '.$oid,$snmptrans,$retVal);
1624
			if ($retVal!=0)
1625
			{
1626
				$this->logging->log('error executing snmptranslate',ERROR,'');
1627
			}
1628
			
1629
			if (!preg_match('/^(.*)::/',$snmptrans[0],$match))
1630
			{
1631
			    $this->logging->log('Error getting mib from trap '.$oid.' : ' . $snmptrans[0],1,'');
1632
			}
1633
			$trapMib=$match[1];
1634
			
1635
			$numLine=1;$trapDesc='';
1636
			while (isset($snmptrans[$numLine]) && !preg_match('/^[\t ]+DESCRIPTION[\t ]+"(.*)/',$snmptrans[$numLine],$match)) $numLine++;
1637
			if (isset($snmptrans[$numLine]))
1638
			{
1639
			    $snmptrans[$numLine] = preg_replace('/^[\t ]+DESCRIPTION[\t ]+"/','',$snmptrans[$numLine]);
1640
1641
			    while (isset($snmptrans[$numLine]) && !preg_match('/"/',$snmptrans[$numLine]))
1642
			    {
1643
			        $trapDesc.=preg_replace('/[\t ]+/',' ',$snmptrans[$numLine]);
1644
			        $numLine++;
1645
			    }
1646
			    if (isset($snmptrans[$numLine])) {
1647
			        $trapDesc.=preg_replace('/".*/','',$snmptrans[$numLine]);
1648
			        $trapDesc=preg_replace('/[\t ]+/',' ',$trapDesc);
1649
			    }
1650
1651
			}
1652
			$update=$this->update_oid($oid,$trapMib,$name,$type,NULL,NULL,NULL,NULL,$trapDesc);
1653
			$time_update += microtime(true) - $time_1; $time_1= microtime(true);
1654
			
1655
			if (($update==0) && ($check_change===false))
1656
			{ // Trapd didn't change & force check disabled
1657
			    $time_objects += microtime(true) - $time_1;
1658
			    if ($display_progress) echo "C";
1659
			    continue;
1660
			}
1661
			
1662
			$synt=null;
1663
			foreach ($snmptrans as $line)
1664
			{	
1665
    			if (preg_match('/OBJECTS.*\{([^\}]+)\}/',$line,$match))
1666
    				{
1667
    					$synt=$match[1];
1668
    				}
1669
			}
1670
			if ($synt == null) 
1671
			{
1672
				//echo "No objects for $trapOID\n";
1673
			    $time_objects += microtime(true) - $time_1;
1674
				continue;
1675
			}
1676
			//echo "$synt \n";
1677
			$trapObjects=array();
1678
			while (preg_match('/ *([^ ,]+) *,* */',$synt,$match))
1679
			{
1680
				array_push($trapObjects,$match[1]);
1681
				$synt=preg_replace('/'.$match[0].'/','',$synt);
1682
			}
1683
			
1684
			$this->trap_objects($oid, $trapMib, $trapObjects, false);
1685
			
1686
			$time_objects += microtime(true) - $time_1;
1687
			$time_objectsN++;
1688
		}
1689
		
1690
		if ($display_progress)
1691
		{
1692
    		echo "\nNumber of processed traps : $time_num_traps \n";
1693
    		echo "\nParsing : " . number_format($time_parse1+$time_check1,1) ." sec / " . ($time_parse1N+ $time_check1N)  . " occurences\n";
1694
    		echo "Detecting traps : " . number_format($time_check2+$time_check3,1) . " sec / " . ($time_check2N+$time_check3N) ." occurences\n";
1695
    		echo "Trap processing ($time_updateN): ".number_format($time_update,1)." sec , ";
1696
    		echo "Objects processing ($time_objectsN) : ".number_format($time_objects,1)." sec \n";
1697
		}
1698
		
1699
		// Timing ends
1700
		$timeTaken=microtime(true) - $timeTaken;
1701
		if ($display_progress)
1702
		{
1703
		    echo "Global time : ".round($timeTaken)." seconds\n";
1704
		}
1705
		
1706
	}
1707
	
1708
}
1709
1710
?>
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...