2012-05-16 16:26:19 +00:00
< ? php
2014-12-15 11:10:26 +00:00
/* Copyright ( C ) 2014 Daniel Preussker < f0o @ devilcode . org >
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http :// www . gnu . org / licenses />. */
2012-05-16 16:26:19 +00:00
/**
2014-12-15 11:10:26 +00:00
* Alerts Tracking
* @ author Daniel Preussker < f0o @ devilcode . org >
* @ copyright 2014 f0o , LibreNMS
* @ license GPL
* @ package LibreNMS
* @ subpackage Alerts
2012-05-16 16:26:19 +00:00
*/
2015-04-08 09:23:33 +00:00
include_once ( $config [ 'install_dir' ] . '/includes/device-groups.inc.php' );
include_once ( $config [ 'install_dir' ] . '/html/includes/authentication/' . $config [ 'auth_mechanism' ] . '.inc.php' );
2015-04-03 18:22:29 +00:00
2012-05-16 16:26:19 +00:00
/**
2014-12-15 11:10:26 +00:00
* Generate SQL from Rule
* @ param string $rule Rule to generate SQL for
2015-04-25 11:10:37 +00:00
* @ return string | boolean
2014-12-15 11:10:26 +00:00
*/
function GenSQL ( $rule ) {
2015-04-24 19:05:55 +00:00
$rule = RunMacros ( $rule );
2015-04-25 11:10:37 +00:00
if ( empty ( $rule ) ) {
2015-05-07 14:09:41 +00:00
//Cannot resolve Macros due to recursion. Rule is invalid.
2015-04-25 11:10:37 +00:00
return false ;
}
2015-04-28 13:49:14 +00:00
//Pretty-print rule to dissect easier
$pretty = array ( '*' => ' * ' , '(' => ' ( ' , ')' => ' ) ' , '/' => ' / ' , '&&' => ' && ' , '||' => ' || ' );
$rule = str_replace ( array_keys ( $pretty ), $pretty , $rule );
2014-12-15 11:10:26 +00:00
$tmp = explode ( " " , $rule );
$tables = array ();
foreach ( $tmp as $opt ) {
if ( strstr ( $opt , '%' ) && strstr ( $opt , '.' ) ) {
$tmpp = explode ( " . " , $opt , 2 );
$tmpp [ 0 ] = str_replace ( " % " , " " , $tmpp [ 0 ]);
2014-12-19 20:20:17 +00:00
$tables [] = mres ( str_replace ( " ( " , " " , $tmpp [ 0 ]));
2014-12-15 11:10:26 +00:00
$rule = str_replace ( $opt , $tmpp [ 0 ] . '.' . $tmpp [ 1 ], $rule );
}
}
2015-03-04 15:33:18 +00:00
$tables = array_keys ( array_flip ( $tables ));
2015-05-07 14:09:41 +00:00
if ( dbFetchCell ( 'SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_NAME = ? && COLUMN_NAME = ?' , array ( $tables [ 0 ], 'device_id' )) != 1 ) {
//Our first table has no valid glue, append the 'devices' table to it!
array_unshift ( $tables , 'devices' );
}
$x = sizeof ( $tables ) - 1 ;
2014-12-15 11:10:26 +00:00
$i = 0 ;
$join = " " ;
while ( $i < $x ) {
if ( isset ( $tables [ $i + 1 ]) ) {
2015-05-07 14:09:41 +00:00
if ( dbFetchCell ( 'SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_NAME = ? && COLUMN_NAME = ?' , array ( $tables [ $i + 1 ], 'device_id' )) == 1 ) {
//Found valid glue in definition.
$join .= $tables [ $i ] . " .device_id = " . $tables [ $i + 1 ] . " .device_id && " ;
} else {
//No valid glue, Resolve a glue-chain.
$gtmp = ResolveGlues ( array ( $tables [ $i + 1 ]), 'device_id' );
if ( $gtmp === false ) {
//Cannot resolve glue-chain. Rule is invalid.
return false ;
}
foreach ( $gtmp as $glue ) {
if ( ! $last ) {
list ( $tmp , $last ) = explode ( '.' , $glue );
$qry .= $glue . ' = ' ;
} else {
list ( $tmp , $new ) = explode ( '.' , $glue );
$qry .= $tmp . '.' . $last . ' && ' . $tmp . '.' . $new . ' = ' ;
$last = $new ;
}
if ( ! in_array ( $tmp , $tables ) ) {
$tables [] = $tmp ;
}
}
$join .= " ( " . $qry . $tables [ 0 ] . " .device_id ) && " ;
}
2014-12-15 11:10:26 +00:00
}
$i ++ ;
}
2014-12-19 20:20:17 +00:00
$sql = " SELECT * FROM " . implode ( " , " , $tables ) . " WHERE ( " . $join . " " . str_replace ( " ( " , " " , $tables [ 0 ]) . " .device_id = ?) && ( " . str_replace ( array ( " % " , " @ " , " !~ " , " ~ " ), array ( " " , " % " , " NOT LIKE " , " LIKE " ), $rule ) . " ) " ;
2014-12-15 11:10:26 +00:00
return $sql ;
2012-05-16 16:26:19 +00:00
}
2015-05-07 14:09:41 +00:00
/**
* Create a glue - chain
* @ param array $tables Initial Tables to construct glue - chain
* @ param string $target Glue to find ( usual device_id )
* @ param int $x Recursion Anchor
* @ param array $hist History of processed tables
* @ param array $last Glues on the fringe
* @ return string | boolean
*/
function ResolveGlues ( $tables , $target , $x = 0 , $hist = array (), $last = array ()) {
if ( sizeof ( $tables ) == 1 && $x != 0 ) {
if ( dbFetchCell ( 'SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_NAME = ? && COLUMN_NAME = ?' , array ( $tables [ 0 ], $target )) == 1 ) {
return array_merge ( $last , array ( $tables [ 0 ] . '.' . $target ));
} else {
return false ;
}
} else {
$x ++ ;
if ( $x > 30 ) {
//Too much recursion. Abort.
return false ;
}
foreach ( $tables as $table ) {
$glues = dbFetchRows ( 'SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = ? && COLUMN_NAME LIKE "%\_id"' , array ( $table ));
if ( sizeof ( $glues ) == 1 && $glues [ 0 ][ 'COLUMN_NAME' ] != $target ) {
//Search for new candidates to expand
$tmp = dbFetchRows ( 'SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_NAME LIKE "' . substr ( $table , 0 , - 1 ) . '_%" && TABLE_NAME != "' . $table . '"' );
$ntables = array ();
foreach ( $tmp as $expand ) {
$ntables [] = $expand [ 'TABLE_NAME' ];
}
$tmp = ResolveGlues ( $ntables , $target , $x ++ , array_merge ( $tables , $ntables ), array_merge ( $last , array ( $table . '.' . $glues [ 0 ][ 'COLUMN_NAME' ])));
if ( is_array ( $tmp ) ) {
return $tmp ;
}
} else {
foreach ( $glues as $glue ) {
if ( $glue [ 'COLUMN_NAME' ] == $target ) {
return array_merge ( $last , array ( $table . '.' . $target ));
} else {
list ( $tmp ) = explode ( '_' , $glue [ 'COLUMN_NAME' ]);
$tmp .= 's' ;
if ( ! in_array ( $tmp , $tables ) && ! in_array ( $tmp , $hist ) ) {
//Expand table
$tmp = ResolveGlues ( array ( $tmp ), $target , $x ++ , array_merge ( $tables , array ( $tmp )), array_merge ( $last , array ( $table . '.' . $glue [ 'COLUMN_NAME' ])));
if ( is_array ( $tmp ) ) {
return $tmp ;
}
}
}
}
}
}
}
//You should never get here.
return false ;
}
2015-04-24 19:05:55 +00:00
/**
* Process Macros
* @ param string $rule Rule to process
2015-05-07 14:09:41 +00:00
* @ param int $x Recursion - Anchor
2015-04-25 11:10:37 +00:00
* @ return string | boolean
2015-04-24 19:05:55 +00:00
*/
function RunMacros ( $rule , $x = 1 ) {
global $config ;
krsort ( $config [ 'alert' ][ 'macros' ][ 'rule' ]);
foreach ( $config [ 'alert' ][ 'macros' ][ 'rule' ] as $macro => $value ) {
if ( ! strstr ( $macro , " " ) ) {
$rule = str_replace ( '%macros.' . $macro , $value , $rule );
}
}
if ( strstr ( $rule , " %macros " ) ) {
if ( ++ $x < 30 ) {
$rule = RunMacros ( $rule , $x );
} else {
return false ;
}
}
return $rule ;
}
2015-04-03 18:22:29 +00:00
/**
* Get Alert - Rules for Devices
* @ param int $device Device - ID
* @ return array
*/
function GetRules ( $device ) {
$groups = GetGroupsFromDevice ( $device );
$params = array ( $device , $device );
$where = " " ;
foreach ( $groups as $group ) {
$where .= " || alert_map.target = ? " ;
$params [] = 'g' . $group ;
}
2015-04-12 14:37:26 +00:00
return dbFetchRows ( 'SELECT alert_rules.* FROM alert_rules LEFT JOIN alert_map ON alert_rules.id=alert_map.rule WHERE alert_rules.disabled = 0 && ( (alert_rules.device_id = -1 || alert_rules.device_id = ? ) || alert_map.target = ? ' . $where . ' )' , $params );
2015-04-03 18:22:29 +00:00
}
2012-05-16 16:26:19 +00:00
2015-04-20 16:39:55 +00:00
/**
* Check if device is under maintenance
* @ param int $device Device - ID
2015-04-20 18:18:22 +00:00
* @ return int
2015-04-20 16:39:55 +00:00
*/
function IsMaintenance ( $device ) {
$groups = GetGroupsFromDevice ( $device );
$params = array ( $device );
$where = " " ;
foreach ( $groups as $group ) {
$where .= " || alert_schedule_items.target = ? " ;
$params [] = 'g' . $group ;
}
2015-04-20 18:18:22 +00:00
return dbFetchCell ( 'SELECT DISTINCT(alert_schedule.schedule_id) FROM alert_schedule LEFT JOIN alert_schedule_items ON alert_schedule.schedule_id=alert_schedule_items.schedule_id WHERE ( alert_schedule_items.target = ?' . $where . ' ) && NOW() BETWEEN alert_schedule.start AND alert_schedule.end LIMIT 1' , $params );
2015-04-20 16:39:55 +00:00
}
2012-05-16 16:26:19 +00:00
/**
2014-12-15 11:10:26 +00:00
* Run all rules for a device
* @ param int $device Device - ID
* @ return void
*/
function RunRules ( $device ) {
global $debug ;
2015-04-20 16:39:55 +00:00
if ( IsMaintenance ( $device ) > 0 ) {
echo " Under Maintenance, Skipping alerts. \r \n " ;
2014-12-15 11:10:26 +00:00
return false ;
}
2015-04-03 18:22:29 +00:00
foreach ( GetRules ( $device ) as $rule ) {
2014-12-15 11:10:26 +00:00
echo " # " . $rule [ 'id' ] . " : " ;
2015-01-25 21:39:33 +00:00
$inv = json_decode ( $rule [ 'extra' ], true );
if ( isset ( $inv [ 'invert' ]) ) {
$inv = ( bool ) $inv [ 'invert' ];
} else {
$inv = false ;
}
2014-12-15 11:10:26 +00:00
$chk = dbFetchRow ( " SELECT state FROM alerts WHERE rule_id = ? && device_id = ? ORDER BY id DESC LIMIT 1 " , array ( $rule [ 'id' ], $device ));
$sql = GenSQL ( $rule [ 'rule' ]);
$qry = dbFetchRows ( $sql , array ( $device ));
2015-01-25 21:39:33 +00:00
$s = sizeof ( $qry );
if ( $s == 0 && $inv === false ) {
$doalert = false ;
} elseif ( $s > 0 && $inv === false ) {
$doalert = true ;
} elseif ( $s == 0 && $inv === true ) {
$doalert = true ;
} else { //( $s > 0 && $inv == false ) {
$doalert = false ;
}
if ( $doalert ) {
2014-12-15 11:10:26 +00:00
if ( $chk [ 'state' ] === " 2 " ) {
echo " SKIP " ;
2015-01-25 21:39:33 +00:00
} elseif ( $chk [ 'state' ] >= " 1 " ) {
2014-12-15 11:10:26 +00:00
echo " NOCHG " ;
} else {
$extra = gzcompress ( json_encode ( array ( 'contacts' => GetContacts ( $qry ), 'rule' => $qry )), 9 );
if ( dbInsert ( array ( 'state' => 1 , 'device_id' => $device , 'rule_id' => $rule [ 'id' ], 'details' => $extra ), 'alert_log' ) ) {
if ( ! dbUpdate ( array ( 'state' => 1 , 'open' => 1 ), 'alerts' , 'device_id = ? && rule_id = ?' , array ( $device , $rule [ 'id' ])) ) {
dbInsert ( array ( 'state' => 1 , 'device_id' => $device , 'rule_id' => $rule [ 'id' ], 'open' => 1 ), 'alerts' );
}
echo " ALERT " ;
}
}
} else {
if ( $chk [ 'state' ] === " 0 " ) {
echo " NOCHG " ;
} else {
if ( dbInsert ( array ( 'state' => 0 , 'device_id' => $device , 'rule_id' => $rule [ 'id' ]), 'alert_log' ) ){
if ( ! dbUpdate ( array ( 'state' => 0 , 'open' => 1 ), 'alerts' , 'device_id = ? && rule_id = ?' , array ( $device , $rule [ 'id' ])) ) {
dbInsert ( array ( 'state' => 0 , 'device_id' => $device , 'rule_id' => $rule [ 'id' ], 'open' => 1 ), 'alerts' );
}
echo " OK " ;
}
}
}
}
2012-05-16 16:26:19 +00:00
}
/**
2014-12-15 11:10:26 +00:00
* Find contacts for alert
* @ param array $results Rule - Result
* @ return array
*/
function GetContacts ( $results ) {
global $config ;
if ( sizeof ( $results ) == 0 ) {
return array ();
}
2015-04-24 19:05:55 +00:00
if ( $config [ 'alert' ][ 'default_only' ] == true || $config [ 'alerts' ][ 'email' ][ 'default_only' ] == true ) {
return array ( '' . ( $config [ 'alert' ][ 'default_mail' ] ? $config [ 'alert' ][ 'default_mail' ] : $config [ 'alerts' ][ 'email' ][ 'default' ]) => 'NOC' );
2014-12-19 20:21:54 +00:00
}
2015-04-05 12:50:38 +00:00
$users = get_userlist ();
2014-12-15 11:10:26 +00:00
$contacts = array ();
$uids = array ();
foreach ( $results as $result ) {
$tmp = NULL ;
2015-05-07 14:09:41 +00:00
if ( is_numeric ( $result [ " bill_id " ]) ) {
$tmpa = dbFetchRows ( " SELECT user_id FROM bill_perms WHERE bill_id = ? " , array ( $result [ " bill_id " ]));
foreach ( $tmpa as $tmp ) {
$uids [ $tmp [ 'user_id' ]] = $tmp [ 'user_id' ];
}
}
2014-12-15 11:10:26 +00:00
if ( is_numeric ( $result [ " port_id " ]) ) {
$tmpa = dbFetchRows ( " SELECT user_id FROM ports_perms WHERE access_level >= 0 AND port_id = ? " , array ( $result [ " port_id " ]));
foreach ( $tmpa as $tmp ) {
$uids [ $tmp [ 'user_id' ]] = $tmp [ 'user_id' ];
}
}
if ( is_numeric ( $result [ " device_id " ]) ) {
$tmpa = dbFetchRow ( " SELECT sysContact FROM devices WHERE device_id = ? " , array ( $result [ " device_id " ]));
$contacts [ $tmpa [ " sysContact " ]] = " NOC " ;
$tmpa = dbFetchRows ( " SELECT user_id FROM devices_perms WHERE access_level >= 0 AND device_id = ? " , array ( $result [ " device_id " ]));
foreach ( $tmpa as $tmp ) {
$uids [ $tmp [ 'user_id' ]] = $tmp [ 'user_id' ];
}
}
}
2015-04-05 12:50:38 +00:00
foreach ( $users as $user ) {
if ( empty ( $user [ 'email' ]) ) {
continue ;
} elseif ( empty ( $user [ 'realname' ]) ) {
$user [ 'realname' ] = $user [ 'username' ];
2014-12-15 11:10:26 +00:00
}
2015-04-05 12:50:38 +00:00
$user [ 'level' ] = get_userlevel ( $user [ 'username' ]);
if ( $config [ " alert " ][ " globals " ] && ( $user [ 'level' ] >= 5 && $user [ 'level' ] < 10 ) ) {
$contacts [ $user [ 'email' ]] = $user [ 'realname' ];
} elseif ( $config [ " alert " ][ " admins " ] && $user [ 'level' ] == 10 ) {
$contacts [ $user [ 'email' ]] = $user [ 'realname' ];
} elseif ( in_array ( $user [ 'user_id' ], $uids ) ) {
$contacts [ $user [ 'email' ]] = $user [ 'realname' ];
2014-12-15 11:10:26 +00:00
}
}
return $contacts ;
2012-05-16 16:26:19 +00:00
}
?>