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
*
* @copyright (C) 2006 - 2012 Adam Armstrong
*/
2020-01-30 13:20:30 +01:00
use App\Models\Device ;
2022-01-26 23:04:26 +01:00
use Illuminate\Support\Facades\Http ;
2020-04-17 17:37:56 -05:00
use Illuminate\Support\Str ;
2017-09-21 12:02:01 -05:00
use LibreNMS\Config ;
2022-03-12 16:14:32 -06:00
use LibreNMS\Enum\PortAssociationMode ;
2016-08-21 08:07:14 -05:00
use LibreNMS\Exceptions\HostExistsException ;
use LibreNMS\Exceptions\HostIpExistsException ;
2022-03-12 16:14:32 -06:00
use LibreNMS\Exceptions\HostnameExistsException ;
use LibreNMS\Exceptions\HostSysnameExistsException ;
2016-08-21 08:07:14 -05:00
use LibreNMS\Exceptions\HostUnreachableException ;
use LibreNMS\Exceptions\HostUnreachablePingException ;
2022-03-12 16:14:32 -06:00
use LibreNMS\Exceptions\HostUnreachableSnmpException ;
2016-08-21 08:07:14 -05:00
use LibreNMS\Exceptions\InvalidPortAssocModeException ;
use LibreNMS\Exceptions\SnmpVersionUnsupportedException ;
2020-10-05 07:26:37 -05:00
use LibreNMS\Modules\Core ;
2021-10-29 03:10:17 -05:00
use LibreNMS\Util\Proxy ;
2016-08-21 08:07:14 -05:00
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 = [];
$sortable_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 ];
}
}
2020-09-21 15:40:17 +02:00
2012-05-25 10:34:01 +00:00
return $new_array ;
2012-04-08 16:21:52 +00:00
}
2016-08-28 12:32:58 -05:00
function only_alphanumeric ( $string )
{
2011-03-23 09:54:56 +00: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
*
2021-09-08 23:35:56 +02:00
* @param string $type discovery or poller
* @param array $options get_opts array (only m key is checked)
2018-07-12 15:30:39 -05:00
* @return bool
*/
function parse_modules ( $type , $options )
{
$override = false ;
2021-11-17 19:23:55 -06:00
if ( ! empty ( $options [ 'm' ])) {
2018-07-12 15:30:39 -05:00
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 " );
2020-09-21 15:40:17 +02:00
2018-07-12 15:30:39 -05:00
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 " );
2011-03-23 09:54:56 +00:00
fclose ( $fd );
2010-11-24 11:32:53 +00:00
}
2016-08-28 12:32:58 -05:00
function percent_colour ( $perc )
{
2011-03-27 10:21:19 +00:00
$r = min ( 255 , 5 * ( $perc - 25 ));
$b = max ( 0 , 255 - ( 5 * ( $perc + 25 )));
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 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 ([ '.svg' , '.png' ], '' , $device [ 'icon' ]) : $device [ 'os' ];
}
function getImageName ( $device , $use_database = true , $dir = 'images/os/' )
2016-08-28 12:32:58 -05:00
{
2022-08-30 12:55:37 -05: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
2021-03-28 17:25:30 -05:00
if ( ! is_dir ( Rrd :: dirFromHost ( $new )) && rename ( Rrd :: dirFromHost ( $host ), Rrd :: dirFromHost ( $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 );
2020-09-21 15:40:17 +02:00
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 );
2020-09-21 15:40:17 +02:00
2018-08-30 14:38:29 -05:00
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 )
{
2021-05-13 07:18:54 -05:00
if ( App :: runningInConsole () === false ) {
2019-12-08 22:17:27 +01:00
ignore_user_abort ( true );
set_time_limit ( 0 );
}
$update = dbUpdate ([ 'last_discovered' => [ 'NULL' ]], 'devices' , '`device_id` = ?' , [ $id ]);
if ( ! empty ( $update ) || $update == '0' ) {
$message = 'Device will be rediscovered' ;
} else {
$message = 'Error rediscovering device' ;
}
2020-09-21 15:40:17 +02:00
2019-12-08 22:17:27 +01:00
return [ 'status' => $update , 'message' => $message ];
}
2016-08-28 12:32:58 -05:00
function delete_device ( $id )
{
2022-01-29 21:09:05 -06:00
$device = DeviceCache :: get ( $id );
if ( ! $device -> exists ) {
return 'No such device.' ;
2015-07-13 20:10:26 +02:00
}
2022-01-29 21:09:05 -06:00
if ( $device -> delete ()) {
return "Removed device $device->hostname \n " ;
2015-07-13 20:10:26 +02:00
}
2022-01-29 21:09:05 -06:00
return "Failed to remove device $device->hostname " ;
2015-07-13 20:10:26 +02:00
}
2016-08-01 22:01:01 -05:00
/**
* Add a device to LibreNMS
*
2021-09-08 23:35:56 +02:00
* @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 int $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
* @param bool $force_add add even if the device isn't reachable
* @param string $port_assoc_mode snmp field to use to determine unique ports
* @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
*/
2021-04-08 15:14:49 +02:00
function addHost ( $host , $snmp_version = '' , $port = 161 , $transport = 'udp' , $poller_group = '0' , $force_add = false , $port_assoc_mode = 'ifIndex' , $additional = [])
2016-08-28 12:32:58 -05:00
{
2012-05-25 12:24:34 +00:00
// Test Database Exists
2017-07-16 22:01:07 +01:00
if ( host_exists ( $host )) {
2022-03-12 16:14:32 -06:00
throw new HostnameExistsException ( $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
2022-03-12 16:14:32 -06:00
if ( ! in_array ( $port_assoc_mode , PortAssociationMode :: getModes ())) {
throw new InvalidPortAssocModeException ( "Invalid port association_mode ' $port_assoc_mode '. Valid modes are: " . join ( ', ' , PortAssociationMode :: getModes ()));
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 ;
}
2022-03-12 16:14:32 -06:00
if ( $force_add !== true && $existing = device_has_ip ( $ip )) {
throw new HostIpExistsException ( $host , $existing -> hostname , $ip );
2016-08-01 22:01:01 -05:00
}
// Test reachability
2016-08-09 15:00:12 -05:00
if ( ! $force_add ) {
2021-10-03 22:45:10 -05:00
if ( ! (( new \LibreNMS\Polling\ConnectivityHelper ( new Device ([ 'hostname' => $ip ]))) -> isPingable () -> success ())) {
2022-03-12 16:14:32 -06:00
throw new HostUnreachablePingException ( $host );
2016-08-09 15:00:12 -05:00
}
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 = [ $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 , [], $poller_group , 1 , true , $overwrite_ip , $additional );
2017-10-28 05:59:25 +02:00
}
2022-03-12 16:14:32 -06:00
$host_unreachable_exception = new HostUnreachableSnmpException ( $host );
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 {
2022-03-12 16:14:32 -06:00
$host_unreachable_exception -> addReason ( $snmpver , $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 , [], $poller_group , $port_assoc_mode , $force_add , $overwrite_ip );
2016-08-01 22:01:01 -05:00
} else {
2022-03-12 16:14:32 -06:00
$host_unreachable_exception -> addReason ( $snmpver , $community );
2012-05-09 16:18:23 +00:00
}
}
2016-08-01 22:01:01 -05:00
} else {
2022-03-12 16:14:32 -06:00
throw new SnmpVersionUnsupportedException ( $snmpver );
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-09-21 15:40:17 +02:00
2020-01-30 13:20:30 +01:00
return createHost ( $host , '' , $snmp_version , $port , $transport , [], $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 = [], $port_assoc_mode = 'ifIndex' , $overwrite_ip = null )
2016-08-28 12:32:58 -05:00
{
2011-03-23 09:54:56 +00:00
$device = [];
$device [ 'hostname' ] = $host ;
2020-04-08 11:47:40 +02:00
$device [ 'overwrite_ip' ] = $overwrite_ip ;
2011-03-23 09:54:56 +00:00
$device [ 'port' ] = $port ;
$device [ 'transport' ] = $transport ;
2015-07-13 20:10:26 +02:00
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 )) {
2022-03-12 16:14:32 -06:00
$port_assoc_mode = PortAssociationMode :: getId ( $port_assoc_mode );
2016-08-28 12:32:58 -05:00
}
2016-01-21 22:05:11 +01:00
$device [ 'port_association_mode' ] = $port_assoc_mode ;
2012-05-09 16:18:23 +00:00
$device [ 'snmpver' ] = $snmpver ;
if ( $snmpver === 'v2c' or $snmpver === 'v1' ) {
$device [ 'community' ] = $community ;
2016-08-28 12:32:58 -05:00
} elseif ( $snmpver === 'v3' ) {
2012-05-09 16:18:23 +00: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' ];
}
2015-07-13 20:10:26 +02:00
2011-03-23 09:54:56 +00:00
return $device ;
2020-04-08 11:47:40 +02:00
} //end deviceArray()
2011-03-15 16:12:44 +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 ) {
2011-03-23 09:54:56 +00: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 ;
}
2011-03-23 09:54:56 +00:00
}
2007-04-03 14:10:23 +00:00
}
2016-08-28 12:32:58 -05:00
function getpollergroup ( $poller_group = '0' )
{
2015-06-22 12:37:00 +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-06-22 12:37:00 +02:00
//Check if it contains a comma
2016-08-28 12:32:58 -05:00
if ( strpos ( $poller_group , ',' ) !== false ) {
2015-06-22 12:37:00 +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 );
2020-09-21 15:40:17 +02:00
2015-06-22 15:18:30 +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-06-22 12:37:00 +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-06-22 12:37:00 +02:00
//If all else fails use default
return '0' ;
}
}
}
}
2017-02-22 03:12:31 -06:00
/**
* Add a host to the database
*
2021-09-08 23:35:56 +02:00
* @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
* @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
2021-09-10 20:09:53 +02:00
*
2017-02-22 03:12:31 -06:00
* @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 = [],
$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 = []
2017-02-22 03:12:31 -06:00
) {
2011-03-23 09:54:56 +00:00
$host = trim ( strtolower ( $host ));
2015-07-13 20:10:26 +02:00
2015-06-22 12:37:00 +02:00
$poller_group = getpollergroup ( $poller_group );
2015-07-13 20:10:26 +02:00
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 )) {
2022-03-12 16:14:32 -06:00
$port_assoc_mode = PortAssociationMode :: getId ( $port_assoc_mode );
2016-08-28 12:32:58 -05:00
}
2016-02-26 08:04:38 -06:00
2021-10-19 15:43:43 -05:00
$device = new Device ( array_merge ([
2017-02-22 03:12:31 -06:00
'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 ,
2011-09-14 17:26:59 +00:00
'community' => $community ,
'port' => $port ,
'transport' => $transport ,
'status' => '1' ,
2015-03-19 12:00:03 +00:00
'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 ,
2021-10-19 15:43:43 -05:00
], $v3 ));
2011-09-14 17:26:59 +00:00
2016-09-16 09:40:00 +01:00
if ( $force_add !== true ) {
2021-10-19 15:43:43 -05:00
$device -> os = Core :: detectOS ( $device );
2011-03-15 16:12:44 +00:00
2021-10-19 15:43:43 -05:00
$device -> sysName = SnmpQuery :: device ( $device ) -> get ( 'SNMPv2-MIB::sysName.0' ) -> value ();
if ( host_exists ( $host , $device -> sysName )) {
2022-03-12 16:14:32 -06:00
throw new HostSysnameExistsException ( $host , $device -> sysName );
2017-07-16 22:01:07 +01:00
}
2010-02-07 22:39:02 +00:00
}
2021-10-19 15:43:43 -05:00
if ( $device -> save ()) {
return $device -> device_id ;
2017-02-22 03:12:31 -06:00
}
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
2020-09-21 15:40:17 +02:00
2017-01-24 15:56:51 -06:00
return ! empty ( $records );
2007-04-03 14:10:23 +00:00
}
2016-08-28 12:32:58 -05:00
function match_network ( $nets , $ip , $first = false )
{
2011-03-23 09:54:56 +00:00
$return = false ;
2016-08-28 12:32:58 -05:00
if ( ! is_array ( $nets )) {
$nets = [ $nets ];
}
2011-03-23 09:54:56 +00:00
foreach ( $nets as $net ) {
2016-08-28 12:32:58 -05:00
$rev = ( preg_match ( "/^\!/" , $net )) ? true : false ;
$net = preg_replace ( "/^\!/" , '' , $net );
2011-03-23 09:54:56 +00:00
$ip_arr = explode ( '/' , $net );
$net_long = ip2long ( $ip_arr [ 0 ]);
$x = ip2long ( $ip_arr [ 1 ]);
2021-09-08 03:33:54 +02:00
$mask = long2ip ( $x ) == $ip_arr [ 1 ] ? $x : 0xFFFFFFFF << ( 32 - $ip_arr [ 1 ]);
2011-03-23 09:54:56 +00:00
$ip_long = ip2long ( $ip );
if ( $rev ) {
if (( $ip_long & $mask ) == ( $net_long & $mask )) {
return false ;
2015-07-13 20:10:26 +02:00
}
2016-08-28 12:32:58 -05:00
} else {
2011-03-23 09:54:56 +00:00
if (( $ip_long & $mask ) == ( $net_long & $mask )) {
$return = true ;
2015-07-13 20:10:26 +02:00
}
2011-03-23 09:54:56 +00:00
if ( $first && $return ) {
return true ;
2011-03-11 18:03:49 +00:00
}
2011-03-23 09:54:56 +00:00
}
2015-07-13 20:10:26 +02:00
}
2011-03-23 09:54:56 +00:00
return $return ;
2007-04-03 14:10:23 +00:00
}
2021-04-08 14:57:17 +02:00
// FIXME port to LibreNMS\Util\IPv6 class
function snmp2ipv6 ( $ipv6_snmp )
{
// 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)"
$ipv6 = array_slice ( explode ( '.' , $ipv6_snmp ), - 16 );
$ipv6_2 = [];
for ( $i = 0 ; $i <= 15 ; $i ++ ) {
$ipv6 [ $i ] = zeropad ( dechex ( $ipv6 [ $i ]));
}
for ( $i = 0 ; $i <= 15 ; $i += 2 ) {
$ipv6_2 [] = $ipv6 [ $i ] . $ipv6 [ $i + 1 ];
}
return implode ( ':' , $ipv6_2 );
}
2016-08-28 12:32:58 -05:00
function get_astext ( $asn )
{
2022-09-13 19:00:30 -05:00
return \LibreNMS\Util\AutonomousSystem :: get ( $asn ) -> name ();
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
*
2021-09-08 23:35:56 +02:00
* @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-03-12 08:05:31 -05:00
*/
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 )
{
2021-10-06 07:29:47 -05:00
return \LibreNMS\Util\Mail :: parseEmails ( $emails );
2012-04-26 12:11:03 +00:00
}
2016-08-28 12:32:58 -05:00
function send_mail ( $emails , $subject , $message , $html = false )
{
2021-10-06 07:29:47 -05:00
return \LibreNMS\Util\Mail :: send ( $emails , $subject , $message , $html );
2014-03-07 22:30:07 +01:00
}
2016-08-28 12:32:58 -05:00
function hex2str ( $hex )
{
2011-03-23 09:54:56 +00:00
$string = '' ;
2011-03-11 18:03:49 +00:00
2011-03-26 19:12:24 +00: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 )));
2011-03-23 09:54:56 +00:00
}
2011-03-11 18:03:49 +00:00
2011-03-23 09:54:56 +00: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
2011-03-23 09:54:56 +00:00
if ( $regex == '' ) {
$regex = "/\.inc\.php$/" ;
}
2019-06-23 00:29:12 -05:00
if ( $handle = opendir ( Config :: get ( 'install_dir' ) . '/' . $dir )) {
2011-03-23 09:54:56 +00: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 ;
2011-03-23 09:54:56 +00:00
}
2010-07-09 22:38:46 +00:00
}
2011-03-23 09:54:56 +00: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
*
2021-09-08 23:35:56 +02:00
* @param array $port
* @param array $device
2017-09-21 12:02:01 -05:00
* @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 " );
2020-09-21 15:40:17 +02:00
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 " );
2020-09-21 15:40:17 +02:00
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' ];
2022-08-21 16:23:43 -05:00
$ifAlias = $port [ 'ifAlias' ] ?? '' ;
2017-09-21 12:02:01 -05:00
$ifType = $port [ 'ifType' ];
2022-08-21 16:23:43 -05: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 " );
2020-09-21 15:40:17 +02:00
2017-09-21 12:02:01 -05:00
return false ;
2012-03-29 12:05:45 +00: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 " );
2020-09-21 15:40:17 +02:00
2017-09-21 12:02:01 -05:00
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 " );
2020-09-21 15:40:17 +02:00
2017-09-21 12:02:01 -05:00
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 " );
2020-09-21 15:40:17 +02:00
2017-09-21 12:02:01 -05:00
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 " );
2020-09-21 15:40:17 +02:00
2017-09-21 12:02:01 -05:00
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 " );
2020-09-21 15:40:17 +02:00
2020-01-24 19:58:01 +08:00
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
2022-10-11 19:50:38 +02:00
* Also trims the data
2019-01-19 18:48:30 +01:00
*
2021-09-08 23:35:56 +02:00
* @param array $port
* @param array $device
2019-01-19 18:48:30 +01:00
*/
2022-10-11 19:50:38 +02:00
function port_fill_missing_and_trim ( & $port , $device )
2019-01-19 18:48:30 +01:00
{
2022-10-11 19:50:38 +02:00
if ( isset ( $port [ 'ifDescr' ])) {
$port [ 'ifDescr' ] = trim ( $port [ 'ifDescr' ]);
}
if ( isset ( $port [ 'ifAlias' ])) {
$port [ 'ifAlias' ] = trim ( $port [ 'ifAlias' ]);
}
if ( isset ( $port [ 'ifName' ])) {
$port [ 'ifName' ] = trim ( $port [ 'ifName' ]);
}
2019-01-19 18:48:30 +01:00
// When devices do not provide data, populate with other data if available
2022-08-21 16:23:43 -05:00
if ( ! isset ( $port [ 'ifDescr' ]) || $port [ 'ifDescr' ] == '' ) {
2019-01-19 18:48:30 +01:00
$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' );
2022-08-21 16:23:43 -05:00
} elseif ( ! isset ( $port [ 'ifAlias' ]) || $port [ 'ifAlias' ] == '' ) {
2019-01-19 18:48:30 +01:00
$port [ 'ifAlias' ] = $port [ 'ifDescr' ];
d_echo ( ' Using ifDescr as ifAlias' );
}
2022-08-21 16:23:43 -05:00
if ( ! isset ( $port [ 'ifName' ]) || $port [ 'ifName' ] == '' ) {
2019-01-19 18:48:30 +01:00
$port [ 'ifName' ] = $port [ 'ifDescr' ];
d_echo ( ' Using ifDescr as ifName' );
}
}
2016-08-28 12:32:58 -05:00
function validate_device_id ( $id )
{
if ( empty ( $id ) || ! is_numeric ( $id )) {
2014-06-26 00:33:00 +01:00
$return = false ;
2016-08-28 12:32:58 -05:00
} else {
2014-06-26 00:33:00 +01:00
$device_id = dbFetchCell ( 'SELECT `device_id` FROM `devices` WHERE `device_id` = ?' , [ $id ]);
2016-08-28 12:32:58 -05:00
if ( $device_id == $id ) {
2014-06-26 00:33:00 +01:00
$return = true ;
2016-08-28 12:32:58 -05:00
} else {
2014-06-26 00:33:00 +01:00
$return = false ;
}
2014-06-24 16:14:42 +01:00
}
2020-09-21 15:40:17 +02:00
2014-06-24 16:14:42 +01:00
return $return ;
}
2014-09-17 21:03:02 +01:00
2016-08-28 12:32:58 -05:00
function convert_delay ( $delay )
{
2021-04-28 15:31:45 -05:00
if ( preg_match ( '/(\d+)([mhd]?)/' , $delay , $matches )) {
$multipliers = [
'm' => 60 ,
'h' => 3600 ,
'd' => 86400 ,
];
$multiplier = $multipliers [ $matches [ 2 ]] ?? 1 ;
return $matches [ 1 ] * $multiplier ;
2014-11-30 17:49:52 +00:00
}
2020-09-21 15:40:17 +02:00
2021-04-28 15:31:45 -05:00
return $delay === '' ? 0 : 300 ;
2014-11-30 17:49:52 +00:00
}
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 );
2021-09-08 03:33:54 +02:00
$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
2015-04-10 17:00:32 +01:00
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
{
2021-10-06 07:29:47 -05:00
\LibreNMS\Util\Proxy :: applyToCurl ( $curl );
2015-04-13 19:51:16 +10:00
}
2015-04-19 20:23:34 +01:00
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 = ?' , [ substr ( $target , 2 )]);
} else {
$target = dbFetchCell ( 'SELECT device_id FROM devices WHERE hostname = ?' , [ $target ]);
2015-04-19 20:23:34 +01:00
}
2020-09-21 15:40:17 +02:00
2015-04-19 20:23:34 +01:00
return $target ;
}
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 ;
}
2020-09-21 15:40:17 +02:00
2015-06-02 17:36:10 +01:00
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.
*
2021-09-08 23:35:56 +02:00
* @param string $ip
2019-01-19 12:46:03 -06:00
* @return \App\Models\Device|false
*/
function device_has_ip ( $ip )
2016-08-01 22:01:01 -05:00
{
2022-03-12 16:14:32 -06:00
return Device :: findByIp ( $ip );
2015-06-11 19:34:11 +01:00
}
2015-06-22 21:55:31 +01:00
2015-10-22 21:10:33 +00:00
/**
* Checks if the $hostname provided exists in the DB already
*
2021-09-08 23:35:56 +02:00
* @param string $hostname The hostname to check for
* @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 = [ $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
}
2020-09-21 15:40:17 +02: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-01-17 23:59:51 +00:00
/**
* Perform DNS lookup
*
2021-09-08 23:35:56 +02:00
* @param array $device Device array from database
* @param string $type The type of record to lookup
2016-01-17 23:59:51 +00:00
* @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 );
2020-09-21 15:40:17 +02:00
2022-08-21 16:23:43 -05:00
return $record [ 0 ][ $return ] ?? null ;
2016-01-17 23:59:51 +00:00
} //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
*
2021-09-08 23:35:56 +02:00
* @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
2017-09-03 13:58:39 -05:00
* @return int|null
*/
function create_state_index ( $state_name , $states = [])
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' , [ $state_name ]);
if ( ! is_numeric ( $state_index_id )) {
2017-09-03 13:58:39 -05:00
$state_index_id = dbInsert ([ '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` = ?' , [ $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
*
2021-09-08 23:35:56 +02:00
* @param int $state_index_id index of the state
* @param array $states array of states, each must contain keys: descr, graph, value, generic
2017-09-03 13:58:39 -05:00
*/
function sync_sensor_states ( $state_index_id , $states )
{
$new_translations = array_reduce ( $states , function ( $array , $state ) use ( $state_index_id ) {
$array [ $state [ 'value' ]] = [
'state_index_id' => $state_index_id ,
'state_descr' => $state [ 'descr' ],
'state_draw_graph' => $state [ 'graph' ],
'state_value' => $state [ 'value' ],
'state_generic_value' => $state [ 'generic' ],
];
2020-09-21 15:40:17 +02:00
2017-09-03 13:58:39 -05:00
return $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`=?' ,
[ $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`=?' ,
[ $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`=?' , [ $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` = ?' , [
'state' ,
$device [ 'device_id' ],
$state_name ,
$index ,
]);
$state_indexes_entry = dbFetchRow ( 'SELECT state_index_id FROM `state_indexes` WHERE `state_name` = ?' , [
$state_name ,
]);
if ( ! empty ( $sensor_entry [ 'sensor_id' ]) && ! empty ( $state_indexes_entry [ 'state_index_id' ])) {
$insert = [
'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 = [];
$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 = [];
$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 );
2022-04-12 08:27:31 -05:00
$tpointnumber = min ( number_format ( $tmppoint [ 0 ] / 2 , strlen ( $binpoint ), '.' , '' ), 1 );
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 = [];
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` = ?' , [ $entphysical [ $location ][ 'entPhysical_id' ]]);
}
$entPhysicalId = $entphysical [ $location ][ 'entPhysical_id' ];
2020-09-21 15:40:17 +02:00
2016-10-06 10:40:37 +10:00
return [ $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 = [
'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=?' , [ $id ]);
2020-09-21 15:40:17 +02:00
2016-10-06 10:40:37 +10:00
return $index ;
} // end if - Level 1
} // end function
2016-10-11 15:29:06 -06:00
2021-02-09 00:29:04 +01:00
/* idea from https://php.net/manual/en/function.hex2bin.php comments */
2016-10-11 15:29:06 -06:00
function hex2bin_compat ( $str )
{
if ( strlen ( $str ) % 2 !== 0 ) {
trigger_error ( __FUNCTION__ . '(): Hexadecimal input string must have an even length' , E_USER_WARNING );
}
2020-09-21 15:40:17 +02:00
2016-10-11 15:29:06 -06:00
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)
*/
2021-12-01 14:24:35 +01:00
$hex_data = str_replace ([ ' ' , " \n " ], '' , $hex_data );
2021-03-30 15:26:01 -05:00
// we need an even number of digits for hex2bin
if ( strlen ( $hex_data ) % 2 === 1 ) {
$hex_data = '0' . $hex_data ;
}
2016-10-11 15:29:06 -06:00
$value = hex2bin ( $hex_data );
$length = strlen ( $value );
$indices = [];
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 ;
}
}
}
2020-09-21 15:40:17 +02:00
2016-10-11 15:29:06 -06:00
return $indices ;
}
2016-10-14 18:14:18 -05:00
2021-05-10 21:56:48 +02:00
/**
* Function to generate Mac OUI Cache
*/
function cache_mac_oui ()
{
// timers:
$mac_oui_refresh_int_min = 86400 * rand ( 7 , 11 ); // 7 days + a random number between 0 and 4 days
$mac_oui_cache_time = 1296000 ; // we keep data during 15 days maximum
$lock = Cache :: lock ( 'macouidb-refresh' , $mac_oui_refresh_int_min ); //We want to refresh after at least $mac_oui_refresh_int_min
if ( Config :: get ( 'mac_oui.enabled' ) !== true ) {
echo 'Mac OUI integration disabled' . PHP_EOL ;
return 0 ;
}
if ( $lock -> get ()) {
echo 'Caching Mac OUI' . PHP_EOL ;
try {
2021-11-09 14:47:38 +01:00
$mac_oui_url = 'https://gitlab.com/wireshark/wireshark/-/raw/master/manuf' ;
//$mac_oui_url_mirror = 'https://raw.githubusercontent.com/wireshark/wireshark/master/manuf';
2021-05-10 21:56:48 +02:00
echo ' -> Downloading ...' . PHP_EOL ;
2022-01-26 23:04:26 +01:00
$get = Http :: withOptions ([ 'proxy' => Proxy :: forGuzzle ()]) -> get ( $mac_oui_url );
2021-11-09 14:47:38 +01:00
echo ' -> Processing CSV ...' . PHP_EOL ;
2022-01-26 23:04:26 +01:00
$csv_data = $get -> body ();
2021-11-09 14:47:38 +01:00
foreach ( explode ( " \n " , $csv_data ) as $csv_line ) {
unset ( $oui );
$entry = str_getcsv ( $csv_line , " \t " );
$length = strlen ( $entry [ 0 ]);
$prefix = strtolower ( str_replace ( ':' , '' , $entry [ 0 ]));
if ( is_array ( $entry ) && count ( $entry ) >= 3 && $length == 8 ) {
// We have a standard OUI xx:xx:xx
$oui = $prefix ;
} elseif ( is_array ( $entry ) && count ( $entry ) >= 3 && $length == 20 ) {
// We have a smaller range (xx:xx:xx:X or xx:xx:xx:xx:X)
if ( substr ( $prefix , - 2 ) == '28' ) {
$oui = substr ( $prefix , 0 , 7 );
} elseif ( substr ( $prefix , - 2 ) == '36' ) {
$oui = substr ( $prefix , 0 , 9 );
}
}
if ( isset ( $oui )) {
echo "Adding $oui , $entry[2] " . PHP_EOL ;
2021-05-10 21:56:48 +02:00
$key = 'OUIDB-' . $oui ;
2021-11-09 14:47:38 +01:00
Cache :: put ( $key , $entry [ 2 ], $mac_oui_cache_time );
2021-05-10 21:56:48 +02:00
}
}
} catch ( Exception $e ) {
echo 'Error processing Mac OUI :' . PHP_EOL ;
echo 'Exception: ' . get_class ( $e ) . PHP_EOL ;
echo $e -> getMessage () . PHP_EOL ;
$lock -> release (); // we did not succeed so we'll try again next time
return 1 ;
}
}
return 0 ;
}
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' ];
2022-01-26 23:04:26 +01:00
$get = Http :: withOptions ([ 'proxy' => Proxy :: forGuzzle ()]) -> get ( $peeringdb_url . '/net?depth=2&asn=' . $asn );
$json_data = $get -> body ();
2017-03-22 10:17:13 +00:00
$data = json_decode ( $json_data );
2020-03-21 15:49:15 -04:00
$ixs = $data -> { 'data' }[ 0 ] -> { 'netixlan_set' };
2022-08-25 10:03:06 +02:00
foreach ( $ixs ?? [] as $ix ) {
2017-03-22 10:17:13 +00:00
$ixid = $ix -> { 'ix_id' };
$tmp_ix = dbFetchRow ( 'SELECT * FROM `pdb_ix` WHERE `ix_id` = ? AND asn = ?' , [ $ixid , $asn ]);
if ( $tmp_ix ) {
$pdb_ix_id = $tmp_ix [ 'pdb_ix_id' ];
$update = [ 'name' => $ix -> { 'name' }, 'timestamp' => time ()];
2017-03-23 10:08:48 +00:00
dbUpdate ( $update , 'pdb_ix' , '`ix_id` = ? AND `asn` = ?' , [ $ixid , $asn ]);
2017-03-22 10:17:13 +00:00
} else {
$insert = [
'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 ;
2022-01-26 23:04:26 +01:00
$get_ix = Http :: withOptions ([ 'proxy' => Proxy :: forGuzzle ()]) -> get ( " $peeringdb_url /netixlan?ix_id= $ixid " );
$ix_json = $get_ix -> body ();
2017-03-22 10:17:13 +00:00
$ix_data = json_decode ( $ix_json );
$peers = $ix_data -> { 'data' };
2022-08-30 16:00:12 +02:00
foreach ( $peers ?? [] as $index => $peer ) {
2017-03-22 10:17:13 +00:00
$peer_name = get_astext ( $peer -> { 'asn' });
$tmp_peer = dbFetchRow ( 'SELECT * FROM `pdb_ix_peers` WHERE `peer_id` = ? AND `ix_id` = ?' , [ $peer -> { 'id' }, $ixid ]);
if ( $tmp_peer ) {
$peer_keep [] = $tmp_peer [ 'pdb_ix_peers_id' ];
$update = [
'remote_asn' => $peer -> { 'asn' },
'remote_ipaddr4' => $peer -> { 'ipaddr4' },
'remote_ipaddr6' => $peer -> { 'ipaddr6' },
'name' => $peer_name ,
];
dbUpdate ( $update , 'pdb_ix_peers' , '`pdb_ix_peers_id` = ?' , [ $tmp_peer [ 'pdb_ix_peers_id' ]]);
} else {
$peer_insert = [
'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
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 ;
2020-09-21 15:40:17 +02:00
2017-04-13 04:18:12 -05:00
return $array ;
2019-01-17 08:53:32 -06:00
}, []);
ksort ( $files ); // fix dbSchema 1000 order
2020-09-21 15:40:17 +02:00
2019-01-17 08:53:32 -06:00
return $files ;
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
2021-02-14 20:36:55 -06:00
if ( ! empty ( $device [ 'attribs' ][ 'snmp_max_oid' ])) {
2019-11-14 21:56:06 +00:00
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 );
2020-09-21 15:40:17 +02:00
2018-11-21 17:25:39 -02:00
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
*
2021-09-08 23:35:56 +02:00
* @param string $table
* @param string $sql
2017-11-24 03:37:52 -06:00
* @return int exit code
*/
function lock_and_purge ( $table , $sql )
{
2020-10-07 07:36:35 -05:00
$purge_name = $table . '_purge' ;
$lock = Cache :: lock ( $purge_name , 86000 );
if ( $lock -> get ()) {
2017-11-24 03:37:52 -06:00
$purge_days = Config :: get ( $purge_name );
$name = str_replace ( '_' , ' ' , ucfirst ( $table ));
if ( is_numeric ( $purge_days )) {
if ( dbDelete ( $table , $sql , [ $purge_days ])) {
echo " $name cleared for entries over $purge_days days \n " ;
}
}
2020-10-07 07:36:35 -05:00
$lock -> release ();
2020-09-21 15:40:17 +02:00
2017-11-24 03:37:52 -06:00
return 0 ;
}
2020-10-07 07:36:35 -05:00
return - 1 ;
2017-11-24 03:37:52 -06:00
}
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
*
2021-09-08 23:35:56 +02:00
* @param string $table
* @param string $sql
* @param string $msg
2019-11-05 14:49:09 +01:00
* @return int exit code
*/
function lock_and_purge_query ( $table , $sql , $msg )
{
$purge_name = $table . '_purge' ;
$purge_duration = Config :: get ( $purge_name );
if ( ! ( is_numeric ( $purge_duration ) && $purge_duration > 0 )) {
return - 2 ;
}
2020-10-07 07:36:35 -05:00
$lock = Cache :: lock ( $purge_name , 86000 );
if ( $lock -> get ()) {
2019-11-05 14:49:09 +01:00
if ( dbQuery ( $sql , [ $purge_duration ])) {
printf ( $msg , $purge_duration );
}
2020-10-07 07:36:35 -05:00
$lock -> release ();
2020-09-21 15:40:17 +02:00
2020-10-07 07:36:35 -05:00
return 0 ;
2019-11-05 14:49:09 +01:00
}
2020-09-21 15:40:17 +02:00
2020-10-07 07:36:35 -05:00
return - 1 ;
2019-11-05 14:49:09 +01:00
}
2018-06-05 09:28:13 +00:00
/**
* Check if disk is valid to poll.
* Settings: bad_disk_regexp
*
2021-09-08 23:35:56 +02:00
* @param array $disk
* @param array $device
2018-06-05 09:28:13 +00:00
* @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 " );
2020-09-21 15:40:17 +02:00
2018-06-05 09:28:13 +00:00
return false ;
}
}
2020-09-21 15:40:17 +02:00
2018-06-05 09:28:13 +00:00
return true ;
}
2018-09-05 02:09:27 +02:00
2020-04-25 05:47:20 +02:00
/**
2022-01-26 23:04:26 +01:00
* Take a BGP error code and subcode to return a string representation of it
*
2020-04-25 05:47:20 +02:00
* @params int code
* @params int subcode
2021-09-10 20:09:53 +02:00
*
2020-04-25 05:47:20 +02:00
* @return string
*/
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 ;
}