Passed
Push — master ( 0baeb0...d4017c )
by Tony
19:18 queued 08:55
created

includes/discovery/functions.inc.php (3 issues)

1
<?php
2
3
/*
4
 * LibreNMS Network Management and Monitoring System
5
 * Copyright (C) 2006-2011, Observium Developers - http://www.observium.org
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * See COPYING for more details.
13
 */
14
15
use LibreNMS\Config;
16
use LibreNMS\Exceptions\HostExistsException;
17
use LibreNMS\Exceptions\InvalidIpException;
18
use LibreNMS\OS;
19
use LibreNMS\Util\IP;
20
use LibreNMS\Util\IPv6;
21
use LibreNMS\Device\YamlDiscovery;
22
23
function discover_new_device($hostname, $device = '', $method = '', $interface = '')
24
{
25
    d_echo("discovering $hostname\n");
26
27
    if (IP::isValid($hostname)) {
28
        $ip = $hostname;
29
        if (!Config::get('discovery_by_ip', false)) {
30
            d_echo('Discovery by IP disabled, skipping ' . $hostname);
31
            log_event("$method discovery of " . $hostname . " failed - Discovery by IP disabled", $device['device_id'], 'discovery', 4);
32
33
            return false;
34
        }
35
    } elseif (is_valid_hostname($hostname)) {
36
        if ($mydomain = Config::get('mydomain')) {
37
            $full_host = rtrim($hostname, '.') . '.' . $mydomain;
38
            if (isDomainResolves($full_host)) {
39
                $hostname = $full_host;
40
            }
41
        }
42
43
        $ip = gethostbyname($hostname);
44
        if ($ip == $hostname) {
45
            d_echo("name lookup of $hostname failed\n");
46
            log_event("$method discovery of " . $hostname . " failed - Check name lookup", $device['device_id'], 'discovery', 5);
47
48
            return false;
49
        }
50
    } else {
51
        d_echo("Discovery failed: '$hostname' is not a valid ip or dns name\n");
52
        return false;
53
    }
54
55
    d_echo("ip lookup result: $ip\n");
56
57
    $hostname = rtrim($hostname, '.'); // remove trailing dot
58
59
    $ip = IP::parse($ip, true);
60
    if ($ip->inNetworks(Config::get('autodiscovery.nets-exclude'))) {
61
        d_echo("$ip in an excluded network - skipping\n");
62
        return false;
63
    }
64
65
    if (!$ip->inNetworks(Config::get('nets'))) {
66
        d_echo("$ip not in a matched network - skipping\n");
67
        return false;
68
    }
69
70
    try {
71
        $remote_device_id = addHost($hostname, '', '161', 'udp', Config::get('distributed_poller_group'));
72
        $remote_device = device_by_id_cache($remote_device_id, 1);
73
        echo '+[' . $remote_device['hostname'] . '(' . $remote_device['device_id'] . ')]';
74
        discover_device($remote_device);
75
        device_by_id_cache($remote_device_id, 1);
76
        if ($remote_device_id && is_array($device) && !empty($method)) {
77
            $extra_log = '';
78
            $int = cleanPort($interface);
79
            if (is_array($int)) {
80
                $extra_log = ' (port ' . $int['label'] . ') ';
81
            }
82
83
            log_event('Device ' . $remote_device['hostname'] . " ($ip) $extra_log autodiscovered through $method on " . $device['hostname'], $remote_device_id, 'discovery', 1);
84
        } else {
85
            log_event("$method discovery of " . $remote_device['hostname'] . " ($ip) failed - Check ping and SNMP access", $device['device_id'], 'discovery', 5);
86
        }
87
88
        return $remote_device_id;
89
    } catch (HostExistsException $e) {
90
        // already have this device
91
    } catch (Exception $e) {
92
        log_event("$method discovery of " . $hostname . " ($ip) failed - " . $e->getMessage(), $device['device_id'], 'discovery', 5);
93
    }
94
95
    return false;
96
}
97
//end discover_new_device()
98
99
/**
100
 * @param $device
101
 */
102
function load_discovery(&$device)
103
{
104
    $yaml_discovery = Config::get('install_dir') . '/includes/definitions/discovery/' . $device['os'] . '.yaml';
105
    if (file_exists($yaml_discovery)) {
106
        $device['dynamic_discovery'] = Symfony\Component\Yaml\Yaml::parse(
107
            file_get_contents($yaml_discovery)
108
        );
109
    } else {
110
        unset($device['dynamic_discovery']);
111
    }
112
}
113
114
/**
115
 * @param array $device The device to poll
116
 * @param bool $force_module Ignore device module overrides
117
 * @return bool if the device was discovered or skipped
118
 */
119
function discover_device(&$device, $force_module = false)
120
{
121
    if ($device['snmp_disable'] == '1') {
122
        return false;
123
    }
124
125
    global $valid;
126
127
    $valid = array();
128
    // Reset $valid array
129
    $attribs = get_dev_attribs($device['device_id']);
130
    $device['attribs'] = $attribs;
131
    $device['snmp_max_repeaters'] = $attribs['snmp_max_repeaters'];
132
133
    $device_start = microtime(true);
134
    // Start counting device poll time
135
    echo $device['hostname'] . ' ' . $device['device_id'] . ' ' . $device['os'] . ' ';
136
137
    $response = device_is_up($device, true);
138
139
    if ($response['status'] !== '1') {
140
        return false;
141
    }
142
143
    if ($device['os'] == 'generic') {
144
        // verify if OS has changed from generic
145
        $device['os'] = getHostOS($device);
146
147
        if ($device['os'] != 'generic') {
148
            echo "\nDevice os was updated to " . $device['os'] . '!';
149
            dbUpdate(array('os' => $device['os']), 'devices', '`device_id` = ?', array($device['device_id']));
150
        }
151
    }
152
153
    load_os($device);
154
    load_discovery($device);
155
    register_mibs($device, Config::getOsSetting($device['os'], 'register_mibs', array()), 'includes/discovery/os/' . $device['os'] . '.inc.php');
156
157
    $os = OS::make($device);
158
159
    echo "\n";
160
161
    $discovery_devices = Config::get('discovery_modules', array());
162
    $discovery_devices = array('core' => true) + $discovery_devices;
163
164
    foreach ($discovery_devices as $module => $module_status) {
165
        $os_module_status = Config::getOsSetting($device['os'], "discovery_modules.$module");
166
        d_echo("Modules status: Global" . (isset($module_status) ? ($module_status ? '+ ' : '- ') : '  '));
167
        d_echo("OS" . (isset($os_module_status) ? ($os_module_status ? '+ ' : '- ') : '  '));
168
        d_echo("Device" . (isset($attribs['discover_' . $module]) ? ($attribs['discover_' . $module] ? '+ ' : '- ') : '  '));
169
        if ($force_module === true ||
170
            $attribs['discover_' . $module] ||
171
            ($os_module_status && !isset($attribs['discover_' . $module])) ||
172
            ($module_status && !isset($os_module_status) && !isset($attribs['discover_' . $module]))
173
        ) {
174
            $module_start = microtime(true);
175
            $start_memory = memory_get_usage();
176
            echo "\n#### Load disco module $module ####\n";
177
178
            try {
179
                include "includes/discovery/$module.inc.php";
180
            } catch (Exception $e) {
181
                // isolate module exceptions so they don't disrupt the polling process
182
                echo $e->getTraceAsString() .PHP_EOL;
183
                c_echo("%rError in $module module.%n " . $e->getMessage() . PHP_EOL);
184
                logfile("Error in $module module. " . $e->getMessage() . PHP_EOL . $e->getTraceAsString() . PHP_EOL);
185
            }
186
187
            $module_time = microtime(true) - $module_start;
188
            $module_time = substr($module_time, 0, 5);
189
            $module_mem = (memory_get_usage() - $start_memory);
190
            printf("\n>> Runtime for discovery module '%s': %.4f seconds with %s bytes\n", $module, $module_time, $module_mem);
191
            printChangedStats();
192
            echo "#### Unload disco module $module ####\n\n";
193
        } elseif (isset($attribs['discover_' . $module]) && $attribs['discover_' . $module] == '0') {
194
            echo "Module [ $module ] disabled on host.\n\n";
195
        } elseif (isset($os_module_status) && $os_module_status == '0') {
196
            echo "Module [ $module ] disabled on os.\n\n";
197
        } else {
198
            echo "Module [ $module ] disabled globally.\n\n";
199
        }
200
    }
201
202
    if (is_mib_poller_enabled($device)) {
203
        $devicemib = array($device['sysObjectID'] => 'all');
204
        register_mibs($device, $devicemib, "includes/discovery/functions.inc.php");
205
    }
206
207
    $device_time  = round(microtime(true) - $device_start, 3);
208
209
    dbUpdate(array('last_discovered' => array('NOW()'), 'last_discovered_timetaken' => $device_time), 'devices', '`device_id` = ?', array($device['device_id']));
210
211
    echo "Discovered in $device_time seconds\n";
212
213
    echo PHP_EOL;
214
    return true;
215
}
216
//end discover_device()
217
218
// Discover sensors
219
function discover_sensor(&$valid, $class, $device, $oid, $index, $type, $descr, $divisor = 1, $multiplier = 1, $low_limit = null, $low_warn_limit = null, $warn_limit = null, $high_limit = null, $current = null, $poller_type = 'snmp', $entPhysicalIndex = null, $entPhysicalIndex_measured = null, $user_func = null, $group = null)
220
{
221
    $guess_limits   = Config::get('sensors.guess_limits', true);
222
223
    $low_limit      = set_null($low_limit);
224
    $low_warn_limit = set_null($low_warn_limit);
225
    $warn_limit     = set_null($warn_limit);
226
    $high_limit     = set_null($high_limit);
227
228
    if (!is_numeric($divisor)) {
229
        $divisor  = 1;
230
    }
231
232
    d_echo("Discover sensor: $oid, $index, $type, $descr, $poller_type, $divisor, $multiplier, $entPhysicalIndex, $current, (limits: LL: $low_limit, LW: $low_warn_limit, W: $warn_limit, H: $high_limit)\n");
233
234
    if (isset($warn_limit, $low_warn_limit) && $low_warn_limit > $warn_limit) {
235
        // Fix high/low thresholds (i.e. on negative numbers)
236
        list($warn_limit, $low_warn_limit) = [$low_warn_limit, $warn_limit];
237
    }
238
239
    if (dbFetchCell('SELECT COUNT(sensor_id) FROM `sensors` WHERE `poller_type`= ? AND `sensor_class` = ? AND `device_id` = ? AND sensor_type = ? AND `sensor_index` = ?', array($poller_type, $class, $device['device_id'], $type, (string)$index)) == '0') {
240
        if ($guess_limits && is_null($high_limit)) {
241
            $high_limit = sensor_limit($class, $current);
242
        }
243
244
        if ($guess_limits && is_null($low_limit)) {
245
            $low_limit = sensor_low_limit($class, $current);
246
        }
247
248
        if (!is_null($high_limit) && $low_limit > $high_limit) {
249
            // Fix high/low thresholds (i.e. on negative numbers)
250
            list($high_limit, $low_limit) = array($low_limit, $high_limit);
251
        }
252
253
        $insert = array(
254
            'poller_type' => $poller_type,
255
            'sensor_class' => $class,
256
            'device_id' => $device['device_id'],
257
            'sensor_oid' => $oid,
258
            'sensor_index' => $index,
259
            'sensor_type' => $type,
260
            'sensor_descr' => $descr,
261
            'sensor_divisor' => $divisor,
262
            'sensor_multiplier' => $multiplier,
263
            'sensor_limit' => $high_limit,
264
            'sensor_limit_warn' => $warn_limit,
265
            'sensor_limit_low' => $low_limit,
266
            'sensor_limit_low_warn' => $low_warn_limit,
267
            'sensor_current' => $current,
268
            'entPhysicalIndex' => $entPhysicalIndex,
269
            'entPhysicalIndex_measured' => $entPhysicalIndex_measured,
270
            'user_func' => $user_func,
271
            'group' => $group,
272
        );
273
274
        foreach ($insert as $key => $val_check) {
275
            if (!isset($val_check)) {
276
                unset($insert[$key]);
277
            }
278
        }
279
280
        $inserted = dbInsert($insert, 'sensors');
281
282
        d_echo("( $inserted inserted )\n");
283
284
        echo '+';
285
        log_event('Sensor Added: ' . $class . ' ' . $type . ' ' . $index . ' ' . $descr, $device, 'sensor', 3, $inserted);
286
    } else {
287
        $sensor_entry = dbFetchRow('SELECT * FROM `sensors` WHERE `sensor_class` = ? AND `device_id` = ? AND `sensor_type` = ? AND `sensor_index` = ?', array($class, $device['device_id'], $type, (string)$index));
288
289
        if (!isset($high_limit)) {
290
            if ($guess_limits && !$sensor_entry['sensor_limit']) {
291
                // Calculate a reasonable limit
292
                $high_limit = sensor_limit($class, $current);
293
            } else {
294
                // Use existing limit
295
                $high_limit = $sensor_entry['sensor_limit'];
296
            }
297
        }
298
299
        if (!isset($low_limit)) {
300
            if ($guess_limits && !$sensor_entry['sensor_limit_low']) {
301
                // Calculate a reasonable limit
302
                $low_limit = sensor_low_limit($class, $current);
303
            } else {
304
                // Use existing limit
305
                $low_limit = $sensor_entry['sensor_limit_low'];
306
            }
307
        }
308
309
        // Fix high/low thresholds (i.e. on negative numbers)
310
        if ($low_limit > $high_limit) {
311
            list($high_limit, $low_limit) = array($low_limit, $high_limit);
312
        }
313
314
        if ($high_limit != $sensor_entry['sensor_limit'] && $sensor_entry['sensor_custom'] == 'No') {
315
            $update = array('sensor_limit' => ($high_limit == null ? array('NULL') : $high_limit));
316
            $updated = dbUpdate($update, 'sensors', '`sensor_id` = ?', array($sensor_entry['sensor_id']));
317
            d_echo("( $updated updated )\n");
318
319
            echo 'H';
320
            log_event('Sensor High Limit Updated: ' . $class . ' ' . $type . ' ' . $index . ' ' . $descr . ' (' . $high_limit . ')', $device, 'sensor', 3, $sensor_id);
321
        }
322
323
        if ($sensor_entry['sensor_limit_low'] != $low_limit && $sensor_entry['sensor_custom'] == 'No') {
324
            $update = array('sensor_limit_low' => ($low_limit == null ? array('NULL') : $low_limit));
325
            $updated = dbUpdate($update, 'sensors', '`sensor_id` = ?', array($sensor_entry['sensor_id']));
326
            d_echo("( $updated updated )\n");
327
328
            echo 'L';
329
            log_event('Sensor Low Limit Updated: ' . $class . ' ' . $type . ' ' . $index . ' ' . $descr . ' (' . $low_limit . ')', $device, 'sensor', 3, $sensor_id);
330
        }
331
332
        if ($warn_limit != $sensor_entry['sensor_limit_warn'] && $sensor_entry['sensor_custom'] == 'No') {
333
            $update = array('sensor_limit_warn' => ($warn_limit == null ? array('NULL') : $warn_limit));
334
            $updated = dbUpdate($update, 'sensors', '`sensor_id` = ?', array($sensor_entry['sensor_id']));
335
            d_echo("( $updated updated )\n");
336
337
            echo 'WH';
338
            log_event('Sensor Warn High Limit Updated: ' . $class . ' ' . $type . ' ' . $index . ' ' . $descr . ' (' . $warn_limit . ')', $device, 'sensor', 3, $sensor_id);
339
        }
340
341
        if ($sensor_entry['sensor_limit_low_warn'] != $low_warn_limit && $sensor_entry['sensor_custom'] == 'No') {
342
            $update = array('sensor_limit_low_warn' => ($low_warn_limit == null ? array('NULL') : $low_warn_limit));
343
            $updated = dbUpdate($update, 'sensors', '`sensor_id` = ?', array($sensor_entry['sensor_id']));
344
            d_echo("( $updated updated )\n");
345
346
            echo 'WL';
347
            log_event('Sensor Warn Low Limit Updated: ' . $class . ' ' . $type . ' ' . $index . ' ' . $descr . ' (' . $low_warn_limit . ')', $device, 'sensor', 3, $sensor_id);
348
        }
349
350
        if ($oid == $sensor_entry['sensor_oid'] &&
351
            $descr == $sensor_entry['sensor_descr'] &&
352
            $multiplier == $sensor_entry['sensor_multiplier'] &&
353
            $divisor == $sensor_entry['sensor_divisor'] &&
354
            $entPhysicalIndex_measured == $sensor_entry['entPhysicalIndex_measured'] &&
355
            $entPhysicalIndex == $sensor_entry['entPhysicalIndex'] &&
356
            $user_func == $sensor_entry['user_func'] &&
357
            $group == $sensor_entry['group']
358
359
        ) {
360
            echo '.';
361
        } else {
362
            $update = array(
363
                'sensor_oid' => $oid,
364
                'sensor_descr' => $descr,
365
                'sensor_multiplier' => $multiplier,
366
                'sensor_divisor' => $divisor,
367
                'entPhysicalIndex' => $entPhysicalIndex,
368
                'entPhysicalIndex_measured' => $entPhysicalIndex_measured,
369
                'user_func' => $user_func,
370
                'group' => $group,
371
            );
372
            $updated = dbUpdate($update, 'sensors', '`sensor_id` = ?', array($sensor_entry['sensor_id']));
373
            echo 'U';
374
            log_event('Sensor Updated: ' . $class . ' ' . $type . ' ' . $index . ' ' . $descr, $device, 'sensor', 3, $sensor_id);
375
            d_echo("( $updated updated )\n");
376
        }
377
    }//end if
378
    $valid[$class][$type][$index] = 1;
379
}
380
381
//end discover_sensor()
382
383
function sensor_low_limit($class, $current)
384
{
385
    $limit = null;
386
387
    switch ($class) {
388
        case 'temperature':
389
            $limit = $current - 10;
390
            break;
391
        case 'voltage':
392
                $limit = $current * 0.85;
393
            break;
394
        case 'humidity':
395
            $limit = 30;
396
            break;
397
        case 'count':
398
        case 'current':
399
            $limit = null;
400
            break;
401
        case 'fanspeed':
402
            $limit = $current * 0.80;
403
            break;
404
        case 'power':
405
            $limit = null;
406
            break;
407
        case 'power_consumed':
408
        case 'power_factor':
409
            $limit = -1;
410
            break;
411
        case 'signal':
412
            $limit = -80;
413
            break;
414
        case 'airflow':
415
        case 'dbm':
416
        case 'snr':
417
        case 'frequency':
418
        case 'pressure':
419
        case 'cooling':
420
            $limit = $current * 0.95;
421
            break;
422
        case 'delay':
423
        case 'quality_factor':
424
        case 'chromatic_dispersion':
425
        case 'ber':
426
        case 'eer':
427
        case 'waterflow':
428
    }//end switch
429
430
    if (is_numeric($limit)) {
431
        return round($limit, 11);
432
    }
433
434
    return $limit;
435
}
436
437
//end sensor_low_limit()
438
439
function sensor_limit($class, $current)
440
{
441
    $limit = null;
442
443
    switch ($class) {
444
        case 'temperature':
445
            $limit = $current + 20;
446
            break;
447
        case 'voltage':
448
            $limit = $current * 1.15;
449
            break;
450
        case 'humidity':
451
            $limit = 70;
452
            break;
453
        case 'count':
454
        case 'current':
455
        case 'power':
456
            $limit = $current * 1.50;
457
            break;
458
        case 'power_consumed':
459
        case 'power_factor':
460
            $limit = 1;
461
            break;
462
        case 'fanspeed':
463
            $limit = $current * 1.80;
464
            break;
465
        case 'signal':
466
            $limit = -30;
467
            break;
468
        case 'load':
469
            $limit = 80;
470
            break;
471
        case 'airflow':
472
        case 'dbm':
473
        case 'snr':
474
        case 'frequency':
475
        case 'pressure':
476
        case 'cooling':
477
            $limit = $current * 1.05;
478
            break;
479
    }//end switch
480
481
    if (is_numeric($limit)) {
482
        return round($limit, 11);
483
    }
484
485
    return $limit;
486
}
487
488
//end sensor_limit()
489
490
function check_valid_sensors($device, $class, $valid, $poller_type = 'snmp')
491
{
492
    $entries = dbFetchRows('SELECT * FROM sensors AS S, devices AS D WHERE S.sensor_class=? AND S.device_id = D.device_id AND D.device_id = ? AND S.poller_type = ?', array($class, $device['device_id'], $poller_type));
493
494
    if (count($entries)) {
495
        foreach ($entries as $entry) {
496
            $index = $entry['sensor_index'];
497
            $type = $entry['sensor_type'];
498
            $class = $entry['sensor_class'];
499
            d_echo($index . ' -> ' . $type . "\n");
500
501
            if (!$valid[$class][$type][$index]) {
502
                echo '-';
503
                if ($class == 'state') {
504
                    dbDelete('sensors_to_state_indexes', '`sensor_id` =  ?', array($entry['sensor_id']));
505
                }
506
                dbDelete('sensors', '`sensor_id` =  ?', array($entry['sensor_id']));
507
                log_event('Sensor Deleted: ' . $entry['sensor_class'] . ' ' . $entry['sensor_type'] . ' ' . $entry['sensor_index'] . ' ' . $entry['sensor_descr'], $device, 'sensor', 3, $sensor_id);
508
            }
509
510
            unset($oid);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $oid seems to be never defined.
Loading history...
511
            unset($type);
512
        }
513
    }
514
}
515
516
//end check_valid_sensors()
517
518
function discover_juniAtmVp(&$valid, $device, $port_id, $vp_id, $vp_descr)
519
{
520
    d_echo("Discover Juniper ATM VP: $port_id, $vp_id, $vp_descr\n");
521
522
    if (dbFetchCell('SELECT COUNT(*) FROM `juniAtmVp` WHERE `port_id` = ? AND `vp_id` = ?', array($port_id, $vp_id)) == '0') {
523
        $inserted = dbInsert(array('port_id' => $port_id, 'vp_id' => $vp_id, 'vp_descr' => $vp_descr), 'juniAtmVp');
524
        d_echo("( $inserted inserted )\n");
525
526
        // FIXME vv no $device!
527
        log_event('Juniper ATM VP Added: port ' . $port_id . ' vp ' . $vp_id . ' descr' . $vp_descr, $device, 'juniAtmVp', 3, $inserted);
528
    } else {
529
        echo '.';
530
    }
531
532
    $valid[$port_id][$vp_id] = 1;
533
}
534
535
//end discover_juniAtmVp()
536
537
function discover_link($local_port_id, $protocol, $remote_port_id, $remote_hostname, $remote_port, $remote_platform, $remote_version, $local_device_id, $remote_device_id)
538
{
539
    global $link_exists;
540
541
    d_echo("Discover link: $local_port_id, $protocol, $remote_port_id, $remote_hostname, $remote_port, $remote_platform, $remote_version, $remote_device_id\n");
542
543
    if (dbFetchCell(
544
        'SELECT COUNT(*) FROM `links` WHERE `remote_hostname` = ? AND `local_port_id` = ? AND `protocol` = ? AND `remote_port` = ?',
545
        array(
546
                $remote_hostname,
547
                $local_port_id,
548
                $protocol,
549
                $remote_port,
550
                    )
551
    ) == '0') {
552
        $insert_data = array(
553
            'local_port_id' => $local_port_id,
554
            'local_device_id' => $local_device_id,
555
            'protocol' => $protocol,
556
            'remote_hostname' => $remote_hostname,
557
            'remote_device_id' => (int)$remote_device_id,
558
            'remote_port' => $remote_port,
559
            'remote_platform' => $remote_platform,
560
            'remote_version' => $remote_version,
561
        );
562
563
        if (!empty($remote_port_id)) {
564
            $insert_data['remote_port_id'] = (int)$remote_port_id;
565
        }
566
567
        $inserted = dbInsert($insert_data, 'links');
568
569
        echo '+';
570
        d_echo("( $inserted inserted )");
571
    } else {
572
        $sql = 'SELECT `id`,`local_device_id`,`remote_platform`,`remote_version`,`remote_device_id`,`remote_port_id` FROM `links`';
573
        $sql .= ' WHERE `remote_hostname` = ? AND `local_port_id` = ? AND `protocol` = ? AND `remote_port` = ?';
574
        $data = dbFetchRow($sql, array($remote_hostname, $local_port_id, $protocol, $remote_port));
575
576
        $update_data = array(
577
            'local_device_id' => $local_device_id,
578
            'remote_platform' => $remote_platform,
579
            'remote_version' => $remote_version,
580
            'remote_device_id' => (int)$remote_device_id,
581
            'remote_port_id' => (int)$remote_port_id
582
        );
583
584
        $id = $data['id'];
585
        unset($data['id']);
586
        if ($data == $update_data) {
587
            echo '.';
588
        } else {
589
            $updated = dbUpdate($update_data, 'links', '`id` = ?', array($id));
590
            echo 'U';
591
            d_echo("( $updated updated )");
592
        }//end if
593
    }//end if
594
    $link_exists[$local_port_id][$remote_hostname][$remote_port] = 1;
595
}
596
597
//end discover_link()
598
599
function discover_storage(&$valid, $device, $index, $type, $mib, $descr, $size, $units, $used = null)
600
{
601
    if (ignore_storage($device['os'], $descr)) {
602
        return;
603
    }
604
    d_echo("Discover Storage: $index, $type, $mib, $descr, $size, $units, $used\n");
605
606
    if ($descr && $size > '0') {
607
        $storage = dbFetchRow('SELECT * FROM `storage` WHERE `storage_index` = ? AND `device_id` = ? AND `storage_mib` = ?', array($index, $device['device_id'], $mib));
608
        if ($storage === false || !count($storage)) {
609
            if (Config::getOsSetting($device['os'], 'storage_perc_warn')) {
610
                $perc_warn = Config::getOsSetting($device['os'], 'storage_perc_warn');
611
            } else {
612
                $perc_warn = Config::get('storage_perc_warn', 60);
613
            }
614
615
            $insert = dbInsert(
0 ignored issues
show
The assignment to $insert is dead and can be removed.
Loading history...
616
                array(
617
                    'device_id' => $device['device_id'],
618
                    'storage_descr' => $descr,
619
                    'storage_index' => $index,
620
                    'storage_mib' => $mib,
621
                    'storage_type' => $type,
622
                    'storage_units' => $units,
623
                    'storage_size' => $size,
624
                    'storage_used' => $used,
625
                    'storage_perc_warn' => $perc_warn,
626
                ),
627
                'storage'
628
            );
629
630
            echo '+';
631
        } else {
632
            $updated = dbUpdate(array('storage_descr' => $descr, 'storage_type' => $type, 'storage_units' => $units, 'storage_size' => $size), 'storage', '`device_id` = ? AND `storage_index` = ? AND `storage_mib` = ?', array($device['device_id'], $index, $mib));
633
            if ($updated) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $updated of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
634
                echo 'U';
635
            } else {
636
                echo '.';
637
            }
638
        }//end if
639
640
        $valid[$mib][$index] = 1;
641
    }//end if
642
}
643
644
//end discover_storage()
645
646
function discover_processor(&$valid, $device, $oid, $index, $type, $descr, $precision = '1', $current = null, $entPhysicalIndex = null, $hrDeviceIndex = null)
647
{
648
    d_echo("Discover Processor: $oid, $index, $type, $descr, $precision, $current, $entPhysicalIndex, $hrDeviceIndex\n");
649
650
    if ($descr) {
651
        $descr = trim(str_replace('"', '', $descr));
652
        if (dbFetchCell('SELECT COUNT(processor_id) FROM `processors` WHERE `processor_index` = ? AND `device_id` = ? AND `processor_type` = ?', array($index, $device['device_id'], $type)) == '0') {
653
            $insert_data = array(
654
                'device_id' => $device['device_id'],
655
                'processor_descr' => $descr,
656
                'processor_index' => $index,
657
                'processor_oid' => $oid,
658
                'processor_usage' => $current,
659
                'processor_type' => $type,
660
                'processor_precision' => $precision,
661
            );
662
663
            $insert_data['hrDeviceIndex'] = (int)$hrDeviceIndex;
664
            $insert_data['entPhysicalIndex'] = (int)$entPhysicalIndex;
665
666
            $inserted = dbInsert($insert_data, 'processors');
667
            echo '+';
668
            log_event('Processor added: type ' . $type . ' index ' . $index . ' descr ' . $descr, $device, 'processor', 3, $inserted);
669
        } else {
670
            echo '.';
671
            $update_data = array(
672
                'processor_descr' => $descr,
673
                'processor_oid' => $oid,
674
                'processor_usage' => $current,
675
                'processor_precision' => $precision,
676
            );
677
            dbUpdate($update_data, 'processors', '`device_id`=? AND `processor_index`=? AND `processor_type`=?', array($device['device_id'], $index, $type));
678
        }//end if
679
        $valid[$type][$index] = 1;
680
    }//end if
681
}
682
683
//end discover_processor()
684
685
function discover_mempool(&$valid, $device, $index, $type, $descr, $precision = '1', $entPhysicalIndex = null, $hrDeviceIndex = null)
686
{
687
688
    $descr = substr($descr, 0, 64);
689
690
    d_echo("Discover Mempool: $index, $type, $descr, $precision, $entPhysicalIndex, $hrDeviceIndex\n");
691
692
    // FIXME implement the mempool_perc, mempool_used, etc.
693
    if ($descr) {
694
        if (dbFetchCell('SELECT COUNT(mempool_id) FROM `mempools` WHERE `mempool_index` = ? AND `device_id` = ? AND `mempool_type` = ?', array($index, $device['device_id'], $type)) == '0') {
695
            $insert_data = array(
696
                'device_id' => $device['device_id'],
697
                'mempool_descr' => $descr,
698
                'mempool_index' => $index,
699
                'mempool_type' => $type,
700
                'mempool_precision' => $precision,
701
                'mempool_perc' => 0,
702
                'mempool_used' => 0,
703
                'mempool_free' => 0,
704
                'mempool_total' => 0,
705
            );
706
707
            if (is_numeric($entPhysicalIndex)) {
708
                $insert_data['entPhysicalIndex'] = $entPhysicalIndex;
709
            }
710
711
            if (is_numeric($hrDeviceIndex)) {
712
                $insert_data['hrDeviceIndex'] = $hrDeviceIndex;
713
            }
714
715
            $inserted = dbInsert($insert_data, 'mempools');
716
            echo '+';
717
            log_event('Memory pool added: type ' . $type . ' index ' . $index . ' descr ' . $descr, $device, 'mempool', 3, $inserted);
718
        } else {
719
            echo '.';
720
            $update_data = array(
721
                'mempool_descr' => $descr,
722
            );
723
724
            if (is_numeric($entPhysicalIndex)) {
725
                $update_data['entPhysicalIndex'] = $entPhysicalIndex;
726
            }
727
728
            if (is_numeric($hrDeviceIndex)) {
729
                $update_data['hrDeviceIndex'] = $hrDeviceIndex;
730
            }
731
732
            dbUpdate($update_data, 'mempools', 'device_id=? AND mempool_index=? AND mempool_type=?', array($device['device_id'], $index, $type));
733
        }//end if
734
        $valid[$type][$index] = 1;
735
    }//end if
736
}
737
738
//end discover_mempool()
739
740
function discover_toner(&$valid, $device, $oid, $index, $type, $descr, $capacity_oid = null, $capacity = null, $current = null)
741
{
742
    d_echo("Discover Toner: $oid, $index, $type, $descr, $capacity_oid, $capacity, $current\n");
743
744
    if (dbFetchCell('SELECT COUNT(toner_id) FROM `toner` WHERE device_id = ? AND toner_type = ? AND `toner_index` = ? AND `toner_oid` =?', array($device['device_id'], $type, $index, $oid)) == '0') {
745
        $inserted = dbInsert(array('device_id' => $device['device_id'], 'toner_oid' => $oid, 'toner_capacity_oid' => $capacity_oid, 'toner_index' => $index, 'toner_type' => $type, 'toner_descr' => $descr, 'toner_capacity' => $capacity, 'toner_current' => $current), 'toner');
746
        echo '+';
747
        log_event('Toner added: type ' . $type . ' index ' . $index . ' descr ' . $descr, $device, 'toner', 3, $inserted);
748
    } else {
749
        $toner_entry = dbFetchRow('SELECT * FROM `toner` WHERE `device_id` = ? AND `toner_type` = ? AND `toner_index` =?', array($device['device_id'], $type, $index));
750
        if ($oid == $toner_entry['toner_oid'] && $descr == $toner_entry['toner_descr'] && $capacity == $toner_entry['toner_capacity'] && $capacity_oid == $toner_entry['toner_capacity_oid']) {
751
            echo '.';
752
        } else {
753
            dbUpdate(array('toner_descr' => $descr, 'toner_oid' => $oid, 'toner_capacity_oid' => $capacity_oid, 'toner_capacity' => $capacity), 'toner', 'device_id=? AND toner_type=? AND `toner_index`=?', array($device['device_id'], $type, $index));
754
            echo 'U';
755
        }
756
    }
757
758
    $valid[$type][$oid] = 1;
759
}
760
761
//end discover_toner()
762
763
function discover_entity_physical(&$valid, $device, $entPhysicalIndex, $entPhysicalDescr, $entPhysicalClass, $entPhysicalName, $entPhysicalModelName, $entPhysicalSerialNum, $entPhysicalContainedIn, $entPhysicalMfgName, $entPhysicalParentRelPos, $entPhysicalVendorType, $entPhysicalHardwareRev, $entPhysicalFirmwareRev, $entPhysicalSoftwareRev, $entPhysicalIsFRU, $entPhysicalAlias, $entPhysicalAssetID, $ifIndex)
764
{
765
    d_echo("Discover Inventory Item: $entPhysicalIndex, $entPhysicalDescr, $entPhysicalClass, $entPhysicalName, $entPhysicalModelName, $entPhysicalSerialNum, $entPhysicalContainedIn, $entPhysicalMfgName, $entPhysicalParentRelPos, $entPhysicalVendorType, $entPhysicalHardwareRev, $entPhysicalFirmwareRev, $entPhysicalSoftwareRev, $entPhysicalIsFRU, $entPhysicalAlias, $entPhysicalAssetID, $ifIndex\n");
766
767
    if ($entPhysicalDescr || $entPhysicalName) {
768
        if (dbFetchCell('SELECT COUNT(entPhysical_id) FROM `entPhysical` WHERE `device_id` = ? AND `entPhysicalIndex` = ?', array($device['device_id'], $entPhysicalIndex)) == '0') {
769
            $insert_data = array(
770
                'device_id'               => $device['device_id'],
771
                'entPhysicalIndex'        => $entPhysicalIndex,
772
                'entPhysicalDescr'        => $entPhysicalDescr,
773
                'entPhysicalClass'        => $entPhysicalClass,
774
                'entPhysicalName'         => $entPhysicalName,
775
                'entPhysicalModelName'    => $entPhysicalModelName,
776
                'entPhysicalSerialNum'    => $entPhysicalSerialNum,
777
                'entPhysicalContainedIn'  => $entPhysicalContainedIn,
778
                'entPhysicalMfgName'      => $entPhysicalMfgName,
779
                'entPhysicalParentRelPos' => $entPhysicalParentRelPos,
780
                'entPhysicalVendorType'   => $entPhysicalVendorType,
781
                'entPhysicalHardwareRev'  => $entPhysicalHardwareRev,
782
                'entPhysicalFirmwareRev'  => $entPhysicalFirmwareRev,
783
                'entPhysicalSoftwareRev'  => $entPhysicalSoftwareRev,
784
                'entPhysicalIsFRU'        => $entPhysicalIsFRU,
785
                'entPhysicalAlias'        => $entPhysicalAlias,
786
                'entPhysicalAssetID'      => $entPhysicalAssetID,
787
            );
788
            if (!empty($ifIndex)) {
789
                $insert_data['ifIndex'] = $ifIndex;
790
            }
791
792
            $inserted = dbInsert($insert_data, 'entPhysical');
793
            echo '+';
794
            log_event('Inventory Item added: index ' . $entPhysicalIndex . ' descr ' . $entPhysicalDescr, $device, 'entity-physical', 3, $inserted);
795
        } else {
796
            echo '.';
797
            $update_data = array(
798
                'entPhysicalIndex'        => $entPhysicalIndex,
799
                'entPhysicalDescr'        => $entPhysicalDescr,
800
                'entPhysicalClass'        => $entPhysicalClass,
801
                'entPhysicalName'         => $entPhysicalName,
802
                'entPhysicalModelName'    => $entPhysicalModelName,
803
                'entPhysicalSerialNum'    => $entPhysicalSerialNum,
804
                'entPhysicalContainedIn'  => $entPhysicalContainedIn,
805
                'entPhysicalMfgName'      => $entPhysicalMfgName,
806
                'entPhysicalParentRelPos' => $entPhysicalParentRelPos,
807
                'entPhysicalVendorType'   => $entPhysicalVendorType,
808
                'entPhysicalHardwareRev'  => $entPhysicalHardwareRev,
809
                'entPhysicalFirmwareRev'  => $entPhysicalFirmwareRev,
810
                'entPhysicalSoftwareRev'  => $entPhysicalSoftwareRev,
811
                'entPhysicalIsFRU'        => $entPhysicalIsFRU,
812
                'entPhysicalAlias'        => $entPhysicalAlias,
813
                'entPhysicalAssetID'      => $entPhysicalAssetID,
814
            );
815
            dbUpdate($update_data, 'entPhysical', '`device_id`=? AND `entPhysicalIndex`=?', array($device['device_id'], $entPhysicalIndex));
816
        }//end if
817
        $valid[$entPhysicalIndex] = 1;
818
    }//end if
819
}
820
821
//end discover_entity_physical()
822
823
function discover_process_ipv6(&$valid, $ifIndex, $ipv6_address, $ipv6_prefixlen, $ipv6_origin, $context_name = '')
824
{
825
    global $device;
826
827
    if (!IPv6::isValid($ipv6_address, true)) {
828
        // ignore link-locals (coming from IPV6-MIB)
829
        return;
830
    }
831
832
    $ipv6 = new IPv6($ipv6_address);
833
    $ipv6_network = $ipv6->getNetwork($ipv6_prefixlen);
834
    $ipv6_compressed = $ipv6->compressed();
835
836
    if (dbFetchCell('SELECT COUNT(*) FROM `ports` WHERE device_id = ? AND `ifIndex` = ?', array($device['device_id'], $ifIndex)) != '0' && $ipv6_prefixlen > '0' && $ipv6_prefixlen < '129' && $ipv6_compressed != '::1') {
837
        $port_id = dbFetchCell('SELECT port_id FROM `ports` WHERE device_id = ? AND ifIndex = ?', array($device['device_id'], $ifIndex));
838
839
        if (is_numeric($port_id)) {
840
            if (dbFetchCell('SELECT COUNT(*) FROM `ipv6_networks` WHERE `ipv6_network` = ?', array($ipv6_network)) < '1') {
841
                dbInsert(array('ipv6_network' => $ipv6_network, 'context_name' => $context_name), 'ipv6_networks');
842
                echo 'N';
843
            } else {
844
                //Update Context
845
                dbUpdate(array('context_name' => $device['context_name']), 'ipv6_networks', '`ipv6_network` = ?', array($ipv6_network));
846
                echo 'n';
847
            }
848
849
            $ipv6_network_id = dbFetchCell('SELECT `ipv6_network_id` FROM `ipv6_networks` WHERE `ipv6_network` = ? AND `context_name` = ?', array($ipv6_network, $context_name));
850
851
            if (dbFetchCell('SELECT COUNT(*) FROM `ipv6_addresses` WHERE `ipv6_address` = ? AND `ipv6_prefixlen` = ? AND `port_id` = ?', array($ipv6_address, $ipv6_prefixlen, $port_id)) == '0') {
852
                dbInsert(array(
853
                    'ipv6_address' => $ipv6_address,
854
                    'ipv6_compressed' => $ipv6_compressed,
855
                    'ipv6_prefixlen' => $ipv6_prefixlen,
856
                    'ipv6_origin' => $ipv6_origin,
857
                    'ipv6_network_id' => $ipv6_network_id,
858
                    'port_id' => $port_id,
859
                    'context_name' => $context_name
860
                ), 'ipv6_addresses');
861
                echo '+';
862
            } else {
863
                //Update Context
864
                dbUpdate(array('context_name' => $device['context_name']), 'ipv6_addresses', '`ipv6_address` = ? AND `ipv6_prefixlen` = ? AND `port_id` = ?', array($ipv6_address, $ipv6_prefixlen, $port_id));
865
                echo '.';
866
            }
867
868
            $full_address = "$ipv6_address/$ipv6_prefixlen";
869
            $valid_address = $full_address . '-' . $port_id;
870
            $valid['ipv6'][$valid_address] = 1;
871
        }
872
    }//end if
873
}//end discover_process_ipv6()
874
875
/*
876
 * Check entity sensors to be excluded
877
 *
878
 * @param string value to check
879
 * @param array device
880
 *
881
 * @return bool true if sensor is valid
882
 *              false if sensor is invalid
883
*/
884
function check_entity_sensor($string, $device)
885
{
886
    $fringe = array_merge(Config::get('bad_entity_sensor_regex', array()), Config::getOsSetting($device['os'], 'bad_entity_sensor_regex', array()));
887
888
    foreach ($fringe as $bad) {
889
        if (preg_match($bad . "i", $string)) {
890
            d_echo("Ignored entity sensor: $bad : $string");
891
            return false;
892
        }
893
    }
894
895
    return true;
896
}
897
898
/**
899
 * Get the device divisor, account for device specific quirks
900
 * The default divisor is 10
901
 *
902
 * @param array $device device array
903
 * @param string $os_version firmware version poweralert quirks
904
 * @param string $sensor_type the type of this sensor
905
 * @param string $oid the OID of this sensor
906
 * @return int
907
 */
908
function get_device_divisor($device, $os_version, $sensor_type, $oid)
909
{
910
    if ($device['os'] == 'poweralert') {
911
        if ($sensor_type == 'current' || $sensor_type == 'frequency') {
912
            if (version_compare($os_version, '12.06.0068', '>=')) {
913
                return 10;
914
            } elseif (version_compare($os_version, '12.04.0055', '=')) {
915
                return 10;
916
            } elseif (version_compare($os_version, '12.04.0056', '>=')) {
917
                return 1;
918
            }
919
        } elseif ($sensor_type == 'load') {
920
            if (version_compare($os_version, '12.06.0064', '=')) {
921
                return 10;
922
            } else {
923
                return 1;
924
            }
925
        }
926
    } elseif ($device['os'] == 'huaweiups') {
927
        if ($sensor_type == 'frequency') {
928
            return 100;
929
        }
930
    } elseif ($device['os'] == 'hpe-rtups') {
931
        if ($sensor_type == 'voltage' && !starts_with($oid, '.1.3.6.1.2.1.33.1.2.5.') && !starts_with($oid, '.1.3.6.1.2.1.33.1.3.3.1.3')) {
932
            return 1;
933
        }
934
    } elseif ($device['os'] == 'apc-mgeups') {
935
        if ($sensor_type == 'voltage') {
936
            return 10;
937
        }
938
    }
939
940
    // UPS-MIB Defaults
941
942
    if ($sensor_type == 'load') {
943
        return 1;
944
    }
945
946
    if ($sensor_type == 'voltage' && !starts_with($oid, '.1.3.6.1.2.1.33.1.2.5.')) {
947
        return 1;
948
    }
949
950
    if ($sensor_type == 'runtime') {
951
        if (starts_with($oid, '.1.3.6.1.2.1.33.1.2.2.')) {
952
            return 60;
953
        }
954
955
        if (starts_with($oid, '.1.3.6.1.2.1.33.1.2.3.')) {
956
            if ($device['os'] == 'routeros') {
957
                return 60;
958
            } else {
959
                return 1;
960
            }
961
        }
962
    }
963
964
    return 10;
965
}
966
967
/**
968
 * @param int $raw_capacity The value return from snmp
969
 * @return int normalized capacity value
970
 */
971
function get_toner_capacity($raw_capacity)
972
{
973
    // unknown or unrestricted capacity, assume 100
974
    if (empty($raw_capacity) || $raw_capacity < 0) {
975
        return 100;
976
    }
977
    return $raw_capacity;
978
}
979
980
/**
981
 * Should we ignore this storage device based on teh description? (usually the mount path or drive)
982
 *
983
 * @param string $os The OS of the device
984
 * @param string $descr The description of the storage
985
 * @return boolean
986
 */
987
function ignore_storage($os, $descr)
988
{
989
    foreach (Config::getOsSetting($os, 'ignore_mount') as $im) {
990
        if ($im == $descr) {
991
            d_echo("ignored $descr (matched: $im)\n");
992
            return true;
993
        }
994
    }
995
996
    foreach (Config::getOsSetting($os, 'ignore_mount_string') as $ims) {
997
        if (str_contains($descr, $ims)) {
998
            d_echo("ignored $descr (matched: $ims)\n");
999
            return true;
1000
        }
1001
    }
1002
1003
    foreach (Config::getOsSetting($os, 'ignore_mount_regexp') as $imr) {
1004
        if (preg_match($imr, $descr)) {
1005
            d_echo("ignored $descr (matched: $imr)\n");
1006
            return true;
1007
        }
1008
    }
1009
1010
    return false;
1011
}
1012
1013
/**
1014
 * @param $valid
1015
 * @param $device
1016
 * @param $sensor_type
1017
 * @param $pre_cache
1018
 */
1019
function discovery_process(&$valid, $device, $sensor_type, $pre_cache)
1020
{
1021
    if ($device['dynamic_discovery']['modules']['sensors'][$sensor_type]) {
1022
        $sensor_options = array();
1023
        if (isset($device['dynamic_discovery']['modules']['sensors'][$sensor_type]['options'])) {
1024
            $sensor_options = $device['dynamic_discovery']['modules']['sensors'][$sensor_type]['options'];
1025
        }
1026
1027
        d_echo("Dynamic Discovery ($sensor_type): ");
1028
        d_echo($device['dynamic_discovery']['modules']['sensors'][$sensor_type]);
1029
1030
        foreach ($device['dynamic_discovery']['modules']['sensors'][$sensor_type]['data'] as $data) {
1031
            $tmp_name = $data['oid'];
1032
            $raw_data = (array)$pre_cache[$tmp_name];
1033
1034
            d_echo("Data $tmp_name: ");
1035
            d_echo($raw_data);
1036
1037
            foreach ($raw_data as $index => $snmp_data) {
1038
                $user_function = null;
1039
                if (isset($data['user_func'])) {
1040
                    $user_function = $data['user_func'];
1041
                }
1042
                // get the value for this sensor, check 'value' and 'oid', if state string, translate to a number
1043
                $data_name = isset($data['value']) ? $data['value'] : $data['oid'];  // fallback to oid if value is not set
1044
1045
                $snmp_value = $snmp_data[$data_name];
1046
                if (!is_numeric($snmp_value)) {
1047
                    if ($sensor_type === 'temperature') {
1048
                        // For temp sensors, try and detect fahrenheit values
1049
                        if (ends_with($snmp_value, array('f', 'F'))) {
1050
                            $user_function = 'fahrenheit_to_celsius';
1051
                        }
1052
                    }
1053
                    preg_match('/-?\d*\.?\d+/', $snmp_value, $temp_response);
1054
                    if (!empty($temp_response[0])) {
1055
                        $snmp_value = $temp_response[0];
1056
                    }
1057
                }
1058
1059
                if (is_numeric($snmp_value)) {
1060
                    $value = $snmp_value;
1061
                } elseif ($sensor_type === 'state') {
1062
                    // translate string states to values (poller does this as well)
1063
                    $states = array_column($data['states'], 'value', 'descr');
1064
                    $value = isset($states[$snmp_value]) ? $states[$snmp_value] : false;
1065
                } else {
1066
                    $value = false;
1067
                }
1068
1069
                d_echo("Final sensor value: $value\n");
1070
1071
                if (YamlDiscovery::canSkipItem($value, $index, $data, $sensor_options, $pre_cache) === false && is_numeric($value)) {
1072
                    $oid = str_replace('{{ $index }}', $index, $data['num_oid']);
1073
1074
                    // process the description
1075
                    $descr = YamlDiscovery::replaceValues('descr', $index, null, $data, $pre_cache);
1076
1077
                    // process the group
1078
                    $group = YamlDiscovery::replaceValues('group', $index, null, $data, $pre_cache);
1079
1080
                    $divisor = $data['divisor'] ?: ($sensor_options['divisor'] ?: 1);
1081
                    $multiplier = $data['multiplier'] ?: ($sensor_options['multiplier'] ?: 1);
1082
1083
                    $limits = ['low_limit', 'low_warn_limit', 'warn_limit', 'high_limit'];
1084
                    foreach ($limits as $limit) {
1085
                        if (is_numeric($data[$limit])) {
1086
                            $$limit = $data[$limit];
1087
                        } else {
1088
                            $$limit = dynamic_discovery_get_value($limit, $index, $data, $pre_cache, 'null');
1089
                            if (is_numeric($$limit)) {
1090
                                $$limit = ($$limit / $divisor) * $multiplier;
1091
                            }
1092
                        }
1093
                    }
1094
1095
                    echo "Cur $value, Low: $low_limit, Low Warn: $low_warn_limit, Warn: $warn_limit, High: $high_limit".PHP_EOL;
1096
                    $entPhysicalIndex = YamlDiscovery::replaceValues('entPhysicalIndex', $index, null, $data, $pre_cache) ?: null;
1097
                    $entPhysicalIndex_measured = isset($data['entPhysicalIndex_measured']) ? $data['entPhysicalIndex_measured'] : null;
1098
1099
                    $sensor_name = $device['os'];
1100
1101
                    if ($sensor_type === 'state') {
1102
                        $sensor_name = $data['state_name'] ?: $data['oid'];
1103
                        create_state_index($sensor_name, $data['states']);
1104
                    } else {
1105
                        // We default to 1 for both divisors / multipliers so it should be safe to do the calculation using both.
1106
                        $value = ($value / $divisor) * $multiplier;
1107
                    }
1108
1109
                    //user_func must be applied after divisor/multiplier
1110
                    if (isset($user_function) && is_callable($user_function)) {
1111
                        $value = $user_function($value);
1112
                    }
1113
1114
                    $uindex = str_replace('{{ $index }}', $index, isset($data['index']) ? $data['index'] : $index);
1115
                    discover_sensor($valid['sensor'], $sensor_type, $device, $oid, $uindex, $sensor_name, $descr, $divisor, $multiplier, $low_limit, $low_warn_limit, $warn_limit, $high_limit, $value, 'snmp', $entPhysicalIndex, $entPhysicalIndex_measured, $user_function, $group);
1116
1117
                    if ($sensor_type === 'state') {
1118
                        create_sensor_to_state_index($device, $sensor_name, $uindex);
1119
                    }
1120
                }
1121
            }
1122
        }
1123
    }
1124
}
1125
1126
/**
1127
 * Helper function for dynamic discovery to search for data from pre_cached snmp data
1128
 *
1129
 * @param string $name The name of the field from the discovery data or just an oid
1130
 * @param int $index The index of the current sensor
1131
 * @param array $discovery_data The discovery data for the current sensor
1132
 * @param array $pre_cache all pre-cached snmp data
1133
 * @param mixed $default The default value to return if data is not found
1134
 * @return mixed
1135
 */
1136
function dynamic_discovery_get_value($name, $index, $discovery_data, $pre_cache, $default = null)
1137
{
1138
    if (isset($discovery_data[$name])) {
1139
        $name = $discovery_data[$name];
1140
    }
1141
1142
    if (isset($pre_cache[$discovery_data['oid']][$index][$name])) {
1143
        return $pre_cache[$discovery_data['oid']][$index][$name];
1144
    }
1145
1146
    if (isset($pre_cache[$name])) {
1147
        if (is_array($pre_cache[$name])) {
1148
            if (isset($pre_cache[$name][$index][$name])) {
1149
                return $pre_cache[$name][$index][$name];
1150
            } elseif (isset($pre_cache[$index][$name])) {
1151
                return $pre_cache[$index][$name];
1152
            } elseif (count($pre_cache[$name]) === 1) {
1153
                return current($pre_cache[$name]);
1154
            }
1155
        } else {
1156
            return $pre_cache[$name];
1157
        }
1158
    }
1159
1160
    return $default;
1161
}
1162
1163
/**
1164
 * @param $types
1165
 * @param $device
1166
 * @param array $pre_cache
1167
 */
1168
function sensors($types, $device, $valid, $pre_cache = array())
1169
{
1170
    foreach ((array)$types as $sensor_type) {
1171
        echo ucfirst($sensor_type) . ': ';
1172
        $dir = Config::get('install_dir') . '/includes/discovery/sensors/' . $sensor_type .'/';
1173
1174
        if (is_file($dir . $device['os_group'] . '.inc.php')) {
1175
            include $dir . $device['os_group'] . '.inc.php';
1176
        }
1177
        if (is_file($dir . $device['os'] . '.inc.php')) {
1178
            include $dir . $device['os'] . '.inc.php';
1179
        }
1180
        if (Config::getOsSetting($device['os'], 'rfc1628_compat', false)) {
1181
            if (is_file($dir  . '/rfc1628.inc.php')) {
1182
                include $dir . '/rfc1628.inc.php';
1183
            }
1184
        }
1185
        discovery_process($valid, $device, $sensor_type, $pre_cache);
1186
        d_echo($valid['sensor'][$sensor_type]);
1187
        check_valid_sensors($device, $sensor_type, $valid['sensor']);
1188
        echo "\n";
1189
    }
1190
}
1191
1192
function build_bgp_peers($device, $data, $peer2)
1193
{
1194
    d_echo("Peers : $data\n");
1195
    $remove = array(
1196
        'ARISTA-BGP4V2-MIB::aristaBgp4V2PeerRemoteAs.1.',
1197
        'CISCO-BGP4-MIB::cbgpPeer2RemoteAs.',
1198
        'BGP4-MIB::bgpPeerRemoteAs.',
1199
        'HUAWEI-BGP-VPN-MIB::hwBgpPeerRemoteAs.',
1200
        '.1.3.6.1.4.1.2636.5.1.1.2.1.1.1.13.',
1201
    );
1202
    $peers = trim(str_replace($remove, '', $data));
1203
1204
    $peerlist = array();
1205
    $ver = '';
1206
    foreach (explode("\n", $peers) as $peer) {
1207
        if ($peer2 === true) {
1208
            list($ver, $peer) = explode('.', $peer, 2);
1209
        }
1210
        list($peer_ip, $peer_as) = explode(' ', $peer);
1211
        if ($device['os'] === 'junos') {
1212
            $ver = '';
1213
            $octets = count(explode(".", $peer_ip));
1214
            if ($octets > 11) {
1215
                // ipv6
1216
                $peer_ip = (string)IP::parse(snmp2ipv6($peer_ip), true);
1217
            } else {
1218
                // ipv4
1219
                $peer_ip = implode('.', array_slice(explode('.', $peer_ip), -4));
1220
            }
1221
        } else {
1222
            if (strstr($peer_ip, ':')) {
1223
                $peer_ip_snmp = preg_replace('/:/', ' ', $peer_ip);
1224
                $peer_ip = preg_replace('/(\S+\s+\S+)\s/', '$1:', $peer_ip_snmp);
1225
                $peer_ip = str_replace('"', '', str_replace(' ', '', $peer_ip));
1226
            }
1227
        }
1228
        if ($peer && $peer_ip != '0.0.0.0') {
1229
            d_echo("Found peer $peer_ip (AS$peer_as)\n");
1230
            $peerlist[] = array(
1231
                'ip'  => $peer_ip,
1232
                'as'  => $peer_as,
1233
                'ver' => $ver,
1234
            );
1235
        }
1236
    }
1237
    return $peerlist;
1238
}
1239
1240
function build_cbgp_peers($device, $peer, $af_data, $peer2)
1241
{
1242
1243
    d_echo('afi data :: ');
1244
    d_echo($af_data);
1245
1246
    $af_list = array();
1247
    foreach ($af_data as $k => $v) {
1248
        if ($peer2 === true) {
1249
            list(,$k) = explode('.', $k, 2);
1250
        }
1251
1252
        d_echo("AFISAFI = $k\n");
1253
1254
        $afisafi_tmp = explode('.', $k);
1255
        if ($device['os_group'] === 'vrp') {
1256
            array_shift($afisafi_tmp); //remove 1st value, always 0 so far
1257
            $afi         = array_shift($afisafi_tmp);
1258
            $safi        = array_shift($afisafi_tmp);
1259
            array_shift($afisafi_tmp); //type, always ipv4 so far
1260
            $bgp_ip      = implode('.', $afisafi_tmp);
1261
        } else {
1262
            $safi        = array_pop($afisafi_tmp);
1263
            $afi         = array_pop($afisafi_tmp);
1264
            $bgp_ip      = str_replace(".$afi.$safi", '', $k);
1265
            if ($device['os_group'] === 'arista') {
1266
                $bgp_ip      = str_replace("$afi.", '', $bgp_ip);
1267
            }
1268
        }
1269
        $bgp_ip      = preg_replace('/:/', ' ', $bgp_ip);
1270
        $bgp_ip      = preg_replace('/(\S+\s+\S+)\s/', '$1:', $bgp_ip);
1271
        $bgp_ip      = str_replace('"', '', str_replace(' ', '', $bgp_ip));
1272
1273
        if ($afi && $safi && $bgp_ip == $peer['ip']) {
1274
            $af_list[$bgp_ip][$afi][$safi] = 1;
1275
            add_cbgp_peer($device, $peer, $afi, $safi);
1276
        }
1277
    }
1278
    return $af_list;
1279
}
1280
1281
function add_bgp_peer($device, $peer)
1282
{
1283
    if (dbFetchCell('SELECT COUNT(*) from `bgpPeers` WHERE device_id = ? AND bgpPeerIdentifier = ?', array($device['device_id'], $peer['ip'])) < '1') {
1284
        $bgpPeers = array(
1285
            'device_id' => $device['device_id'],
1286
            'bgpPeerIdentifier' => $peer['ip'],
1287
            'bgpPeerRemoteAs' => $peer['as'],
1288
            'context_name' => $device['context_name'],
1289
            'astext' => $peer['astext'],
1290
            'bgpPeerState' => 'idle',
1291
            'bgpPeerAdminStatus' => 'stop',
1292
            'bgpLocalAddr' => '0.0.0.0',
1293
            'bgpPeerRemoteAddr' => '0.0.0.0',
1294
            'bgpPeerInUpdates' => 0,
1295
            'bgpPeerOutUpdates' => 0,
1296
            'bgpPeerInTotalMessages' => 0,
1297
            'bgpPeerOutTotalMessages' => 0,
1298
            'bgpPeerFsmEstablishedTime' => 0,
1299
            'bgpPeerInUpdateElapsedTime' => 0,
1300
        );
1301
        dbInsert($bgpPeers, 'bgpPeers');
1302
        if (Config::get('autodiscovery.bgp')) {
1303
            $name = gethostbyaddr($peer['ip']);
1304
            discover_new_device($name, $device, 'BGP');
1305
        }
1306
        echo '+';
1307
    } else {
1308
        dbUpdate(array('bgpPeerRemoteAs' => $peer['as'], 'astext' => $peer['astext']), 'bgpPeers', 'device_id=? AND bgpPeerIdentifier=?', array($device['device_id'], $peer['ip']));
1309
        echo '.';
1310
    }
1311
}
1312
1313
function add_cbgp_peer($device, $peer, $afi, $safi)
1314
{
1315
    if (dbFetchCell('SELECT COUNT(*) from `bgpPeers_cbgp` WHERE device_id = ? AND bgpPeerIdentifier = ? AND afi=? AND safi=?', array($device['device_id'], $peer['ip'], $afi, $safi)) == 0) {
1316
        $cbgp = array(
1317
            'device_id' => $device['device_id'],
1318
            'bgpPeerIdentifier' => $peer['ip'],
1319
            'afi' => $afi,
1320
            'safi' => $safi,
1321
            'context_name' => $device['context_name'],
1322
            'AcceptedPrefixes' => 0,
1323
            'DeniedPrefixes' => 0,
1324
            'PrefixAdminLimit' => 0,
1325
            'PrefixThreshold' => 0,
1326
            'PrefixClearThreshold' => 0,
1327
            'AdvertisedPrefixes' => 0,
1328
            'SuppressedPrefixes' => 0,
1329
            'WithdrawnPrefixes' => 0,
1330
            'AcceptedPrefixes_delta' => 0,
1331
            'AcceptedPrefixes_prev' => 0,
1332
            'DeniedPrefixes_delta' => 0,
1333
            'DeniedPrefixes_prev' => 0,
1334
            'AdvertisedPrefixes_delta' => 0,
1335
            'AdvertisedPrefixes_prev' => 0,
1336
            'SuppressedPrefixes_delta' => 0,
1337
            'SuppressedPrefixes_prev' => 0,
1338
            'WithdrawnPrefixes_delta' => 0,
1339
            'WithdrawnPrefixes_prev' => 0,
1340
        );
1341
        dbInsert($cbgp, 'bgpPeers_cbgp');
1342
    }
1343
}
1344
1345
/**
1346
 * check if we should skip this device from discovery
1347
 * @param string $sysName
1348
 * @param string $sysDescr
1349
 * @param string $platform
1350
 * @return bool
1351
 */
1352
function can_skip_discovery($sysName, $sysDescr = '', $platform = '')
1353
{
1354
    if ($sysName) {
1355
        foreach ((array)Config::get('autodiscovery.xdp_exclude.sysname_regexp') as $needle) {
1356
            if (preg_match($needle .'i', $sysName)) {
1357
                d_echo("$sysName - regexp '$needle' matches '$sysName' - skipping device discovery \n");
1358
                return true;
1359
            }
1360
        }
1361
    }
1362
1363
    if ($sysDescr) {
1364
        foreach ((array)Config::get('autodiscovery.xdp_exclude.sysdesc_regexp') as $needle) {
1365
            if (preg_match($needle .'i', $sysDescr)) {
1366
                d_echo("$sysName - regexp '$needle' matches '$sysDescr' - skipping device discovery \n");
1367
                return true;
1368
            }
1369
        }
1370
    }
1371
1372
    if ($platform) {
1373
        foreach ((array)Config::get('autodiscovery.cdp_exclude.platform_regexp') as $needle) {
1374
            if (preg_match($needle .'i', $platform)) {
1375
                d_echo("$sysName - regexp '$needle' matches '$platform' - skipping device discovery \n");
1376
                return true;
1377
            }
1378
        }
1379
    }
1380
1381
    return false;
1382
}
1383
1384
/**
1385
 * Try to find a device by sysName, hostname, ip, or mac_address
1386
 * If a device cannot be found, returns 0
1387
 *
1388
 * @param string $name sysName or hostname
1389
 * @param string $ip May be an IP or hex string
1390
 * @param string $mac_address
1391
 * @return int the device_id or 0
1392
 */
1393
function find_device_id($name = '', $ip = '', $mac_address = '')
1394
{
1395
    $where = array();
1396
    $params = array();
1397
1398
    if ($name && is_valid_hostname($name)) {
1399
        $where[] = '`sysName`=?';
1400
        $params[] = $name;
1401
1402
        $where[] = '`hostname`=?';
1403
        $params[] = $name;
1404
1405
        if ($mydomain = Config::get('mydomain')) {
1406
            $where[] = '`hostname`=?';
1407
            $params[] = "$name.$mydomain";
1408
        }
1409
    }
1410
1411
    if ($ip) {
1412
        $where[] = '`hostname`=?';
1413
        $params[] = $ip;
1414
1415
        try {
1416
            $params[] = IP::fromHexString($ip)->packed();
1417
            $where[] = '`ip`=?';
1418
        } catch (InvalidIpException $e) {
1419
            //
1420
        }
1421
    }
1422
1423
    if (!empty($where)) {
1424
        $sql = 'SELECT `device_id` FROM `devices` WHERE ' . implode(' OR ', $where);
1425
        if ($device_id = dbFetchCell($sql, $params)) {
1426
            return (int)$device_id;
1427
        }
1428
    }
1429
1430
    if ($mac_address && $mac_address != '000000000000') {
1431
        if ($device_id = dbFetchCell('SELECT `device_id` FROM `ports` WHERE `ifPhysAddress`=?', array($mac_address))) {
1432
            return (int)$device_id;
1433
        }
1434
    }
1435
1436
    return 0;
1437
}
1438
1439
/**
1440
 * Try to find a port by ifDescr, ifName, ifAlias, or MAC
1441
 *
1442
 * @param string $description matched against ifDescr, ifName, and ifAlias
1443
 * @param string $identifier matched against ifDescr, ifName, and ifAlias
1444
 * @param int $device_id restrict search to ports on a specific device
1445
 * @param string $mac_address check against ifPhysAddress (should be in lowercase hexadecimal)
1446
 * @return int
1447
 */
1448
function find_port_id($description, $identifier = '', $device_id = 0, $mac_address = null)
1449
{
1450
    if (!($device_id || $mac_address)) {
1451
        return 0;
1452
    }
1453
1454
    $statements = array();
1455
    $params = array();
1456
1457
    if ($device_id) {
1458
        if ($description) {
1459
            // order is important here, the standard says this is ifDescr, which some mfg confuse with ifName
1460
            $statements[] = "SELECT `port_id` FROM `ports` WHERE `device_id`=? AND (`ifDescr`=? OR `ifName`=?)";
1461
            $params[] = $device_id;
1462
            $params[] = $description;
1463
            $params[] = $description;
1464
1465
            // we check ifAlias last because this is a user editable field, but some bad LLDP implementations use it
1466
            $statements[] = "SELECT `port_id` FROM `ports` WHERE `device_id`=? AND `ifAlias`=?";
1467
            $params[] = $device_id;
1468
            $params[] = $description;
1469
        }
1470
1471
        if ($identifier) {
1472
            if (is_numeric($identifier)) {
1473
                $statements[] = 'SELECT `port_id` FROM `ports` WHERE `device_id`=? AND (`ifIndex`=? OR `ifAlias`=?)';
1474
            } else {
1475
                $statements[] = 'SELECT `port_id` FROM `ports` WHERE `device_id`=? AND (`ifDescr`=? OR `ifName`=?)';
1476
            }
1477
            $params[] = $device_id;
1478
            $params[] = $identifier;
1479
            $params[] = $identifier;
1480
        }
1481
    }
1482
1483
    if ($mac_address) {
1484
        $mac_statement = 'SELECT `port_id` FROM `ports` WHERE ';
1485
        if ($device_id) {
1486
            $mac_statement .= '`device_id`=? AND ';
1487
            $params[] = $device_id;
1488
        }
1489
        $mac_statement .= '`ifPhysAddress`=?';
1490
1491
        $statements[] = $mac_statement;
1492
        $params[] = $mac_address;
1493
    }
1494
1495
    if (empty($statements)) {
1496
        return 0;
1497
    }
1498
1499
    $queries = implode(' UNION ', $statements);
1500
    $sql = "SELECT * FROM ($queries LIMIT 1) p";
1501
1502
    return (int)dbFetchCell($sql, $params);
1503
}
1504