2009-09-07 11:07:59 +00:00
<? php
2007-04-03 14:10:23 +00:00
2012-05-21 16:52:02 +00:00
/**
2016-09-08 14:12:23 +01:00
* LibreNMS
2012-05-21 16:52:02 +00:00
*
2016-09-08 14:12:23 +01:00
* This file is part of LibreNMS.
2012-05-21 16:52:02 +00:00
*
2016-09-08 14:12:23 +01:00
* @package LibreNMS
2012-05-21 16:52:02 +00:00
* @subpackage functions
* @copyright (C) 2006 - 2012 Adam Armstrong
*
*/
2020-01-30 13:20:30 +01:00
use App\Models\Device ;
2020-04-17 17:37:56 -05:00
use Illuminate\Support\Str ;
2017-09-21 12:02:01 -05:00
use LibreNMS\Config ;
2016-08-21 08:07:14 -05:00
use LibreNMS\Exceptions\HostExistsException ;
use LibreNMS\Exceptions\HostIpExistsException ;
use LibreNMS\Exceptions\HostUnreachableException ;
use LibreNMS\Exceptions\HostUnreachablePingException ;
use LibreNMS\Exceptions\InvalidPortAssocModeException ;
2017-11-24 03:37:52 -06:00
use LibreNMS\Exceptions\LockException ;
2016-08-21 08:07:14 -05:00
use LibreNMS\Exceptions\SnmpVersionUnsupportedException ;
2020-05-19 22:08:41 -05:00
use LibreNMS\Fping ;
2019-01-19 12:46:03 -06:00
use LibreNMS\Util\IPv4 ;
use LibreNMS\Util\IPv6 ;
2017-11-24 03:37:52 -06:00
use LibreNMS\Util\MemcacheLock ;
2019-03-18 03:09:58 +01:00
use LibreNMS\Util\Time ;
2019-08-05 14:16:05 -05:00
use PHPMailer\PHPMailer\PHPMailer ;
use Symfony\Component\Process\Process ;
2016-08-21 08:07:14 -05:00
2019-01-09 19:36:32 -06:00
if ( ! function_exists ( 'set_debug' )) {
/**
* Set debugging output
*
* @param bool $state If debug is enabled or not
* @param bool $silence When not debugging, silence every php error
* @return bool
*/
function set_debug ( $state = true , $silence = false )
{
global $debug ;
2018-07-13 17:08:00 -05:00
2019-01-09 19:36:32 -06:00
$debug = $state ; // set to global
2018-07-13 17:08:00 -05:00
2019-01-09 19:36:32 -06:00
restore_error_handler (); // disable Laravel error handler
2018-07-13 17:08:00 -05:00
2019-01-09 19:36:32 -06:00
if ( isset ( $debug ) && $debug ) {
ini_set ( 'display_errors' , 1 );
ini_set ( 'display_startup_errors' , 1 );
ini_set ( 'log_errors' , 0 );
error_reporting ( E_ALL & ~ E_NOTICE );
2018-07-13 17:08:00 -05:00
2019-01-09 19:36:32 -06:00
\LibreNMS\Util\Laravel :: enableCliDebugOutput ();
\LibreNMS\Util\Laravel :: enableQueryDebug ();
} else {
ini_set ( 'display_errors' , 0 );
ini_set ( 'display_startup_errors' , 0 );
ini_set ( 'log_errors' , 1 );
error_reporting ( $silence ? 0 : E_ERROR );
2018-07-13 17:08:00 -05:00
2019-01-09 19:36:32 -06:00
\LibreNMS\Util\Laravel :: disableCliDebugOutput ();
\LibreNMS\Util\Laravel :: disableQueryDebug ();
}
2018-07-13 17:08:00 -05:00
2019-01-09 19:36:32 -06:00
return $debug ;
}
2016-09-07 18:42:49 +01:00
} //end set_debug()
2018-04-01 15:27:41 -05:00
function array_sort_by_column ( $array , $on , $order = SORT_ASC )
2016-08-28 12:32:58 -05:00
{
2012-05-25 10:34:01 +00:00
$new_array = array ();
$sortable_array = array ();
if ( count ( $array ) > 0 ) {
foreach ( $array as $k => $v ) {
if ( is_array ( $v )) {
foreach ( $v as $k2 => $v2 ) {
if ( $k2 == $on ) {
$sortable_array [ $k ] = $v2 ;
}
}
2016-08-28 12:32:58 -05:00
} else {
2012-05-25 10:34:01 +00:00
$sortable_array [ $k ] = $v ;
}
}
switch ( $order ) {
2016-08-28 12:32:58 -05:00
case SORT_ASC :
asort ( $sortable_array );
break ;
case SORT_DESC :
arsort ( $sortable_array );
break ;
2012-05-25 10:34:01 +00:00
}
foreach ( $sortable_array as $k => $v ) {
$new_array [ $k ] = $array [ $k ];
}
}
return $new_array ;
2012-04-08 16:21:52 +00:00
}
2016-08-28 12:32:58 -05:00
function mac_clean_to_readable ( $mac )
{
2018-12-20 01:18:30 -02:00
return \LibreNMS\Util\Rewrite :: readableMac ( $mac );
2009-05-03 22:32:01 +00:00
}
2016-08-28 12:32:58 -05:00
function only_alphanumeric ( $string )
{
2015-07-13 20:10:26 +02:00
return preg_replace ( '/[^a-zA-Z0-9]/' , '' , $string );
2009-04-23 21:13:56 +00:00
}
2018-07-12 15:30:39 -05:00
/**
* Parse cli discovery or poller modules and set config for this run
*
* @param string $type discovery or poller
* @param array $options get_opts array (only m key is checked)
* @return bool
*/
function parse_modules ( $type , $options )
{
$override = false ;
if ( $options [ 'm' ]) {
Config :: set ( " { $type } _modules" , []);
foreach ( explode ( ',' , $options [ 'm' ]) as $module ) {
// parse submodules (only supported by some modules)
2020-04-17 17:37:56 -05:00
if ( Str :: contains ( $module , '/' )) {
2020-05-19 14:35:32 -05:00
[ $module , $submodule ] = explode ( '/' , $module , 2 );
2018-07-12 15:30:39 -05:00
$existing_submodules = Config :: get ( " { $type } _submodules. $module " , []);
$existing_submodules [] = $submodule ;
Config :: set ( " { $type } _submodules. $module " , $existing_submodules );
}
$dir = $type == 'poller' ? 'polling' : $type ;
if ( is_file ( "includes/ $dir / $module .inc.php" )) {
Config :: set ( " { $type } _modules. $module " , 1 );
$override = true ;
}
}
// display selected modules
$modules = array_map ( function ( $module ) use ( $type ) {
$submodules = Config :: get ( " { $type } _submodules. $module " );
return $module . ( $submodules ? '(' . implode ( ',' , $submodules ) . ')' : '' );
}, array_keys ( Config :: get ( " { $type } _modules" , [])));
d_echo ( "Override $type modules: " . implode ( ', ' , $modules ) . PHP_EOL );
}
return $override ;
}
2016-08-28 12:32:58 -05:00
function logfile ( $string )
{
2019-06-23 00:29:12 -05:00
$fd = fopen ( Config :: get ( 'log_file' ), 'a' );
2016-08-28 12:32:58 -05:00
fputs ( $fd , $string . " \n " );
2015-07-13 20:10:26 +02:00
fclose ( $fd );
2010-11-24 11:32:53 +00:00
}
2017-01-12 11:01:34 -06:00
/**
* Detect the os of the given device.
*
* @param array $device device to check
2020-05-14 11:27:59 -05:00
* @param bool $fetch fetch sysDescr and sysObjectID fresh from the device
2017-01-12 11:01:34 -06:00
* @return string the name of the os
2020-05-14 11:27:59 -05:00
* @throws Exception
2017-01-12 11:01:34 -06:00
*/
2020-05-14 11:27:59 -05:00
function getHostOS ( $device , $fetch = true )
2016-08-28 12:32:58 -05:00
{
2020-05-14 11:27:59 -05:00
if ( $fetch ) {
$device [ 'sysDescr' ] = snmp_get ( $device , "SNMPv2-MIB::sysDescr.0" , "-Ovq" );
$device [ 'sysObjectID' ] = snmp_get ( $device , "SNMPv2-MIB::sysObjectID.0" , "-Ovqn" );
}
2017-10-28 05:53:05 -05:00
2018-01-07 05:00:47 +00:00
d_echo ( "| { $device [ 'sysDescr' ] } | { $device [ 'sysObjectID' ] } | \n " );
2017-10-28 05:53:05 -05:00
2017-11-02 07:41:18 -05:00
$deferred_os = array (
'freebsd' ,
'linux' ,
);
2017-01-11 16:22:16 -06:00
// check yaml files
2017-11-02 07:41:18 -05:00
$os_defs = Config :: get ( 'os' );
foreach ( $os_defs as $os => $def ) {
2017-11-03 16:10:24 -05:00
if ( isset ( $def [ 'discovery' ]) && ! in_array ( $os , $deferred_os )) {
2017-11-02 07:41:18 -05:00
foreach ( $def [ 'discovery' ] as $item ) {
2018-01-07 05:00:47 +00:00
if ( checkDiscovery ( $device , $item )) {
2017-11-02 07:41:18 -05:00
return $os ;
2017-01-03 20:04:18 +00:00
}
}
}
}
2017-01-11 16:22:16 -06:00
// check include files
$os = null ;
2017-11-03 16:10:24 -05:00
$pattern = Config :: get ( 'install_dir' ) . '/includes/discovery/os/*.inc.php' ;
2017-01-11 16:22:16 -06:00
foreach ( glob ( $pattern ) as $file ) {
include $file ;
if ( isset ( $os )) {
return $os ;
}
}
2017-11-02 07:41:18 -05:00
// check deferred os
foreach ( $deferred_os as $os ) {
if ( isset ( $os_defs [ $os ][ 'discovery' ])) {
foreach ( $os_defs [ $os ][ 'discovery' ] as $item ) {
2018-01-07 05:00:47 +00:00
if ( checkDiscovery ( $device , $item )) {
2017-11-02 07:41:18 -05:00
return $os ;
}
}
}
}
2017-01-03 20:04:18 +00:00
return 'generic' ;
}
2011-03-08 17:12:43 +00:00
2017-01-12 11:01:34 -06:00
/**
* Check an array of conditions if all match, return true
2018-01-07 05:00:47 +00:00
* sysObjectID if sysObjectID starts with any of the values under this item
2017-01-12 11:01:34 -06:00
* sysDescr if sysDescr contains any of the values under this item
* sysDescr_regex if sysDescr matches any of the regexes under this item
2017-11-02 07:41:18 -05:00
* snmpget perform an snmpget on `oid` and check if the result contains `value`. Other subkeys: options, mib, mibdir
*
* Appending _except to any condition will invert the match.
2017-01-12 11:01:34 -06:00
*
2017-11-02 07:41:18 -05:00
* @param array $device
2018-01-07 05:00:47 +00:00
* @param array $array Array of items, keys should be sysObjectID, sysDescr, or sysDescr_regex
2017-01-12 11:01:34 -06:00
* @return bool the result (all items passed return true)
*/
2018-01-07 05:00:47 +00:00
function checkDiscovery ( $device , $array )
2017-01-12 11:01:34 -06:00
{
// all items must be true
foreach ( $array as $key => $value ) {
2020-04-17 17:37:56 -05:00
if ( $check = Str :: endsWith ( $key , '_except' )) {
2017-04-18 15:39:08 -05:00
$key = substr ( $key , 0 , - 7 );
}
2018-01-07 05:00:47 +00:00
if ( $key == 'sysObjectID' ) {
2020-04-17 17:37:56 -05:00
if ( Str :: startsWith ( $device [ 'sysObjectID' ], $value ) == $check ) {
2017-01-12 11:01:34 -06:00
return false ;
}
} elseif ( $key == 'sysDescr' ) {
2020-04-17 17:37:56 -05:00
if ( Str :: contains ( $device [ 'sysDescr' ], $value ) == $check ) {
2017-01-12 11:01:34 -06:00
return false ;
}
} elseif ( $key == 'sysDescr_regex' ) {
2018-01-07 05:00:47 +00:00
if ( preg_match_any ( $device [ 'sysDescr' ], $value ) == $check ) {
2017-01-12 11:01:34 -06:00
return false ;
}
2018-01-07 05:00:47 +00:00
} elseif ( $key == 'sysObjectID_regex' ) {
if ( preg_match_any ( $device [ 'sysObjectID' ], $value ) == $check ) {
2017-02-04 04:02:05 -06:00
return false ;
}
2017-11-02 07:41:18 -05:00
} elseif ( $key == 'snmpget' ) {
$options = isset ( $value [ 'options' ]) ? $value [ 'options' ] : '-Oqv' ;
$mib = isset ( $value [ 'mib' ]) ? $value [ 'mib' ] : null ;
2017-11-13 14:45:00 -06:00
$mib_dir = isset ( $value [ 'mib_dir' ]) ? $value [ 'mib_dir' ] : null ;
2017-11-02 07:41:18 -05:00
$op = isset ( $value [ 'op' ]) ? $value [ 'op' ] : 'contains' ;
$get_value = snmp_get ( $device , $value [ 'oid' ], $options , $mib , $mib_dir );
if ( compare_var ( $get_value , $value [ 'value' ], $op ) == $check ) {
return false ;
}
2017-01-12 11:01:34 -06:00
}
}
return true ;
}
/**
* Check an array of regexes against a subject if any match, return true
*
* @param string $subject the string to match against
* @param array|string $regexes an array of regexes or single regex to check
* @return bool if any of the regexes matched, return true
*/
2017-01-03 20:04:18 +00:00
function preg_match_any ( $subject , $regexes )
{
foreach (( array ) $regexes as $regex ) {
if ( preg_match ( $regex , $subject )) {
return true ;
}
}
return false ;
2008-03-12 11:15:58 +00:00
}
2017-11-02 07:41:18 -05:00
/**
* Perform comparison of two items based on give comparison method
* Valid comparisons: =, !=, ==, !==, >=, <=, >, <, contains, starts, ends, regex
* contains, starts, ends: $a haystack, $b needle(s)
* regex: $a subject, $b regex
*
* @param mixed $a
* @param mixed $b
* @param string $comparison =, !=, ==, !== >=, <=, >, <, contains, starts, ends, regex
* @return bool
*/
function compare_var ( $a , $b , $comparison = '=' )
{
switch ( $comparison ) {
case "=" :
return $a == $b ;
case "!=" :
return $a != $b ;
case "==" :
return $a === $b ;
case "!==" :
return $a !== $b ;
case ">=" :
return $a >= $b ;
case "<=" :
return $a <= $b ;
case ">" :
return $a > $b ;
case "<" :
return $a < $b ;
case "contains" :
2020-04-17 17:37:56 -05:00
return Str :: contains ( $a , $b );
2019-07-09 16:47:02 +02:00
case "not_contains" :
2020-04-17 17:37:56 -05:00
return ! Str :: contains ( $a , $b );
2017-11-02 07:41:18 -05:00
case "starts" :
2020-04-17 17:37:56 -05:00
return Str :: startsWith ( $a , $b );
2019-07-09 16:47:02 +02:00
case "not_starts" :
2020-04-17 17:37:56 -05:00
return ! Str :: startsWith ( $a , $b );
2017-11-02 07:41:18 -05:00
case "ends" :
2020-04-17 17:37:56 -05:00
return Str :: endsWith ( $a , $b );
2019-07-09 16:47:02 +02:00
case "not_ends" :
2020-04-17 17:37:56 -05:00
return ! Str :: endsWith ( $a , $b );
2017-11-02 07:41:18 -05:00
case "regex" :
return ( bool ) preg_match ( $b , $a );
2019-07-09 16:47:02 +02:00
case "not regex" :
return ! (( bool ) preg_match ( $b , $a ));
case "in_array" :
return in_array ( $a , $b );
case "not_in_array" :
return ! in_array ( $a , $b );
2017-11-02 07:41:18 -05:00
default :
return false ;
}
}
2016-08-28 12:32:58 -05:00
function percent_colour ( $perc )
{
2015-07-13 20:10:26 +02:00
$r = min ( 255 , 5 * ( $perc - 25 ));
$b = max ( 0 , 255 - ( 5 * ( $perc + 25 )));
2011-03-27 10:21:19 +00:00
2015-07-13 20:10:26 +02:00
return sprintf ( '#%02x%02x%02x' , $r , $b , $b );
2011-03-08 17:12:43 +00:00
}
2007-06-24 14:56:47 +00:00
2017-01-24 16:16:01 -06:00
/**
* @param $device
* @return string the logo image path for this device. Images are often wide, not square.
*/
function getLogo ( $device )
{
$img = getImageName ( $device , true , 'images/logos/' );
2020-04-17 17:37:56 -05:00
if ( ! Str :: startsWith ( $img , 'generic' )) {
2017-01-24 16:16:01 -06:00
return 'images/logos/' . $img ;
}
return getIcon ( $device );
}
/**
2017-02-24 03:59:30 -06:00
* @param array $device
* @param string $class to apply to the image tag
2017-01-24 16:16:01 -06:00
* @return string an image tag with the logo for this device. Images are often wide, not square.
*/
2017-02-24 03:59:30 -06:00
function getLogoTag ( $device , $class = null )
2016-08-28 12:32:58 -05:00
{
2019-05-21 08:50:45 -05:00
$tag = '<img src="' . url ( getLogo ( $device )) . '" title="' . getImageTitle ( $device ) . '"' ;
2017-02-24 03:59:30 -06:00
if ( isset ( $class )) {
$tag .= " class= \" $class \" " ;
}
$tag .= ' />' ;
return $tag ;
2014-01-13 10:05:19 +00:00
}
2017-01-24 16:16:01 -06:00
/**
* @param $device
* @return string the path to the icon image for this device. Close to square.
*/
function getIcon ( $device )
2016-08-28 12:32:58 -05:00
{
2017-01-08 20:32:17 +01:00
return 'images/os/' . getImageName ( $device );
2016-02-23 23:44:51 -06:00
}
2017-01-24 16:16:01 -06:00
/**
* @param $device
* @return string an image tag with the icon for this device. Close to square.
*/
function getIconTag ( $device )
{
return '<img src="' . getIcon ( $device ) . '" title="' . getImageTitle ( $device ) . '"/>' ;
}
2017-01-24 23:36:33 +00:00
function getImageTitle ( $device )
{
2017-01-24 16:16:01 -06:00
return $device [ 'icon' ] ? str_replace ( array ( '.svg' , '.png' ), '' , $device [ 'icon' ]) : $device [ 'os' ];
}
function getImageName ( $device , $use_database = true , $dir = 'images/os/' )
2016-08-28 12:32:58 -05:00
{
2019-03-01 23:06:01 -06:00
return \LibreNMS\Util\Url :: findOsImage ( $device [ 'os' ], $device [ 'features' ], $use_database ? $device [ 'icon' ] : null , $dir );
2008-11-19 12:12:54 +00:00
}
2016-08-28 12:32:58 -05:00
function renamehost ( $id , $new , $source = 'console' )
{
2018-08-30 14:38:29 -05:00
$host = gethostbyid ( $id );
2015-07-13 20:10:26 +02:00
2017-09-02 20:45:31 +02:00
if ( ! is_dir ( get_rrd_dir ( $new )) && rename ( get_rrd_dir ( $host ), get_rrd_dir ( $new )) === true ) {
2018-08-30 14:38:29 -05:00
dbUpdate ([ 'hostname' => $new , 'ip' => null ], 'devices' , 'device_id=?' , [ $id ]);
2017-02-13 00:41:05 +02:00
log_event ( "Hostname changed -> $new ( $source )" , $id , 'system' , 3 );
2018-08-30 14:38:29 -05:00
return '' ;
2015-07-13 20:10:26 +02:00
}
2018-08-30 14:38:29 -05:00
log_event ( "Renaming of $host failed" , $id , 'system' , 5 );
return "Renaming of $host failed \n " ;
2007-04-03 14:10:23 +00:00
}
2019-12-08 22:17:27 +01:00
function device_discovery_trigger ( $id )
{
global $debug ;
if ( isCli () === false ) {
ignore_user_abort ( true );
set_time_limit ( 0 );
}
$update = dbUpdate ( array ( 'last_discovered' => array ( 'NULL' )), 'devices' , '`device_id` = ?' , array ( $id ));
if ( ! empty ( $update ) || $update == '0' ) {
$message = 'Device will be rediscovered' ;
} else {
$message = 'Error rediscovering device' ;
}
return array ( 'status' => $update , 'message' => $message );
}
2016-08-28 12:32:58 -05:00
function delete_device ( $id )
{
2019-06-23 00:29:12 -05:00
global $debug ;
2017-02-01 20:17:35 +00:00
if ( isCli () === false ) {
ignore_user_abort ( true );
set_time_limit ( 0 );
}
2015-07-13 20:10:26 +02:00
$ret = '' ;
$host = dbFetchCell ( "SELECT hostname FROM devices WHERE device_id = ?" , array ( $id ));
2016-08-28 12:32:58 -05:00
if ( empty ( $host )) {
2015-07-13 20:10:26 +02:00
return "No such host." ;
}
// Remove IPv4/IPv6 addresses before removing ports as they depend on port_id
2016-08-28 12:32:58 -05:00
dbQuery ( "DELETE `ipv4_addresses` FROM `ipv4_addresses` INNER JOIN `ports` ON `ports`.`port_id`=`ipv4_addresses`.`port_id` WHERE `device_id`=?" , array ( $id ));
dbQuery ( "DELETE `ipv6_addresses` FROM `ipv6_addresses` INNER JOIN `ports` ON `ports`.`port_id`=`ipv6_addresses`.`port_id` WHERE `device_id`=?" , array ( $id ));
2015-07-13 20:10:26 +02:00
2020-04-16 09:19:58 -05:00
\App\Models\Port :: where ( 'device_id' , $id )
-> with ( 'device' )
-> select ([ 'port_id' , 'device_id' , 'ifIndex' , 'ifName' , 'ifAlias' , 'ifDescr' ])
-> chunk ( 100 , function ( $ports ) use ( & $ret ) {
foreach ( $ports as $port ) {
$port -> delete ();
$ret .= "Removed interface $port->port_id (" . $port -> getLabel () . ") \n " ;
}
});
2015-07-13 20:10:26 +02:00
2017-02-23 23:03:07 +00:00
// Remove sensors manually due to constraints
foreach ( dbFetchRows ( "SELECT * FROM `sensors` WHERE `device_id` = ?" , array ( $id )) as $sensor ) {
$sensor_id = $sensor [ 'sensor_id' ];
2017-11-02 21:40:51 +01:00
dbDelete ( 'sensors_to_state_indexes' , "`sensor_id` = ?" , array ( $sensor_id ));
2017-02-23 23:03:07 +00:00
}
2015-07-13 20:10:26 +02:00
$fields = array ( 'device_id' , 'host' );
2018-04-11 10:15:13 -05:00
$db_name = dbFetchCell ( 'SELECT DATABASE()' );
2016-08-28 12:32:58 -05:00
foreach ( $fields as $field ) {
2020-02-18 16:16:04 +01:00
foreach ( dbFetch ( "SELECT TABLE_NAME FROM information_schema.columns WHERE table_schema = ? AND column_name = ?" , [ $db_name , $field ]) as $table ) {
$table = $table [ 'TABLE_NAME' ];
2015-07-13 20:10:26 +02:00
$entries = ( int ) dbDelete ( $table , "` $field ` = ?" , array ( $id ));
2016-08-28 12:32:58 -05:00
if ( $entries > 0 && $debug === true ) {
2015-07-13 20:10:26 +02:00
$ret .= " $field @ $table = # $entries \n " ;
2012-05-20 23:19:28 +00:00
}
2012-05-09 16:18:23 +00:00
}
2015-07-13 20:10:26 +02:00
}
2017-09-02 20:45:31 +02:00
$ex = shell_exec ( "bash -c '( [ ! -d " . trim ( get_rrd_dir ( $host )) . " ] || rm -vrf " . trim ( get_rrd_dir ( $host )) . " 2>&1 ) && echo -n OK'" );
2016-08-28 12:32:58 -05:00
$tmp = explode ( " \n " , $ex );
if ( $tmp [ sizeof ( $tmp ) - 1 ] != "OK" ) {
2015-07-13 20:10:26 +02:00
$ret .= "Could not remove files: \n $ex \n " ;
}
$ret .= "Removed device $host \n " ;
2017-02-13 00:41:05 +02:00
log_event ( "Device $host has been removed" , 0 , 'system' , 3 );
2017-04-28 04:31:48 +01:00
oxidized_reload_nodes ();
2015-07-13 20:10:26 +02:00
return $ret ;
}
2016-08-01 22:01:01 -05:00
/**
* Add a device to LibreNMS
*
* @param string $host dns name or ip address
* @param string $snmp_version If this is empty, try v2c,v3,v1. Otherwise, use this specific version.
* @param string $port the port to connect to for snmp
* @param string $transport udp or tcp
* @param string $poller_group the poller group this device will belong to
2016-08-09 15:00:12 -05:00
* @param boolean $force_add add even if the device isn't reachable
2016-08-01 22:01:01 -05:00
* @param string $port_assoc_mode snmp field to use to determine unique ports
2017-10-28 05:59:25 +02:00
* @param array $additional an array with additional parameters to take into consideration when adding devices
2016-08-07 12:16:40 -05:00
*
* @return int returns the device_id of the added device
*
* @throws HostExistsException This hostname already exists
* @throws HostIpExistsException We already have a host with this IP
* @throws HostUnreachableException We could not reach this device is some way
* @throws HostUnreachablePingException We could not ping the device
* @throws InvalidPortAssocModeException The given port association mode was invalid
* @throws SnmpVersionUnsupportedException The given snmp version was invalid
2016-08-01 22:01:01 -05:00
*/
2017-10-28 05:59:25 +02:00
function addHost ( $host , $snmp_version = '' , $port = '161' , $transport = 'udp' , $poller_group = '0' , $force_add = false , $port_assoc_mode = 'ifIndex' , $additional = array ())
2016-08-28 12:32:58 -05:00
{
2015-07-13 20:10:26 +02:00
// Test Database Exists
2017-07-16 22:01:07 +01:00
if ( host_exists ( $host )) {
2016-08-07 12:16:40 -05:00
throw new HostExistsException ( "Already have host $host " );
2016-08-01 22:01:01 -05:00
}
2016-01-21 22:05:11 +01:00
2016-08-01 22:01:01 -05:00
// Valid port assoc mode
2018-08-05 03:50:13 -05:00
if ( ! in_array ( $port_assoc_mode , get_port_assoc_modes ())) {
2016-08-07 12:16:40 -05:00
throw new InvalidPortAssocModeException ( "Invalid port association_mode ' $port_assoc_mode '. Valid modes are: " . join ( ', ' , get_port_assoc_modes ()));
2016-08-01 22:01:01 -05:00
}
2015-07-13 20:10:26 +02:00
2016-08-01 22:01:01 -05:00
// check if we have the host by IP
2020-04-08 11:47:40 +02:00
$overwrite_ip = null ;
if ( ! empty ( $additional [ 'overwrite_ip' ])) {
$overwrite_ip = $additional [ 'overwrite_ip' ];
2020-01-30 13:20:30 +01:00
$ip = $overwrite_ip ;
} elseif ( Config :: get ( 'addhost_alwayscheckip' ) === true ) {
2016-08-01 22:01:01 -05:00
$ip = gethostbyname ( $host );
} else {
$ip = $host ;
}
2019-01-19 12:46:03 -06:00
if ( $force_add !== true && $device = device_has_ip ( $ip )) {
$message = "Cannot add $host , already have device with this IP $ip " ;
if ( $ip != $device -> hostname ) {
$message .= " ( $device->hostname )" ;
}
$message .= '. You may force add to ignore this.' ;
throw new HostIpExistsException ( $message );
2016-08-01 22:01:01 -05:00
}
// Test reachability
2016-08-09 15:00:12 -05:00
if ( ! $force_add ) {
$address_family = snmpTransportToAddressFamily ( $transport );
2020-01-30 13:20:30 +01:00
$ping_result = isPingable ( $ip , $address_family );
2016-08-09 15:00:12 -05:00
if ( ! $ping_result [ 'result' ]) {
throw new HostUnreachablePingException ( "Could not ping $host " );
}
2016-08-01 22:01:01 -05:00
}
2015-07-13 20:10:26 +02:00
2016-08-01 22:01:01 -05:00
// if $snmpver isn't set, try each version of snmp
if ( empty ( $snmp_version )) {
2018-04-12 04:35:51 +01:00
$snmpvers = Config :: get ( 'snmp.version' );
2016-08-01 22:01:01 -05:00
} else {
$snmpvers = array ( $snmp_version );
}
2017-10-28 05:59:25 +02:00
if ( isset ( $additional [ 'snmp_disable' ]) && $additional [ 'snmp_disable' ] == 1 ) {
2020-01-30 13:20:30 +01:00
return createHost ( $host , '' , $snmp_version , $port , $transport , array (), $poller_group , 1 , true , $overwrite_ip , $additional );
2017-10-28 05:59:25 +02:00
}
2017-05-18 22:03:55 +02:00
$host_unreachable_exception = new HostUnreachableException ( "Could not connect to $host , please check the snmp details and snmp reachability" );
2016-08-01 22:01:01 -05:00
// try different snmp variables to add the device
foreach ( $snmpvers as $snmpver ) {
if ( $snmpver === "v3" ) {
// Try each set of parameters from config
2019-06-23 00:29:12 -05:00
foreach ( Config :: get ( 'snmp.v3' ) as $v3 ) {
2020-04-08 11:47:40 +02:00
$device = deviceArray ( $host , null , $snmpver , $port , $transport , $v3 , $port_assoc_mode , $overwrite_ip );
2016-09-16 09:40:00 +01:00
if ( $force_add === true || isSNMPable ( $device )) {
2020-01-30 13:20:30 +01:00
return createHost ( $host , null , $snmpver , $port , $transport , $v3 , $poller_group , $port_assoc_mode , $force_add , $overwrite_ip );
2016-08-01 22:01:01 -05:00
} else {
2016-08-07 12:16:40 -05:00
$host_unreachable_exception -> addReason ( "SNMP $snmpver : No reply with credentials " . $v3 [ 'authname' ] . "/" . $v3 [ 'authlevel' ]);
2015-07-13 20:10:26 +02:00
}
2011-09-08 12:24:18 +00:00
}
2016-08-01 22:01:01 -05:00
} elseif ( $snmpver === "v2c" || $snmpver === "v1" ) {
// try each community from config
2019-06-23 00:29:12 -05:00
foreach ( Config :: get ( 'snmp.community' ) as $community ) {
2020-04-08 11:47:40 +02:00
$device = deviceArray ( $host , $community , $snmpver , $port , $transport , null , $port_assoc_mode , $overwrite_ip );
2016-08-07 12:16:40 -05:00
2016-09-16 09:40:00 +01:00
if ( $force_add === true || isSNMPable ( $device )) {
2020-01-30 13:20:30 +01:00
return createHost ( $host , $community , $snmpver , $port , $transport , array (), $poller_group , $port_assoc_mode , $force_add , $overwrite_ip );
2016-08-01 22:01:01 -05:00
} else {
2016-08-07 12:16:40 -05:00
$host_unreachable_exception -> addReason ( "SNMP $snmpver : No reply with community $community " );
2015-07-13 20:10:26 +02:00
}
2012-05-09 16:18:23 +00:00
}
2016-08-01 22:01:01 -05:00
} else {
2016-08-07 12:16:40 -05:00
throw new SnmpVersionUnsupportedException ( "Unsupported SNMP Version \" $snmpver \" , must be v1, v2c, or v3" );
2015-06-11 19:34:11 +01:00
}
}
2017-10-28 05:59:25 +02:00
if ( isset ( $additional [ 'ping_fallback' ]) && $additional [ 'ping_fallback' ] == 1 ) {
$additional [ 'snmp_disable' ] = 1 ;
$additional [ 'os' ] = "ping" ;
2020-01-30 13:20:30 +01:00
return createHost ( $host , '' , $snmp_version , $port , $transport , array (), $poller_group , 1 , true , $overwrite_ip , $additional );
2017-10-28 05:59:25 +02:00
}
2016-08-07 12:16:40 -05:00
throw $host_unreachable_exception ;
2007-04-03 14:10:23 +00:00
}
2020-04-08 11:47:40 +02:00
function deviceArray ( $host , $community , $snmpver , $port = 161 , $transport = 'udp' , $v3 = array (), $port_assoc_mode = 'ifIndex' , $overwrite_ip = null )
2016-08-28 12:32:58 -05:00
{
2015-07-13 20:10:26 +02:00
$device = array ();
$device [ 'hostname' ] = $host ;
2020-04-08 11:47:40 +02:00
$device [ 'overwrite_ip' ] = $overwrite_ip ;
2015-07-13 20:10:26 +02:00
$device [ 'port' ] = $port ;
$device [ 'transport' ] = $transport ;
2016-01-21 22:05:11 +01:00
/* Get port_assoc_mode id if neccessary
* We can work with names of IDs here */
2016-08-28 12:32:58 -05:00
if ( ! is_int ( $port_assoc_mode )) {
$port_assoc_mode = get_port_assoc_mode_id ( $port_assoc_mode );
}
2016-01-21 22:05:11 +01:00
$device [ 'port_association_mode' ] = $port_assoc_mode ;
2015-07-13 20:10:26 +02:00
$device [ 'snmpver' ] = $snmpver ;
if ( $snmpver === "v2c" or $snmpver === "v1" ) {
$device [ 'community' ] = $community ;
2016-08-28 12:32:58 -05:00
} elseif ( $snmpver === "v3" ) {
2015-07-13 20:10:26 +02:00
$device [ 'authlevel' ] = $v3 [ 'authlevel' ];
$device [ 'authname' ] = $v3 [ 'authname' ];
$device [ 'authpass' ] = $v3 [ 'authpass' ];
$device [ 'authalgo' ] = $v3 [ 'authalgo' ];
$device [ 'cryptopass' ] = $v3 [ 'cryptopass' ];
$device [ 'cryptoalgo' ] = $v3 [ 'cryptoalgo' ];
}
return $device ;
2020-04-08 11:47:40 +02:00
} //end deviceArray()
2011-03-15 16:12:44 +00:00
2019-03-18 03:09:58 +01:00
2016-08-28 12:32:58 -05:00
function formatUptime ( $diff , $format = "long" )
{
2019-03-18 03:09:58 +01:00
return Time :: formatInterval ( $diff , $format );
2007-04-03 14:10:23 +00:00
}
2016-08-28 12:32:58 -05:00
function isSNMPable ( $device )
{
2017-02-23 22:47:18 +00:00
$pos = snmp_check ( $device );
if ( $pos === true ) {
2015-07-13 20:10:26 +02:00
return true ;
2017-02-23 22:47:18 +00:00
} else {
$pos = snmp_get ( $device , "sysObjectID.0" , "-Oqv" , "SNMPv2-MIB" );
if ( $pos === '' || $pos === false ) {
return false ;
} else {
return true ;
}
2015-07-13 20:10:26 +02:00
}
2007-04-03 14:10:23 +00:00
}
2015-09-24 02:07:15 +02:00
/**
* Check if the given host responds to ICMP echo requests ("pings").
*
* @param string $hostname The hostname or IP address to send ping requests to.
2018-08-11 17:34:52 -05:00
* @param string $address_family The address family ('ipv4' or 'ipv6') to use. Defaults to IPv4.
* Will *not* be autodetected for IP addresses, so it has to be set to 'ipv6' when pinging an IPv6 address or an IPv6-only host.
2015-10-17 19:11:21 +00:00
* @param array $attribs The device attributes
2015-09-24 02:07:15 +02:00
*
2016-08-01 22:01:01 -05:00
* @return array 'result' => bool pingable, 'last_ping_timetaken' => int time for last ping, 'db' => fping results
2015-09-24 02:07:15 +02:00
*/
2018-08-11 17:34:52 -05:00
function isPingable ( $hostname , $address_family = 'ipv4' , $attribs = [])
2016-08-28 12:32:58 -05:00
{
2018-08-11 17:34:52 -05:00
if ( can_ping_device ( $attribs ) !== true ) {
return [
'result' => true ,
'last_ping_timetaken' => 0
];
}
2020-05-19 22:08:41 -05:00
$status = app () -> make ( Fping :: class ) -> ping (
2018-08-11 17:34:52 -05:00
$hostname ,
Config :: get ( 'fping_options.count' , 3 ),
Config :: get ( 'fping_options.interval' , 500 ),
Config :: get ( 'fping_options.timeout' , 500 ),
$address_family
);
2015-07-13 20:10:26 +02:00
2019-10-16 08:36:54 +00:00
if ( $status [ 'dup' ] > 0 ) {
Log :: event ( 'Duplicate ICMP response detected! This could indicate a network issue.' , getidbyname ( $hostname ), 'icmp' , 4 );
$status [ 'exitcode' ] = 0 ; // when duplicate is detected fping returns 1. The device is up, but there is another issue. Clue admins in with above event.
}
2018-08-11 17:34:52 -05:00
return [
'result' => ( $status [ 'exitcode' ] == 0 && $status [ 'loss' ] < 100 ),
'last_ping_timetaken' => $status [ 'avg' ],
'db' => array_intersect_key ( $status , array_flip ([ 'xmt' , 'rcv' , 'loss' , 'min' , 'max' , 'avg' ]))
];
2007-04-03 14:10:23 +00:00
}
2016-08-28 12:32:58 -05:00
function getpollergroup ( $poller_group = '0' )
{
2015-07-13 20:10:26 +02:00
//Is poller group an integer
if ( is_int ( $poller_group ) || ctype_digit ( $poller_group )) {
return $poller_group ;
2016-08-28 12:32:58 -05:00
} else {
2015-07-13 20:10:26 +02:00
//Check if it contains a comma
2016-08-28 12:32:58 -05:00
if ( strpos ( $poller_group , ',' ) !== false ) {
2015-07-13 20:10:26 +02:00
//If it has a comma use the first element as the poller group
2016-08-28 12:32:58 -05:00
$poller_group_array = explode ( ',' , $poller_group );
2015-07-13 20:10:26 +02:00
return getpollergroup ( $poller_group_array [ 0 ]);
2016-08-28 12:32:58 -05:00
} else {
2019-06-23 00:29:12 -05:00
if ( Config :: get ( 'distributed_poller_group' )) {
2015-07-13 20:10:26 +02:00
//If not use the poller's group from the config
2019-06-23 00:29:12 -05:00
return getpollergroup ( Config :: get ( 'distributed_poller_group' ));
2016-08-28 12:32:58 -05:00
} else {
2015-07-13 20:10:26 +02:00
//If all else fails use default
return '0' ;
}
}
}
2015-06-22 12:37:00 +02:00
}
2017-02-22 03:12:31 -06:00
/**
* Add a host to the database
*
* @param string $host The IP or hostname to add
* @param string $community The snmp community
* @param string $snmpver snmp version: v1 | v2c | v3
* @param int $port SNMP port number
* @param string $transport SNMP transport: udp | udp6 | udp | tcp6
* @param array $v3 SNMPv3 settings required array keys: authlevel, authname, authpass, authalgo, cryptopass, cryptoalgo
* @param int $poller_group distributed poller group to assign this host to
* @param string $port_assoc_mode field to use to identify ports: ifIndex, ifName, ifDescr, ifAlias
* @param bool $force_add Do not detect the host os
2017-10-28 05:59:25 +02:00
* @param array $additional an array with additional parameters to take into consideration when adding devices
2017-02-22 03:12:31 -06:00
* @return int the id of the added host
* @throws HostExistsException Throws this exception if the host already exists
* @throws Exception Throws this exception if insertion into the database fails
*/
function createHost (
$host ,
$community ,
$snmpver ,
$port = 161 ,
$transport = 'udp' ,
$v3 = array (),
$poller_group = 0 ,
$port_assoc_mode = 'ifIndex' ,
2017-10-28 05:59:25 +02:00
$force_add = false ,
2020-01-30 13:20:30 +01:00
$overwrite_ip = null ,
2017-10-28 05:59:25 +02:00
$additional = array ()
2017-02-22 03:12:31 -06:00
) {
2015-07-13 20:10:26 +02:00
$host = trim ( strtolower ( $host ));
$poller_group = getpollergroup ( $poller_group );
2016-08-01 22:01:01 -05:00
/* Get port_assoc_mode id if necessary
2016-02-26 08:04:38 -06:00
* We can work with names of IDs here */
2016-08-28 12:32:58 -05:00
if ( ! is_int ( $port_assoc_mode )) {
$port_assoc_mode = get_port_assoc_mode_id ( $port_assoc_mode );
}
2016-02-26 08:04:38 -06:00
2017-02-22 03:12:31 -06:00
$device = array (
'hostname' => $host ,
2020-01-30 13:20:30 +01:00
'overwrite_ip' => $overwrite_ip ,
2020-04-20 00:36:01 +02:00
'sysName' => $additional [ 'sysName' ] ?? $host ,
'os' => $additional [ 'os' ] ?? 'generic' ,
'hardware' => $additional [ 'hardware' ] ?? null ,
2015-07-13 20:10:26 +02:00
'community' => $community ,
'port' => $port ,
'transport' => $transport ,
'status' => '1' ,
'snmpver' => $snmpver ,
2015-08-11 11:38:05 +00:00
'poller_group' => $poller_group ,
'status_reason' => '' ,
2016-01-21 22:05:11 +01:00
'port_association_mode' => $port_assoc_mode ,
2020-04-20 00:36:01 +02:00
'snmp_disable' => $additional [ 'snmp_disable' ] ?? 0 ,
2015-07-13 20:10:26 +02:00
);
2012-05-09 16:18:23 +00:00
2017-02-22 03:12:31 -06:00
$device = array_merge ( $device , $v3 ); // merge v3 settings
2011-09-14 17:26:59 +00:00
2016-09-16 09:40:00 +01:00
if ( $force_add !== true ) {
$device [ 'os' ] = getHostOS ( $device );
2011-03-15 16:12:44 +00:00
2017-07-16 22:01:07 +01:00
$snmphost = snmp_get ( $device , "sysName.0" , "-Oqv" , "SNMPv2-MIB" );
if ( host_exists ( $host , $snmphost )) {
throw new HostExistsException ( "Already have host $host ( $snmphost ) due to duplicate sysName" );
}
2010-02-07 22:39:02 +00:00
}
2016-08-01 22:01:01 -05:00
2017-02-22 03:12:31 -06:00
$device_id = dbInsert ( $device , 'devices' );
if ( $device_id ) {
return $device_id ;
}
throw new \Exception ( "Failed to add host to the database, please run ./validate.php" );
2007-04-03 14:10:23 +00:00
}
2016-08-28 12:32:58 -05:00
function isDomainResolves ( $domain )
{
2017-01-24 15:56:51 -06:00
if ( gethostbyname ( $domain ) != $domain ) {
return true ;
}
$records = dns_get_record ( $domain ); // returns array or false
return ! empty ( $records );
2007-04-03 14:10:23 +00:00
}
2016-08-28 12:32:58 -05:00
function hoststatus ( $id )
{
2015-07-13 20:10:26 +02:00
return dbFetchCell ( "SELECT `status` FROM `devices` WHERE `device_id` = ?" , array ( $id ));
2007-04-03 14:10:23 +00:00
}
2016-08-28 12:32:58 -05:00
function match_network ( $nets , $ip , $first = false )
{
2015-07-13 20:10:26 +02:00
$return = false ;
2016-08-28 12:32:58 -05:00
if ( ! is_array ( $nets )) {
$nets = array ( $nets );
}
2015-07-13 20:10:26 +02:00
foreach ( $nets as $net ) {
2016-08-28 12:32:58 -05:00
$rev = ( preg_match ( "/^\!/" , $net )) ? true : false ;
$net = preg_replace ( "/^\!/" , "" , $net );
2015-07-13 20:10:26 +02:00
$ip_arr = explode ( '/' , $net );
$net_long = ip2long ( $ip_arr [ 0 ]);
$x = ip2long ( $ip_arr [ 1 ]);
$mask = long2ip ( $x ) == $ip_arr [ 1 ] ? $x : 0xffffffff << ( 32 - $ip_arr [ 1 ]);
$ip_long = ip2long ( $ip );
if ( $rev ) {
if (( $ip_long & $mask ) == ( $net_long & $mask )) {
return false ;
}
2016-08-28 12:32:58 -05:00
} else {
2015-07-13 20:10:26 +02:00
if (( $ip_long & $mask ) == ( $net_long & $mask )) {
$return = true ;
}
if ( $first && $return ) {
return true ;
}
}
}
return $return ;
2007-04-03 14:10:23 +00:00
}
2017-08-08 14:14:58 -05:00
// FIXME port to LibreNMS\Util\IPv6 class
2016-08-28 12:32:58 -05:00
function snmp2ipv6 ( $ipv6_snmp )
{
2015-07-13 20:10:26 +02:00
# Workaround stupid Microsoft bug in Windows 2008 -- this is fixed length!
# < fenestro> "because whoever implemented this mib for Microsoft was ignorant of RFC 2578 section 7.7 (2)"
2018-01-18 14:54:38 -06:00
$ipv6 = array_slice ( explode ( '.' , $ipv6_snmp ), - 16 );
$ipv6_2 = array ();
2011-04-21 17:11:58 +00:00
2016-08-28 12:32:58 -05:00
for ( $i = 0 ; $i <= 15 ; $i ++ ) {
2015-07-13 20:10:26 +02:00
$ipv6 [ $i ] = zeropad ( dechex ( $ipv6 [ $i ]));
}
2016-08-28 12:32:58 -05:00
for ( $i = 0 ; $i <= 15 ; $i += 2 ) {
2015-07-13 20:10:26 +02:00
$ipv6_2 [] = $ipv6 [ $i ] . $ipv6 [ $i + 1 ];
}
2011-03-08 17:12:43 +00:00
2016-08-28 12:32:58 -05:00
return implode ( ':' , $ipv6_2 );
2010-01-01 14:09:57 +00:00
}
2016-08-28 12:32:58 -05:00
function get_astext ( $asn )
{
2018-08-17 12:17:45 -05:00
global $cache ;
2015-07-13 20:10:26 +02:00
2018-08-17 12:17:45 -05:00
if ( Config :: has ( "astext. $asn " )) {
return Config :: get ( "astext. $asn " );
}
if ( isset ( $cache [ 'astext' ][ $asn ])) {
return $cache [ 'astext' ][ $asn ];
}
2018-09-10 21:40:41 -05:00
$result = @ dns_get_record ( "AS $asn .asn.cymru.com" , DNS_TXT );
2018-08-17 12:17:45 -05:00
if ( ! empty ( $result [ 0 ][ 'txt' ])) {
$txt = explode ( '|' , $result [ 0 ][ 'txt' ]);
$result = trim ( $txt [ 4 ], ' "' );
$cache [ 'astext' ][ $asn ] = $result ;
return $result ;
2015-07-13 20:10:26 +02:00
}
2018-08-17 12:17:45 -05:00
return '' ;
2010-01-03 20:13:10 +00:00
}
2010-01-07 16:50:52 +00:00
2017-03-12 08:05:31 -05:00
/**
* Log events to the event table
*
* @param string $text message describing the event
* @param array|int $device device array or device_id
* @param string $type brief category for this event. Examples: sensor, state, stp, system, temperature, interface
* @param int $severity 1: ok, 2: info, 3: notice, 4: warning, 5: critical, 0: unknown
* @param int $reference the id of the referenced entity. Supported types: interface
*/
2017-02-13 00:41:05 +02:00
function log_event ( $text , $device = null , $type = null , $severity = 2 , $reference = null )
2016-08-28 12:32:58 -05:00
{
2020-04-11 19:53:25 -05:00
// handle legacy device array
if ( is_array ( $device ) && isset ( $device [ 'device_id' ])) {
$device = $device [ 'device_id' ];
}
Log :: event ( $text , $device , $type , $severity , $reference );
2011-03-08 17:12:43 +00:00
}
2010-02-17 11:02:18 +00:00
2012-04-26 12:11:03 +00:00
// Parse string with emails. Return array with email (as key) and name (as value)
2016-08-28 12:32:58 -05:00
function parse_email ( $emails )
{
2015-07-13 20:10:26 +02:00
$result = array ();
$regex = '/^[\"\']?([^\"\']+)[\"\']?\s{0,}<([^@]+@[^>]+)>$/' ;
if ( is_string ( $emails )) {
$emails = preg_split ( '/[,;]\s{0,}/' , $emails );
foreach ( $emails as $email ) {
if ( preg_match ( $regex , $email , $out , PREG_OFFSET_CAPTURE )) {
$result [ $out [ 2 ][ 0 ]] = $out [ 1 ][ 0 ];
2016-08-28 12:32:58 -05:00
} else {
2015-07-13 20:10:26 +02:00
if ( strpos ( $email , "@" )) {
2018-05-14 19:56:43 +01:00
$from_name = Config :: get ( 'email_user' );
$result [ $email ] = $from_name ;
2015-07-13 20:10:26 +02:00
}
}
}
2016-08-28 12:32:58 -05:00
} else {
2015-07-13 20:10:26 +02:00
// Return FALSE if input not string
2016-08-28 12:32:58 -05:00
return false ;
2015-07-13 20:10:26 +02:00
}
return $result ;
2012-04-26 12:11:03 +00:00
}
2016-08-28 12:32:58 -05:00
function send_mail ( $emails , $subject , $message , $html = false )
{
if ( is_array ( $emails ) || ( $emails = parse_email ( $emails ))) {
2018-08-31 20:48:04 -05:00
d_echo ( "Attempting to email $subject to: " . implode ( '; ' , array_keys ( $emails )) . PHP_EOL );
2018-09-02 15:45:39 -07:00
$mail = new PHPMailer ( true );
try {
$mail -> Hostname = php_uname ( 'n' );
2017-03-03 18:22:33 +00:00
2019-06-23 00:29:12 -05:00
foreach ( parse_email ( Config :: get ( 'email_from' )) as $from => $from_name ) {
2018-09-02 15:45:39 -07:00
$mail -> setFrom ( $from , $from_name );
}
foreach ( $emails as $email => $email_name ) {
$mail -> addAddress ( $email , $email_name );
}
$mail -> Subject = $subject ;
2019-10-16 21:22:05 +00:00
$mail -> XMailer = Config :: get ( 'project_name' );
2018-09-02 15:45:39 -07:00
$mail -> CharSet = 'utf-8' ;
$mail -> WordWrap = 76 ;
$mail -> Body = $message ;
if ( $html ) {
$mail -> isHTML ( true );
}
2019-06-23 00:29:12 -05:00
switch ( strtolower ( trim ( Config :: get ( 'email_backend' )))) {
2018-09-02 15:45:39 -07:00
case 'sendmail' :
$mail -> Mailer = 'sendmail' ;
2019-06-23 00:29:12 -05:00
$mail -> Sendmail = Config :: get ( 'email_sendmail_path' );
2018-09-02 15:45:39 -07:00
break ;
case 'smtp' :
$mail -> isSMTP ();
2019-06-23 00:29:12 -05:00
$mail -> Host = Config :: get ( 'email_smtp_host' );
$mail -> Timeout = Config :: get ( 'email_smtp_timeout' );
$mail -> SMTPAuth = Config :: get ( 'email_smtp_auth' );
$mail -> SMTPSecure = Config :: get ( 'email_smtp_secure' );
$mail -> Port = Config :: get ( 'email_smtp_port' );
$mail -> Username = Config :: get ( 'email_smtp_username' );
$mail -> Password = Config :: get ( 'email_smtp_password' );
$mail -> SMTPAutoTLS = Config :: get ( 'email_auto_tls' );
2018-09-02 15:45:39 -07:00
$mail -> SMTPDebug = false ;
break ;
default :
$mail -> Mailer = 'mail' ;
break ;
}
$mail -> send ();
return true ;
2019-03-12 23:59:03 -05:00
} catch ( \PHPMailer\PHPMailer\Exception $e ) {
2018-09-02 15:45:39 -07:00
return $e -> errorMessage ();
} catch ( Exception $e ) {
return $e -> getMessage ();
2015-07-13 20:10:26 +02:00
}
}
2018-07-31 15:53:03 -05:00
return "No contacts found" ;
2014-03-07 22:30:07 +01:00
}
2016-08-28 12:32:58 -05:00
function formatCiscoHardware ( & $device , $short = false )
{
2019-01-25 15:31:33 -06:00
return \LibreNMS\Util\Rewrite :: ciscoHardware ( $device , $short );
2010-02-21 17:02:20 +00:00
}
2010-06-18 16:38:41 +00:00
2016-08-28 12:32:58 -05:00
function hex2str ( $hex )
{
2015-07-13 20:10:26 +02:00
$string = '' ;
2011-03-11 18:03:49 +00:00
2015-07-13 20:10:26 +02:00
for ( $i = 0 ; $i < strlen ( $hex ) - 1 ; $i += 2 ) {
2017-02-12 07:20:06 -06:00
$string .= chr ( hexdec ( substr ( $hex , $i , 2 )));
2015-07-13 20:10:26 +02:00
}
2011-03-11 18:03:49 +00:00
2015-07-13 20:10:26 +02:00
return $string ;
2010-06-18 16:38:41 +00:00
}
2010-07-05 15:27:01 +00:00
2010-07-07 13:58:11 +00:00
# Convert an SNMP hex string to regular string
2016-08-28 12:32:58 -05:00
function snmp_hexstring ( $hex )
{
return hex2str ( str_replace ( ' ' , '' , str_replace ( ' 00' , '' , $hex )));
2010-07-05 15:27:01 +00:00
}
2010-07-07 13:58:11 +00:00
# Check if the supplied string is an SNMP hex string
2016-08-28 12:32:58 -05:00
function isHexString ( $str )
{
2017-02-16 02:15:20 -06:00
return ( bool ) preg_match ( "/^[a-f0-9][a-f0-9]( [a-f0-9][a-f0-9])*$/is" , trim ( $str ));
2010-07-05 15:27:01 +00:00
}
2010-07-09 22:38:46 +00:00
# Include all .inc.php files in $dir
2016-08-28 12:32:58 -05:00
function include_dir ( $dir , $regex = "" )
{
2019-06-23 00:29:12 -05:00
global $device , $valid ;
2011-09-16 10:31:48 +00:00
2015-07-13 20:10:26 +02:00
if ( $regex == "" ) {
$regex = "/\.inc\.php$/" ;
}
2011-03-23 09:54:56 +00:00
2019-06-23 00:29:12 -05:00
if ( $handle = opendir ( Config :: get ( 'install_dir' ) . '/' . $dir )) {
2015-07-13 20:10:26 +02:00
while ( false !== ( $file = readdir ( $handle ))) {
2019-06-23 00:29:12 -05:00
if ( filetype ( Config :: get ( 'install_dir' ) . '/' . $dir . '/' . $file ) == 'file' && preg_match ( $regex , $file )) {
d_echo ( "Including: " . Config :: get ( 'install_dir' ) . '/' . $dir . '/' . $file . " \n " );
2012-04-05 16:44:58 +00:00
2019-06-23 00:29:12 -05:00
include ( Config :: get ( 'install_dir' ) . '/' . $dir . '/' . $file );
2015-07-13 20:10:26 +02:00
}
}
2010-07-09 22:38:46 +00:00
2015-07-13 20:10:26 +02:00
closedir ( $handle );
}
2010-07-09 22:38:46 +00:00
}
2017-09-21 12:02:01 -05:00
/**
* Check if port is valid to poll.
2020-01-24 19:58:01 +08:00
* Settings: empty_ifdescr, good_if, bad_if, bad_if_regexp, bad_ifname_regexp, bad_ifalias_regexp, bad_iftype, bad_ifoperstatus
2017-09-21 12:02:01 -05:00
*
* @param array $port
* @param array $device
* @return bool
*/
2016-08-28 12:32:58 -05:00
function is_port_valid ( $port , $device )
{
2017-09-21 12:02:01 -05:00
// check empty values first
if ( empty ( $port [ 'ifDescr' ])) {
2017-02-03 19:49:40 +00:00
// If these are all empty, we are just going to show blank names in the ui
2017-09-21 12:02:01 -05:00
if ( empty ( $port [ 'ifAlias' ]) && empty ( $port [ 'ifName' ])) {
2018-08-04 16:10:57 -05:00
d_echo ( "ignored: empty ifDescr, ifAlias and ifName \n " );
2017-09-21 12:02:01 -05:00
return false ;
2015-07-13 20:10:26 +02:00
}
2017-09-21 12:02:01 -05:00
// ifDescr should not be empty unless it is explicitly allowed
2020-05-19 14:35:32 -05:00
if ( ! Config :: getOsSetting ( $device [ 'os' ], 'empty_ifdescr' , Config :: get ( 'empty_ifdescr' , false ))) {
2018-08-04 16:10:57 -05:00
d_echo ( "ignored: empty ifDescr \n " );
2017-09-21 12:02:01 -05:00
return false ;
2015-07-13 20:10:26 +02:00
}
2017-09-21 12:02:01 -05:00
}
$ifDescr = $port [ 'ifDescr' ];
$ifName = $port [ 'ifName' ];
$ifAlias = $port [ 'ifAlias' ];
$ifType = $port [ 'ifType' ];
2020-01-24 19:58:01 +08:00
$ifOperStatus = $port [ 'ifOperStatus' ];
2017-09-21 12:02:01 -05:00
2020-05-19 14:35:32 -05:00
if ( str_i_contains ( $ifDescr , Config :: getOsSetting ( $device [ 'os' ], 'good_if' , Config :: get ( 'good_if' )))) {
2017-09-21 12:02:01 -05:00
return true ;
}
foreach ( Config :: getCombined ( $device [ 'os' ], 'bad_if' ) as $bi ) {
2018-01-29 15:58:21 -06:00
if ( str_i_contains ( $ifDescr , $bi )) {
2017-09-21 12:02:01 -05:00
d_echo ( "ignored by ifDescr: $ifDescr (matched: $bi ) \n " );
return false ;
2015-07-13 20:10:26 +02:00
}
2017-09-21 12:02:01 -05:00
}
foreach ( Config :: getCombined ( $device [ 'os' ], 'bad_if_regexp' ) as $bir ) {
if ( preg_match ( $bir . "i" , $ifDescr )) {
d_echo ( "ignored by ifDescr: $ifDescr (matched: $bir ) \n " );
return false ;
2017-09-17 08:21:28 +01:00
}
2017-09-21 12:02:01 -05:00
}
foreach ( Config :: getCombined ( $device [ 'os' ], 'bad_ifname_regexp' ) as $bnr ) {
if ( preg_match ( $bnr . "i" , $ifName )) {
d_echo ( "ignored by ifName: $ifName (matched: $bnr ) \n " );
return false ;
2017-09-17 08:21:28 +01:00
}
2017-09-21 12:02:01 -05:00
}
foreach ( Config :: getCombined ( $device [ 'os' ], 'bad_ifalias_regexp' ) as $bar ) {
if ( preg_match ( $bar . "i" , $ifAlias )) {
d_echo ( "ignored by ifName: $ifAlias (matched: $bar ) \n " );
return false ;
2017-09-17 08:21:28 +01:00
}
2017-09-21 12:02:01 -05:00
}
foreach ( Config :: getCombined ( $device [ 'os' ], 'bad_iftype' ) as $bt ) {
2020-04-17 17:37:56 -05:00
if ( Str :: contains ( $ifType , $bt )) {
2017-09-21 12:02:01 -05:00
d_echo ( "ignored by ifType: $ifType (matched: $bt ) \n " );
return false ;
2012-03-29 12:05:45 +00:00
}
}
2011-05-18 23:08:45 +00:00
2020-01-24 19:58:01 +08:00
foreach ( Config :: getCombined ( $device [ 'os' ], 'bad_ifoperstatus' ) as $bos ) {
2020-04-17 17:37:56 -05:00
if ( Str :: contains ( $ifOperStatus , $bos )) {
2020-01-24 19:58:01 +08:00
d_echo ( "ignored by ifOperStatus: $ifOperStatus (matched: $bos ) \n " );
return false ;
}
}
2017-09-21 12:02:01 -05:00
return true ;
2011-05-18 23:08:45 +00:00
}
2019-01-19 18:48:30 +01:00
/**
* Try to fill in data for ifDescr, ifName, and ifAlias if devices do not provide them.
* Will not fill ifAlias if the user has overridden it
*
* @param array $port
* @param array $device
*/
function port_fill_missing ( & $port , $device )
{
// When devices do not provide data, populate with other data if available
if ( $port [ 'ifDescr' ] == '' || $port [ 'ifDescr' ] == null ) {
$port [ 'ifDescr' ] = $port [ 'ifName' ];
d_echo ( ' Using ifName as ifDescr' );
}
if ( ! empty ( $device [ 'attribs' ][ 'ifName:' . $port [ 'ifName' ]])) {
// ifAlias overridden by user, don't update it
unset ( $port [ 'ifAlias' ]);
d_echo ( ' ifAlias overriden by user' );
} elseif ( $port [ 'ifAlias' ] == '' || $port [ 'ifAlias' ] == null ) {
$port [ 'ifAlias' ] = $port [ 'ifDescr' ];
d_echo ( ' Using ifDescr as ifAlias' );
}
if ( $port [ 'ifName' ] == '' || $port [ 'ifName' ] == null ) {
$port [ 'ifName' ] = $port [ 'ifDescr' ];
d_echo ( ' Using ifDescr as ifName' );
}
}
2016-08-28 12:32:58 -05:00
function scan_new_plugins ()
{
2015-07-13 20:10:26 +02:00
$installed = 0 ; // Track how many plugins we install.
2019-06-23 00:29:12 -05:00
if ( file_exists ( Config :: get ( 'plugin_dir' ))) {
$plugin_files = scandir ( Config :: get ( 'plugin_dir' ));
2016-08-28 12:32:58 -05:00
foreach ( $plugin_files as $name ) {
2019-06-23 00:29:12 -05:00
if ( is_dir ( Config :: get ( 'plugin_dir' ) . '/' . $name )) {
2016-08-28 12:32:58 -05:00
if ( $name != '.' && $name != '..' ) {
2019-06-23 00:29:12 -05:00
if ( is_file ( Config :: get ( 'plugin_dir' ) . '/' . $name . '/' . $name . '.php' ) && is_file ( Config :: get ( 'plugin_dir' ) . '/' . $name . '/' . $name . '.inc.php' )) {
2019-08-27 19:47:04 +02:00
$plugin_id = dbFetchRow ( "SELECT `plugin_id` FROM `plugins` WHERE `plugin_name` = ?" , [ $name ]);
2016-08-28 12:32:58 -05:00
if ( empty ( $plugin_id )) {
2019-08-27 19:47:04 +02:00
if ( dbInsert ([ 'plugin_name' => $name , 'plugin_active' => '0' ], 'plugins' )) {
2015-07-13 20:10:26 +02:00
$installed ++ ;
}
}
}
}
2014-02-25 12:51:07 +00:00
}
}
}
2019-08-27 19:47:04 +02:00
return $installed ;
}
function scan_removed_plugins ()
{
$removed = 0 ; # Track how many plugins will be removed from database
if ( file_exists ( Config :: get ( 'plugin_dir' ))) {
$plugin_files = scandir ( Config :: get ( 'plugin_dir' ));
$installed_plugins = dbFetchColumn ( "SELECT `plugin_name` FROM `plugins`" );
foreach ( $installed_plugins as $name ) {
if ( in_array ( $name , $plugin_files )) {
continue ;
}
if ( dbDelete ( 'plugins' , "`plugin_name` = ?" , $name )) {
$removed ++ ;
}
}
}
return ( $removed );
2014-02-25 12:51:07 +00:00
}
2016-08-28 12:32:58 -05:00
function validate_device_id ( $id )
{
if ( empty ( $id ) || ! is_numeric ( $id )) {
2015-07-13 20:10:26 +02:00
$return = false ;
2016-08-28 12:32:58 -05:00
} else {
2015-07-13 20:10:26 +02:00
$device_id = dbFetchCell ( "SELECT `device_id` FROM `devices` WHERE `device_id` = ?" , array ( $id ));
2016-08-28 12:32:58 -05:00
if ( $device_id == $id ) {
2015-07-13 20:10:26 +02:00
$return = true ;
2016-08-28 12:32:58 -05:00
} else {
2015-07-13 20:10:26 +02:00
$return = false ;
}
}
return ( $return );
2014-06-24 16:14:42 +01:00
}
2014-09-17 21:03:02 +01:00
2014-10-07 11:29:54 +01:00
// The original source of this code is from Stackoverflow (www.stackoverflow.com).
// http://stackoverflow.com/questions/6054033/pretty-printing-json-with-php
// Answer provided by stewe (http://stackoverflow.com/users/3202187/ulk200
2016-08-28 12:32:58 -05:00
if ( ! defined ( 'JSON_UNESCAPED_SLASHES' )) {
2014-10-02 20:17:45 +01:00
define ( 'JSON_UNESCAPED_SLASHES' , 64 );
2016-08-28 12:32:58 -05:00
}
if ( ! defined ( 'JSON_PRETTY_PRINT' )) {
2014-10-02 20:17:45 +01:00
define ( 'JSON_PRETTY_PRINT' , 128 );
2016-08-28 12:32:58 -05:00
}
if ( ! defined ( 'JSON_UNESCAPED_UNICODE' )) {
2014-10-02 20:17:45 +01:00
define ( 'JSON_UNESCAPED_UNICODE' , 256 );
2016-08-28 12:32:58 -05:00
}
2014-10-02 20:17:45 +01:00
2016-08-28 12:32:58 -05:00
function _json_encode ( $data , $options = 448 )
{
2014-10-25 09:16:07 +10:00
if ( version_compare ( PHP_VERSION , '5.4' , '>=' )) {
2014-10-02 20:17:45 +01:00
return json_encode ( $data , $options );
2016-08-28 12:32:58 -05:00
} else {
2015-07-13 20:10:26 +02:00
return _json_format ( json_encode ( $data ), $options );
2014-10-25 09:16:07 +10:00
}
2014-10-02 20:17:45 +01:00
}
2016-08-28 12:32:58 -05:00
function _json_format ( $json , $options = 448 )
{
2014-10-02 20:17:45 +01:00
$prettyPrint = ( bool ) ( $options & JSON_PRETTY_PRINT );
$unescapeUnicode = ( bool ) ( $options & JSON_UNESCAPED_UNICODE );
$unescapeSlashes = ( bool ) ( $options & JSON_UNESCAPED_SLASHES );
2015-07-13 20:10:26 +02:00
if ( ! $prettyPrint && ! $unescapeUnicode && ! $unescapeSlashes ) {
2014-10-02 20:17:45 +01:00
return $json ;
}
$result = '' ;
$pos = 0 ;
$strLen = strlen ( $json );
$indentStr = ' ' ;
$newLine = " \n " ;
$outOfQuotes = true ;
$buffer = '' ;
$noescape = true ;
2015-07-13 20:10:26 +02:00
for ( $i = 0 ; $i < $strLen ; $i ++ ) {
2014-10-02 20:17:45 +01:00
// Grab the next character in the string
$char = substr ( $json , $i , 1 );
// Are we inside a quoted string?
2015-07-13 20:10:26 +02:00
if ( '"' === $char && $noescape ) {
2014-10-02 20:17:45 +01:00
$outOfQuotes = ! $outOfQuotes ;
}
2015-07-13 20:10:26 +02:00
if ( ! $outOfQuotes ) {
2014-10-02 20:17:45 +01:00
$buffer .= $char ;
$noescape = '\\' === $char ? ! $noescape : true ;
continue ;
2016-08-28 12:32:58 -05:00
} elseif ( '' !== $buffer ) {
2015-07-13 20:10:26 +02:00
if ( $unescapeSlashes ) {
2014-10-02 20:17:45 +01:00
$buffer = str_replace ( '\\/' , '/' , $buffer );
}
2015-07-13 20:10:26 +02:00
if ( $unescapeUnicode && function_exists ( 'mb_convert_encoding' )) {
2014-10-02 20:17:45 +01:00
// http://stackoverflow.com/questions/2934563/how-to-decode-unicode-escape-sequences-like-u00ed-to-proper-utf-8-encoded-cha
2016-08-28 12:32:58 -05:00
$buffer = preg_replace_callback (
'/\\\\u([0-9a-f]{4})/i' ,
2015-07-13 20:10:26 +02:00
function ( $match ) {
2014-10-02 20:17:45 +01:00
return mb_convert_encoding ( pack ( 'H*' , $match [ 1 ]), 'UTF-8' , 'UCS-2BE' );
2016-08-28 12:32:58 -05:00
},
$buffer
);
2014-10-02 20:17:45 +01:00
}
$result .= $buffer . $char ;
$buffer = '' ;
continue ;
2016-08-28 12:32:58 -05:00
} elseif ( false !== strpos ( " \t\r\n " , $char )) {
2014-10-02 20:17:45 +01:00
continue ;
}
2015-07-13 20:10:26 +02:00
if ( ':' === $char ) {
2014-10-02 20:17:45 +01:00
// Add a space after the : character
$char .= ' ' ;
2016-08-28 12:32:58 -05:00
} elseif (( '}' === $char || ']' === $char )) {
2014-10-02 20:17:45 +01:00
$pos -- ;
$prevChar = substr ( $json , $i - 1 , 1 );
2015-07-13 20:10:26 +02:00
if ( '{' !== $prevChar && '[' !== $prevChar ) {
2014-10-02 20:17:45 +01:00
// If this character is the end of an element,
// output a new line and indent the next line
$result .= $newLine ;
2015-07-13 20:10:26 +02:00
for ( $j = 0 ; $j < $pos ; $j ++ ) {
2014-10-02 20:17:45 +01:00
$result .= $indentStr ;
}
2016-08-28 12:32:58 -05:00
} else {
2014-10-02 20:17:45 +01:00
// Collapse empty {} and []
$result = rtrim ( $result ) . " \n\n " . $indentStr ;
}
}
$result .= $char ;
// If the last character was the beginning of an element,
// output a new line and indent the next line
2015-07-13 20:10:26 +02:00
if ( ',' === $char || '{' === $char || '[' === $char ) {
2014-10-02 20:17:45 +01:00
$result .= $newLine ;
2015-07-13 20:10:26 +02:00
if ( '{' === $char || '[' === $char ) {
2014-10-02 20:17:45 +01:00
$pos ++ ;
}
2015-07-13 20:10:26 +02:00
for ( $j = 0 ; $j < $pos ; $j ++ ) {
2014-10-02 20:17:45 +01:00
$result .= $indentStr ;
}
}
}
// If buffer not empty after formating we have an unclosed quote
2015-07-13 20:10:26 +02:00
if ( strlen ( $buffer ) > 0 ) {
2014-10-02 20:17:45 +01:00
//json is incorrectly formatted
$result = false ;
}
return $result ;
}
2014-11-30 17:49:52 +00:00
2016-08-28 12:32:58 -05:00
function convert_delay ( $delay )
{
$delay = preg_replace ( '/\s/' , '' , $delay );
if ( strstr ( $delay , 'm' , true )) {
2014-11-30 17:49:52 +00:00
$delay_sec = $delay * 60 ;
2016-08-28 12:32:58 -05:00
} elseif ( strstr ( $delay , 'h' , true )) {
2014-11-30 17:49:52 +00:00
$delay_sec = $delay * 3600 ;
2016-08-28 12:32:58 -05:00
} elseif ( strstr ( $delay , 'd' , true )) {
2014-11-30 17:49:52 +00:00
$delay_sec = $delay * 86400 ;
2016-08-28 12:32:58 -05:00
} elseif ( is_numeric ( $delay )) {
2014-11-30 17:49:52 +00:00
$delay_sec = $delay ;
2016-08-28 12:32:58 -05:00
} else {
2015-02-26 01:25:25 +00:00
$delay_sec = 300 ;
2014-11-30 17:49:52 +00:00
}
return ( $delay_sec );
}
2019-11-17 16:30:43 +01:00
function normalize_snmp_ip_address ( $data )
{
// $data is received from snmpwalk, can be ipv4 xxx.xxx.xxx.xxx or ipv6 xx:xx:...:xx (16 chunks)
// ipv4 is returned unchanged, ipv6 is returned with one ':' removed out of two, like
// xxxx:xxxx:...:xxxx (8 chuncks)
return ( preg_replace ( '/([0-9a-fA-F]{2}):([0-9a-fA-F]{2})/' , '\1\2' , explode ( '%' , $data , 2 )[ 0 ]));
}
2016-08-28 12:32:58 -05:00
function guidv4 ( $data )
{
2015-04-10 17:00:32 +01:00
// http://stackoverflow.com/questions/2040240/php-function-to-generate-v4-uuid#15875555
// From: Jack http://stackoverflow.com/users/1338292/ja%CD%A2ck
assert ( strlen ( $data ) == 16 );
$data [ 6 ] = chr ( ord ( $data [ 6 ]) & 0x0f | 0x40 ); // set version to 0100
$data [ 8 ] = chr ( ord ( $data [ 8 ]) & 0x3f | 0x80 ); // set bits 6-7 to 10
return vsprintf ( '%s%s-%s-%s-%s-%s%s%s' , str_split ( bin2hex ( $data ), 4 ));
}
2016-10-14 02:07:07 +01:00
/**
* @param $curl
*/
function set_curl_proxy ( $curl )
2016-08-28 12:32:58 -05:00
{
2017-03-22 10:17:13 +00:00
$proxy = get_proxy ();
2016-10-14 02:07:07 +01:00
$tmp = rtrim ( $proxy , "/" );
$proxy = str_replace ( array ( "http://" , "https://" ), "" , $tmp );
if ( ! empty ( $proxy )) {
curl_setopt ( $curl , CURLOPT_PROXY , $proxy );
2015-04-13 19:51:16 +10:00
}
}
2015-04-19 20:23:34 +01:00
2017-03-22 10:17:13 +00:00
/**
* Return the proxy url
*
* @return array|bool|false|string
*/
function get_proxy ()
{
if ( getenv ( 'http_proxy' )) {
return getenv ( 'http_proxy' );
} elseif ( getenv ( 'https_proxy' )) {
return getenv ( 'https_proxy' );
2019-06-23 00:29:12 -05:00
} elseif ( $callback_proxy = Config :: get ( 'callback_proxy' )) {
return $callback_proxy ;
} elseif ( $http_proxy = Config :: get ( 'http_proxy' )) {
return $http_proxy ;
2017-03-22 10:17:13 +00:00
}
return false ;
}
2016-08-28 12:32:58 -05:00
function target_to_id ( $target )
{
if ( $target [ 0 ] . $target [ 1 ] == "g:" ) {
$target = "g" . dbFetchCell ( 'SELECT id FROM device_groups WHERE name = ?' , array ( substr ( $target , 2 )));
} else {
$target = dbFetchCell ( 'SELECT device_id FROM devices WHERE hostname = ?' , array ( $target ));
2015-04-19 20:23:34 +01:00
}
return $target ;
}
2016-08-28 12:32:58 -05:00
function id_to_target ( $id )
{
if ( $id [ 0 ] == "g" ) {
$id = 'g:' . dbFetchCell ( "SELECT name FROM device_groups WHERE id = ?" , array ( substr ( $id , 1 )));
} else {
$id = dbFetchCell ( "SELECT hostname FROM devices WHERE device_id = ?" , array ( $id ));
2015-04-19 20:23:34 +01:00
}
return $id ;
}
2015-05-26 23:58:29 +10:00
2016-08-28 12:32:58 -05:00
function first_oid_match ( $device , $list )
{
2015-05-26 23:58:29 +10:00
foreach ( $list as $item ) {
2015-07-13 20:10:26 +02:00
$tmp = trim ( snmp_get ( $device , $item , "-Ovq" ), '" ' );
if ( ! empty ( $tmp )) {
return $tmp ;
}
2015-05-26 23:58:29 +10:00
}
}
2015-06-02 17:36:10 +01:00
2017-06-22 15:08:20 -05:00
2016-08-28 12:32:58 -05:00
function fix_integer_value ( $value )
{
2015-06-02 17:36:10 +01:00
if ( $value < 0 ) {
$return = 4294967296 + $value ;
2016-08-28 12:32:58 -05:00
} else {
2015-06-02 17:36:10 +01:00
$return = $value ;
}
return $return ;
}
2015-06-11 19:34:11 +01:00
2019-01-19 12:46:03 -06:00
/**
* Find a device that has this IP. Checks ipv4_addresses and ipv6_addresses tables.
*
* @param string $ip
* @return \App\Models\Device|false
*/
function device_has_ip ( $ip )
2016-08-01 22:01:01 -05:00
{
2019-01-19 12:46:03 -06:00
if ( IPv6 :: isValid ( $ip )) {
$ip_address = \App\Models\Ipv6Address :: query ()
-> where ( 'ipv6_address' , IPv6 :: parse ( $ip , true ) -> uncompressed ())
-> with ( 'port.device' )
-> first ();
} elseif ( IPv4 :: isValid ( $ip )) {
$ip_address = \App\Models\Ipv4Address :: query ()
-> where ( 'ipv4_address' , $ip )
-> with ( 'port.device' )
-> first ();
2015-07-13 20:10:26 +02:00
}
2016-08-01 22:01:01 -05:00
2019-01-19 12:46:03 -06:00
if ( isset ( $ip_address ) && $ip_address -> port ) {
return $ip_address -> port -> device ;
}
return false ; // not an ipv4 or ipv6 address...
2015-06-11 19:34:11 +01:00
}
2015-06-22 21:55:31 +01:00
2015-09-25 19:03:58 +02:00
/**
* Try to determine the address family (IPv4 or IPv6) associated with an SNMP
* transport specifier (like "udp", "udp6", etc.).
*
* @param string $transport The SNMP transport specifier, for example "udp",
* "udp6", "tcp", or "tcp6". See `man snmpcmd`,
* section "Agent Specification" for a full list.
*
2018-07-13 17:08:00 -05:00
* @return string The address family associated with the given transport
* specifier: 'ipv4' (or local connections not associated
* with an IP stack) or 'ipv6'.
2015-09-25 19:03:58 +02:00
*/
2016-08-28 12:32:58 -05:00
function snmpTransportToAddressFamily ( $transport )
{
2018-07-13 17:08:00 -05:00
$ipv6_snmp_transport_specifiers = [ 'udp6' , 'udpv6' , 'udpipv6' , 'tcp6' , 'tcpv6' , 'tcpipv6' ];
2015-09-25 19:03:47 +02:00
if ( in_array ( $transport , $ipv6_snmp_transport_specifiers )) {
2018-07-13 17:08:00 -05:00
return 'ipv6' ;
2015-09-22 02:25:35 +02:00
}
2018-07-13 17:08:00 -05:00
return 'ipv4' ;
2015-09-22 02:25:35 +02:00
}
2015-10-22 21:10:33 +00:00
/**
* Checks if the $hostname provided exists in the DB already
*
* @param string $hostname The hostname to check for
2017-07-16 22:01:07 +01:00
* @param string $sysName The sysName to check
2015-10-22 21:10:33 +00:00
* @return bool true if hostname already exists
* false if hostname doesn't exist
2017-02-22 03:12:31 -06:00
*/
2017-07-16 22:01:07 +01:00
function host_exists ( $hostname , $sysName = null )
2016-08-28 12:32:58 -05:00
{
2017-07-16 22:01:07 +01:00
$query = "SELECT COUNT(*) FROM `devices` WHERE `hostname`=?" ;
$params = array ( $hostname );
2019-06-23 00:29:12 -05:00
if ( ! empty ( $sysName ) && ! Config :: get ( 'allow_duplicate_sysName' )) {
2017-07-16 22:01:07 +01:00
$query .= " OR `sysName`=?" ;
$params [] = $sysName ;
2019-06-23 00:29:12 -05:00
if ( ! empty ( Config :: get ( 'mydomain' ))) {
$full_sysname = rtrim ( $sysName , '.' ) . '.' . Config :: get ( 'mydomain' );
2017-07-16 22:01:07 +01:00
$query .= " OR `sysName`=?" ;
$params [] = $full_sysname ;
2016-05-02 20:20:29 +00:00
}
2015-10-22 21:10:33 +00:00
}
2017-07-16 22:01:07 +01:00
return dbFetchCell ( $query , $params ) > 0 ;
2015-10-22 21:10:33 +00:00
}
2015-11-19 10:20:56 +00:00
2016-08-28 12:32:58 -05:00
function oxidized_reload_nodes ()
{
2019-06-23 00:29:12 -05:00
if ( Config :: get ( 'oxidized.enabled' ) === true && Config :: get ( 'oxidized.reload_nodes' ) === true && Config :: has ( 'oxidized.url' )) {
$oxidized_reload_url = Config :: get ( 'oxidized.url' ) . '/reload.json' ;
2016-01-17 17:47:26 +01:00
$ch = curl_init ( $oxidized_reload_url );
curl_setopt ( $ch , CURLOPT_TIMEOUT , 5 );
2017-02-03 14:12:42 +00:00
curl_setopt ( $ch , CURLOPT_TIMEOUT_MS , 5000 );
2016-01-17 17:47:26 +01:00
curl_setopt ( $ch , CURLOPT_CONNECTTIMEOUT , 5 );
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
curl_setopt ( $ch , CURLOPT_HEADER , 1 );
curl_exec ( $ch );
curl_close ( $ch );
}
}
2016-01-17 23:59:51 +00:00
/**
* Perform DNS lookup
*
* @param array $device Device array from database
* @param string $type The type of record to lookup
*
* @return string ip
*
**/
2016-08-28 12:32:58 -05:00
function dnslookup ( $device , $type = false , $return = false )
{
2016-12-30 00:13:12 +00:00
if ( filter_var ( $device [ 'hostname' ], FILTER_VALIDATE_IP , FILTER_FLAG_IPV4 ) == true || filter_var ( $device [ 'hostname' ], FILTER_VALIDATE_IP , FILTER_FLAG_IPV6 ) == true ) {
2017-01-28 00:02:39 +00:00
return false ;
2016-01-18 00:04:30 +00:00
}
2016-01-17 23:59:51 +00:00
if ( empty ( $type )) {
// We are going to use the transport to work out the record type
if ( $device [ 'transport' ] == 'udp6' || $device [ 'transport' ] == 'tcp6' ) {
$type = DNS_AAAA ;
$return = 'ipv6' ;
2016-08-28 12:32:58 -05:00
} else {
2016-01-17 23:59:51 +00:00
$type = DNS_A ;
$return = 'ip' ;
}
}
2016-01-18 12:54:25 +00:00
if ( empty ( $return )) {
2017-01-28 00:02:39 +00:00
return false ;
2016-01-18 12:54:25 +00:00
}
2016-08-28 12:32:58 -05:00
$record = dns_get_record ( $device [ 'hostname' ], $type );
2016-01-17 23:59:51 +00:00
return $record [ 0 ][ $return ];
} //end dnslookup
2016-02-01 23:29:37 +00:00
2017-09-03 13:58:39 -05:00
/**
* Create a new state index. Update translations if $states is given.
*
* For for backward compatibility:
* Returns null if $states is empty, $state_name already exists, and contains state translations
*
* @param string $state_name the unique name for this state translation
* @param array $states array of states, each must contain keys: descr, graph, value, generic
* @return int|null
*/
function create_state_index ( $state_name , $states = array ())
2016-08-28 12:32:58 -05:00
{
2017-04-28 04:33:56 +01:00
$state_index_id = dbFetchCell ( 'SELECT `state_index_id` FROM state_indexes WHERE state_name = ? LIMIT 1' , array ( $state_name ));
if ( ! is_numeric ( $state_index_id )) {
2017-09-03 13:58:39 -05:00
$state_index_id = dbInsert ( array ( 'state_name' => $state_name ), 'state_indexes' );
// legacy code, return index so states are created
if ( empty ( $states )) {
return $state_index_id ;
}
}
// check or synchronize states
if ( empty ( $states )) {
2017-04-28 04:33:56 +01:00
$translations = dbFetchRows ( 'SELECT * FROM `state_translations` WHERE `state_index_id` = ?' , array ( $state_index_id ));
2017-04-29 16:58:06 +01:00
if ( count ( $translations ) == 0 ) {
2017-04-28 04:33:56 +01:00
// If we don't have any translations something has gone wrong so return the state_index_id so they get created.
return $state_index_id ;
}
2017-09-03 13:58:39 -05:00
} else {
sync_sensor_states ( $state_index_id , $states );
2016-02-27 16:23:58 +01:00
}
2017-09-03 13:58:39 -05:00
return null ;
}
/**
* Synchronize the sensor state translations with the database
*
* @param int $state_index_id index of the state
* @param array $states array of states, each must contain keys: descr, graph, value, generic
*/
function sync_sensor_states ( $state_index_id , $states )
{
$new_translations = array_reduce ( $states , function ( $array , $state ) use ( $state_index_id ) {
$array [ $state [ 'value' ]] = array (
'state_index_id' => $state_index_id ,
'state_descr' => $state [ 'descr' ],
'state_draw_graph' => $state [ 'graph' ],
'state_value' => $state [ 'value' ],
'state_generic_value' => $state [ 'generic' ]
);
return $array ;
}, array ());
$existing_translations = dbFetchRows (
'SELECT `state_index_id`,`state_descr`,`state_draw_graph`,`state_value`,`state_generic_value` FROM `state_translations` WHERE `state_index_id`=?' ,
array ( $state_index_id )
);
foreach ( $existing_translations as $translation ) {
$value = $translation [ 'state_value' ];
if ( isset ( $new_translations [ $value ])) {
if ( $new_translations [ $value ] != $translation ) {
dbUpdate (
$new_translations [ $value ],
'state_translations' ,
'`state_index_id`=? AND `state_value`=?' ,
array ( $state_index_id , $value )
);
}
// this translation is synchronized, it doesn't need to be inserted
unset ( $new_translations [ $value ]);
} else {
dbDelete ( 'state_translations' , '`state_index_id`=? AND `state_value`=?' , array ( $state_index_id , $value ));
}
}
// insert any new translations
dbBulkInsert ( $new_translations , 'state_translations' );
2016-02-26 23:40:34 +01:00
}
function create_sensor_to_state_index ( $device , $state_name , $index )
{
$sensor_entry = dbFetchRow ( 'SELECT sensor_id FROM `sensors` WHERE `sensor_class` = ? AND `device_id` = ? AND `sensor_type` = ? AND `sensor_index` = ?' , array (
'state' ,
$device [ 'device_id' ],
$state_name ,
$index
));
$state_indexes_entry = dbFetchRow ( 'SELECT state_index_id FROM `state_indexes` WHERE `state_name` = ?' , array (
$state_name
));
if ( ! empty ( $sensor_entry [ 'sensor_id' ]) && ! empty ( $state_indexes_entry [ 'state_index_id' ])) {
$insert = array (
'sensor_id' => $sensor_entry [ 'sensor_id' ],
'state_index_id' => $state_indexes_entry [ 'state_index_id' ],
);
2016-08-28 12:32:58 -05:00
foreach ( $insert as $key => $val_check ) {
2016-02-26 23:40:34 +01:00
if ( ! isset ( $val_check )) {
unset ( $insert [ $key ]);
}
}
2016-02-26 23:56:54 +01:00
dbInsert ( $insert , 'sensors_to_state_indexes' );
2016-02-26 23:40:34 +01:00
}
}
2016-06-15 16:25:14 +00:00
2016-08-28 12:32:58 -05:00
function delta_to_bits ( $delta , $period )
{
2016-07-07 19:10:37 +01:00
return round (( $delta * 8 / $period ), 2 );
2016-06-15 16:25:14 +00:00
}
2016-07-07 19:11:13 +01:00
2016-08-28 12:32:58 -05:00
function report_this ( $message )
{
2019-06-23 00:29:12 -05:00
return '<h2>' . $message . ' Please <a href="' . Config :: get ( 'project_issues' ) . '">report this</a> to the ' . Config :: get ( 'project_name' ) . ' developers.</h2>' ;
2016-06-29 00:14:21 +01:00
} //end report_this()
2016-08-23 20:44:45 +02:00
2016-08-28 12:32:58 -05:00
function hytera_h2f ( $number , $nd )
2016-08-23 20:44:45 +02:00
{
2016-08-28 12:32:58 -05:00
if ( strlen ( str_replace ( " " , "" , $number )) == 4 ) {
2016-08-23 20:44:45 +02:00
$hex = '' ;
for ( $i = 0 ; $i < strlen ( $number ); $i ++ ) {
2020-03-21 15:49:15 -04:00
$byte = strtoupper ( dechex ( ord ( $number [ $i ])));
2016-08-23 20:44:45 +02:00
$byte = str_repeat ( '0' , 2 - strlen ( $byte )) . $byte ;
$hex .= $byte . " " ;
}
$number = $hex ;
unset ( $hex );
}
$r = '' ;
$y = explode ( ' ' , $number );
foreach ( $y as $z ) {
$r = $z . '' . $r ;
}
$hex = array ();
$number = substr ( $r , 0 , - 1 );
//$number = str_replace(" ", "", $number);
for ( $i = 0 ; $i < strlen ( $number ); $i ++ ) {
2016-08-28 12:32:58 -05:00
$hex [] = substr ( $number , $i , 1 );
2016-08-23 20:44:45 +02:00
}
$dec = array ();
$hexCount = count ( $hex );
for ( $i = 0 ; $i < $hexCount ; $i ++ ) {
$dec [] = hexdec ( $hex [ $i ]);
}
$binfinal = "" ;
$decCount = count ( $dec );
for ( $i = 0 ; $i < $decCount ; $i ++ ) {
2016-08-28 12:32:58 -05:00
$binfinal .= sprintf ( "%04d" , decbin ( $dec [ $i ]));
2016-08-23 20:44:45 +02:00
}
2016-08-28 12:32:58 -05:00
$sign = substr ( $binfinal , 0 , 1 );
$exp = substr ( $binfinal , 1 , 8 );
2016-08-23 20:44:45 +02:00
$exp = bindec ( $exp );
$exp -= 127 ;
2016-08-28 12:32:58 -05:00
$scibin = substr ( $binfinal , 9 );
$binint = substr ( $scibin , 0 , $exp );
$binpoint = substr ( $scibin , $exp );
2016-08-23 20:44:45 +02:00
$intnumber = bindec ( "1" . $binint );
2019-05-30 09:56:27 -05:00
$tmppoint = [];
2016-08-23 20:44:45 +02:00
for ( $i = 0 ; $i < strlen ( $binpoint ); $i ++ ) {
2016-08-28 12:32:58 -05:00
$tmppoint [] = substr ( $binpoint , $i , 1 );
2016-08-23 20:44:45 +02:00
}
$tmppoint = array_reverse ( $tmppoint );
2016-08-28 12:32:58 -05:00
$tpointnumber = number_format ( $tmppoint [ 0 ] / 2 , strlen ( $binpoint ), '.' , '' );
2016-08-23 20:44:45 +02:00
$pointnumber = "" ;
for ( $i = 1 ; $i < strlen ( $binpoint ); $i ++ ) {
2016-08-28 12:32:58 -05:00
$pointnumber = number_format ( $tpointnumber / 2 , strlen ( $binpoint ), '.' , '' );
$tpointnumber = $tmppoint [ $i + 1 ] . substr ( $pointnumber , 1 );
2016-08-23 20:44:45 +02:00
}
$floatfinal = $intnumber + $pointnumber ;
if ( $sign == 1 ) {
$floatfinal =- $floatfinal ;
}
2016-08-28 12:32:58 -05:00
return number_format ( $floatfinal , $nd , '.' , '' );
2016-08-23 20:44:45 +02:00
}
2016-10-06 10:40:37 +10:00
/*
* Cisco CIMC functions
*/
// Create an entry in the entPhysical table if it doesnt already exist.
function setCIMCentPhysical ( $location , $data , & $entphysical , & $index )
{
// Go get the location, this will create it if it doesnt exist.
$entPhysicalIndex = getCIMCentPhysical ( $location , $entphysical , $index );
// See if we need to update
$update = array ();
foreach ( $data as $key => $value ) {
// Is the Array(DB) value different to the supplied data
if ( $entphysical [ $location ][ $key ] != $value ) {
$update [ $key ] = $value ;
$entphysical [ $location ][ $key ] = $value ;
} // End if
} // end foreach
// Do we need to update
if ( count ( $update ) > 0 ) {
dbUpdate ( $update , 'entPhysical' , '`entPhysical_id` = ?' , array ( $entphysical [ $location ][ 'entPhysical_id' ]));
}
$entPhysicalId = $entphysical [ $location ][ 'entPhysical_id' ];
return array ( $entPhysicalId , $entPhysicalIndex );
}
function getCIMCentPhysical ( $location , & $entphysical , & $index )
{
global $device ;
// Level 1 - Does the location exist
if ( isset ( $entphysical [ $location ])) {
// Yes, return the entPhysicalIndex.
return $entphysical [ $location ][ 'entPhysicalIndex' ];
} else {
/*
* No, the entry doesnt exist.
* Find its parent so we can create it.
*/
// Pull apart the location
$parts = explode ( '/' , $location );
// Level 2 - Are we at the root
if ( count ( $parts ) == 1 ) {
// Level 2 - Yes. We are the root, there is no parent
d_echo ( "ROOT - " . $location . " \n " );
$shortlocation = $location ;
$parent = 0 ;
} else {
// Level 2 - No. Need to go deeper.
d_echo ( "NON-ROOT - " . $location . " \n " );
$shortlocation = array_pop ( $parts );
$parentlocation = implode ( '/' , $parts );
d_echo ( "Decend - parent location: " . $parentlocation . " \n " );
$parent = getCIMCentPhysical ( $parentlocation , $entphysical , $index );
} // end if - Level 2
d_echo ( "Parent: " . $parent . " \n " );
// Now we have an ID, create the entry.
$index ++ ;
$insert = array (
'device_id' => $device [ 'device_id' ],
'entPhysicalIndex' => $index ,
'entPhysicalClass' => 'container' ,
'entPhysicalVendorType' => $location ,
'entPhysicalName' => $shortlocation ,
'entPhysicalContainedIn' => $parent ,
'entPhysicalParentRelPos' => '-1' ,
);
// Add to the DB and Array.
$id = dbInsert ( $insert , 'entPhysical' );
$entphysical [ $location ] = dbFetchRow ( 'SELECT * FROM entPhysical WHERE entPhysical_id=?' , array ( $id ));
return $index ;
} // end if - Level 1
} // end function
2016-10-11 15:29:06 -06:00
/* idea from http://php.net/manual/en/function.hex2bin.php comments */
function hex2bin_compat ( $str )
{
if ( strlen ( $str ) % 2 !== 0 ) {
trigger_error ( __FUNCTION__ . '(): Hexadecimal input string must have an even length' , E_USER_WARNING );
}
return pack ( "H*" , $str );
}
if ( ! function_exists ( 'hex2bin' )) {
// This is only a hack
function hex2bin ( $str )
{
return hex2bin_compat ( $str );
}
}
function q_bridge_bits2indices ( $hex_data )
{
/* convert hex string to an array of 1-based indices of the nonzero bits
* ie. '9a00' -> '100110100000' -> array(1, 4, 5, 7)
*/
$hex_data = str_replace ( ' ' , '' , $hex_data );
$value = hex2bin ( $hex_data );
$length = strlen ( $value );
$indices = array ();
for ( $i = 0 ; $i < $length ; $i ++ ) {
$byte = ord ( $value [ $i ]);
for ( $j = 7 ; $j >= 0 ; $j -- ) {
if ( $byte & ( 1 << $j )) {
$indices [] = 8 * $i + 8 - $j ;
}
}
}
return $indices ;
}
2016-10-14 18:14:18 -05:00
/**
* @param array $device
* @param int|string $raw_value The value returned from snmp
* @param int $capacity the normalized capacity
* @return int the toner level as a percentage
*/
function get_toner_levels ( $device , $raw_value , $capacity )
{
// -3 means some toner is left
if ( $raw_value == '-3' ) {
return 50 ;
}
2017-01-31 08:07:50 +00:00
// -2 means unknown
if ( $raw_value == '-2' ) {
return false ;
}
// -1 mean no restrictions
if ( $raw_value == '-1' ) {
2016-10-14 18:14:18 -05:00
return 0 ; // FIXME: is 0 what we should return?
}
// Non-standard snmp values
if ( $device [ 'os' ] == 'ricoh' || $device [ 'os' ] == 'nrg' || $device [ 'os' ] == 'lanier' ) {
if ( $raw_value == '-100' ) {
return 0 ;
}
} elseif ( $device [ 'os' ] == 'brother' ) {
2020-04-17 17:37:56 -05:00
if ( ! Str :: contains ( $device [ 'hardware' ], 'MFC-L8850' )) {
2016-10-14 18:14:18 -05:00
switch ( $raw_value ) {
case '0' :
return 100 ;
case '1' :
return 5 ;
case '2' :
return 0 ;
case '3' :
return 1 ;
}
}
}
return round ( $raw_value / $capacity * 100 );
}
2016-10-18 03:06:03 +00:00
2016-11-23 00:57:19 -06:00
/**
* Intialize global stat arrays
*/
function initStats ()
{
2020-03-16 09:17:58 -05:00
global $snmp_stats , $snmp_stats_last ;
2016-11-23 00:57:19 -06:00
2020-03-16 09:17:58 -05:00
if ( ! isset ( $snmp_stats )) {
2016-11-23 00:57:19 -06:00
$snmp_stats = array (
2017-12-02 16:55:53 -06:00
'ops' => array (
'snmpget' => 0 ,
'snmpgetnext' => 0 ,
'snmpwalk' => 0 ,
),
'time' => array (
'snmpget' => 0.0 ,
'snmpgetnext' => 0.0 ,
'snmpwalk' => 0.0 ,
)
2016-11-23 00:57:19 -06:00
);
2018-07-13 17:08:00 -05:00
$snmp_stats_last = $snmp_stats ;
2017-11-11 13:44:25 -06:00
}
2016-11-23 00:57:19 -06:00
}
2017-12-02 16:55:53 -06:00
/**
* Print out the stats totals since the last time this function was called
*
* @param bool $update_only Only update the stats checkpoint, don't print them
*/
function printChangedStats ( $update_only = false )
{
2020-03-16 09:17:58 -05:00
global $snmp_stats , $db_stats ;
global $snmp_stats_last , $db_stats_last ;
$output = sprintf (
">> SNMP: [%d/%.2fs] MySQL: [%d/%.2fs]" ,
array_sum ( $snmp_stats [ 'ops' ]) - array_sum ( $snmp_stats_last [ 'ops' ]),
array_sum ( $snmp_stats [ 'time' ]) - array_sum ( $snmp_stats_last [ 'time' ]),
array_sum ( $db_stats [ 'ops' ]) - array_sum ( $db_stats_last [ 'ops' ]),
array_sum ( $db_stats [ 'time' ]) - array_sum ( $db_stats_last [ 'time' ])
);
foreach ( app ( 'Datastore' ) -> getStats () as $datastore => $stats ) {
/** @var \LibreNMS\Data\Measure\MeasurementCollection $stats */
$output .= sprintf ( " %s: [%d/%.2fs]" , $datastore , $stats -> getCountDiff (), $stats -> getDurationDiff ());
$stats -> checkpoint ();
}
2017-12-02 16:55:53 -06:00
if ( ! $update_only ) {
2020-03-16 09:17:58 -05:00
echo $output . PHP_EOL ;
2017-12-02 16:55:53 -06:00
}
// make a new checkpoint
$snmp_stats_last = $snmp_stats ;
$db_stats_last = $db_stats ;
}
2016-11-23 00:57:19 -06:00
/**
* Print global stat arrays
*/
function printStats ()
{
2020-03-16 09:17:58 -05:00
global $snmp_stats , $db_stats ;
2016-11-23 00:57:19 -06:00
2018-07-13 17:08:00 -05:00
if ( $snmp_stats ) {
printf (
"SNMP [%d/%.2fs]: Get[%d/%.2fs] Getnext[%d/%.2fs] Walk[%d/%.2fs] \n " ,
array_sum ( $snmp_stats [ 'ops' ]),
array_sum ( $snmp_stats [ 'time' ]),
$snmp_stats [ 'ops' ][ 'snmpget' ],
$snmp_stats [ 'time' ][ 'snmpget' ],
$snmp_stats [ 'ops' ][ 'snmpgetnext' ],
$snmp_stats [ 'time' ][ 'snmpgetnext' ],
$snmp_stats [ 'ops' ][ 'snmpwalk' ],
$snmp_stats [ 'time' ][ 'snmpwalk' ]
);
}
if ( $db_stats ) {
printf (
"MySQL [%d/%.2fs]: Cell[%d/%.2fs] Row[%d/%.2fs] Rows[%d/%.2fs] Column[%d/%.2fs] Update[%d/%.2fs] Insert[%d/%.2fs] Delete[%d/%.2fs] \n " ,
array_sum ( $db_stats [ 'ops' ]),
array_sum ( $db_stats [ 'time' ]),
$db_stats [ 'ops' ][ 'fetchcell' ],
$db_stats [ 'time' ][ 'fetchcell' ],
$db_stats [ 'ops' ][ 'fetchrow' ],
$db_stats [ 'time' ][ 'fetchrow' ],
$db_stats [ 'ops' ][ 'fetchrows' ],
$db_stats [ 'time' ][ 'fetchrows' ],
$db_stats [ 'ops' ][ 'fetchcolumn' ],
$db_stats [ 'time' ][ 'fetchcolumn' ],
$db_stats [ 'ops' ][ 'update' ],
$db_stats [ 'time' ][ 'update' ],
$db_stats [ 'ops' ][ 'insert' ],
$db_stats [ 'time' ][ 'insert' ],
$db_stats [ 'ops' ][ 'delete' ],
$db_stats [ 'time' ][ 'delete' ]
);
}
2020-03-16 09:17:58 -05:00
foreach ( app ( 'Datastore' ) -> getStats () as $datastore => $stats ) {
/** @var \LibreNMS\Data\Measure\MeasurementCollection $stats */
printf ( "%s [%d/%.2fs]:" , $datastore , $stats -> getTotalCount (), $stats -> getTotalDuration ());
2020-03-11 07:52:52 -05:00
2020-03-16 09:17:58 -05:00
foreach ( $stats as $stat ) {
/** @var \LibreNMS\Data\Measure\MeasurementSummary $stat */
printf ( " %s[%d/%.2fs]" , ucfirst ( $stat -> getType ()), $stat -> getCount (), $stat -> getDuration ());
}
echo PHP_EOL ;
}
2020-03-11 07:52:52 -05:00
}
2016-11-23 00:57:19 -06:00
/**
* @param string $stat snmpget, snmpwalk
* @param float $start_time The time the operation started with 'microtime(true)'
* @return float The calculated run time
*/
function recordSnmpStatistic ( $stat , $start_time )
{
global $snmp_stats ;
initStats ();
$runtime = microtime ( true ) - $start_time ;
2017-12-02 16:55:53 -06:00
$snmp_stats [ 'ops' ][ $stat ] ++ ;
$snmp_stats [ 'time' ][ $stat ] += $runtime ;
2016-11-23 00:57:19 -06:00
return $runtime ;
}
2017-02-14 12:56:16 +00:00
2018-11-19 15:58:59 +00:00
function runTraceroute ( $device )
{
$address_family = snmpTransportToAddressFamily ( $device [ 'transport' ]);
$trace_name = $address_family == 'ipv6' ? 'traceroute6' : 'traceroute' ;
$trace_path = Config :: get ( $trace_name , $trace_name );
$process = new Process ([ $trace_path , '-q' , '1' , '-w' , '1' , $device [ 'hostname' ]]);
$process -> run ();
if ( $process -> isSuccessful ()) {
return [ 'traceroute' => $process -> getOutput ()];
}
return [ 'output' => $process -> getErrorOutput ()];
}
2017-02-15 15:22:09 +00:00
/**
* @param $device
* @param bool $record_perf
* @return array
*/
function device_is_up ( $device , $record_perf = false )
{
$address_family = snmpTransportToAddressFamily ( $device [ 'transport' ]);
2020-01-30 13:20:30 +01:00
$poller_target = Device :: pollerTarget ( $device [ 'hostname' ]);
$ping_response = isPingable ( $poller_target , $address_family , $device [ 'attribs' ]);
2017-02-15 15:22:09 +00:00
$device_perf = $ping_response [ 'db' ];
$device_perf [ 'device_id' ] = $device [ 'device_id' ];
$device_perf [ 'timestamp' ] = array ( 'NOW()' );
2018-11-19 15:58:59 +00:00
if ( $record_perf === true && can_ping_device ( $device [ 'attribs' ])) {
$trace_debug = [];
if ( $ping_response [ 'result' ] === false && Config :: get ( 'debug.run_trace' , false )) {
$trace_debug = runTraceroute ( $device );
}
$device_perf [ 'debug' ] = json_encode ( $trace_debug );
2017-02-15 15:22:09 +00:00
dbInsert ( $device_perf , 'device_perf' );
2020-02-09 09:19:30 -05:00
// if device_perf is inserted and the ping was successful then update device last_ping timestamp
if ( ! empty ( $ping_response [ 'last_ping_timetaken' ]) && $ping_response [ 'last_ping_timetaken' ] != "0" ) {
dbUpdate (
array ( 'last_ping' => NOW (), 'last_ping_timetaken' => $ping_response [ 'last_ping_timetaken' ]),
'devices' ,
'device_id=?' ,
array ( $device [ 'device_id' ])
);
}
2017-02-15 15:22:09 +00:00
}
$response = array ();
$response [ 'ping_time' ] = $ping_response [ 'last_ping_timetaken' ];
if ( $ping_response [ 'result' ]) {
2017-10-28 05:59:25 +02:00
if ( $device [ 'snmp_disable' ] || isSNMPable ( $device )) {
2017-02-15 15:22:09 +00:00
$response [ 'status' ] = '1' ;
$response [ 'status_reason' ] = '' ;
} else {
echo 'SNMP Unreachable' ;
$response [ 'status' ] = '0' ;
$response [ 'status_reason' ] = 'snmp' ;
}
} else {
echo 'Unpingable' ;
$response [ 'status' ] = '0' ;
$response [ 'status_reason' ] = 'icmp' ;
}
2017-10-28 05:59:25 +02:00
if ( $device [ 'status' ] != $response [ 'status' ] || $device [ 'status_reason' ] != $response [ 'status_reason' ]) {
2017-07-27 08:27:52 -05:00
dbUpdate (
array ( 'status' => $response [ 'status' ], 'status_reason' => $response [ 'status_reason' ]),
'devices' ,
'device_id=?' ,
array ( $device [ 'device_id' ])
);
if ( $response [ 'status' ]) {
$type = 'up' ;
$reason = $device [ 'status_reason' ];
} else {
$type = 'down' ;
$reason = $response [ 'status_reason' ];
}
log_event ( 'Device status changed to ' . ucfirst ( $type ) . " from $reason check." , $device , $type );
2017-02-15 15:22:09 +00:00
}
return $response ;
}
2017-02-14 17:04:55 -06:00
function update_device_logo ( & $device )
2017-02-14 12:56:16 +00:00
{
$icon = getImageName ( $device , false );
if ( $icon != $device [ 'icon' ]) {
log_event ( 'Device Icon changed ' . $device [ 'icon' ] . " => $icon " , $device , 'system' , 3 );
$device [ 'icon' ] = $icon ;
2017-02-14 17:04:55 -06:00
dbUpdate ( array ( 'icon' => $icon ), 'devices' , 'device_id=?' , array ( $device [ 'device_id' ]));
2017-02-14 12:56:16 +00:00
echo "Changed Icon! : $icon \n " ;
}
}
2017-03-22 10:17:13 +00:00
/**
* Function to generate PeeringDB Cache
*/
function cache_peeringdb ()
{
2019-06-23 00:29:12 -05:00
if ( Config :: get ( 'peeringdb.enabled' ) === true ) {
2017-03-22 10:17:13 +00:00
$peeringdb_url = 'https://peeringdb.com/api' ;
// We cache for 71 hours
$cached = dbFetchCell ( "SELECT count(*) FROM `pdb_ix` WHERE (UNIX_TIMESTAMP() - timestamp) < 255600" );
if ( $cached == 0 ) {
2017-12-09 17:19:56 +00:00
$rand = rand ( 3 , 30 );
2017-03-22 10:17:13 +00:00
echo "No cached PeeringDB data found, sleeping for $rand seconds" . PHP_EOL ;
sleep ( $rand );
2018-08-26 07:42:21 -05:00
$peer_keep = [];
$ix_keep = [];
2017-03-22 10:17:13 +00:00
foreach ( dbFetchRows ( "SELECT `bgpLocalAs` FROM `devices` WHERE `disabled` = 0 AND `ignore` = 0 AND `bgpLocalAs` > 0 AND (`bgpLocalAs` < 64512 OR `bgpLocalAs` > 65535) AND `bgpLocalAs` < 4200000000 GROUP BY `bgpLocalAs`" ) as $as ) {
$asn = $as [ 'bgpLocalAs' ];
$get = Requests :: get ( $peeringdb_url . '/net?depth=2&asn=' . $asn , array (), array ( 'proxy' => get_proxy ()));
$json_data = $get -> body ;
$data = json_decode ( $json_data );
2020-03-21 15:49:15 -04:00
$ixs = $data -> { 'data' }[ 0 ] -> { 'netixlan_set' };
2017-03-22 10:17:13 +00:00
foreach ( $ixs as $ix ) {
$ixid = $ix -> { 'ix_id' };
$tmp_ix = dbFetchRow ( "SELECT * FROM `pdb_ix` WHERE `ix_id` = ? AND asn = ?" , array ( $ixid , $asn ));
if ( $tmp_ix ) {
$pdb_ix_id = $tmp_ix [ 'pdb_ix_id' ];
$update = array ( 'name' => $ix -> { 'name' }, 'timestamp' => time ());
2017-03-23 10:08:48 +00:00
dbUpdate ( $update , 'pdb_ix' , '`ix_id` = ? AND `asn` = ?' , array ( $ixid , $asn ));
2017-03-22 10:17:13 +00:00
} else {
$insert = array (
'ix_id' => $ixid ,
'name' => $ix -> { 'name' },
'asn' => $asn ,
'timestamp' => time ()
);
$pdb_ix_id = dbInsert ( $insert , 'pdb_ix' );
}
2018-08-26 07:42:21 -05:00
$ix_keep [] = $pdb_ix_id ;
2017-03-22 10:17:13 +00:00
$get_ix = Requests :: get ( " $peeringdb_url /netixlan?ix_id= $ixid " , array (), array ( 'proxy' => get_proxy ()));
$ix_json = $get_ix -> body ;
$ix_data = json_decode ( $ix_json );
$peers = $ix_data -> { 'data' };
foreach ( $peers as $index => $peer ) {
$peer_name = get_astext ( $peer -> { 'asn' });
$tmp_peer = dbFetchRow ( "SELECT * FROM `pdb_ix_peers` WHERE `peer_id` = ? AND `ix_id` = ?" , array ( $peer -> { 'id' }, $ixid ));
if ( $tmp_peer ) {
$peer_keep [] = $tmp_peer [ 'pdb_ix_peers_id' ];
$update = array (
'remote_asn' => $peer -> { 'asn' },
'remote_ipaddr4' => $peer -> { 'ipaddr4' },
'remote_ipaddr6' => $peer -> { 'ipaddr6' },
'name' => $peer_name ,
);
dbUpdate ( $update , 'pdb_ix_peers' , '`pdb_ix_peers_id` = ?' , array ( $tmp_peer [ 'pdb_ix_peers_id' ]));
} else {
$peer_insert = array (
'ix_id' => $ixid ,
'peer_id' => $peer -> { 'id' },
'remote_asn' => $peer -> { 'asn' },
'remote_ipaddr4' => $peer -> { 'ipaddr4' },
'remote_ipaddr6' => $peer -> { 'ipaddr6' },
'name' => $peer_name ,
'timestamp' => time ()
);
$peer_keep [] = dbInsert ( $peer_insert , 'pdb_ix_peers' );
}
}
}
2018-08-26 07:42:21 -05:00
}
// cleanup
if ( empty ( $peer_keep )) {
dbDelete ( 'pdb_ix_peers' );
} else {
dbDelete ( 'pdb_ix_peers' , "`pdb_ix_peers_id` NOT IN " . dbGenPlaceholders ( count ( $peer_keep )), $peer_keep );
}
if ( empty ( $ix_keep )) {
dbDelete ( 'pdb_ix' );
} else {
dbDelete ( 'pdb_ix' , "`pdb_ix_id` NOT IN " . dbGenPlaceholders ( count ( $ix_keep )), $ix_keep );
2017-03-22 10:17:13 +00:00
}
} else {
echo "Cached PeeringDB data found....." . PHP_EOL ;
}
} else {
echo 'Peering DB integration disabled' . PHP_EOL ;
}
}
2017-04-05 09:00:28 +01:00
/**
* Dump the database schema to an array.
* The top level will be a list of tables
* Each table contains the keys Columns and Indexes.
*
* Each entry in the Columns array contains these keys: Field, Type, Null, Default, Extra
* Each entry in the Indexes array contains these keys: Name, Columns(array), Unique
*
2020-05-22 16:49:21 -05:00
* @param string $connection use a specific connection
2017-04-05 09:00:28 +01:00
* @return array
*/
2020-05-22 16:49:21 -05:00
function dump_db_schema ( $connection = null )
2017-04-05 09:00:28 +01:00
{
2019-01-17 08:59:42 -06:00
$output = [];
2020-05-22 16:49:21 -05:00
$db_name = DB :: connection ( $connection ) -> getDatabaseName ();
2017-04-05 09:00:28 +01:00
2020-05-22 16:49:21 -05:00
foreach ( DB :: connection ( $connection ) -> select ( DB :: raw ( "SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ' $db_name ' ORDER BY TABLE_NAME;" )) as $table ) {
$table = $table -> TABLE_NAME ;
foreach ( DB :: connection ( $connection ) -> select ( DB :: raw ( "SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, EXTRA FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ' $db_name ' AND TABLE_NAME=' $table '" )) as $data ) {
2019-01-17 08:59:42 -06:00
$def = [
2020-05-22 16:49:21 -05:00
'Field' => $data -> COLUMN_NAME ,
2020-05-30 17:06:53 -05:00
'Type' => preg_replace ( '/int\([0-9]+\)/' , 'int' , $data -> COLUMN_TYPE ),
2020-05-22 16:49:21 -05:00
'Null' => $data -> IS_NULLABLE === 'YES' ,
'Extra' => str_replace ( 'current_timestamp()' , 'CURRENT_TIMESTAMP' , $data -> EXTRA ),
2019-01-17 08:59:42 -06:00
];
2017-10-26 01:56:09 -05:00
2020-05-22 16:49:21 -05:00
if ( isset ( $data -> COLUMN_DEFAULT ) && $data -> COLUMN_DEFAULT != 'NULL' ) {
$default = trim ( $data -> COLUMN_DEFAULT , "'" );
2017-10-26 01:56:09 -05:00
$def [ 'Default' ] = str_replace ( 'current_timestamp()' , 'CURRENT_TIMESTAMP' , $default );
}
2020-05-30 17:06:53 -05:00
// MySQL 8 fix, remove DEFAULT_GENERATED from timestamp extra columns
if ( $def [ 'Type' ] == 'timestamp' ) {
$def [ 'Extra' ] = preg_replace ( "/DEFAULT_GENERATED[ ]*/" , '' , $def [ 'Extra' ]);
}
2017-10-26 01:56:09 -05:00
$output [ $table ][ 'Columns' ][] = $def ;
2017-04-05 09:00:28 +01:00
}
2020-05-22 16:49:21 -05:00
$keys = DB :: connection ( $connection ) -> select ( DB :: raw ( "SHOW INDEX FROM ` $table `" ));
usort ( $keys , function ( $a , $b ) {
return $a -> Key_name <=> $b -> Key_name ;
});
foreach ( $keys as $key ) {
$key_name = $key -> Key_name ;
2017-04-05 09:00:28 +01:00
if ( isset ( $output [ $table ][ 'Indexes' ][ $key_name ])) {
2020-05-22 16:49:21 -05:00
$output [ $table ][ 'Indexes' ][ $key_name ][ 'Columns' ][] = $key -> Column_name ;
2017-04-05 09:00:28 +01:00
} else {
2019-01-17 08:59:42 -06:00
$output [ $table ][ 'Indexes' ][ $key_name ] = [
2020-05-22 16:49:21 -05:00
'Name' => $key -> Key_name ,
'Columns' => [ $key -> Column_name ],
'Unique' => ! $key -> Non_unique ,
'Type' => $key -> Index_type ,
2019-01-17 08:59:42 -06:00
];
2017-04-05 09:00:28 +01:00
}
}
2019-01-17 08:59:42 -06:00
2020-05-22 16:49:21 -05:00
$create = DB :: connection ( $connection ) -> select ( DB :: raw ( "SHOW CREATE TABLE ` $table `" ))[ 0 ];
if ( isset ( $create -> { 'Create Table' })) {
2019-02-13 13:19:45 -06:00
$constraint_regex = '/CONSTRAINT `(?<name>[A-Za-z_0-9]+)` FOREIGN KEY \(`(?<foreign_key>[A-Za-z_0-9]+)`\) REFERENCES `(?<table>[A-Za-z_0-9]+)` \(`(?<key>[A-Za-z_0-9]+)`\) ?(?<extra>[ A-Z]+)?/' ;
2020-05-22 16:49:21 -05:00
$constraint_count = preg_match_all ( $constraint_regex , $create -> { 'Create Table' }, $constraints );
2019-02-13 13:19:45 -06:00
for ( $i = 0 ; $i < $constraint_count ; $i ++ ) {
$constraint_name = $constraints [ 'name' ][ $i ];
$output [ $table ][ 'Constraints' ][ $constraint_name ] = [
'name' => $constraint_name ,
'foreign_key' => $constraints [ 'foreign_key' ][ $i ],
'table' => $constraints [ 'table' ][ $i ],
'key' => $constraints [ 'key' ][ $i ],
'extra' => $constraints [ 'extra' ][ $i ],
];
}
2019-01-17 08:59:42 -06:00
}
2017-04-05 09:00:28 +01:00
}
2019-01-17 08:59:42 -06:00
2017-04-05 09:00:28 +01:00
return $output ;
}
2017-12-20 08:36:49 -06:00
2017-04-13 04:18:12 -05:00
/**
* Get an array of the schema files.
* schema_version => full_file_name
*
* @return mixed
*/
function get_schema_list ()
{
// glob returns an array sorted by filename
2019-06-23 00:29:12 -05:00
$files = glob ( Config :: get ( 'install_dir' ) . '/sql-schema/*.sql' );
2017-04-13 04:18:12 -05:00
// set the keys to the db schema version
2019-01-17 08:53:32 -06:00
$files = array_reduce ( $files , function ( $array , $file ) {
$array [( int ) basename ( $file , '.sql' )] = $file ;
2017-04-13 04:18:12 -05:00
return $array ;
2019-01-17 08:53:32 -06:00
}, []);
ksort ( $files ); // fix dbSchema 1000 order
return $files ;
2017-04-13 04:18:12 -05:00
}
/**
* Get the current database schema, will return 0 if there is no schema.
*
* @return int
*/
function get_db_schema ()
{
2018-08-17 15:29:20 -05:00
try {
2018-11-28 16:49:18 -06:00
$db = \LibreNMS\DB\Eloquent :: DB ();
if ( $db ) {
2019-01-14 07:44:23 -05:00
return ( int ) $db -> table ( 'dbSchema' )
2018-11-28 16:49:18 -06:00
-> orderBy ( 'version' , 'DESC' )
-> value ( 'version' );
}
2018-08-17 15:29:20 -05:00
} catch ( PDOException $e ) {
2018-11-28 16:49:18 -06:00
// return default
2018-08-17 15:29:20 -05:00
}
2018-11-28 16:49:18 -06:00
return 0 ;
2017-04-13 04:18:12 -05:00
}
2017-05-01 23:49:11 -05:00
/**
* @param $device
* @return int|null
*/
function get_device_oid_limit ( $device )
{
2018-11-21 17:25:39 -02:00
// device takes priority
2019-11-14 21:56:06 +00:00
if ( $device [ 'attribs' ][ 'snmp_max_oid' ] > 0 ) {
return $device [ 'attribs' ][ 'snmp_max_oid' ];
2018-11-21 17:25:39 -02:00
}
2017-05-01 23:49:11 -05:00
2018-11-21 17:25:39 -02:00
// then os
$os_max = Config :: getOsSetting ( $device [ 'os' ], 'snmp_max_oid' , 0 );
if ( $os_max > 0 ) {
return $os_max ;
2017-05-01 23:49:11 -05:00
}
2018-11-21 17:25:39 -02:00
// then global
$global_max = Config :: get ( 'snmp.max_oid' , 10 );
return $global_max > 0 ? $global_max : 10 ;
2017-05-01 23:49:11 -05:00
}
2017-10-17 11:36:49 -05:00
2017-11-24 03:37:52 -06:00
/**
* If Distributed, create a lock, then purge the mysql table
*
* @param string $table
* @param string $sql
* @return int exit code
*/
function lock_and_purge ( $table , $sql )
{
try {
$purge_name = $table . '_purge' ;
if ( Config :: get ( 'distributed_poller' )) {
MemcacheLock :: lock ( $purge_name , 0 , 86000 );
}
$purge_days = Config :: get ( $purge_name );
$name = str_replace ( '_' , ' ' , ucfirst ( $table ));
if ( is_numeric ( $purge_days )) {
if ( dbDelete ( $table , $sql , array ( $purge_days ))) {
echo " $name cleared for entries over $purge_days days \n " ;
}
}
return 0 ;
} catch ( LockException $e ) {
echo $e -> getMessage () . PHP_EOL ;
return - 1 ;
}
}
2018-04-22 21:01:37 +08:00
2019-11-05 14:49:09 +01:00
/**
* If Distributed, create a lock, then purge the mysql table according to the sql query
*
* @param string $table
* @param string $sql
* @param string $msg
* @return int exit code
*/
function lock_and_purge_query ( $table , $sql , $msg )
{
$purge_name = $table . '_purge' ;
if ( Config :: get ( 'distributed_poller' )) {
MemcacheLock :: lock ( $purge_name , 0 , 86000 );
}
$purge_duration = Config :: get ( $purge_name );
if ( ! ( is_numeric ( $purge_duration ) && $purge_duration > 0 )) {
return - 2 ;
}
try {
if ( dbQuery ( $sql , array ( $purge_duration ))) {
printf ( $msg , $purge_duration );
}
} catch ( LockException $e ) {
echo $e -> getMessage () . PHP_EOL ;
return - 1 ;
}
return 0 ;
}
2018-04-22 21:01:37 +08:00
/**
* Convert space separated hex OID content to character
*
* @param string $hex_string
* @return string $chr_string
*/
function hexbin ( $hex_string )
{
$chr_string = '' ;
foreach ( explode ( ' ' , $hex_string ) as $a ) {
$chr_string .= chr ( hexdec ( $a ));
}
return $chr_string ;
}
2018-06-05 09:28:13 +00:00
/**
* Check if disk is valid to poll.
* Settings: bad_disk_regexp
*
* @param array $disk
* @param array $device
* @return bool
*/
function is_disk_valid ( $disk , $device )
{
foreach ( Config :: getCombined ( $device [ 'os' ], 'bad_disk_regexp' ) as $bir ) {
if ( preg_match ( $bir . "i" , $disk [ 'diskIODevice' ])) {
d_echo ( "Ignored Disk: { $disk [ 'diskIODevice' ] } (matched: $bir ) \n " );
return false ;
}
}
return true ;
}
2018-09-05 02:09:27 +02:00
/**
* Queues a hostname to be refreshed by Oxidized
* Settings: oxidized.url
*
* @param string $hostname
* @param string $msg
* @param string $username
* @return bool
*/
function oxidized_node_update ( $hostname , $msg , $username = 'not_provided' )
{
// Work around https://github.com/rack/rack/issues/337
$msg = str_replace ( "%" , "" , $msg );
$postdata = [ "user" => $username , "msg" => $msg ];
$oxidized_url = Config :: get ( 'oxidized.url' );
if ( ! empty ( $oxidized_url )) {
Requests :: put ( " $oxidized_url /node/next/ $hostname " , [], json_encode ( $postdata ), [ 'proxy' => get_proxy ()]);
return true ;
}
return false ;
} //end oxidized_node_update()
2020-04-25 05:47:20 +02:00
/**
* @params int code
* @params int subcode
* @return string
* Take a BGP error code and subcode to return a string representation of it
*/
function describe_bgp_error_code ( $code , $subcode )
{
// https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-3
$message = "Unknown" ;
$error_code_key = "bgp.error_codes." . $code ;
$error_subcode_key = "bgp.error_subcodes." . $code . "." . $subcode ;
$error_code_message = __ ( $error_code_key );
$error_subcode_message = __ ( $error_subcode_key );
if ( $error_subcode_message != $error_subcode_key ) {
$message = $error_code_message . " - " . $error_subcode_message ;
} elseif ( $error_code_message != $error_code_key ) {
$message = $error_code_message ;
}
return $message ;
}