From 9940c884f51ca25428a54a55d9b40e90135507dc Mon Sep 17 00:00:00 2001 From: TheGreatDoc <32565115+TheGreatDoc@users.noreply.github.com> Date: Sat, 11 Aug 2018 23:37:45 +0200 Subject: [PATCH] Fixed snmptraps. (#8898) * Fixed snmptraps. * Fixed space * Added bgp down/up and authentication failure * Fixed typo * Fixed some typos, arrays, astext and format_hostname * Updated documentation * Moved code to a function * Some refactor * Minor fixes * Minor fixes 2 * More minor fixes * Changes requested by Tony * Minor fixes * Moved include to snmptrap.php * Refactor traps to use object oriented code. Should trigger events too/instead, but we'll leave that. Testing todo * Add tests and fix things so they actually work Not checking events yet. * Fixed typo and severity level * Update composer deps, I think the lock file wasn't right. add json and mbstring extension deps while I'm at it. * Fix several issues with phpunit fixtures --- LibreNMS/Interfaces/SnmptrapHandler.php | 42 +++ .../Handler/AuthenticationFailure.php | 49 ++++ .../Handler/BgpBackwardTransition.php | 63 +++++ LibreNMS/Snmptrap/Handler/BgpEstablished.php | 63 +++++ LibreNMS/Snmptrap/Handler/Fallback.php | 51 ++++ LibreNMS/Snmptrap/Handler/LinkDown.php | 71 +++++ LibreNMS/Snmptrap/Handler/LinkUp.php | 72 +++++ LibreNMS/Snmptrap/Trap.php | 167 ++++++++++++ LibreNMS/Util/ModuleTestHelper.php | 4 +- app/Models/Device.php | 42 +++ app/Models/Ipv4Address.php | 46 ++++ app/Models/Ipv4Network.php | 41 +++ app/Models/Ipv6Address.php | 46 ++++ app/Models/Port.php | 4 +- app/Providers/SnmptrapProvider.php | 36 +++ composer.json | 5 +- composer.lock | 255 +++++++++++------- config/app.php | 5 +- config/snmptraps.php | 11 + database/factories/ModelFactory.php | 57 ++++ doc/Extensions/SNMP-Trap-Handler.md | 6 +- includes/snmptrap.inc.php | 16 ++ includes/snmptrap/linkDown.inc.php | 20 -- includes/snmptrap/linkUp.inc.php | 22 -- snmptrap.php | 29 +- tests/AuthSSOTest.php | 5 + tests/CreatesApplication.php | 2 +- tests/LaravelTestCase.php | 4 +- tests/SnmpTrapTest.php | 178 ++++++++++++ tests/bootstrap.php | 1 + 30 files changed, 1237 insertions(+), 176 deletions(-) create mode 100644 LibreNMS/Interfaces/SnmptrapHandler.php create mode 100644 LibreNMS/Snmptrap/Handler/AuthenticationFailure.php create mode 100644 LibreNMS/Snmptrap/Handler/BgpBackwardTransition.php create mode 100644 LibreNMS/Snmptrap/Handler/BgpEstablished.php create mode 100644 LibreNMS/Snmptrap/Handler/Fallback.php create mode 100644 LibreNMS/Snmptrap/Handler/LinkDown.php create mode 100644 LibreNMS/Snmptrap/Handler/LinkUp.php create mode 100644 LibreNMS/Snmptrap/Trap.php create mode 100644 app/Models/Ipv4Address.php create mode 100644 app/Models/Ipv4Network.php create mode 100644 app/Models/Ipv6Address.php create mode 100644 app/Providers/SnmptrapProvider.php create mode 100644 config/snmptraps.php create mode 100644 includes/snmptrap.inc.php delete mode 100644 includes/snmptrap/linkDown.inc.php delete mode 100644 includes/snmptrap/linkUp.inc.php create mode 100644 tests/SnmpTrapTest.php diff --git a/LibreNMS/Interfaces/SnmptrapHandler.php b/LibreNMS/Interfaces/SnmptrapHandler.php new file mode 100644 index 0000000000..33aab44b67 --- /dev/null +++ b/LibreNMS/Interfaces/SnmptrapHandler.php @@ -0,0 +1,42 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Interfaces; + +use App\Models\Device; +use LibreNMS\Snmptrap\Trap; + +interface SnmptrapHandler +{ + /** + * Handle snmptrap. + * Data is pre-parsed and delivered as a Trap. + * + * @param Device $device + * @param Trap $trap + * @return void + */ + public function handle(Device $device, Trap $trap); +} diff --git a/LibreNMS/Snmptrap/Handler/AuthenticationFailure.php b/LibreNMS/Snmptrap/Handler/AuthenticationFailure.php new file mode 100644 index 0000000000..e9f52680c8 --- /dev/null +++ b/LibreNMS/Snmptrap/Handler/AuthenticationFailure.php @@ -0,0 +1,49 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Snmptrap\Handler; + +use App\Models\Device; +use LibreNMS\Interfaces\SnmptrapHandler; +use LibreNMS\Snmptrap\Trap; + +class AuthenticationFailure implements SnmptrapHandler +{ + + /** + * Handle snmptrap. + * Data is pre-parsed and delivered as a Trap. + * + * @param Device $device + * @param Trap $trap + * @return void + */ + public function handle(Device $device, Trap $trap) + { + //FIXME added device hostname format helper in some branch, use that when merged + $device_array = $device->toArray(); + log_event('SNMP Trap: Authentication Failure: ' . format_hostname($device_array), $device_array, 'auth', 3, $device->hostname); + } +} diff --git a/LibreNMS/Snmptrap/Handler/BgpBackwardTransition.php b/LibreNMS/Snmptrap/Handler/BgpBackwardTransition.php new file mode 100644 index 0000000000..092bccdf2d --- /dev/null +++ b/LibreNMS/Snmptrap/Handler/BgpBackwardTransition.php @@ -0,0 +1,63 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Snmptrap\Handler; + +use App\Models\Device; +use LibreNMS\Interfaces\SnmptrapHandler; +use LibreNMS\Snmptrap\Trap; +use Log; + +class BgpBackwardTransition implements SnmptrapHandler +{ + /** + * Handle snmptrap. + * Data is pre-parsed and delivered as a Trap. + * + * @param Device $device + * @param Trap $trap + * @return void + */ + public function handle(Device $device, Trap $trap) + { + $state_oid = $trap->findOid('BGP4-MIB::bgpPeerState'); + $bgpPeerIp = substr($state_oid, 23); + + $bgpPeer = $device->bgppeers()->where('bgpPeerIdentifier', $bgpPeerIp)->first(); + + if (!$bgpPeer) { + Log::error('Unknown bgp peer handling bgpEstablished trap: ' . $bgpPeerIp); + return; + } + + $bgpPeer->bgpPeerState = $trap->getOidData($state_oid); + + if ($bgpPeer->isDirty('bgpPeerState')) { + log_event('SNMP Trap: BGP Down ' . $bgpPeer->bgpPeerIdentifier . ' ' . get_astext($bgpPeer->bgpPeerRemoteAs) . ' is now ' . $bgpPeer->bgpPeerState, $device->toArray(), 'bgpPeer', 5, $bgpPeerIp); + } + + $bgpPeer->save(); + } +} diff --git a/LibreNMS/Snmptrap/Handler/BgpEstablished.php b/LibreNMS/Snmptrap/Handler/BgpEstablished.php new file mode 100644 index 0000000000..29d139e7bd --- /dev/null +++ b/LibreNMS/Snmptrap/Handler/BgpEstablished.php @@ -0,0 +1,63 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Snmptrap\Handler; + +use App\Models\Device; +use LibreNMS\Interfaces\SnmptrapHandler; +use LibreNMS\Snmptrap\Trap; +use Log; + +class BgpEstablished implements SnmptrapHandler +{ + /** + * Handle snmptrap. + * Data is pre-parsed and delivered as a Trap. + * + * @param Device $device + * @param Trap $trap + * @return void + */ + public function handle(Device $device, Trap $trap) + { + $state_oid = $trap->findOid('BGP4-MIB::bgpPeerState'); + $bgpPeerIp = substr($state_oid, 23); + + $bgpPeer = $device->bgppeers()->where('bgpPeerIdentifier', $bgpPeerIp)->first(); + + if (!$bgpPeer) { + Log::error('Unknown bgp peer handling bgpEstablished trap: ' . $bgpPeerIp); + return; + } + + $bgpPeer->bgpPeerState = $trap->getOidData($state_oid); + + if ($bgpPeer->isDirty('bgpPeerState')) { + log_event('SNMP Trap: BGP Up ' . $bgpPeer->bgpPeerIdentifier . ' ' . get_astext($bgpPeer->bgpPeerRemoteAs) . ' is now ' . $bgpPeer->bgpPeerState, $device->toArray(), 'bgpPeer', 1, $bgpPeerIp); + } + + $bgpPeer->save(); + } +} diff --git a/LibreNMS/Snmptrap/Handler/Fallback.php b/LibreNMS/Snmptrap/Handler/Fallback.php new file mode 100644 index 0000000000..3d5e81a5f5 --- /dev/null +++ b/LibreNMS/Snmptrap/Handler/Fallback.php @@ -0,0 +1,51 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Snmptrap\Handler; + +use App\Models\Device; +use LibreNMS\Interfaces\SnmptrapHandler; +use LibreNMS\Snmptrap\Trap; +use Log; + +class Fallback implements SnmptrapHandler +{ + + /** + * Handle snmptrap. + * Data is pre-parsed and delivered as a Trap. + * + * @param Device $device + * @param Trap $trap + * @return void + */ + public function handle(Device $device, Trap $trap) + { + Log::info("Unhandled trap snmptrap", [ + 'device' => $device->hostname, + 'oid' => $trap->getTrapOid() + ]); + } +} diff --git a/LibreNMS/Snmptrap/Handler/LinkDown.php b/LibreNMS/Snmptrap/Handler/LinkDown.php new file mode 100644 index 0000000000..50237bcd1d --- /dev/null +++ b/LibreNMS/Snmptrap/Handler/LinkDown.php @@ -0,0 +1,71 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Snmptrap\Handler; + +use App\Models\Device; +use LibreNMS\Interfaces\SnmptrapHandler; +use LibreNMS\Snmptrap\Trap; +use Log; + +class LinkDown implements SnmptrapHandler +{ + /** + * Handle snmptrap. + * Data is pre-parsed and delivered as a Trap. + * + * @param Device $device + * @param Trap $trap + * @return void + */ + public function handle(Device $device, Trap $trap) + { + $ifIndex = $trap->getOidData($trap->findOid('IF-MIB::ifIndex')); + + $port = $device->ports()->where('ifIndex', $ifIndex)->first(); + + if (!$port) { + Log::warning("Snmptrap linkDown: Could not find port at ifIndex $ifIndex for device: " . $device->hostname); + return; + } + + $port->ifOperStatus = $trap->getOidData("IF-MIB::ifOperStatus.$ifIndex"); + $port->ifAdminStatus = $trap->getOidData("IF-MIB::ifAdminStatus.$ifIndex"); + + $device_array = $device->toArray(); + + log_event("SNMP Trap: linkDown $port->ifAdminStatus/$port->ifOperStatus " . $port->ifDescr, $device_array, 'interface', 5, $port->port_id); + + if ($port->isDirty('ifAdminStatus')) { + log_event("Interface Disabled : " . $port['ifDescr'] . " (TRAP)", $device_array, "interface", 3, $port['port_id']); + } + + if ($port->isDirty('ifOperStatus')) { + log_event("Interface went Down : " . $port['ifDescr'] . " (TRAP)", $device_array, "interface", 5, $port['port_id']); + } + + $port->save(); + } +} diff --git a/LibreNMS/Snmptrap/Handler/LinkUp.php b/LibreNMS/Snmptrap/Handler/LinkUp.php new file mode 100644 index 0000000000..555d3df60e --- /dev/null +++ b/LibreNMS/Snmptrap/Handler/LinkUp.php @@ -0,0 +1,72 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Snmptrap\Handler; + +use App\Models\Device; +use LibreNMS\Interfaces\SnmptrapHandler; +use LibreNMS\Snmptrap\Trap; +use Log; + +class LinkUp implements SnmptrapHandler +{ + + /** + * Handle snmptrap. + * Data is pre-parsed and delivered as a Trap. + * + * @param Device $device + * @param Trap $trap + * @return void + */ + public function handle(Device $device, Trap $trap) + { + $ifIndex = $trap->getOidData($trap->findOid('IF-MIB::ifIndex')); + + $port = $device->ports()->where('ifIndex', $ifIndex)->first(); + + if (!$port) { + Log::warning("Snmptrap linkUp: Could not find port at ifIndex $ifIndex for device: " . $device->hostname); + return; + } + + $port->ifOperStatus = $trap->getOidData("IF-MIB::ifAdminStatus.$ifIndex"); + $port->ifAdminStatus = $trap->getOidData("IF-MIB::ifOperStatus.$ifIndex"); + + $device_array = $device->toArray(); + + log_event("SNMP Trap: linkUp $port->ifAdminStatus/$port->ifOperStatus " . $port->ifDescr, $device_array, "interface", 1, $port->port_id); + + if ($port->isDirty('ifAdminStatus')) { + log_event("Interface Enabled : $port->ifDescr (TRAP)", $device_array, "interface", 3, $port->port_id); + } + + if ($port->isDirty('ifOperStatus')) { + log_event("Interface went Up : $port->ifDescr (TRAP)", $device_array, "interface", 1, $port->port_id); + } + + $port->save(); + } +} diff --git a/LibreNMS/Snmptrap/Trap.php b/LibreNMS/Snmptrap/Trap.php new file mode 100644 index 0000000000..bccb1d0cc5 --- /dev/null +++ b/LibreNMS/Snmptrap/Trap.php @@ -0,0 +1,167 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Snmptrap; + +use App\Models\Device; +use Illuminate\Support\Collection; +use LibreNMS\Snmptrap\Handler\Fallback; +use LibreNMS\Util\IP; +use Log; + +class Trap +{ + protected $raw; + protected $hostname; + protected $ip; + + protected $device; + + /** @var Collection $oid_data */ + protected $oid_data; + + /** + * Construct a trap from raw trap text + * @param $trap + */ + public function __construct($trap) + { + $this->raw = $trap; + $this->parse(); + } + + protected function parse() + { + $lines = explode(PHP_EOL, trim($this->raw)); + + $this->hostname = array_shift($lines); + + $line = array_shift($lines); + if (preg_match('/\[([0-9.:a-fA-F]+)\]/', $line, $matches)) { + $this->ip = $matches[1]; + }; + + // parse the oid data + $this->oid_data = collect($lines)->mapWithKeys(function ($line) { + list($oid, $data) = explode(' ', $line, 2); + return [$oid => trim($data, '"')]; + }); + } + + /** + * Instantiate the correct handler for this trap and call it's handle method + * + */ + public function handle() + { + $this->getDevice(); + + if (empty($this->device)) { + Log::warning("Could not find device for trap", ['trap_text' => $this->raw]); + return false; + } + + // note, this doesn't clear the resolved SnpmtrapHandler so only one per run + /** @var \LibreNMS\Interfaces\SnmptrapHandler $handler */ + $handler = app(\LibreNMS\Interfaces\SnmptrapHandler::class, [$this->getTrapOid()]); + $handler->handle($this->getDevice(), $this); + + return !($handler instanceof Fallback); + } + + /** + * Find the first in this trap by substring + * + * @param $search + * @return string + */ + public function findOid($search) + { + return $this->oid_data->keys()->first(function ($oid) use ($search) { + return str_contains($oid, $search); + }); + } + + /** + * Find all oids that match the given string + * @param $search + * @return array + */ + public function findOids($search) + { + return $this->oid_data->keys()->filter(function ($oid) use ($search) { + return str_contains($oid, $search); + })->all(); + } + + public function getOidData($oid) + { + return $this->oid_data->get($oid); + } + + /** + * @return Device|null + */ + public function getDevice() + { + if (is_null($this->device) && IP::isValid($this->ip)) { + $this->device = Device::findByHostname($this->hostname) ?: Device::findByIp($this->ip); + } + + return $this->device; + } + + /** + * @return string + */ + public function getHostname() + { + return $this->hostname; + } + + /** + * @return string + */ + public function getIp() + { + return $this->ip; + } + + /** + * @return string + */ + public function getTrapOid() + { + return $this->getOidData('SNMPv2-MIB::snmpTrapOID.0'); + } + + /** + * @return string + */ + public function getRaw() + { + return $this->raw; + } +} diff --git a/LibreNMS/Util/ModuleTestHelper.php b/LibreNMS/Util/ModuleTestHelper.php index bf461c97cf..cb065112bc 100644 --- a/LibreNMS/Util/ModuleTestHelper.php +++ b/LibreNMS/Util/ModuleTestHelper.php @@ -515,7 +515,7 @@ class ModuleTestHelper $save_vedbug = $vdebug; if ($this->quiet) { $debug = true; - $vdebug = false; + $vdebug = true; } ob_start(); @@ -543,7 +543,7 @@ class ModuleTestHelper // Run the poller if ($this->quiet) { $debug = true; - $vdebug = false; + $vdebug = true; } ob_start(); diff --git a/app/Models/Device.php b/app/Models/Device.php index 170163d868..5d60a1a182 100644 --- a/app/Models/Device.php +++ b/app/Models/Device.php @@ -3,8 +3,12 @@ namespace App\Models; use Fico7489\Laravel\Pivot\Traits\PivotEventTrait; +use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Query\JoinClause; +use LibreNMS\Exceptions\InvalidIpException; +use LibreNMS\Util\IPv4; +use LibreNMS\Util\IPv6; class Device extends BaseModel { @@ -82,6 +86,44 @@ class Device extends BaseModel // ---- Helper Functions ---- + public static function findByHostname($hostname) + { + return static::where('hostname', $hostname)->first(); + } + + public static function findByIp($ip) + { + $device = static::where('hostname', $ip)->orWhere('ip', inet_pton($ip))->first(); + + if ($device) { + return $device; + } + + try { + $ipv4 = new IPv4($ip); + return Ipv4Address::where('ipv4_address', $ipv4) + ->with('port', 'port.device') + ->firstOrFail()->port->device; + } catch (InvalidIpException $e) { + // + } catch (ModelNotFoundException $e) { + // + } + + try { + $ipv6 = new IPv6($ip); + return Ipv6Address::where('ipv6_address', $ipv6->uncompressed()) + ->with(['port', 'port.device']) + ->firstOrFail()->port->device; + } catch (InvalidIpException $e) { + // + } catch (ModelNotFoundException $e) { + // + } + + return null; + } + /** * @return string */ diff --git a/app/Models/Ipv4Address.php b/app/Models/Ipv4Address.php new file mode 100644 index 0000000000..22910b0a54 --- /dev/null +++ b/app/Models/Ipv4Address.php @@ -0,0 +1,46 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Models; + +class Ipv4Address extends BaseModel +{ + public $timestamps = false; + protected $primaryKey = 'ipv4_address_id'; + + // ---- Query scopes ---- + + public function scopeHasAccess($query, User $user) + { + return $this->hasPortAccess($query, $user); + } + + // ---- Define Relationships ---- + + public function port() + { + return $this->belongsTo('App\Models\Port', 'port_id', 'port_id'); + } +} diff --git a/app/Models/Ipv4Network.php b/app/Models/Ipv4Network.php new file mode 100644 index 0000000000..668a34107e --- /dev/null +++ b/app/Models/Ipv4Network.php @@ -0,0 +1,41 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Models; + +use Illuminate\Database\Eloquent\Model; + +class Ipv4Network extends Model +{ + public $timestamps = false; + protected $primaryKey = 'ipv4_network_id'; + + // ---- Define Relationships ---- + + public function ipv4() + { + return $this->hasMany('App\Models\Ipv4Address', 'ipv4_network_id'); + } +} diff --git a/app/Models/Ipv6Address.php b/app/Models/Ipv6Address.php new file mode 100644 index 0000000000..f65932eb5e --- /dev/null +++ b/app/Models/Ipv6Address.php @@ -0,0 +1,46 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace App\Models; + +class Ipv6Address extends BaseModel +{ + public $timestamps = false; + protected $primaryKey = 'ipv6_address_id'; + + // ---- Query scopes ---- + + public function scopeHasAccess($query, User $user) + { + return $this->hasPortAccess($query, $user); + } + + // ---- Define Relationships ---- + + public function port() + { + return $this->belongsTo('App\Models\Port', 'port_id', 'port_id'); + } +} diff --git a/app/Models/Port.php b/app/Models/Port.php index 6b9a596f21..6cf33bc74c 100644 --- a/app/Models/Port.php +++ b/app/Models/Port.php @@ -117,11 +117,11 @@ class Port extends BaseModel public function ipv4() { - return $this->hasMany('App\Models\General\IPv4', 'port_id'); + return $this->hasMany('App\Models\Ipv4Address', 'port_id'); } public function ipv6() { - return $this->hasMany('App\Models\General\IPv6', 'port_id'); + return $this->hasMany('App\Models\Ipv6Address', 'port_id'); } } diff --git a/app/Providers/SnmptrapProvider.php b/app/Providers/SnmptrapProvider.php new file mode 100644 index 0000000000..93c3d5f2a7 --- /dev/null +++ b/app/Providers/SnmptrapProvider.php @@ -0,0 +1,36 @@ +app->bind(SnmptrapHandler::class, function ($app, $oid) { + if ($handler = config('snmptraps.trap_handlers.' . reset($oid))) { + return $app->make($handler); + } + + return $app->make(Fallback::class); + }); + } +} diff --git a/composer.json b/composer.json index 39271a810e..bfb6f680ef 100644 --- a/composer.json +++ b/composer.json @@ -27,6 +27,8 @@ "ext-session": "*", "ext-xml": "*", "ext-gd": "*", + "ext-json": "*", + "ext-mbstring": "*", "ezyang/htmlpurifier": "^4.8", "phpmailer/phpmailer": "^5.2.21", "slim/slim": "^2.6", @@ -65,7 +67,8 @@ "fojuth/readmegen": "1.*", "barryvdh/laravel-ide-helper": "^2.4", "barryvdh/laravel-debugbar": "~2.4", - "justinrainbow/json-schema": "^5.2" + "justinrainbow/json-schema": "^5.2", + "fzaninotto/faker": "^1.8" }, "suggest": { "ext-memcached": "Required if you utilize distributed polling", diff --git a/composer.lock b/composer.lock index d0e08e1b55..105a081d82 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f57760426989ee971f25f10f73d7d661", + "content-hash": "bba34ce2b3e7e60c03af5707da7a8015", "packages": [ { "name": "amenadiel/jpgraph", @@ -1286,16 +1286,16 @@ }, { "name": "nesbot/carbon", - "version": "1.32.0", + "version": "1.33.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "64563e2b9f69e4db1b82a60e81efa327a30ff343" + "reference": "55667c1007a99e82030874b1bb14d24d07108413" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/64563e2b9f69e4db1b82a60e81efa327a30ff343", - "reference": "64563e2b9f69e4db1b82a60e81efa327a30ff343", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/55667c1007a99e82030874b1bb14d24d07108413", + "reference": "55667c1007a99e82030874b1bb14d24d07108413", "shasum": "" }, "require": { @@ -1337,7 +1337,7 @@ "datetime", "time" ], - "time": "2018-07-05T06:59:26+00:00" + "time": "2018-08-07T08:39:47+00:00" }, { "name": "nikic/php-parser", @@ -2308,16 +2308,16 @@ }, { "name": "swiftmailer/swiftmailer", - "version": "v5.4.9", + "version": "v5.4.12", "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "7ffc1ea296ed14bf8260b6ef11b80208dbadba91" + "reference": "181b89f18a90f8925ef805f950d47a7190e9b950" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/7ffc1ea296ed14bf8260b6ef11b80208dbadba91", - "reference": "7ffc1ea296ed14bf8260b6ef11b80208dbadba91", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/181b89f18a90f8925ef805f950d47a7190e9b950", + "reference": "181b89f18a90f8925ef805f950d47a7190e9b950", "shasum": "" }, "require": { @@ -2358,20 +2358,20 @@ "mail", "mailer" ], - "time": "2018-01-23T07:37:21+00:00" + "time": "2018-07-31T09:26:32+00:00" }, { "name": "symfony/console", - "version": "v3.4.13", + "version": "v3.4.14", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "e54f84c50e3b12972e7750edfc5ca84b2284c44e" + "reference": "6b217594552b9323bcdcfc14f8a0ce126e84cd73" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/e54f84c50e3b12972e7750edfc5ca84b2284c44e", - "reference": "e54f84c50e3b12972e7750edfc5ca84b2284c44e", + "url": "https://api.github.com/repos/symfony/console/zipball/6b217594552b9323bcdcfc14f8a0ce126e84cd73", + "reference": "6b217594552b9323bcdcfc14f8a0ce126e84cd73", "shasum": "" }, "require": { @@ -2427,20 +2427,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-07-10T14:02:11+00:00" + "time": "2018-07-26T11:19:56+00:00" }, { "name": "symfony/css-selector", - "version": "v3.4.13", + "version": "v3.4.14", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "d2ce52290b648ae33b5301d09bc14ee378612914" + "reference": "edda5a6155000ff8c3a3f85ee5c421af93cca416" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/d2ce52290b648ae33b5301d09bc14ee378612914", - "reference": "d2ce52290b648ae33b5301d09bc14ee378612914", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/edda5a6155000ff8c3a3f85ee5c421af93cca416", + "reference": "edda5a6155000ff8c3a3f85ee5c421af93cca416", "shasum": "" }, "require": { @@ -2480,20 +2480,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2018-05-16T12:49:49+00:00" + "time": "2018-07-26T09:06:28+00:00" }, { "name": "symfony/debug", - "version": "v3.4.13", + "version": "v3.4.14", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "0e3ca9cbde90fffec8038f4d4e16fd4046bbd018" + "reference": "d5a058ff6ecad26b30c1ba452241306ea34c65cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/0e3ca9cbde90fffec8038f4d4e16fd4046bbd018", - "reference": "0e3ca9cbde90fffec8038f4d4e16fd4046bbd018", + "url": "https://api.github.com/repos/symfony/debug/zipball/d5a058ff6ecad26b30c1ba452241306ea34c65cc", + "reference": "d5a058ff6ecad26b30c1ba452241306ea34c65cc", "shasum": "" }, "require": { @@ -2536,20 +2536,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2018-06-26T08:45:54+00:00" + "time": "2018-07-26T11:19:56+00:00" }, { "name": "symfony/dotenv", - "version": "v3.4.13", + "version": "v3.4.14", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "66265f80c0f585cd6aec3fbdfc4ffdf7a0d75992" + "reference": "fcc8c8c73899e65ec528aac439c49e7929cdb87b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/66265f80c0f585cd6aec3fbdfc4ffdf7a0d75992", - "reference": "66265f80c0f585cd6aec3fbdfc4ffdf7a0d75992", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/fcc8c8c73899e65ec528aac439c49e7929cdb87b", + "reference": "fcc8c8c73899e65ec528aac439c49e7929cdb87b", "shasum": "" }, "require": { @@ -2593,20 +2593,20 @@ "env", "environment" ], - "time": "2018-01-03T17:14:19+00:00" + "time": "2018-07-26T11:19:56+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v3.4.13", + "version": "v3.4.14", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "fdd5abcebd1061ec647089c6c41a07ed60af09f8" + "reference": "b2e1f19280c09a42dc64c0b72b80fe44dd6e88fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/fdd5abcebd1061ec647089c6c41a07ed60af09f8", - "reference": "fdd5abcebd1061ec647089c6c41a07ed60af09f8", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b2e1f19280c09a42dc64c0b72b80fe44dd6e88fb", + "reference": "b2e1f19280c09a42dc64c0b72b80fe44dd6e88fb", "shasum": "" }, "require": { @@ -2656,20 +2656,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2018-04-06T07:35:25+00:00" + "time": "2018-07-26T09:06:28+00:00" }, { "name": "symfony/finder", - "version": "v3.4.13", + "version": "v3.4.14", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "3a8c3de91d2b2c68cd2d665cf9d00f7ef9eaa394" + "reference": "8a84fcb207451df0013b2c74cbbf1b62d47b999a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/3a8c3de91d2b2c68cd2d665cf9d00f7ef9eaa394", - "reference": "3a8c3de91d2b2c68cd2d665cf9d00f7ef9eaa394", + "url": "https://api.github.com/repos/symfony/finder/zipball/8a84fcb207451df0013b2c74cbbf1b62d47b999a", + "reference": "8a84fcb207451df0013b2c74cbbf1b62d47b999a", "shasum": "" }, "require": { @@ -2705,20 +2705,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-06-19T20:52:10+00:00" + "time": "2018-07-26T11:19:56+00:00" }, { "name": "symfony/http-foundation", - "version": "v3.4.13", + "version": "v3.4.14", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "2b8e08c085e2dc7449ee6d55a238be87d3727c96" + "reference": "19a3267828046a2a4a05e3dc2954bbd2e0ad9fa6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/2b8e08c085e2dc7449ee6d55a238be87d3727c96", - "reference": "2b8e08c085e2dc7449ee6d55a238be87d3727c96", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/19a3267828046a2a4a05e3dc2954bbd2e0ad9fa6", + "reference": "19a3267828046a2a4a05e3dc2954bbd2e0ad9fa6", "shasum": "" }, "require": { @@ -2759,20 +2759,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2018-07-19T07:08:28+00:00" + "time": "2018-08-01T14:04:26+00:00" }, { "name": "symfony/http-kernel", - "version": "v3.4.13", + "version": "v3.4.14", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "22a1d000d45f09966a363223548a150aec759e61" + "reference": "8e84cc498f0ffecfbabdea78b87828fd66189544" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/22a1d000d45f09966a363223548a150aec759e61", - "reference": "22a1d000d45f09966a363223548a150aec759e61", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/8e84cc498f0ffecfbabdea78b87828fd66189544", + "reference": "8e84cc498f0ffecfbabdea78b87828fd66189544", "shasum": "" }, "require": { @@ -2785,7 +2785,7 @@ }, "conflict": { "symfony/config": "<2.8", - "symfony/dependency-injection": "<3.4.5|<4.0.5,>=4", + "symfony/dependency-injection": "<3.4.10|<4.0.10,>=4", "symfony/var-dumper": "<3.3", "twig/twig": "<1.34|<2.4,>=2" }, @@ -2799,7 +2799,7 @@ "symfony/config": "~2.8|~3.0|~4.0", "symfony/console": "~2.8|~3.0|~4.0", "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "^3.4.5|^4.0.5", + "symfony/dependency-injection": "^3.4.10|^4.0.10", "symfony/dom-crawler": "~2.8|~3.0|~4.0", "symfony/expression-language": "~2.8|~3.0|~4.0", "symfony/finder": "~2.8|~3.0|~4.0", @@ -2848,29 +2848,32 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2018-07-23T16:37:31+00:00" + "time": "2018-08-01T14:47:47+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.8.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae" + "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae", - "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", + "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", "shasum": "" }, "require": { "php": ">=5.3.3" }, + "suggest": { + "ext-ctype": "For best performance" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -2903,20 +2906,20 @@ "polyfill", "portable" ], - "time": "2018-04-30T19:57:29+00:00" + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.8.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "3296adf6a6454a050679cde90f95350ad604b171" + "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171", - "reference": "3296adf6a6454a050679cde90f95350ad604b171", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8", + "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8", "shasum": "" }, "require": { @@ -2928,7 +2931,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -2962,30 +2965,30 @@ "portable", "shim" ], - "time": "2018-04-26T10:06:28+00:00" + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/polyfill-php70", - "version": "v1.8.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6" + "reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/77454693d8f10dd23bb24955cffd2d82db1007a6", - "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/1e24b0c4a56d55aaf368763a06c6d1c7d3194934", + "reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934", "shasum": "" }, "require": { - "paragonie/random_compat": "~1.0|~2.0", + "paragonie/random_compat": "~1.0|~2.0|~9.99", "php": ">=5.3.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -3021,20 +3024,20 @@ "portable", "shim" ], - "time": "2018-04-26T10:06:28+00:00" + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/process", - "version": "v3.4.13", + "version": "v3.4.14", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "f741672edfcfe3a2ea77569d419006f23281d909" + "reference": "0414db29bd770ec5a4152683e655f55efd4fa60f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/f741672edfcfe3a2ea77569d419006f23281d909", - "reference": "f741672edfcfe3a2ea77569d419006f23281d909", + "url": "https://api.github.com/repos/symfony/process/zipball/0414db29bd770ec5a4152683e655f55efd4fa60f", + "reference": "0414db29bd770ec5a4152683e655f55efd4fa60f", "shasum": "" }, "require": { @@ -3070,7 +3073,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-07-09T09:01:07+00:00" + "time": "2018-07-26T11:19:56+00:00" }, { "name": "symfony/routing", @@ -3213,16 +3216,16 @@ }, { "name": "symfony/var-dumper", - "version": "v3.4.13", + "version": "v3.4.14", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "c501f46bb1eaf4c8d65ba070ab65a1986da1cd7f" + "reference": "f62a394bd3de96f2f5e8f4c7d685035897fb3cb3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c501f46bb1eaf4c8d65ba070ab65a1986da1cd7f", - "reference": "c501f46bb1eaf4c8d65ba070ab65a1986da1cd7f", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/f62a394bd3de96f2f5e8f4c7d685035897fb3cb3", + "reference": "f62a394bd3de96f2f5e8f4c7d685035897fb3cb3", "shasum": "" }, "require": { @@ -3278,20 +3281,20 @@ "debug", "dump" ], - "time": "2018-07-09T08:21:26+00:00" + "time": "2018-07-26T11:19:56+00:00" }, { "name": "symfony/yaml", - "version": "v2.8.43", + "version": "v2.8.44", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "51356b7a2ff7c9fd06b2f1681cc463bb62b5c1ff" + "reference": "fbf876678e29dc634430dcf0096e216eb0004467" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/51356b7a2ff7c9fd06b2f1681cc463bb62b5c1ff", - "reference": "51356b7a2ff7c9fd06b2f1681cc463bb62b5c1ff", + "url": "https://api.github.com/repos/symfony/yaml/zipball/fbf876678e29dc634430dcf0096e216eb0004467", + "reference": "fbf876678e29dc634430dcf0096e216eb0004467", "shasum": "" }, "require": { @@ -3328,7 +3331,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-05-01T22:52:40+00:00" + "time": "2018-07-26T09:03:18+00:00" }, { "name": "tecnickcom/tcpdf", @@ -3849,6 +3852,56 @@ ], "time": "2015-07-17T18:39:03+00:00" }, + { + "name": "fzaninotto/faker", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/f72816b43e74063c8b10357394b6bba8cb1c10de", + "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "ext-intl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7", + "squizlabs/php_codesniffer": "^1.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "time": "2018-07-12T10:23:15+00:00" + }, { "name": "jakub-onderka/php-parallel-lint", "version": "v1.0.0", @@ -4026,16 +4079,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.7.6", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", "shasum": "" }, "require": { @@ -4047,12 +4100,12 @@ }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.8.x-dev" } }, "autoload": { @@ -4085,7 +4138,7 @@ "spy", "stub" ], - "time": "2018-04-18T13:57:24+00:00" + "time": "2018-08-05T17:53:17+00:00" }, { "name": "phpunit/php-code-coverage", @@ -5021,16 +5074,16 @@ }, { "name": "symfony/class-loader", - "version": "v3.4.13", + "version": "v3.4.14", "source": { "type": "git", "url": "https://github.com/symfony/class-loader.git", - "reference": "e63c12699822bb3b667e7216ba07fbcc3a3e203e" + "reference": "31db283fc86d3143e7ff87e922177b457d909c30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/class-loader/zipball/e63c12699822bb3b667e7216ba07fbcc3a3e203e", - "reference": "e63c12699822bb3b667e7216ba07fbcc3a3e203e", + "url": "https://api.github.com/repos/symfony/class-loader/zipball/31db283fc86d3143e7ff87e922177b457d909c30", + "reference": "31db283fc86d3143e7ff87e922177b457d909c30", "shasum": "" }, "require": { @@ -5073,7 +5126,7 @@ ], "description": "Symfony ClassLoader Component", "homepage": "https://symfony.com", - "time": "2018-01-03T07:37:34+00:00" + "time": "2018-07-26T11:19:56+00:00" }, { "name": "ulrichsg/getopt-php", @@ -5137,7 +5190,9 @@ "ext-curl": "*", "ext-session": "*", "ext-xml": "*", - "ext-gd": "*" + "ext-gd": "*", + "ext-json": "*", + "ext-mbstring": "*" }, "platform-dev": [] } diff --git a/config/app.php b/config/app.php index efc02aa3e4..69db90e969 100644 --- a/config/app.php +++ b/config/app.php @@ -166,6 +166,7 @@ return [ * Package Service Providers... */ Laravel\Tinker\TinkerServiceProvider::class, + Kamaln7\Toastr\ToastrServiceProvider::class, /* * Application Service Providers... @@ -179,9 +180,9 @@ return [ App\Providers\ViewServiceProvider::class, /* - * Vendor Service Providers... + * LibreNMS Service Providers... */ - Kamaln7\Toastr\ToastrServiceProvider::class, + App\Providers\SnmptrapProvider::class, ], /* diff --git a/config/snmptraps.php b/config/snmptraps.php new file mode 100644 index 0000000000..d060baa6d1 --- /dev/null +++ b/config/snmptraps.php @@ -0,0 +1,11 @@ + [ + 'SNMPv2-MIB::authenticationFailure' => \LibreNMS\Snmptrap\Handler\AuthenticationFailure::class, + 'BGP4-MIB::bgpEstablished' => \LibreNMS\Snmptrap\Handler\BgpEstablished::class, + 'BGP4-MIB::bgpBackwardTransition' => \LibreNMS\Snmptrap\Handler\BgpBackwardTransition::class, + 'IF-MIB::linkUp' => \LibreNMS\Snmptrap\Handler\LinkUp::class, + 'IF-MIB::linkDown' => \LibreNMS\Snmptrap\Handler\LinkDown::class, + ] +]; diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index 7926c79461..1c82a53f1e 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -12,6 +12,9 @@ */ /** @var \Illuminate\Database\Eloquent\Factory $factory */ + +use LibreNMS\Util\IPv4; + $factory->define(App\User::class, function (Faker\Generator $faker) { static $password; @@ -22,3 +25,57 @@ $factory->define(App\User::class, function (Faker\Generator $faker) { 'remember_token' => str_random(10), ]; }); + +$factory->define(\App\Models\Device::class, function (Faker\Generator $faker) { + return [ + 'hostname' => $faker->domainWord.'.'.$faker->domainName, + 'ip' => $faker->randomElement([$faker->ipv4, $faker->ipv6]), + 'status' => $status = random_int(0, 1), + 'status_reason' => $status == 0 ? $faker->randomElement(['snmp', 'icmp']) : '', // allow invalid states? + ]; +}); + +$factory->define(\App\Models\Port::class, function (Faker\Generator $faker) { + return [ + 'ifIndex' => $faker->unique()->numberBetween(), + 'ifName' => $faker->text(20), + 'ifLastChange' => $faker->unixTime(), + ]; +}); + +$factory->define(\App\Models\BgpPeer::class, function (Faker\Generator $faker) { + return [ + 'bgpPeerIdentifier' => $faker->ipv4, + 'bgpLocalAddr' => $faker->ipv4, + 'bgpPeerRemoteAddr' => $faker->ipv4, + 'bgpPeerRemoteAs' => $faker->numberBetween(1, 65535), + 'bgpPeerState' => $faker->randomElement(['established', 'idle']), + 'astext' => $faker->sentence(), + 'bgpPeerAdminStatus' => $faker->randomElement(['start', 'stop']), + 'bgpPeerInUpdates' => $faker->randomDigit, + 'bgpPeerOutUpdates' => $faker->randomDigit, + 'bgpPeerInTotalMessages' => $faker->randomDigit, + 'bgpPeerOutTotalMessages' => $faker->randomDigit, + 'bgpPeerFsmEstablishedTime' => $faker->unixTime, + 'bgpPeerInUpdateElapsedTime' => $faker->unixTime, + ]; +}); + +$factory->define(\App\Models\Ipv4Address::class, function (Faker\Generator $faker) { + $prefix = $faker->numberBetween(0, 32); + $ip = new IPv4($faker->ipv4 . '/' . $prefix); + + return [ + 'ipv4_address' => $ip->uncompressed(), + 'ipv4_prefixlen' => $prefix, + 'ipv4_network_id' => function () use ($ip) { + return factory(\App\Models\Ipv4Network::class)->create(['ipv4_network' => $ip->getNetworkAddress() . '/' . $ip->cidr])->ipv4_network_id; + } + ]; +}); + +$factory->define(\App\Models\Ipv4Network::class, function (Faker\Generator $faker) { + return [ + 'ipv4_network' => $faker->ipv4 . '/' . $faker->numberBetween(0, 32), + ]; +}); diff --git a/doc/Extensions/SNMP-Trap-Handler.md b/doc/Extensions/SNMP-Trap-Handler.md index 80f8f63bf6..ef7072b9a8 100644 --- a/doc/Extensions/SNMP-Trap-Handler.md +++ b/doc/Extensions/SNMP-Trap-Handler.md @@ -1,12 +1,16 @@ source: Extensions/SNMP-Trap-Handler.md # SNMP trap handling -Currently, librenms only supports port up/down SNMP traps. Traps are handled via snmptrapd. +Currently, librenms only supports linkUp/linkDown (port up/down), bgpEstablished/bgpBackwardTransition (BGP Sessions Up/Down) and authenticationFailure SNMP traps. + +Traps are handled via snmptrapd. ## Configure snmptrapd Install snmptrapd via your package manager. +Modify startup options to include `-M /opt/librenms/mibs -m ALL` + In `/etc/snmp/snmptrapd.conf`, add something like the following: ```text diff --git a/includes/snmptrap.inc.php b/includes/snmptrap.inc.php new file mode 100644 index 0000000000..4b4aac49d8 --- /dev/null +++ b/includes/snmptrap.inc.php @@ -0,0 +1,16 @@ + 'down'), 'ports', 'port_id=?', array($interface['port_id'])); -} diff --git a/includes/snmptrap/linkUp.inc.php b/includes/snmptrap/linkUp.inc.php deleted file mode 100644 index 364f1013a4..0000000000 --- a/includes/snmptrap/linkUp.inc.php +++ /dev/null @@ -1,22 +0,0 @@ - 'up'), 'ports', 'port_id=?', array($interface['port_id'])); -} - -if ($ifOperStatus != $interface['ifOperStatus']) { - log_event("Interface went Up : " . $interface['ifDescr'] . " (TRAP)", $device, "interface", 1, $interface['port_id']); - dbUpdate(array('ifOperStatus' => 'up'), 'ports', 'port_id=?', array($interface['port_id'])); -} diff --git a/snmptrap.php b/snmptrap.php index e25b662145..be9f021fec 100755 --- a/snmptrap.php +++ b/snmptrap.php @@ -9,11 +9,11 @@ * @package LibreNMS * @subpackage snmptraps * @copyright (C) 2006 - 2012 Adam Armstrong + * @copyright (C) 2018 LibreNMS + * Adapted from old snmptrap.php handler */ -chdir(__DIR__); // cwd to the directory containing this script - -$init_modules = array(); +$init_modules = ['laravel', 'alerts-cli']; // so I don't have to rebase yet require __DIR__ . '/includes/init.php'; $options = getopt('d::'); @@ -22,24 +22,7 @@ if (set_debug(isset($options['d']))) { echo "DEBUG!\n"; } -$entry = explode(',', $argv[1]); +$text = stream_get_contents(STDIN); +$trap = new \LibreNMS\Snmptrap\Trap($text); -logfile($argv[1]); - -// print_r($entry); -$device = @dbFetchRow('SELECT * FROM devices WHERE `hostname` = ?', array($entry['0'])); - -if (!$device['device_id']) { - $device = @dbFetchRow('SELECT * FROM ipv4_addresses AS A, ports AS I WHERE A.ipv4_address = ? AND I.port_id = A.port_id', array($entry['0'])); -} - -if (!$device['device_id']) { - exit; -} - -$file = $config['install_dir'].'/includes/snmptrap/'.$entry['1'].'.inc.php'; -if (is_file($file)) { - include "$file"; -} else { - echo "unknown trap ($file)"; -} +$trap->handle(); // create handle and send it this trap diff --git a/tests/AuthSSOTest.php b/tests/AuthSSOTest.php index c61c49fc01..89bd0ec012 100644 --- a/tests/AuthSSOTest.php +++ b/tests/AuthSSOTest.php @@ -32,6 +32,7 @@ class AuthSSOTest extends DBTestCase { private $last_user = null; private $original_auth_mech = null; + private $server; public function setUp() { @@ -40,6 +41,8 @@ class AuthSSOTest extends DBTestCase $this->original_auth_mech = $config['auth_mechanism']; $config['auth_mechanism'] = 'sso'; + + $this->server = $_SERVER; } // Set up an SSO config for tests @@ -503,5 +506,7 @@ class AuthSSOTest extends DBTestCase $config['auth_mechanism'] = $this->original_auth_mech; unset($config['sso']); $this->breakUser(); + + $_SERVER = $this->server; } } diff --git a/tests/CreatesApplication.php b/tests/CreatesApplication.php index 547152f6a9..799885cecc 100644 --- a/tests/CreatesApplication.php +++ b/tests/CreatesApplication.php @@ -1,6 +1,6 @@ . + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Tests; + +use App\Models\BgpPeer; +use App\Models\Device; +use App\Models\Ipv4Address; +use App\Models\Port; +use Illuminate\Foundation\Testing\DatabaseTransactions; +use LibreNMS\Snmptrap\Trap; + +class SnmpTrapTest extends LaravelTestCase +{ + use DatabaseTransactions; + + public function testGarbage() + { + $trapText = "Garbage\n"; + + $trap = new Trap($trapText); + $this->assertFalse($trap->handle(), 'Found handler for trap with no snmpTrapOID'); + } + + public function testFindByIp() + { + $device = factory(Device::class)->create(); + $port = factory(Port::class)->make(); + $device->ports()->save($port); + $ipv4 = factory(Ipv4Address::class)->make(); // test ipv4 lookup of device + $port->ipv4()->save($ipv4); + + $trapText = "something +UDP: [$ipv4->ipv4_address]:64610->[192.168.5.5]:162 +DISMAN-EVENT-MIB::sysUpTimeInstance 198:2:10:48.91\n"; + + $trap = new Trap($trapText); + $this->assertFalse($trap->handle(), 'Found handler for trap with no snmpTrapOID'); + + // check that the device was found + $this->assertEquals($device->hostname, $trap->getDevice()->hostname); + } + + public function testAuthorization() + { + $device = factory(Device::class)->create(); + + $trapText = "$device->hostname +UDP: [$device->ip]:64610->[192.168.5.5]:162 +DISMAN-EVENT-MIB::sysUpTimeInstance 198:2:10:48.91 +SNMPv2-MIB::snmpTrapOID.0 SNMPv2-MIB::authenticationFailure\n"; + + $trap = new Trap($trapText); + $this->assertTrue($trap->handle()); + + // check that the device was found + $this->assertEquals($device->hostname, $trap->getDevice()->hostname); + +// $event = \App\Models\LogEvent::orderBy('datetime', 'desc')->first(); + +// dd($event); + } + + public function testBgpUp() + { + $device = factory(Device::class)->create(); + $bgppeer = factory(BgpPeer::class)->make(['bgpPeerState' => 'idle']); + $device->bgppeers()->save($bgppeer); + + $trapText = "$device->hostname +UDP: [$device->ip]:57602->[192.168.5.5]:162 +DISMAN-EVENT-MIB::sysUpTimeInstance 302:12:56:24.81 +SNMPv2-MIB::snmpTrapOID.0 BGP4-MIB::bgpEstablished +BGP4-MIB::bgpPeerLastError.$bgppeer->bgpPeerIdentifier \"04 00 \" +BGP4-MIB::bgpPeerState.$bgppeer->bgpPeerIdentifier established\n"; + + $trap = new Trap($trapText); + $this->assertTrue($trap->handle(), 'Could not handle bgpEstablished'); + + $bgppeer = $bgppeer->fresh(); // refresh from database + $this->assertEquals($bgppeer->bgpPeerState, 'established'); + } + + public function testBgpDown() + { + $device = factory(Device::class)->create(); + $bgppeer = factory(BgpPeer::class)->make(['bgpPeerState' => 'established']); + $device->bgppeers()->save($bgppeer); + + $trapText = "$device->hostname +UDP: [$device->ip]:57602->[185.29.68.52]:162 +DISMAN-EVENT-MIB::sysUpTimeInstance 302:12:55:33.47 +SNMPv2-MIB::snmpTrapOID.0 BGP4-MIB::bgpBackwardTransition +BGP4-MIB::bgpPeerLastError.$bgppeer->bgpPeerIdentifier \"04 00 \" +BGP4-MIB::bgpPeerState.$bgppeer->bgpPeerIdentifier idle\n"; + + $trap = new Trap($trapText); + $this->assertTrue($trap->handle(), 'Could not handle bgpBackwardTransition'); + + $bgppeer = $bgppeer->fresh(); // refresh from database + $this->assertEquals($bgppeer->bgpPeerState, 'idle'); + } + + public function testLinkDown() + { + // make a device and associate a port with it + $device = factory(Device::class)->create(); + $port = factory(Port::class)->make(['ifAdminStatus' => 'up', 'ifOperStatus' => 'up']); + $device->ports()->save($port); + + $trapText = " +UDP: [$device->ip]:57123->[192.168.4.4]:162 +DISMAN-EVENT-MIB::sysUpTimeInstance 2:15:07:12.87 +SNMPv2-MIB::snmpTrapOID.0 IF-MIB::linkDown +IF-MIB::ifIndex.$port->ifIndex $port->ifIndex +IF-MIB::ifAdminStatus.$port->ifIndex down +IF-MIB::ifOperStatus.$port->ifIndex down +IF-MIB::ifDescr.$port->ifIndex GigabitEthernet0/5 +IF-MIB::ifType.$port->ifIndex ethernetCsmacd +OLD-CISCO-INTERFACES-MIB::locIfReason.$port->ifIndex \"down\"\n"; + + $trap = new Trap($trapText); + $this->assertTrue($trap->handle(), 'Could not handle linkDown'); + + + $port = $port->fresh(); // refresh from database + $this->assertEquals($port->ifAdminStatus, 'down'); + $this->assertEquals($port->ifOperStatus, 'down'); + } + + public function testLinkUp() + { + // make a device and associate a port with it + $device = factory(Device::class)->create(); + $port = factory(Port::class)->make(['ifAdminStatus' => 'down', 'ifOperStatus' => 'down']); + $device->ports()->save($port); + + $trapText = " +UDP: [$device->ip]:57123->[185.29.68.52]:162 +DISMAN-EVENT-MIB::sysUpTimeInstance 2:15:07:18.21 +SNMPv2-MIB::snmpTrapOID.0 IF-MIB::linkUp +IF-MIB::ifIndex.$port->ifIndex $port->ifIndex +IF-MIB::ifAdminStatus.$port->ifIndex up +IF-MIB::ifOperStatus.$port->ifIndex up +IF-MIB::ifDescr.$port->ifIndex GigabitEthernet0/5 +IF-MIB::ifType.$port->ifIndex ethernetCsmacd +OLD-CISCO-INTERFACES-MIB::locIfReason.$port->ifIndex \"up\"\n"; + + $trap = new Trap($trapText); + $this->assertTrue($trap->handle(), 'Could not handle linkUp'); + + $port = $port->fresh(); // refresh from database + $this->assertEquals($port->ifAdminStatus, 'up'); + $this->assertEquals($port->ifOperStatus, 'up'); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 28590445a0..86a6e24d4b 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -79,6 +79,7 @@ if (getenv('DBTEST')) { exec($cmd, $schema); Config::load(); // reload the config including database config + load_all_os(); register_shutdown_function(function () use ($empty_db, $sql_mode) { global $config;