diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2022-06-09 04:52:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2022-06-09 04:52:39 +0000 |
commit | 89f3604407aff8f4cb2ed958252c61e23c767e24 (patch) | |
tree | 7fbf408102cab051557d38193524d8c6e991d070 /collectors/node.d.plugin | |
parent | Adding upstream version 1.34.1. (diff) | |
download | netdata-upstream/1.35.0.tar.xz netdata-upstream/1.35.0.zip |
Adding upstream version 1.35.0.upstream/1.35.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'collectors/node.d.plugin')
17 files changed, 0 insertions, 7073 deletions
diff --git a/collectors/node.d.plugin/Makefile.am b/collectors/node.d.plugin/Makefile.am deleted file mode 100644 index 1b8281748..000000000 --- a/collectors/node.d.plugin/Makefile.am +++ /dev/null @@ -1,57 +0,0 @@ -# SPDX-License-Identifier: GPL-3.0-or-later - -MAINTAINERCLEANFILES = $(srcdir)/Makefile.in -CLEANFILES = \ - node.d.plugin \ - $(NULL) - -include $(top_srcdir)/build/subst.inc -SUFFIXES = .in - -dist_libconfig_DATA = \ - node.d.conf \ - $(NULL) - -dist_plugins_SCRIPTS = \ - node.d.plugin \ - $(NULL) - -dist_noinst_DATA = \ - node.d.plugin.in \ - README.md \ - $(NULL) - -usernodeconfigdir=$(configdir)/node.d -dist_usernodeconfig_DATA = \ - $(NULL) - -# Explicitly install directories to avoid permission issues due to umask -install-exec-local: - $(INSTALL) -d $(DESTDIR)$(usernodeconfigdir) - -nodeconfigdir=$(libconfigdir)/node.d -dist_nodeconfig_DATA = \ - $(NULL) - -dist_node_DATA = \ - $(NULL) - -include snmp/Makefile.inc - -nodemodulesdir=$(nodedir)/node_modules -dist_nodemodules_DATA = \ - node_modules/netdata.js \ - node_modules/extend.js \ - node_modules/pixl-xml.js \ - node_modules/net-snmp.js \ - node_modules/asn1-ber.js \ - $(NULL) - -nodemoduleslibberdir=$(nodedir)/node_modules/lib/ber -dist_nodemoduleslibber_DATA = \ - node_modules/lib/ber/index.js \ - node_modules/lib/ber/errors.js \ - node_modules/lib/ber/reader.js \ - node_modules/lib/ber/types.js \ - node_modules/lib/ber/writer.js \ - $(NULL) diff --git a/collectors/node.d.plugin/README.md b/collectors/node.d.plugin/README.md deleted file mode 100644 index 4c5f278bd..000000000 --- a/collectors/node.d.plugin/README.md +++ /dev/null @@ -1,236 +0,0 @@ -<!-- -title: "node.d.plugin" -custom_edit_url: https://github.com/netdata/netdata/edit/master/collectors/node.d.plugin/README.md ---> - -# node.d.plugin - -`node.d.plugin` is a Netdata external plugin. It is an **orchestrator** for data collection modules written in `node.js`. - -1. It runs as an independent process `ps fax` shows it -2. It is started and stopped automatically by Netdata -3. It communicates with Netdata via a unidirectional pipe (sending data to the `netdata` daemon) -4. Supports any number of data collection **modules** -5. Allows each **module** to have one or more data collection **jobs** -6. Each **job** is collecting one or more metrics from a single data source - -## Pull Request Checklist for Node.js Plugins - -This is a generic checklist for submitting a new Node.js plugin for Netdata. It is by no means comprehensive. - -At minimum, to be buildable and testable, the PR needs to include: - -- The module itself, following proper naming conventions: `node.d/<module_dir>/<module_name>.node.js` -- A README.md file for the plugin. -- The configuration file for the module -- A basic configuration for the plugin in the appropriate global config file: `conf.d/node.d.conf`, which is also in JSON format. If the module should be enabled by default, add a section for it in the `modules` dictionary. -- A line for the plugin in the appropriate `Makefile.am` file: `node.d/Makefile.am` under `dist_node_DATA`. -- A line for the plugin configuration file in `conf.d/Makefile.am`: under `dist_nodeconfig_DATA` -- Optionally, chart information in `web/dashboard_info.js`. This generally involves specifying a name and icon for the section, and may include descriptions for the section or individual charts. - -## Motivation - -Node.js is perfect for asynchronous operations. It is very fast and quite common (actually the whole web is based on it). -Since data collection is not a CPU intensive task, node.js is an ideal solution for it. - -`node.d.plugin` is a Netdata plugin that provides an abstraction layer to allow easy and quick development of data -collectors in node.js. It also manages all its data collectors (placed in `/usr/libexec/netdata/node.d`) using a single -instance of node, thus lowering the memory footprint of data collection. - -Of course, there can be independent plugins written in node.js (placed in `/usr/libexec/netdata/plugins`). -These will have to be developed using the guidelines of **[External Plugins](/collectors/plugins.d/README.md)**. - -To run `node.js` plugins you need to have `node` installed in your system. - -In some older systems, the package named `node` is not node.js. It is a terminal emulation program called `ax25-node`. -In this case the node.js package may be referred as `nodejs`. Once you install `nodejs`, we suggest to link -`/usr/bin/nodejs` to `/usr/bin/node`, so that typing `node` in your terminal, opens node.js. - -## configuring `node.d.plugin` - -`node.d.plugin` can work even without any configuration. Its default configuration file is -`node.d.conf`. To edit it on your system, run `/etc/netdata/edit-config node.d.conf`. - -## configuring `node.d.plugin` modules - -`node.d.plugin` modules accept configuration in `JSON` format. - -Unfortunately, `JSON` files do not accept comments. So, the best way to describe them is to have markdown text files -with instructions. - -`JSON` has a very strict formatting. If you get errors from Netdata at `/var/log/netdata/error.log` that a certain -configuration file cannot be loaded, we suggest to verify it at <http://jsonlint.com/>. - -The files in this directory, provide usable examples for configuring each `node.d.plugin` module. - -## debugging modules written for node.d.plugin - -To test `node.d.plugin` modules, which are placed in `/usr/libexec/netdata/node.d`, you can run `node.d.plugin` by hand, -like this: - -```sh -# become user netdata -sudo su -s /bin/sh netdata - -# run the plugin in debug mode -/usr/libexec/netdata/plugins.d/node.d.plugin debug 1 X Y Z -``` - -`node.d.plugin` will run in `debug` mode (lots of debug info), with an update frequency of `1` second, evaluating only -the collector scripts `X` (i.e. `/usr/libexec/netdata/node.d/X.node.js`), `Y` and `Z`. -You can define zero or more modules. If none is defined, `node.d.plugin` will evaluate all modules available. - -Keep in mind that if your configs are not in `/etc/netdata`, you should do the following before running `node.d.plugin`: - -```sh -export NETDATA_USER_CONFIG_DIR="/path/to/etc/netdata" -``` - ---- - -## developing `node.d.plugin` modules - -Your data collection module should be split in 3 parts: - -- a function to fetch the data from its source. `node.d.plugin` already can fetch data from web sources, - so you don't need to do anything about it for http. - -- a function to process the fetched/manipulate the data fetched. This function will make a number of calls - to create charts and dimensions and pass the collected values to Netdata. - This is the only function you need to write for collecting http JSON data. - -- a `configure` and an `update` function, which take care of your module configuration and data refresh - respectively. You can use the supplied ones. - -Your module will automatically be able to process any number of servers, with different settings (even different -data collection frequencies). You will write just the work needed for one and `node.d.plugin` will do the rest. -For each server you are going to fetch data from, you will have to create a `service` (more later). - -### writing the data collection module - -To provide a module called `mymodule`, you have create the file `/usr/libexec/netdata/node.d/mymodule.node.js`, with this structure: - -```js -// the processor is needed only -// if you need a custom processor -// other than http -netdata.processors.myprocessor = { - name: 'myprocessor', - - process: function(service, callback) { - - /* do data collection here */ - - callback(data); - } -}; - -// this is the mymodule definition -var mymodule = { - processResponse: function(service, data) { - - /* send information to the Netdata server here */ - - }, - - configure: function(config) { - var eligible_services = 0; - - if(typeof(config.servers) === 'undefined' || config.servers.length === 0) { - - /* - * create a service using internal defaults; - * this is used for auto-detecting the settings - * if possible - */ - - netdata.service({ - name: 'a name for this service', - update_every: this.update_every, - module: this, - processor: netdata.processors.myprocessor, - // any other information your processor needs - }).execute(this.processResponse); - - eligible_services++; - } - else { - - /* - * create a service for each server in the - * configuration file - */ - - var len = config.servers.length; - while(len--) { - var server = config.servers[len]; - - netdata.service({ - name: server.name, - update_every: server.update_every, - module: this, - processor: netdata.processors.myprocessor, - // any other information your processor needs - }).execute(this.processResponse); - - eligible_services++; - } - } - - return eligible_services; - }, - - update: function(service, callback) { - - /* - * this function is called when each service - * created by the configure function, needs to - * collect updated values. - * - * You normally will not need to change it. - */ - - service.execute(function(service, data) { - mymodule.processResponse(service, data); - callback(); - }); - }, -}; - -module.exports = mymodule; -``` - -#### configure(config) - -`configure(config)` is called just once, when `node.d.plugin` starts. -The config file will contain the contents of `/etc/netdata/node.d/mymodule.conf`. -This file should have the following format: - -```js -{ - "enable_autodetect": false, - "update_every": 5, - "servers": [ { /* server 1 */ }, { /* server 2 */ } ] -} -``` - -If the config file `/etc/netdata/node.d/mymodule.conf` does not give a `enable_autodetect` or `update_every`, these -will be added by `node.d.plugin`. So you module will always have them. - -The configuration file `/etc/netdata/node.d/mymodule.conf` may contain whatever else is needed for `mymodule`. - -#### processResponse(data) - -`data` may be `null` or whatever the processor specified in the `service` returned. - -The `service` object defines a set of functions to allow you send information to the Netdata core about: - -1. Charts and dimension definitions -2. Updated values, from the collected values - ---- - -_FIXME: document an operational node.d.plugin data collector - the best example is the -[snmp collector](https://raw.githubusercontent.com/netdata/netdata/master/collectors/node.d.plugin/snmp/snmp.node.js)_ - - diff --git a/collectors/node.d.plugin/node.d.conf b/collectors/node.d.plugin/node.d.conf deleted file mode 100644 index c79274a5e..000000000 --- a/collectors/node.d.plugin/node.d.conf +++ /dev/null @@ -1,33 +0,0 @@ -{
- "___help_1": "Default options for node.d.plugin - this is a JSON file.",
- "___help_2": "Use http://jsonlint.com/ to verify it is valid JSON.",
- "___help_3": "------------------------------------------------------------",
-
- "___help_update_every": "Minimum data collection frequency for all node.d/*.node.js modules. Set it to 0 to inherit it from netdata.",
- "update_every": 0,
-
- "___help_modules_enable_autodetect": "Enable/disable auto-detection for node.d/*.node.js modules that support it.",
- "modules_enable_autodetect": true,
-
- "___help_modules_enable_all": "Enable all node.d/*.node.js modules by default.",
- "modules_enable_all": true,
-
- "___help_modules": "Enable/disable the following modules. Give only XXX for node.d/XXX.node.js",
- "modules": {
- "snmp": {
- "enabled": true
- }
- },
-
- "___help_paths": "Paths that control the operation of node.d.plugin",
- "paths": {
- "___help_plugins": "The full path to the modules javascript node.d/ directory",
- "plugins": null,
-
- "___help_config": "The full path to the modules configs node.d/ directory",
- "config": null,
-
- "___help_modules": "Array of paths to add to node.js when searching for node_modules",
- "modules": []
- }
-}
diff --git a/collectors/node.d.plugin/node.d.plugin.in b/collectors/node.d.plugin/node.d.plugin.in deleted file mode 100755 index 05c126e90..000000000 --- a/collectors/node.d.plugin/node.d.plugin.in +++ /dev/null @@ -1,303 +0,0 @@ -#!/usr/bin/env bash -':' //; exec "$(command -v nodejs || command -v node || echo "ERROR node IS NOT AVAILABLE IN THIS SYSTEM")" "$0" "$@" - -// shebang hack from: -// http://unix.stackexchange.com/questions/65235/universal-node-js-shebang - -// Initially this is run as a shell script. -// Then, the second line, finds nodejs or node or js in the system path -// and executes it with the shell parameters. - -// netdata -// real-time performance and health monitoring, done right! -// (C) 2017 Costa Tsaousis <costa@tsaousis.gr> -// SPDX-License-Identifier: GPL-3.0-or-later - -// -------------------------------------------------------------------------------------------------------------------- - -'use strict'; - -// -------------------------------------------------------------------------------------------------------------------- -// get NETDATA environment variables - -var NETDATA_PLUGINS_DIR = process.env.NETDATA_PLUGINS_DIR || __dirname; -var NETDATA_USER_CONFIG_DIR = process.env.NETDATA_USER_CONFIG_DIR || '@configdir_POST@'; -var NETDATA_STOCK_CONFIG_DIR = process.env.NETDATA_STOCK_CONFIG_DIR || '@libconfigdir_POST@'; -var NETDATA_UPDATE_EVERY = process.env.NETDATA_UPDATE_EVERY || 1; -var NODE_D_DIR = NETDATA_PLUGINS_DIR + '/../node.d'; - -// make sure the modules are found -process.mainModule.paths.unshift(NODE_D_DIR + '/node_modules'); -process.mainModule.paths.unshift(NODE_D_DIR); - - -// -------------------------------------------------------------------------------------------------------------------- -// load required modules - -var fs = require('fs'); -var url = require('url'); -var util = require('util'); -var http = require('http'); -var path = require('path'); -var extend = require('extend'); -var netdata = require('netdata'); - - -// -------------------------------------------------------------------------------------------------------------------- -// configuration - -function netdata_read_json_config_file(module_filename) { - var f = path.basename(module_filename); - - var ufilename, sfilename; - - var m = f.match('.plugin' + '$'); - if(m !== null) { - ufilename = netdata.options.paths.config + '/' + f.substring(0, m.index) + '.conf'; - sfilename = netdata.options.paths.stock_config + '/' + f.substring(0, m.index) + '.conf'; - } - - m = f.match('.node.js' + '$'); - if(m !== null) { - ufilename = netdata.options.paths.config + '/node.d/' + f.substring(0, m.index) + '.conf'; - sfilename = netdata.options.paths.stock_config + '/node.d/' + f.substring(0, m.index) + '.conf'; - } - - try { - netdata.debug('loading module\'s ' + module_filename + ' user-config ' + ufilename); - return JSON.parse(fs.readFileSync(ufilename, 'utf8')); - } - catch(e) { - netdata.error('Cannot read user-configuration file ' + ufilename + ': ' + e.message + '.'); - dumpError(e); - } - - try { - netdata.debug('loading module\'s ' + module_filename + ' stock-config ' + sfilename); - return JSON.parse(fs.readFileSync(sfilename, 'utf8')); - } - catch(e) { - netdata.error('Cannot read stock-configuration file ' + sfilename + ': ' + e.message + ', using internal defaults.'); - dumpError(e); - } - - return {}; -} - -// internal defaults -extend(true, netdata.options, { - filename: path.basename(__filename), - - update_every: NETDATA_UPDATE_EVERY, - - paths: { - plugins: NETDATA_PLUGINS_DIR, - config: NETDATA_USER_CONFIG_DIR, - stock_config: NETDATA_STOCK_CONFIG_DIR, - modules: [] - }, - - modules_enable_autodetect: true, - modules_enable_all: true, - modules: {} -}); - -// load configuration file -netdata.options_loaded = netdata_read_json_config_file(__filename); -extend(true, netdata.options, netdata.options_loaded); - -if(!netdata.options.paths.plugins) - netdata.options.paths.plugins = NETDATA_PLUGINS_DIR; - -if(!netdata.options.paths.config) - netdata.options.paths.config = NETDATA_USER_CONFIG_DIR; - -if(!netdata.options.paths.stock_config) - netdata.options.paths.stock_config = NETDATA_STOCK_CONFIG_DIR; - -// console.error('merged netdata object:'); -// console.error(util.inspect(netdata, {depth: 10})); - - -// apply module paths to node.js process -function applyModulePaths() { - var len = netdata.options.paths.modules.length; - while(len--) - process.mainModule.paths.unshift(netdata.options.paths.modules[len]); -} -applyModulePaths(); - - -// -------------------------------------------------------------------------------------------------------------------- -// tracing - -function dumpError(err) { - if (typeof err === 'object') { - if (err.stack) { - netdata.debug(err.stack); - } - } -} - -// -------------------------------------------------------------------------------------------------------------------- -// get command line arguments -{ - var found_myself = false; - var found_number = false; - var found_modules = false; - process.argv.forEach(function (val, index, array) { - netdata.debug('PARAM: ' + val); - - if(!found_myself) { - if(val === __filename) - found_myself = true; - } - else { - switch(val) { - case 'debug': - netdata.options.DEBUG = true; - netdata.debug('DEBUG enabled'); - break; - - default: - if(found_number === true) { - if(found_modules === false) { - for(var i in netdata.options.modules) - netdata.options.modules[i].enabled = false; - } - - if(typeof netdata.options.modules[val] === 'undefined') - netdata.options.modules[val] = {}; - - netdata.options.modules[val].enabled = true; - netdata.options.modules_enable_all = false; - netdata.debug('enabled module ' + val); - } - else { - try { - var x = parseInt(val); - if(x > 0) { - netdata.options.update_every = x; - if(netdata.options.update_every < NETDATA_UPDATE_EVERY) { - netdata.options.update_every = NETDATA_UPDATE_EVERY; - netdata.debug('Update frequency ' + x + 's is too low'); - } - - found_number = true; - netdata.debug('Update frequency set to ' + netdata.options.update_every + ' seconds'); - } - else netdata.error('Ignoring parameter: ' + val); - } - catch(e) { - netdata.error('Cannot get value of parameter: ' + val); - dumpError(e); - } - } - break; - } - } - }); -} - -if(netdata.options.update_every < 1) { - netdata.debug('Adjusting update frequency to 1 second'); - netdata.options.update_every = 1; -} - -// -------------------------------------------------------------------------------------------------------------------- -// find modules - -function findModules() { - var found = 0; - - var files = fs.readdirSync(NODE_D_DIR); - var len = files.length; - while(len--) { - var m = files[len].match('.node.js' + '$'); - if(m !== null) { - var n = files[len].substring(0, m.index); - - if(typeof(netdata.options.modules[n]) === 'undefined') - netdata.options.modules[n] = { name: n, enabled: netdata.options.modules_enable_all }; - - if(netdata.options.modules[n].enabled === true) { - netdata.options.modules[n].name = n; - netdata.options.modules[n].filename = NODE_D_DIR + '/' + files[len]; - netdata.options.modules[n].loaded = false; - - // load the module - try { - netdata.debug('loading module ' + netdata.options.modules[n].filename); - netdata.options.modules[n].module = require(netdata.options.modules[n].filename); - netdata.options.modules[n].module.name = n; - netdata.debug('loaded module ' + netdata.options.modules[n].name + ' from ' + netdata.options.modules[n].filename); - } - catch(e) { - netdata.options.modules[n].enabled = false; - netdata.error('Cannot load module: ' + netdata.options.modules[n].filename + ' exception: ' + e); - dumpError(e); - continue; - } - - // load its configuration - var c = { - enable_autodetect: netdata.options.modules_enable_autodetect, - update_every: netdata.options.update_every - }; - - var c2 = netdata_read_json_config_file(files[len]); - extend(true, c, c2); - - // call module auto-detection / configuration - try { - netdata.modules_configuring++; - netdata.debug('Configuring module ' + netdata.options.modules[n].name); - var serv = netdata.configure(netdata.options.modules[n].module, c, function() { - netdata.debug('Configured module ' + netdata.options.modules[n].name); - netdata.modules_configuring--; - }); - - netdata.debug('Configuring module ' + netdata.options.modules[n].name + ' reports ' + serv + ' eligible services.'); - } - catch(e) { - netdata.modules_configuring--; - netdata.options.modules[n].enabled = false; - netdata.error('Failed module auto-detection: ' + netdata.options.modules[n].name + ' exception: ' + e + ', disabling module.'); - dumpError(e); - continue; - } - - netdata.options.modules[n].loaded = true; - found++; - } - } - } - - // netdata.debug(netdata.options.modules); - return found; -} - -if(findModules() === 0) { - netdata.error('Cannot load any .node.js module from: ' + NODE_D_DIR); - netdata.disableNodePlugin(); - process.exit(1); -} - - -// -------------------------------------------------------------------------------------------------------------------- -// start - -function start_when_configuring_ends() { - if(netdata.modules_configuring > 0) { - netdata.debug('Waiting modules configuration, still running ' + netdata.modules_configuring); - setTimeout(start_when_configuring_ends, 500); - return; - } - - netdata.modules_configuring = 0; - netdata.start(); -} -start_when_configuring_ends(); - -//netdata.debug('netdata object:') -//netdata.debug(netdata); diff --git a/collectors/node.d.plugin/node_modules/asn1-ber.js b/collectors/node.d.plugin/node_modules/asn1-ber.js deleted file mode 100644 index 55c8f688e..000000000 --- a/collectors/node.d.plugin/node_modules/asn1-ber.js +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -var Ber = require('./lib/ber/index') - -exports.Ber = Ber -exports.BerReader = Ber.Reader -exports.BerWriter = Ber.Writer diff --git a/collectors/node.d.plugin/node_modules/extend.js b/collectors/node.d.plugin/node_modules/extend.js deleted file mode 100644 index 3cd2e9155..000000000 --- a/collectors/node.d.plugin/node_modules/extend.js +++ /dev/null @@ -1,88 +0,0 @@ -// https://github.com/justmoon/node-extend -// SPDX-License-Identifier: MIT - -'use strict'; - -var hasOwn = Object.prototype.hasOwnProperty; -var toStr = Object.prototype.toString; - -var isArray = function isArray(arr) { - if (typeof Array.isArray === 'function') { - return Array.isArray(arr); - } - - return toStr.call(arr) === '[object Array]'; -}; - -var isPlainObject = function isPlainObject(obj) { - if (!obj || toStr.call(obj) !== '[object Object]') { - return false; - } - - var hasOwnConstructor = hasOwn.call(obj, 'constructor'); - var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf'); - // Not own constructor property must be Object - if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) { - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - var key; - for (key in obj) { /**/ } - - return typeof key === 'undefined' || hasOwn.call(obj, key); -}; - -module.exports = function extend() { - var options, name, src, copy, copyIsArray, clone; - var target = arguments[0]; - var i = 1; - var length = arguments.length; - var deep = false; - - // Handle a deep copy situation - if (typeof target === 'boolean') { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } else if ((typeof target !== 'object' && typeof target !== 'function') || target == null) { - target = {}; - } - - for (; i < length; ++i) { - options = arguments[i]; - // Only deal with non-null/undefined values - if (options != null) { - // Extend the base object - for (name in options) { - src = target[name]; - copy = options[name]; - - // Prevent never-ending loop - if (target !== copy) { - // Recurse if we're merging plain objects or arrays - if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) { - if (copyIsArray) { - copyIsArray = false; - clone = src && isArray(src) ? src : []; - } else { - clone = src && isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[name] = extend(deep, clone, copy); - - // Don't bring in undefined values - } else if (typeof copy !== 'undefined') { - target[name] = copy; - } - } - } - } - } - - // Return the modified object - return target; -}; diff --git a/collectors/node.d.plugin/node_modules/lib/ber/errors.js b/collectors/node.d.plugin/node_modules/lib/ber/errors.js deleted file mode 100644 index 1c0df7b13..000000000 --- a/collectors/node.d.plugin/node_modules/lib/ber/errors.js +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT - -module.exports = { - InvalidAsn1Error: function(msg) { - var e = new Error() - e.name = 'InvalidAsn1Error' - e.message = msg || '' - return e - } -} diff --git a/collectors/node.d.plugin/node_modules/lib/ber/index.js b/collectors/node.d.plugin/node_modules/lib/ber/index.js deleted file mode 100644 index eb69ec526..000000000 --- a/collectors/node.d.plugin/node_modules/lib/ber/index.js +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT - -var errors = require('./errors') -var types = require('./types') - -var Reader = require('./reader') -var Writer = require('./writer') - -for (var t in types) - if (types.hasOwnProperty(t)) - exports[t] = types[t] - -for (var e in errors) - if (errors.hasOwnProperty(e)) - exports[e] = errors[e] - -exports.Reader = Reader -exports.Writer = Writer diff --git a/collectors/node.d.plugin/node_modules/lib/ber/reader.js b/collectors/node.d.plugin/node_modules/lib/ber/reader.js deleted file mode 100644 index 06decf4b9..000000000 --- a/collectors/node.d.plugin/node_modules/lib/ber/reader.js +++ /dev/null @@ -1,270 +0,0 @@ -// SPDX-License-Identifier: MIT - -var assert = require('assert'); - -var ASN1 = require('./types'); -var errors = require('./errors'); - - -///--- Globals - -var InvalidAsn1Error = errors.InvalidAsn1Error; - - - -///--- API - -function Reader(data) { - if (!data || !Buffer.isBuffer(data)) - throw new TypeError('data must be a node Buffer'); - - this._buf = data; - this._size = data.length; - - // These hold the "current" state - this._len = 0; - this._offset = 0; -} - -Object.defineProperty(Reader.prototype, 'length', { - enumerable: true, - get: function () { return (this._len); } -}); - -Object.defineProperty(Reader.prototype, 'offset', { - enumerable: true, - get: function () { return (this._offset); } -}); - -Object.defineProperty(Reader.prototype, 'remain', { - get: function () { return (this._size - this._offset); } -}); - -Object.defineProperty(Reader.prototype, 'buffer', { - get: function () { return (this._buf.slice(this._offset)); } -}); - - -/** - * Reads a single byte and advances offset; you can pass in `true` to make this - * a "peek" operation (i.e., get the byte, but don't advance the offset). - * - * @param {Boolean} peek true means don't move offset. - * @return {Number} the next byte, null if not enough data. - */ -Reader.prototype.readByte = function(peek) { - if (this._size - this._offset < 1) - return null; - - var b = this._buf[this._offset] & 0xff; - - if (!peek) - this._offset += 1; - - return b; -}; - - -Reader.prototype.peek = function() { - return this.readByte(true); -}; - - -/** - * Reads a (potentially) variable length off the BER buffer. This call is - * not really meant to be called directly, as callers have to manipulate - * the internal buffer afterwards. - * - * As a result of this call, you can call `Reader.length`, until the - * next thing called that does a readLength. - * - * @return {Number} the amount of offset to advance the buffer. - * @throws {InvalidAsn1Error} on bad ASN.1 - */ -Reader.prototype.readLength = function(offset) { - if (offset === undefined) - offset = this._offset; - - if (offset >= this._size) - return null; - - var lenB = this._buf[offset++] & 0xff; - if (lenB === null) - return null; - - if ((lenB & 0x80) == 0x80) { - lenB &= 0x7f; - - if (lenB == 0) - throw InvalidAsn1Error('Indefinite length not supported'); - - if (lenB > 4) - throw InvalidAsn1Error('encoding too long'); - - if (this._size - offset < lenB) - return null; - - this._len = 0; - for (var i = 0; i < lenB; i++) - this._len = (this._len << 8) + (this._buf[offset++] & 0xff); - - } else { - // Wasn't a variable length - this._len = lenB; - } - - return offset; -}; - - -/** - * Parses the next sequence in this BER buffer. - * - * To get the length of the sequence, call `Reader.length`. - * - * @return {Number} the sequence's tag. - */ -Reader.prototype.readSequence = function(tag) { - var seq = this.peek(); - if (seq === null) - return null; - if (tag !== undefined && tag !== seq) - throw InvalidAsn1Error('Expected 0x' + tag.toString(16) + - ': got 0x' + seq.toString(16)); - - var o = this.readLength(this._offset + 1); // stored in `length` - if (o === null) - return null; - - this._offset = o; - return seq; -}; - - -Reader.prototype.readInt = function(tag) { - if (typeof(tag) !== 'number') - tag = ASN1.Integer; - - return this._readTag(ASN1.Integer); -}; - - -Reader.prototype.readBoolean = function(tag) { - if (typeof(tag) !== 'number') - tag = ASN1.Boolean; - - return (this._readTag(tag) === 0 ? false : true); -}; - - -Reader.prototype.readEnumeration = function(tag) { - if (typeof(tag) !== 'number') - tag = ASN1.Enumeration; - - return this._readTag(ASN1.Enumeration); -}; - - -Reader.prototype.readString = function(tag, retbuf) { - if (!tag) - tag = ASN1.OctetString; - - var b = this.peek(); - if (b === null) - return null; - - if (b !== tag) - throw InvalidAsn1Error('Expected 0x' + tag.toString(16) + - ': got 0x' + b.toString(16)); - - var o = this.readLength(this._offset + 1); // stored in `length` - - if (o === null) - return null; - - if (this.length > this._size - o) - return null; - - this._offset = o; - - if (this.length === 0) - return retbuf ? new Buffer(0) : ''; - - var str = this._buf.slice(this._offset, this._offset + this.length); - this._offset += this.length; - - return retbuf ? str : str.toString('utf8'); -}; - -Reader.prototype.readOID = function(tag) { - if (!tag) - tag = ASN1.OID; - - var b = this.readString(tag, true); - if (b === null) - return null; - - var values = []; - var value = 0; - - for (var i = 0; i < b.length; i++) { - var byte = b[i] & 0xff; - - value <<= 7; - value += byte & 0x7f; - if ((byte & 0x80) == 0) { - values.push(value >>> 0); - value = 0; - } - } - - value = values.shift(); - values.unshift(value % 40); - values.unshift((value / 40) >> 0); - - return values.join('.'); -}; - - -Reader.prototype._readTag = function(tag) { - assert.ok(tag !== undefined); - - var b = this.peek(); - - if (b === null) - return null; - - if (b !== tag) - throw InvalidAsn1Error('Expected 0x' + tag.toString(16) + - ': got 0x' + b.toString(16)); - - var o = this.readLength(this._offset + 1); // stored in `length` - if (o === null) - return null; - - if (this.length > 4) - throw InvalidAsn1Error('Integer too long: ' + this.length); - - if (this.length > this._size - o) - return null; - this._offset = o; - - var fb = this._buf[this._offset]; - var value = 0; - - for (var i = 0; i < this.length; i++) { - value <<= 8; - value |= (this._buf[this._offset++] & 0xff); - } - - if ((fb & 0x80) == 0x80 && i !== 4) - value -= (1 << (i * 8)); - - return value >> 0; -}; - - - -///--- Exported API - -module.exports = Reader; diff --git a/collectors/node.d.plugin/node_modules/lib/ber/types.js b/collectors/node.d.plugin/node_modules/lib/ber/types.js deleted file mode 100644 index 7519ddcf5..000000000 --- a/collectors/node.d.plugin/node_modules/lib/ber/types.js +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: MIT - -module.exports = { - EOC: 0, - Boolean: 1, - Integer: 2, - BitString: 3, - OctetString: 4, - Null: 5, - OID: 6, - ObjectDescriptor: 7, - External: 8, - Real: 9, - Enumeration: 10, - PDV: 11, - Utf8String: 12, - RelativeOID: 13, - Sequence: 16, - Set: 17, - NumericString: 18, - PrintableString: 19, - T61String: 20, - VideotexString: 21, - IA5String: 22, - UTCTime: 23, - GeneralizedTime: 24, - GraphicString: 25, - VisibleString: 26, - GeneralString: 28, - UniversalString: 29, - CharacterString: 30, - BMPString: 31, - Constructor: 32, - Context: 128 -} diff --git a/collectors/node.d.plugin/node_modules/lib/ber/writer.js b/collectors/node.d.plugin/node_modules/lib/ber/writer.js deleted file mode 100644 index d3a718f14..000000000 --- a/collectors/node.d.plugin/node_modules/lib/ber/writer.js +++ /dev/null @@ -1,318 +0,0 @@ -// SPDX-License-Identifier: MIT - -var assert = require('assert'); -var ASN1 = require('./types'); -var errors = require('./errors'); - - -///--- Globals - -var InvalidAsn1Error = errors.InvalidAsn1Error; - -var DEFAULT_OPTS = { - size: 1024, - growthFactor: 8 -}; - - -///--- Helpers - -function merge(from, to) { - assert.ok(from); - assert.equal(typeof(from), 'object'); - assert.ok(to); - assert.equal(typeof(to), 'object'); - - var keys = Object.getOwnPropertyNames(from); - keys.forEach(function(key) { - if (to[key]) - return; - - var value = Object.getOwnPropertyDescriptor(from, key); - Object.defineProperty(to, key, value); - }); - - return to; -} - - - -///--- API - -function Writer(options) { - options = merge(DEFAULT_OPTS, options || {}); - - this._buf = new Buffer(options.size || 1024); - this._size = this._buf.length; - this._offset = 0; - this._options = options; - - // A list of offsets in the buffer where we need to insert - // sequence tag/len pairs. - this._seq = []; -} - -Object.defineProperty(Writer.prototype, 'buffer', { - get: function () { - if (this._seq.length) - throw new InvalidAsn1Error(this._seq.length + ' unended sequence(s)'); - - return (this._buf.slice(0, this._offset)); - } -}); - -Writer.prototype.writeByte = function(b) { - if (typeof(b) !== 'number') - throw new TypeError('argument must be a Number'); - - this._ensure(1); - this._buf[this._offset++] = b; -}; - - -Writer.prototype.writeInt = function(i, tag) { - if (typeof(i) !== 'number') - throw new TypeError('argument must be a Number'); - if (typeof(tag) !== 'number') - tag = ASN1.Integer; - - var sz = 4; - - while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000 >> 0)) && - (sz > 1)) { - sz--; - i <<= 8; - } - - if (sz > 4) - throw new InvalidAsn1Error('BER ints cannot be > 0xffffffff'); - - this._ensure(2 + sz); - this._buf[this._offset++] = tag; - this._buf[this._offset++] = sz; - - while (sz-- > 0) { - this._buf[this._offset++] = ((i & 0xff000000) >>> 24); - i <<= 8; - } - -}; - - -Writer.prototype.writeNull = function() { - this.writeByte(ASN1.Null); - this.writeByte(0x00); -}; - - -Writer.prototype.writeEnumeration = function(i, tag) { - if (typeof(i) !== 'number') - throw new TypeError('argument must be a Number'); - if (typeof(tag) !== 'number') - tag = ASN1.Enumeration; - - return this.writeInt(i, tag); -}; - - -Writer.prototype.writeBoolean = function(b, tag) { - if (typeof(b) !== 'boolean') - throw new TypeError('argument must be a Boolean'); - if (typeof(tag) !== 'number') - tag = ASN1.Boolean; - - this._ensure(3); - this._buf[this._offset++] = tag; - this._buf[this._offset++] = 0x01; - this._buf[this._offset++] = b ? 0xff : 0x00; -}; - - -Writer.prototype.writeString = function(s, tag) { - if (typeof(s) !== 'string') - throw new TypeError('argument must be a string (was: ' + typeof(s) + ')'); - if (typeof(tag) !== 'number') - tag = ASN1.OctetString; - - var len = Buffer.byteLength(s); - this.writeByte(tag); - this.writeLength(len); - if (len) { - this._ensure(len); - this._buf.write(s, this._offset); - this._offset += len; - } -}; - - -Writer.prototype.writeBuffer = function(buf, tag) { - if (!Buffer.isBuffer(buf)) - throw new TypeError('argument must be a buffer'); - - // If no tag is specified we will assume `buf` already contains tag and length - if (typeof(tag) === 'number') { - this.writeByte(tag); - this.writeLength(buf.length); - } - - this._ensure(buf.length); - buf.copy(this._buf, this._offset, 0, buf.length); - this._offset += buf.length; -}; - - -Writer.prototype.writeStringArray = function(strings, tag) { - if (! (strings instanceof Array)) - throw new TypeError('argument must be an Array[String]'); - - var self = this; - strings.forEach(function(s) { - self.writeString(s, tag); - }); -}; - -// This is really to solve DER cases, but whatever for now -Writer.prototype.writeOID = function(s, tag) { - if (typeof(s) !== 'string') - throw new TypeError('argument must be a string'); - if (typeof(tag) !== 'number') - tag = ASN1.OID; - - if (!/^([0-9]+\.){3,}[0-9]+$/.test(s)) - throw new Error('argument is not a valid OID string'); - - function encodeOctet(bytes, octet) { - if (octet < 128) { - bytes.push(octet); - } else if (octet < 16384) { - bytes.push((octet >>> 7) | 0x80); - bytes.push(octet & 0x7F); - } else if (octet < 2097152) { - bytes.push((octet >>> 14) | 0x80); - bytes.push(((octet >>> 7) | 0x80) & 0xFF); - bytes.push(octet & 0x7F); - } else if (octet < 268435456) { - bytes.push((octet >>> 21) | 0x80); - bytes.push(((octet >>> 14) | 0x80) & 0xFF); - bytes.push(((octet >>> 7) | 0x80) & 0xFF); - bytes.push(octet & 0x7F); - } else { - bytes.push(((octet >>> 28) | 0x80) & 0xFF); - bytes.push(((octet >>> 21) | 0x80) & 0xFF); - bytes.push(((octet >>> 14) | 0x80) & 0xFF); - bytes.push(((octet >>> 7) | 0x80) & 0xFF); - bytes.push(octet & 0x7F); - } - } - - var tmp = s.split('.'); - var bytes = []; - bytes.push(parseInt(tmp[0], 10) * 40 + parseInt(tmp[1], 10)); - tmp.slice(2).forEach(function(b) { - encodeOctet(bytes, parseInt(b, 10)); - }); - - var self = this; - this._ensure(2 + bytes.length); - this.writeByte(tag); - this.writeLength(bytes.length); - bytes.forEach(function(b) { - self.writeByte(b); - }); -}; - - -Writer.prototype.writeLength = function(len) { - if (typeof(len) !== 'number') - throw new TypeError('argument must be a Number'); - - this._ensure(4); - - if (len <= 0x7f) { - this._buf[this._offset++] = len; - } else if (len <= 0xff) { - this._buf[this._offset++] = 0x81; - this._buf[this._offset++] = len; - } else if (len <= 0xffff) { - this._buf[this._offset++] = 0x82; - this._buf[this._offset++] = len >> 8; - this._buf[this._offset++] = len; - } else if (len <= 0xffffff) { - this._buf[this._offset++] = 0x83; - this._buf[this._offset++] = len >> 16; - this._buf[this._offset++] = len >> 8; - this._buf[this._offset++] = len; - } else { - throw new InvalidAsn1Error('Length too long (> 4 bytes)'); - } -}; - -Writer.prototype.startSequence = function(tag) { - if (typeof(tag) !== 'number') - tag = ASN1.Sequence | ASN1.Constructor; - - this.writeByte(tag); - this._seq.push(this._offset); - this._ensure(3); - this._offset += 3; -}; - - -Writer.prototype.endSequence = function() { - var seq = this._seq.pop(); - var start = seq + 3; - var len = this._offset - start; - - if (len <= 0x7f) { - this._shift(start, len, -2); - this._buf[seq] = len; - } else if (len <= 0xff) { - this._shift(start, len, -1); - this._buf[seq] = 0x81; - this._buf[seq + 1] = len; - } else if (len <= 0xffff) { - this._buf[seq] = 0x82; - this._buf[seq + 1] = len >> 8; - this._buf[seq + 2] = len; - } else if (len <= 0xffffff) { - this._shift(start, len, 1); - this._buf[seq] = 0x83; - this._buf[seq + 1] = len >> 16; - this._buf[seq + 2] = len >> 8; - this._buf[seq + 3] = len; - } else { - throw new InvalidAsn1Error('Sequence too long'); - } -}; - - -Writer.prototype._shift = function(start, len, shift) { - assert.ok(start !== undefined); - assert.ok(len !== undefined); - assert.ok(shift); - - this._buf.copy(this._buf, start + shift, start, start + len); - this._offset += shift; -}; - -Writer.prototype._ensure = function(len) { - assert.ok(len); - - if (this._size - this._offset < len) { - var sz = this._size * this._options.growthFactor; - if (sz - this._offset < len) - sz += len; - - var buf = new Buffer(sz); - - this._buf.copy(buf, 0, 0, this._offset); - this._buf = buf; - this._size = sz; - } -}; - - - -///--- Exported API - -module.exports = Writer; diff --git a/collectors/node.d.plugin/node_modules/net-snmp.js b/collectors/node.d.plugin/node_modules/net-snmp.js deleted file mode 100644 index 6b5b754ea..000000000 --- a/collectors/node.d.plugin/node_modules/net-snmp.js +++ /dev/null @@ -1,3452 +0,0 @@ -// Copyright 2013 Stephen Vickers <stephen.vickers.sv@gmail.com> -// SPDX-License-Identifier: MIT - -var ber = require("asn1-ber").Ber; -var dgram = require("dgram"); -var events = require("events"); -var util = require("util"); -var crypto = require("crypto"); - -var DEBUG = false; - -var MAX_INT32 = 2147483647; - -function debug(line) { - if (DEBUG) { - console.debug(line); - } -} - -/***************************************************************************** - ** Constants - **/ - - -function _expandConstantObject(object) { - var keys = []; - for (var key in object) - keys.push(key); - for (var i = 0; i < keys.length; i++) - object[object[keys[i]]] = parseInt(keys[i]); -} - -var ErrorStatus = { - 0: "NoError", - 1: "TooBig", - 2: "NoSuchName", - 3: "BadValue", - 4: "ReadOnly", - 5: "GeneralError", - 6: "NoAccess", - 7: "WrongType", - 8: "WrongLength", - 9: "WrongEncoding", - 10: "WrongValue", - 11: "NoCreation", - 12: "InconsistentValue", - 13: "ResourceUnavailable", - 14: "CommitFailed", - 15: "UndoFailed", - 16: "AuthorizationError", - 17: "NotWritable", - 18: "InconsistentName" -}; - -_expandConstantObject(ErrorStatus); - -var ObjectType = { - 1: "Boolean", - 2: "Integer", - 4: "OctetString", - 5: "Null", - 6: "OID", - 64: "IpAddress", - 65: "Counter", - 66: "Gauge", - 67: "TimeTicks", - 68: "Opaque", - 70: "Counter64", - 128: "NoSuchObject", - 129: "NoSuchInstance", - 130: "EndOfMibView" -}; - -_expandConstantObject(ObjectType); - -ObjectType.Integer32 = ObjectType.Integer; -ObjectType.Counter32 = ObjectType.Counter; -ObjectType.Gauge32 = ObjectType.Gauge; -ObjectType.Unsigned32 = ObjectType.Gauge32; - -var PduType = { - 160: "GetRequest", - 161: "GetNextRequest", - 162: "GetResponse", - 163: "SetRequest", - 164: "Trap", - 165: "GetBulkRequest", - 166: "InformRequest", - 167: "TrapV2", - 168: "Report" -}; - -_expandConstantObject(PduType); - -var TrapType = { - 0: "ColdStart", - 1: "WarmStart", - 2: "LinkDown", - 3: "LinkUp", - 4: "AuthenticationFailure", - 5: "EgpNeighborLoss", - 6: "EnterpriseSpecific" -}; - -_expandConstantObject(TrapType); - -var SecurityLevel = { - 1: "noAuthNoPriv", - 2: "authNoPriv", - 3: "authPriv" -}; - -_expandConstantObject(SecurityLevel); - -var AuthProtocols = { - "1": "none", - "2": "md5", - "3": "sha" -}; - -_expandConstantObject(AuthProtocols); - -var PrivProtocols = { - "1": "none", - "2": "des" -}; - -_expandConstantObject(PrivProtocols); - -var MibProviderType = { - "1": "Scalar", - "2": "Table" -}; - -_expandConstantObject(MibProviderType); - -var Version1 = 0; -var Version2c = 1; -var Version3 = 3; - -var Version = { - "1": Version1, - "2c": Version2c, - "3": Version3 -}; - -/***************************************************************************** - ** Exception class definitions - **/ - -function ResponseInvalidError(message) { - this.name = "ResponseInvalidError"; - this.message = message; - Error.captureStackTrace(this, ResponseInvalidError); -} - -util.inherits(ResponseInvalidError, Error); - -function RequestInvalidError(message) { - this.name = "RequestInvalidError"; - this.message = message; - Error.captureStackTrace(this, RequestInvalidError); -} - -util.inherits(RequestInvalidError, Error); - -function RequestFailedError(message, status) { - this.name = "RequestFailedError"; - this.message = message; - this.status = status; - Error.captureStackTrace(this, RequestFailedError); -} - -util.inherits(RequestFailedError, Error); - -function RequestTimedOutError(message) { - this.name = "RequestTimedOutError"; - this.message = message; - Error.captureStackTrace(this, RequestTimedOutError); -} - -util.inherits(RequestTimedOutError, Error); - -/***************************************************************************** - ** OID and varbind helper functions - **/ - -function isVarbindError(varbind) { - return !!(varbind.type == ObjectType.NoSuchObject - || varbind.type == ObjectType.NoSuchInstance - || varbind.type == ObjectType.EndOfMibView); -} - -function varbindError(varbind) { - return (ObjectType[varbind.type] || "NotAnError") + ": " + varbind.oid; -} - -function oidFollowsOid(oidString, nextString) { - var oid = {str: oidString, len: oidString.length, idx: 0}; - var next = {str: nextString, len: nextString.length, idx: 0}; - var dotCharCode = ".".charCodeAt(0); - - function getNumber(item) { - var n = 0; - if (item.idx >= item.len) - return null; - while (item.idx < item.len) { - var charCode = item.str.charCodeAt(item.idx++); - if (charCode == dotCharCode) - return n; - n = (n ? (n * 10) : n) + (charCode - 48); - } - return n; - } - - while (1) { - var oidNumber = getNumber(oid); - var nextNumber = getNumber(next); - - if (oidNumber !== null) { - if (nextNumber !== null) { - if (nextNumber > oidNumber) { - return true; - } else if (nextNumber < oidNumber) { - return false; - } - } else { - return true; - } - } else { - return true; - } - } -} - -function oidInSubtree(oidString, nextString) { - var oid = oidString.split("."); - var next = nextString.split("."); - - if (oid.length > next.length) - return false; - - for (var i = 0; i < oid.length; i++) { - if (next[i] != oid[i]) - return false; - } - - return true; -} - -/** - ** Some SNMP agents produce integers on the wire such as 00 ff ff ff ff. - ** The ASN.1 BER parser we use throws an error when parsing this, which we - ** believe is correct. So, we decided not to bother the "asn1" developer(s) - ** with this, instead opting to work around it here. - ** - ** If an integer is 5 bytes in length we check if the first byte is 0, and if so - ** simply drop it and parse it like it was a 4 byte integer, otherwise throw - ** an error since the integer is too large. - **/ - -function readInt(buffer) { - return readUint(buffer, true); -} - -function readIpAddress(buffer) { - var bytes = buffer.readString(ObjectType.IpAddress, true); - if (bytes.length != 4) - throw new ResponseInvalidError("Length '" + bytes.length - + "' of IP address '" + bytes.toString("hex") - + "' is not 4"); - var value = bytes[0] + "." + bytes[1] + "." + bytes[2] + "." + bytes[3]; - return value; -} - -function readUint(buffer, isSigned) { - buffer.readByte(); - var length = buffer.readByte(); - var value = 0; - var signedBitSet = false; - - if (length > 5) { - throw new RangeError("Integer too long '" + length + "'"); - } else if (length == 5) { - if (buffer.readByte() !== 0) - throw new RangeError("Integer too long '" + length + "'"); - length = 4; - } - - for (var i = 0; i < length; i++) { - value *= 256; - value += buffer.readByte(); - - if (isSigned && i <= 0) { - if ((value & 0x80) == 0x80) - signedBitSet = true; - } - } - - if (signedBitSet) - value -= (1 << (i * 8)); - - return value; -} - -function readUint64(buffer) { - var value = buffer.readString(ObjectType.Counter64, true); - - return value; -} - -function readVarbinds(buffer, varbinds) { - buffer.readSequence(); - - while (1) { - buffer.readSequence(); - if (buffer.peek() != ObjectType.OID) - break; - var oid = buffer.readOID(); - var type = buffer.peek(); - - if (type == null) - break; - - var value; - - if (type == ObjectType.Boolean) { - value = buffer.readBoolean(); - } else if (type == ObjectType.Integer) { - value = readInt(buffer); - } else if (type == ObjectType.OctetString) { - value = buffer.readString(null, true); - } else if (type == ObjectType.Null) { - buffer.readByte(); - buffer.readByte(); - value = null; - } else if (type == ObjectType.OID) { - value = buffer.readOID(); - } else if (type == ObjectType.IpAddress) { - var bytes = buffer.readString(ObjectType.IpAddress, true); - if (bytes.length != 4) - throw new ResponseInvalidError("Length '" + bytes.length - + "' of IP address '" + bytes.toString("hex") - + "' is not 4"); - value = bytes[0] + "." + bytes[1] + "." + bytes[2] + "." + bytes[3]; - } else if (type == ObjectType.Counter) { - value = readUint(buffer); - } else if (type == ObjectType.Gauge) { - value = readUint(buffer); - } else if (type == ObjectType.TimeTicks) { - value = readUint(buffer); - } else if (type == ObjectType.Opaque) { - value = buffer.readString(ObjectType.Opaque, true); - } else if (type == ObjectType.Counter64) { - value = readUint64(buffer); - } else if (type == ObjectType.NoSuchObject) { - buffer.readByte(); - buffer.readByte(); - value = null; - } else if (type == ObjectType.NoSuchInstance) { - buffer.readByte(); - buffer.readByte(); - value = null; - } else if (type == ObjectType.EndOfMibView) { - buffer.readByte(); - buffer.readByte(); - value = null; - } else { - throw new ResponseInvalidError("Unknown type '" + type - + "' in response"); - } - - varbinds.push({ - oid: oid, - type: type, - value: value - }); - } -} - -function writeUint(buffer, type, value) { - var b = Buffer.alloc(4); - b.writeUInt32BE(value, 0); - buffer.writeBuffer(b, type); -} - -function writeUint64(buffer, value) { - buffer.writeBuffer(value, ObjectType.Counter64); -} - -function writeVarbinds(buffer, varbinds) { - buffer.startSequence(); - for (var i = 0; i < varbinds.length; i++) { - buffer.startSequence(); - buffer.writeOID(varbinds[i].oid); - - if (varbinds[i].type && varbinds[i].hasOwnProperty("value")) { - var type = varbinds[i].type; - var value = varbinds[i].value; - - if (type == ObjectType.Boolean) { - buffer.writeBoolean(value ? true : false); - } else if (type == ObjectType.Integer) { // also Integer32 - buffer.writeInt(value); - } else if (type == ObjectType.OctetString) { - if (typeof value == "string") - buffer.writeString(value); - else - buffer.writeBuffer(value, ObjectType.OctetString); - } else if (type == ObjectType.Null) { - buffer.writeNull(); - } else if (type == ObjectType.OID) { - buffer.writeOID(value); - } else if (type == ObjectType.IpAddress) { - var bytes = value.split("."); - if (bytes.length != 4) - throw new RequestInvalidError("Invalid IP address '" - + value + "'"); - buffer.writeBuffer(Buffer.from(bytes), 64); - } else if (type == ObjectType.Counter) { // also Counter32 - writeUint(buffer, ObjectType.Counter, value); - } else if (type == ObjectType.Gauge) { // also Gauge32 & Unsigned32 - writeUint(buffer, ObjectType.Gauge, value); - } else if (type == ObjectType.TimeTicks) { - writeUint(buffer, ObjectType.TimeTicks, value); - } else if (type == ObjectType.Opaque) { - buffer.writeBuffer(value, ObjectType.Opaque); - } else if (type == ObjectType.Counter64) { - writeUint64(buffer, value); - } else if (type == ObjectType.EndOfMibView) { - buffer.writeByte(130); - buffer.writeByte(0); - } else { - throw new RequestInvalidError("Unknown type '" + type - + "' in request"); - } - } else { - buffer.writeNull(); - } - - buffer.endSequence(); - } - buffer.endSequence(); -} - -/***************************************************************************** - ** PDU class definitions - **/ - -var SimplePdu = function () { -}; - -SimplePdu.prototype.toBuffer = function (buffer) { - buffer.startSequence(this.type); - - buffer.writeInt(this.id); - buffer.writeInt((this.type == PduType.GetBulkRequest) - ? (this.options.nonRepeaters || 0) - : 0); - buffer.writeInt((this.type == PduType.GetBulkRequest) - ? (this.options.maxRepetitions || 0) - : 0); - - writeVarbinds(buffer, this.varbinds); - - buffer.endSequence(); -}; - -SimplePdu.prototype.initializeFromVariables = function (id, varbinds, options) { - this.id = id; - this.varbinds = varbinds; - this.options = options || {}; - this.contextName = (options && options.context) ? options.context : ""; -} - -SimplePdu.prototype.initializeFromBuffer = function (reader) { - this.type = reader.peek(); - reader.readSequence(); - - this.id = reader.readInt(); - this.nonRepeaters = reader.readInt(); - this.maxRepetitions = reader.readInt(); - - this.varbinds = []; - readVarbinds(reader, this.varbinds); - -}; - -SimplePdu.prototype.getResponsePduForRequest = function () { - var responsePdu = GetResponsePdu.createFromVariables(this.id, [], {}); - if (this.contextEngineID) { - responsePdu.contextEngineID = this.contextEngineID; - responsePdu.contextName = this.contextName; - } - return responsePdu; -}; - -SimplePdu.createFromVariables = function (pduClass, id, varbinds, options) { - var pdu = new pduClass(id, varbinds, options); - pdu.id = id; - pdu.varbinds = varbinds; - pdu.options = options || {}; - pdu.contextName = (options && options.context) ? options.context : ""; - return pdu; -}; - -var GetBulkRequestPdu = function () { - this.type = PduType.GetBulkRequest; - GetBulkRequestPdu.super_.apply(this, arguments); -}; - -util.inherits(GetBulkRequestPdu, SimplePdu); - -GetBulkRequestPdu.createFromBuffer = function (reader) { - var pdu = new GetBulkRequestPdu(); - pdu.initializeFromBuffer(reader); - return pdu; -}; - -var GetNextRequestPdu = function () { - this.type = PduType.GetNextRequest; - GetNextRequestPdu.super_.apply(this, arguments); -}; - -util.inherits(GetNextRequestPdu, SimplePdu); - -GetNextRequestPdu.createFromBuffer = function (reader) { - var pdu = new GetNextRequestPdu(); - pdu.initializeFromBuffer(reader); - return pdu; -}; - -var GetRequestPdu = function () { - this.type = PduType.GetRequest; - GetRequestPdu.super_.apply(this, arguments); -}; - -util.inherits(GetRequestPdu, SimplePdu); - -GetRequestPdu.createFromBuffer = function (reader) { - var pdu = new GetRequestPdu(); - pdu.initializeFromBuffer(reader); - return pdu; -}; - -GetRequestPdu.createFromVariables = function (id, varbinds, options) { - var pdu = new GetRequestPdu(); - pdu.initializeFromVariables(id, varbinds, options); - return pdu; -}; - -var InformRequestPdu = function () { - this.type = PduType.InformRequest; - InformRequestPdu.super_.apply(this, arguments); -}; - -util.inherits(InformRequestPdu, SimplePdu); - -InformRequestPdu.createFromBuffer = function (reader) { - var pdu = new InformRequestPdu(); - pdu.initializeFromBuffer(reader); - return pdu; -}; - -var SetRequestPdu = function () { - this.type = PduType.SetRequest; - SetRequestPdu.super_.apply(this, arguments); -}; - -util.inherits(SetRequestPdu, SimplePdu); - -SetRequestPdu.createFromBuffer = function (reader) { - var pdu = new SetRequestPdu(); - pdu.initializeFromBuffer(reader); - return pdu; -}; - -var TrapPdu = function () { - this.type = PduType.Trap; -}; - -TrapPdu.prototype.toBuffer = function (buffer) { - buffer.startSequence(this.type); - - buffer.writeOID(this.enterprise); - buffer.writeBuffer(Buffer.from(this.agentAddr.split(".")), - ObjectType.IpAddress); - buffer.writeInt(this.generic); - buffer.writeInt(this.specific); - writeUint(buffer, ObjectType.TimeTicks, - this.upTime || Math.floor(process.uptime() * 100)); - - writeVarbinds(buffer, this.varbinds); - - buffer.endSequence(); -}; - -TrapPdu.createFromBuffer = function (reader) { - var pdu = new TrapPdu(); - reader.readSequence(); - - pdu.enterprise = reader.readOID(); - pdu.agentAddr = readIpAddress(reader); - pdu.generic = reader.readInt(); - pdu.specific = reader.readInt(); - pdu.upTime = readUint(reader) - - pdu.varbinds = []; - readVarbinds(reader, pdu.varbinds); - - return pdu; -}; - -TrapPdu.createFromVariables = function (typeOrOid, varbinds, options) { - var pdu = new TrapPdu(); - pdu.agentAddr = options.agentAddr || "127.0.0.1"; - pdu.upTime = options.upTime; - - if (typeof typeOrOid == "string") { - pdu.generic = TrapType.EnterpriseSpecific; - pdu.specific = parseInt(typeOrOid.match(/\.(\d+)$/)[1]); - pdu.enterprise = typeOrOid.replace(/\.(\d+)$/, ""); - } else { - pdu.generic = typeOrOid; - pdu.specific = 0; - pdu.enterprise = "1.3.6.1.4.1"; - } - - pdu.varbinds = varbinds; - - return pdu; -}; - -var TrapV2Pdu = function () { - this.type = PduType.TrapV2; - TrapV2Pdu.super_.apply(this, arguments); -}; - -util.inherits(TrapV2Pdu, SimplePdu); - -TrapV2Pdu.createFromBuffer = function (reader) { - var pdu = new TrapV2Pdu(); - pdu.initializeFromBuffer(reader); - return pdu; -}; - -TrapV2Pdu.createFromVariables = function (id, varbinds, options) { - var pdu = new TrapV2Pdu(); - pdu.initializeFromVariables(id, varbinds, options); - return pdu; -}; - -var SimpleResponsePdu = function () { -}; - -SimpleResponsePdu.prototype.toBuffer = function (writer) { - writer.startSequence(this.type); - - writer.writeInt(this.id); - writer.writeInt(this.errorStatus || 0); - writer.writeInt(this.errorIndex || 0); - writeVarbinds(writer, this.varbinds); - writer.endSequence(); - -}; - -SimpleResponsePdu.prototype.initializeFromBuffer = function (reader) { - reader.readSequence(this.type); - - this.id = reader.readInt(); - this.errorStatus = reader.readInt(); - this.errorIndex = reader.readInt(); - - this.varbinds = []; - readVarbinds(reader, this.varbinds); -}; - -SimpleResponsePdu.prototype.initializeFromVariables = function (id, varbinds, options) { - this.id = id; - this.varbinds = varbinds; - this.options = options || {}; -}; - -var GetResponsePdu = function () { - this.type = PduType.GetResponse; - GetResponsePdu.super_.apply(this, arguments); -}; - -util.inherits(GetResponsePdu, SimpleResponsePdu); - -GetResponsePdu.createFromBuffer = function (reader) { - var pdu = new GetResponsePdu(); - pdu.initializeFromBuffer(reader); - return pdu; -}; - -GetResponsePdu.createFromVariables = function (id, varbinds, options) { - var pdu = new GetResponsePdu(); - pdu.initializeFromVariables(id, varbinds, options); - return pdu; -}; - -var ReportPdu = function () { - this.type = PduType.Report; - ReportPdu.super_.apply(this, arguments); -}; - -util.inherits(ReportPdu, SimpleResponsePdu); - -ReportPdu.createFromBuffer = function (reader) { - var pdu = new ReportPdu(); - pdu.initializeFromBuffer(reader); - return pdu; -}; - -ReportPdu.createFromVariables = function (id, varbinds, options) { - var pdu = new ReportPdu(); - pdu.initializeFromVariables(id, varbinds, options); - return pdu; -}; - -var readPdu = function (reader, scoped) { - var pdu; - var contextEngineID; - var contextName; - if (scoped) { - reader.readSequence(); - contextEngineID = reader.readString(ber.OctetString, true); - contextName = reader.readString(); - } - var type = reader.peek(); - - if (type == PduType.GetResponse) { - pdu = GetResponsePdu.createFromBuffer(reader); - } else if (type == PduType.Report) { - pdu = ReportPdu.createFromBuffer(reader); - } else if (type == PduType.Trap) { - pdu = TrapPdu.createFromBuffer(reader); - } else if (type == PduType.TrapV2) { - pdu = TrapV2Pdu.createFromBuffer(reader); - } else if (type == PduType.InformRequest) { - pdu = InformRequestPdu.createFromBuffer(reader); - } else if (type == PduType.GetRequest) { - pdu = GetRequestPdu.createFromBuffer(reader); - } else if (type == PduType.SetRequest) { - pdu = SetRequestPdu.createFromBuffer(reader); - } else if (type == PduType.GetNextRequest) { - pdu = GetNextRequestPdu.createFromBuffer(reader); - } else if (type == PduType.GetBulkRequest) { - pdu = GetBulkRequestPdu.createFromBuffer(reader); - } else { - throw new ResponseInvalidError("Unknown PDU type '" + type - + "' in response"); - } - if (scoped) { - pdu.contextEngineID = contextEngineID; - pdu.contextName = contextName; - } - pdu.scoped = scoped; - return pdu; -}; - -var createDiscoveryPdu = function (context) { - return GetRequestPdu.createFromVariables(_generateId(), [], {context: context}); -}; - -var Authentication = {}; - -Authentication.HMAC_BUFFER_SIZE = 1024 * 1024; -Authentication.HMAC_BLOCK_SIZE = 64; -Authentication.AUTHENTICATION_CODE_LENGTH = 12; -Authentication.AUTH_PARAMETERS_PLACEHOLDER = Buffer.from('8182838485868788898a8b8c', 'hex'); - -Authentication.algorithms = {}; - -Authentication.algorithms[AuthProtocols.md5] = { - // KEY_LENGTH: 16, - CRYPTO_ALGORITHM: 'md5' -}; - -Authentication.algorithms[AuthProtocols.sha] = { - // KEY_LENGTH: 20, - CRYPTO_ALGORITHM: 'sha1' -}; - -// Adapted from RFC3414 Appendix A.2.1. Password to Key Sample Code for MD5 -Authentication.passwordToKey = function (authProtocol, authPasswordString, engineID) { - var hashAlgorithm; - var firstDigest; - var finalDigest; - var buf = Buffer.alloc(Authentication.HMAC_BUFFER_SIZE); - var bufOffset = 0; - var passwordIndex = 0; - var count = 0; - var password = Buffer.from(authPasswordString); - var cryptoAlgorithm = Authentication.algorithms[authProtocol].CRYPTO_ALGORITHM; - - while (count < Authentication.HMAC_BUFFER_SIZE) { - for (var i = 0; i < Authentication.HMAC_BLOCK_SIZE; i++) { - buf.writeUInt8(password[passwordIndex++ % password.length], bufOffset++); - } - count += Authentication.HMAC_BLOCK_SIZE; - } - hashAlgorithm = crypto.createHash(cryptoAlgorithm); - hashAlgorithm.update(buf); - firstDigest = hashAlgorithm.digest(); - // debug ("First digest: " + firstDigest.toString('hex')); - - hashAlgorithm = crypto.createHash(cryptoAlgorithm); - hashAlgorithm.update(firstDigest); - hashAlgorithm.update(engineID); - hashAlgorithm.update(firstDigest); - finalDigest = hashAlgorithm.digest(); - debug("Localized key: " + finalDigest.toString('hex')); - - return finalDigest; -}; - -Authentication.addParametersToMessageBuffer = function (messageBuffer, authProtocol, authPassword, engineID) { - var authenticationParametersOffset; - var digestToAdd; - - // clear the authenticationParameters field in message - authenticationParametersOffset = messageBuffer.indexOf(Authentication.AUTH_PARAMETERS_PLACEHOLDER); - messageBuffer.fill(0, authenticationParametersOffset, authenticationParametersOffset + Authentication.AUTHENTICATION_CODE_LENGTH); - - digestToAdd = Authentication.calculateDigest(messageBuffer, authProtocol, authPassword, engineID); - digestToAdd.copy(messageBuffer, authenticationParametersOffset, 0, Authentication.AUTHENTICATION_CODE_LENGTH); - debug("Added Auth Parameters: " + digestToAdd.toString('hex')); -}; - -Authentication.isAuthentic = function (messageBuffer, authProtocol, authPassword, engineID, digestInMessage) { - var authenticationParametersOffset; - var calculatedDigest; - - // clear the authenticationParameters field in message - authenticationParametersOffset = messageBuffer.indexOf(digestInMessage); - messageBuffer.fill(0, authenticationParametersOffset, authenticationParametersOffset + Authentication.AUTHENTICATION_CODE_LENGTH); - - calculatedDigest = Authentication.calculateDigest(messageBuffer, authProtocol, authPassword, engineID); - - // replace previously cleared authenticationParameters field in message - digestInMessage.copy(messageBuffer, authenticationParametersOffset, 0, Authentication.AUTHENTICATION_CODE_LENGTH); - - debug("Digest in message: " + digestInMessage.toString('hex')); - debug("Calculated digest: " + calculatedDigest.toString('hex')); - return calculatedDigest.equals(digestInMessage, Authentication.AUTHENTICATION_CODE_LENGTH); -}; - -Authentication.calculateDigest = function (messageBuffer, authProtocol, authPassword, engineID) { - var authKey = Authentication.passwordToKey(authProtocol, authPassword, engineID); - - // Adapted from RFC3147 Section 6.3.1. Processing an Outgoing Message - var hashAlgorithm; - var kIpad; - var kOpad; - var firstDigest; - var finalDigest; - var truncatedDigest; - var i; - var cryptoAlgorithm = Authentication.algorithms[authProtocol].CRYPTO_ALGORITHM; - - if (authKey.length > Authentication.HMAC_BLOCK_SIZE) { - hashAlgorithm = crypto.createHash(cryptoAlgorithm); - hashAlgorithm.update(authKey); - authKey = hashAlgorithm.digest(); - } - - // MD(K XOR opad, MD(K XOR ipad, msg)) - kIpad = Buffer.alloc(Authentication.HMAC_BLOCK_SIZE); - kOpad = Buffer.alloc(Authentication.HMAC_BLOCK_SIZE); - for (i = 0; i < authKey.length; i++) { - kIpad[i] = authKey[i] ^ 0x36; - kOpad[i] = authKey[i] ^ 0x5c; - } - kIpad.fill(0x36, authKey.length); - kOpad.fill(0x5c, authKey.length); - - // inner MD - hashAlgorithm = crypto.createHash(cryptoAlgorithm); - hashAlgorithm.update(kIpad); - hashAlgorithm.update(messageBuffer); - firstDigest = hashAlgorithm.digest(); - // outer MD - hashAlgorithm = crypto.createHash(cryptoAlgorithm); - hashAlgorithm.update(kOpad); - hashAlgorithm.update(firstDigest); - finalDigest = hashAlgorithm.digest(); - - truncatedDigest = Buffer.alloc(Authentication.AUTHENTICATION_CODE_LENGTH); - finalDigest.copy(truncatedDigest, 0, 0, Authentication.AUTHENTICATION_CODE_LENGTH); - return truncatedDigest; -}; - -var Encryption = {}; - -Encryption.INPUT_KEY_LENGTH = 16; -Encryption.DES_KEY_LENGTH = 8; -Encryption.DES_BLOCK_LENGTH = 8; -Encryption.CRYPTO_DES_ALGORITHM = 'des-cbc'; -Encryption.PRIV_PARAMETERS_PLACEHOLDER = Buffer.from('9192939495969798', 'hex'); - -Encryption.encryptPdu = function (scopedPdu, privProtocol, privPassword, authProtocol, engineID) { - var privLocalizedKey; - var encryptionKey; - var preIv; - var salt; - var iv; - var i; - var paddedScopedPduLength; - var paddedScopedPdu; - var encryptedPdu; - var cbcProtocol = Encryption.CRYPTO_DES_ALGORITHM; - - privLocalizedKey = Authentication.passwordToKey(authProtocol, privPassword, engineID); - encryptionKey = Buffer.alloc(Encryption.DES_KEY_LENGTH); - privLocalizedKey.copy(encryptionKey, 0, 0, Encryption.DES_KEY_LENGTH); - preIv = Buffer.alloc(Encryption.DES_BLOCK_LENGTH); - privLocalizedKey.copy(preIv, 0, Encryption.DES_KEY_LENGTH, Encryption.DES_KEY_LENGTH + Encryption.DES_BLOCK_LENGTH); - - salt = Buffer.alloc(Encryption.DES_BLOCK_LENGTH); - // set local SNMP engine boots part of salt to 1, as we have no persistent engine state - salt.fill('00000001', 0, 4, 'hex'); - // set local integer part of salt to random - salt.fill(crypto.randomBytes(4), 4, 8); - iv = Buffer.alloc(Encryption.DES_BLOCK_LENGTH); - for (i = 0; i < iv.length; i++) { - iv[i] = preIv[i] ^ salt[i]; - } - - if (scopedPdu.length % Encryption.DES_BLOCK_LENGTH == 0) { - paddedScopedPdu = scopedPdu; - } else { - paddedScopedPduLength = Encryption.DES_BLOCK_LENGTH * (Math.floor(scopedPdu.length / Encryption.DES_BLOCK_LENGTH) + 1); - paddedScopedPdu = Buffer.alloc(paddedScopedPduLength); - scopedPdu.copy(paddedScopedPdu, 0, 0, scopedPdu.length); - } - cipher = crypto.createCipheriv(cbcProtocol, encryptionKey, iv); - encryptedPdu = cipher.update(paddedScopedPdu); - encryptedPdu = Buffer.concat([encryptedPdu, cipher.final()]); - debug("Key: " + encryptionKey.toString('hex')); - debug("IV: " + iv.toString('hex')); - debug("Plain: " + paddedScopedPdu.toString('hex')); - debug("Encrypted: " + encryptedPdu.toString('hex')); - - return { - encryptedPdu: encryptedPdu, - msgPrivacyParameters: salt - }; -}; - -Encryption.decryptPdu = function (encryptedPdu, privProtocol, privParameters, privPassword, authProtocol, engineID, forceAutoPaddingDisable) { - var privLocalizedKey; - var decryptionKey; - var preIv; - var salt; - var iv; - var i; - var decryptedPdu; - var cbcProtocol = Encryption.CRYPTO_DES_ALGORITHM; - ; - - privLocalizedKey = Authentication.passwordToKey(authProtocol, privPassword, engineID); - decryptionKey = Buffer.alloc(Encryption.DES_KEY_LENGTH); - privLocalizedKey.copy(decryptionKey, 0, 0, Encryption.DES_KEY_LENGTH); - preIv = Buffer.alloc(Encryption.DES_BLOCK_LENGTH); - privLocalizedKey.copy(preIv, 0, Encryption.DES_KEY_LENGTH, Encryption.DES_KEY_LENGTH + Encryption.DES_BLOCK_LENGTH); - - salt = privParameters; - iv = Buffer.alloc(Encryption.DES_BLOCK_LENGTH); - for (i = 0; i < iv.length; i++) { - iv[i] = preIv[i] ^ salt[i]; - } - - decipher = crypto.createDecipheriv(cbcProtocol, decryptionKey, iv); - if (forceAutoPaddingDisable) { - decipher.setAutoPadding(false); - } - decryptedPdu = decipher.update(encryptedPdu); - // This try-catch is a workaround for a seemingly incorrect error condition - // - where sometimes a decrypt error is thrown with decipher.final() - // It replaces this line which should have been sufficient: - // decryptedPdu = Buffer.concat ([decryptedPdu, decipher.final()]); - try { - decryptedPdu = Buffer.concat([decryptedPdu, decipher.final()]); - } catch (error) { - // debug("Decrypt error: " + error); - decipher = crypto.createDecipheriv(cbcProtocol, decryptionKey, iv); - decipher.setAutoPadding(false); - decryptedPdu = decipher.update(encryptedPdu); - decryptedPdu = Buffer.concat([decryptedPdu, decipher.final()]); - } - debug("Key: " + decryptionKey.toString('hex')); - debug("IV: " + iv.toString('hex')); - debug("Encrypted: " + encryptedPdu.toString('hex')); - debug("Plain: " + decryptedPdu.toString('hex')); - - return decryptedPdu; - -}; - -Encryption.addParametersToMessageBuffer = function (messageBuffer, msgPrivacyParameters) { - privacyParametersOffset = messageBuffer.indexOf(Encryption.PRIV_PARAMETERS_PLACEHOLDER); - msgPrivacyParameters.copy(messageBuffer, privacyParametersOffset, 0, Encryption.DES_IV_LENGTH); -}; - -/***************************************************************************** - ** Message class definition - **/ - -var Message = function () { -} - -Message.prototype.getReqId = function () { - return this.version == Version3 ? this.msgGlobalData.msgID : this.pdu.id; -}; - -Message.prototype.toBuffer = function () { - if (this.version == Version3) { - return this.toBufferV3(); - } else { - return this.toBufferCommunity(); - } -} - -Message.prototype.toBufferCommunity = function () { - if (this.buffer) - return this.buffer; - - var writer = new ber.Writer(); - - writer.startSequence(); - - writer.writeInt(this.version); - writer.writeString(this.community); - - this.pdu.toBuffer(writer); - - writer.endSequence(); - - this.buffer = writer.buffer; - - return this.buffer; -}; - -Message.prototype.toBufferV3 = function () { - var encryptionResult; - - if (this.buffer) - return this.buffer; - - var writer = new ber.Writer(); - - writer.startSequence(); - - writer.writeInt(this.version); - - // HeaderData - writer.startSequence(); - writer.writeInt(this.msgGlobalData.msgID); - writer.writeInt(this.msgGlobalData.msgMaxSize); - writer.writeByte(ber.OctetString); - writer.writeByte(1); - writer.writeByte(this.msgGlobalData.msgFlags); - writer.writeInt(this.msgGlobalData.msgSecurityModel); - writer.endSequence(); - - // msgSecurityParameters - var msgSecurityParametersWriter = new ber.Writer(); - msgSecurityParametersWriter.startSequence(); - //msgSecurityParametersWriter.writeString (this.msgSecurityParameters.msgAuthoritativeEngineID); - // writing a zero-length buffer fails - should fix asn1-ber for this condition - if (this.msgSecurityParameters.msgAuthoritativeEngineID.length == 0) { - msgSecurityParametersWriter.writeString(""); - } else { - msgSecurityParametersWriter.writeBuffer(this.msgSecurityParameters.msgAuthoritativeEngineID, ber.OctetString); - } - msgSecurityParametersWriter.writeInt(this.msgSecurityParameters.msgAuthoritativeEngineBoots); - msgSecurityParametersWriter.writeInt(this.msgSecurityParameters.msgAuthoritativeEngineTime); - msgSecurityParametersWriter.writeString(this.msgSecurityParameters.msgUserName); - - if (this.hasAuthentication()) { - msgSecurityParametersWriter.writeBuffer(Authentication.AUTH_PARAMETERS_PLACEHOLDER, ber.OctetString); - // should never happen where msgFlags has no authentication but authentication parameters still present - } else if (this.msgSecurityParameters.msgAuthenticationParameters.length > 0) { - msgSecurityParametersWriter.writeBuffer(this.msgSecurityParameters.msgAuthenticationParameters, ber.OctetString); - } else { - msgSecurityParametersWriter.writeString(""); - } - - if (this.hasPrivacy()) { - msgSecurityParametersWriter.writeBuffer(Encryption.PRIV_PARAMETERS_PLACEHOLDER, ber.OctetString); - // should never happen where msgFlags has no privacy but privacy parameters still present - } else if (this.msgSecurityParameters.msgPrivacyParameters.length > 0) { - msgSecurityParametersWriter.writeBuffer(this.msgSecurityParameters.msgPrivacyParameters, ber.OctetString); - } else { - msgSecurityParametersWriter.writeString(""); - } - msgSecurityParametersWriter.endSequence(); - - writer.writeBuffer(msgSecurityParametersWriter.buffer, ber.OctetString); - - // ScopedPDU - var scopedPduWriter = new ber.Writer(); - scopedPduWriter.startSequence(); - var contextEngineID = this.pdu.contextEngineID ? this.pdu.contextEngineID : this.msgSecurityParameters.msgAuthoritativeEngineID; - if (contextEngineID.length == 0) { - scopedPduWriter.writeString(""); - } else { - scopedPduWriter.writeBuffer(contextEngineID, ber.OctetString); - } - scopedPduWriter.writeString(this.pdu.contextName); - this.pdu.toBuffer(scopedPduWriter); - scopedPduWriter.endSequence(); - - if (this.hasPrivacy()) { - encryptionResult = Encryption.encryptPdu(scopedPduWriter.buffer, this.user.privProtocol, this.user.privKey, this.user.authProtocol, this.msgSecurityParameters.msgAuthoritativeEngineID); - writer.writeBuffer(encryptionResult.encryptedPdu, ber.OctetString); - } else { - writer.writeBuffer(scopedPduWriter.buffer); - } - - writer.endSequence(); - - this.buffer = writer.buffer; - - if (this.hasPrivacy()) { - Encryption.addParametersToMessageBuffer(this.buffer, encryptionResult.msgPrivacyParameters); - } - - if (this.hasAuthentication()) { - Authentication.addParametersToMessageBuffer(this.buffer, this.user.authProtocol, this.user.authKey, - this.msgSecurityParameters.msgAuthoritativeEngineID); - } - - return this.buffer; -}; - -Message.prototype.processIncomingSecurity = function (user, responseCb) { - if (this.hasPrivacy()) { - if (!this.decryptPdu(user, responseCb)) { - return false; - } - } - - if (this.hasAuthentication() && !this.isAuthenticationDisabled()) { - return this.checkAuthentication(user, responseCb); - } else { - return true; - } -}; - -Message.prototype.decryptPdu = function (user, responseCb) { - var decryptedPdu; - var decryptedPduReader; - try { - decryptedPdu = Encryption.decryptPdu(this.encryptedPdu, user.privProtocol, - this.msgSecurityParameters.msgPrivacyParameters, user.privKey, user.authProtocol, - this.msgSecurityParameters.msgAuthoritativeEngineID); - decryptedPduReader = new ber.Reader(decryptedPdu); - this.pdu = readPdu(decryptedPduReader, true); - return true; - // really really occasionally the decrypt truncates a single byte - // causing an ASN read failure in readPdu() - // in this case, disabling auto padding decrypts the PDU correctly - // this try-catch provides the workaround for this condition - } catch (possibleTruncationError) { - try { - decryptedPdu = Encryption.decryptPdu(this.encryptedPdu, user.privProtocol, - this.msgSecurityParameters.msgPrivacyParameters, user.privKey, user.authProtocol, - this.msgSecurityParameters.msgAuthoritativeEngineID, true); - decryptedPduReader = new ber.Reader(decryptedPdu); - this.pdu = readPdu(decryptedPduReader, true); - return true; - } catch (error) { - responseCb(new ResponseInvalidError("Failed to decrypt PDU: " + error)); - return false; - } - } - -}; - -Message.prototype.checkAuthentication = function (user, responseCb) { - if (Authentication.isAuthentic(this.buffer, user.authProtocol, user.authKey, - this.msgSecurityParameters.msgAuthoritativeEngineID, this.msgSecurityParameters.msgAuthenticationParameters)) { - return true; - } else { - responseCb(new ResponseInvalidError("Authentication digest " - + this.msgSecurityParameters.msgAuthenticationParameters.toString('hex') - + " received in message does not match digest " - + Authentication.calculateDigest(buffer, user.authProtocol, user.authKey, - this.msgSecurityParameters.msgAuthoritativeEngineID).toString('hex') - + " calculated for message")); - return false; - } - -}; - -Message.prototype.hasAuthentication = function () { - return this.msgGlobalData && this.msgGlobalData.msgFlags && this.msgGlobalData.msgFlags & 1; -}; - -Message.prototype.hasPrivacy = function () { - return this.msgGlobalData && this.msgGlobalData.msgFlags && this.msgGlobalData.msgFlags & 2; -}; - -Message.prototype.isReportable = function () { - return this.msgGlobalData && this.msgGlobalData.msgFlags && this.msgGlobalData.msgFlags & 4; -}; - -Message.prototype.setReportable = function (flag) { - if (this.msgGlobalData && this.msgGlobalData.msgFlags) { - if (flag) { - this.msgGlobalData.msgFlags = this.msgGlobalData.msgFlags | 4; - } else { - this.msgGlobalData.msgFlags = this.msgGlobalData.msgFlags & (255 - 4); - } - } -}; - -Message.prototype.isAuthenticationDisabled = function () { - return this.disableAuthentication; -}; - -Message.prototype.hasAuthoritativeEngineID = function () { - return this.msgSecurityParameters && this.msgSecurityParameters.msgAuthoritativeEngineID && - this.msgSecurityParameters.msgAuthoritativeEngineID != ""; -}; - -Message.prototype.createReportResponseMessage = function (engine, context) { - var user = { - name: "", - level: SecurityLevel.noAuthNoPriv - }; - var responseSecurityParameters = { - msgAuthoritativeEngineID: engine.engineID, - msgAuthoritativeEngineBoots: engine.engineBoots, - msgAuthoritativeEngineTime: engine.engineTime, - msgUserName: user.name, - msgAuthenticationParameters: "", - msgPrivacyParameters: "" - }; - var reportPdu = ReportPdu.createFromVariables(this.pdu.id, [], {}); - reportPdu.contextName = context; - var responseMessage = Message.createRequestV3(user, responseSecurityParameters, reportPdu); - responseMessage.msgGlobalData.msgID = this.msgGlobalData.msgID; - return responseMessage; -}; - -Message.prototype.createResponseForRequest = function (responsePdu) { - if (this.version == Version3) { - return this.createV3ResponseFromRequest(responsePdu); - } else { - return this.createCommunityResponseFromRequest(responsePdu); - } -}; - -Message.prototype.createCommunityResponseFromRequest = function (responsePdu) { - return Message.createCommunity(this.version, this.community, responsePdu); -}; - -Message.prototype.createV3ResponseFromRequest = function (responsePdu) { - var responseUser = { - name: this.user.name, - level: this.user.name, - authProtocol: this.user.authProtocol, - authKey: this.user.authKey, - privProtocol: this.user.privProtocol, - privKey: this.user.privKey - }; - var responseSecurityParameters = { - msgAuthoritativeEngineID: this.msgSecurityParameters.msgAuthoritativeEngineID, - msgAuthoritativeEngineBoots: this.msgSecurityParameters.msgAuthoritativeEngineBoots, - msgAuthoritativeEngineTime: this.msgSecurityParameters.msgAuthoritativeEngineTime, - msgUserName: this.msgSecurityParameters.msgUserName, - msgAuthenticationParameters: "", - msgPrivacyParameters: "" - }; - var responseGlobalData = { - msgID: this.msgGlobalData.msgID, - msgMaxSize: 65507, - msgFlags: this.msgGlobalData.msgFlags & (255 - 4), - msgSecurityModel: 3 - }; - return Message.createV3(responseUser, responseGlobalData, responseSecurityParameters, responsePdu); -}; - -Message.createCommunity = function (version, community, pdu) { - var message = new Message(); - - message.version = version; - message.community = community; - message.pdu = pdu; - - return message; -}; - -Message.createRequestV3 = function (user, msgSecurityParameters, pdu) { - var authFlag = user.level == SecurityLevel.authNoPriv || user.level == SecurityLevel.authPriv ? 1 : 0; - var privFlag = user.level == SecurityLevel.authPriv ? 1 : 0; - var reportableFlag = (pdu.type == PduType.GetResponse || pdu.type == PduType.TrapV2) ? 0 : 1; - var msgGlobalData = { - msgID: _generateId(), // random ID - msgMaxSize: 65507, - msgFlags: reportableFlag * 4 | privFlag * 2 | authFlag * 1, - msgSecurityModel: 3 - }; - return Message.createV3(user, msgGlobalData, msgSecurityParameters, pdu); -}; - -Message.createV3 = function (user, msgGlobalData, msgSecurityParameters, pdu) { - var message = new Message(); - - message.version = 3; - message.user = user; - message.msgGlobalData = msgGlobalData; - message.msgSecurityParameters = { - msgAuthoritativeEngineID: msgSecurityParameters.msgAuthoritativeEngineID || Buffer.from(""), - msgAuthoritativeEngineBoots: msgSecurityParameters.msgAuthoritativeEngineBoots || 0, - msgAuthoritativeEngineTime: msgSecurityParameters.msgAuthoritativeEngineTime || 0, - msgUserName: user.name || "", - msgAuthenticationParameters: "", - msgPrivacyParameters: "" - }; - message.pdu = pdu; - - return message; -}; - -Message.createDiscoveryV3 = function (pdu) { - var msgSecurityParameters = { - msgAuthoritativeEngineID: Buffer.from(""), - msgAuthoritativeEngineBoots: 0, - msgAuthoritativeEngineTime: 0 - }; - var emptyUser = { - name: "", - level: SecurityLevel.noAuthNoPriv - }; - return Message.createRequestV3(emptyUser, msgSecurityParameters, pdu); -} - -Message.createFromBuffer = function (buffer, user) { - var reader = new ber.Reader(buffer); - var message = new Message(); - - reader.readSequence(); - - message.version = reader.readInt(); - - if (message.version != 3) { - message.community = reader.readString(); - message.pdu = readPdu(reader, false); - } else { - // HeaderData - message.msgGlobalData = {}; - reader.readSequence(); - message.msgGlobalData.msgID = reader.readInt(); - message.msgGlobalData.msgMaxSize = reader.readInt(); - message.msgGlobalData.msgFlags = reader.readString(ber.OctetString, true)[0]; - message.msgGlobalData.msgSecurityModel = reader.readInt(); - - // msgSecurityParameters - message.msgSecurityParameters = {}; - var msgSecurityParametersReader = new ber.Reader(reader.readString(ber.OctetString, true)); - msgSecurityParametersReader.readSequence(); - message.msgSecurityParameters.msgAuthoritativeEngineID = msgSecurityParametersReader.readString(ber.OctetString, true); - message.msgSecurityParameters.msgAuthoritativeEngineBoots = msgSecurityParametersReader.readInt(); - message.msgSecurityParameters.msgAuthoritativeEngineTime = msgSecurityParametersReader.readInt(); - message.msgSecurityParameters.msgUserName = msgSecurityParametersReader.readString(); - message.msgSecurityParameters.msgAuthenticationParameters = Buffer.from(msgSecurityParametersReader.readString(ber.OctetString, true)); - message.msgSecurityParameters.msgPrivacyParameters = Buffer.from(msgSecurityParametersReader.readString(ber.OctetString, true)); - scopedPdu = true; - - if (message.hasPrivacy()) { - message.encryptedPdu = reader.readString(ber.OctetString, true); - message.pdu = null; - } else { - message.pdu = readPdu(reader, true); - } - } - - message.buffer = buffer; - - return message; -}; - - -var Req = function (session, message, feedCb, responseCb, options) { - - this.message = message; - this.responseCb = responseCb; - this.retries = session.retries; - this.timeout = session.timeout; - this.onResponse = session.onSimpleGetResponse; - this.feedCb = feedCb; - this.port = (options && options.port) ? options.port : session.port; - this.context = session.context; -}; - -Req.prototype.getId = function () { - return this.message.getReqId(); -}; - - -/***************************************************************************** - ** Session class definition - **/ - -var Session = function (target, authenticator, options) { - this.target = target || "127.0.0.1"; - - this.version = (options && options.version) - ? options.version - : Version1; - - if (this.version == Version3) { - this.user = authenticator; - } else { - this.community = authenticator || "public"; - } - - this.transport = (options && options.transport) - ? options.transport - : "udp4"; - this.port = (options && options.port) - ? options.port - : 161; - this.trapPort = (options && options.trapPort) - ? options.trapPort - : 162; - - this.retries = (options && (options.retries || options.retries == 0)) - ? options.retries - : 1; - this.timeout = (options && options.timeout) - ? options.timeout - : 5000; - - this.sourceAddress = (options && options.sourceAddress) - ? options.sourceAddress - : undefined; - this.sourcePort = (options && options.sourcePort) - ? parseInt(options.sourcePort) - : undefined; - - this.idBitsSize = (options && options.idBitsSize) - ? parseInt(options.idBitsSize) - : 32; - - this.context = (options && options.context) ? options.context : ""; - - DEBUG = options.debug; - - this.reqs = {}; - this.reqCount = 0; - - this.dgram = dgram.createSocket(this.transport); - this.dgram.unref(); - - var me = this; - this.dgram.on("message", me.onMsg.bind(me)); - this.dgram.on("close", me.onClose.bind(me)); - this.dgram.on("error", me.onError.bind(me)); - - if (this.sourceAddress || this.sourcePort) - this.dgram.bind(this.sourcePort, this.sourceAddress); -}; - -util.inherits(Session, events.EventEmitter); - -Session.prototype.close = function () { - this.dgram.close(); - return this; -}; - -Session.prototype.cancelRequests = function (error) { - var id; - for (id in this.reqs) { - var req = this.reqs[id]; - this.unregisterRequest(req.getId()); - req.responseCb(error); - } -}; - -function _generateId(bitSize) { - if (bitSize === 16) { - return Math.floor(Math.random() * 10000) % 65535; - } - return Math.floor(Math.random() * 100000000) % 4294967295; -} - -Session.prototype.get = function (oids, responseCb) { - function feedCb(req, message) { - var pdu = message.pdu; - var varbinds = []; - - if (req.message.pdu.varbinds.length != pdu.varbinds.length) { - req.responseCb(new ResponseInvalidError("Requested OIDs do not " - + "match response OIDs")); - } else { - for (var i = 0; i < req.message.pdu.varbinds.length; i++) { - if (req.message.pdu.varbinds[i].oid != pdu.varbinds[i].oid) { - req.responseCb(new ResponseInvalidError("OID '" - + req.message.pdu.varbinds[i].oid - + "' in request at positiion '" + i + "' does not " - + "match OID '" + pdu.varbinds[i].oid + "' in response " - + "at position '" + i + "'")); - return; - } else { - varbinds.push(pdu.varbinds[i]); - } - } - - req.responseCb(null, varbinds); - } - } - - var pduVarbinds = []; - - for (var i = 0; i < oids.length; i++) { - var varbind = { - oid: oids[i] - }; - pduVarbinds.push(varbind); - } - - this.simpleGet(GetRequestPdu, feedCb, pduVarbinds, responseCb); - - return this; -}; - -Session.prototype.getBulk = function () { - var oids, nonRepeaters, maxRepetitions, responseCb; - - if (arguments.length >= 4) { - oids = arguments[0]; - nonRepeaters = arguments[1]; - maxRepetitions = arguments[2]; - responseCb = arguments[3]; - } else if (arguments.length >= 3) { - oids = arguments[0]; - nonRepeaters = arguments[1]; - maxRepetitions = 10; - responseCb = arguments[2]; - } else { - oids = arguments[0]; - nonRepeaters = 0; - maxRepetitions = 10; - responseCb = arguments[1]; - } - - function feedCb(req, message) { - var pdu = message.pdu; - var varbinds = []; - var i = 0; - - // first walk through and grab non-repeaters - if (pdu.varbinds.length < nonRepeaters) { - req.responseCb(new ResponseInvalidError("Varbind count in " - + "response '" + pdu.varbinds.length + "' is less than " - + "non-repeaters '" + nonRepeaters + "' in request")); - } else { - for (; i < nonRepeaters; i++) { - if (isVarbindError(pdu.varbinds[i])) { - varbinds.push(pdu.varbinds[i]); - } else if (!oidFollowsOid(req.message.pdu.varbinds[i].oid, - pdu.varbinds[i].oid)) { - req.responseCb(new ResponseInvalidError("OID '" - + req.message.pdu.varbinds[i].oid + "' in request at " - + "positiion '" + i + "' does not precede " - + "OID '" + pdu.varbinds[i].oid + "' in response " - + "at position '" + i + "'")); - return; - } else { - varbinds.push(pdu.varbinds[i]); - } - } - } - - var repeaters = req.message.pdu.varbinds.length - nonRepeaters; - - // secondly walk through and grab repeaters - if (pdu.varbinds.length % (repeaters)) { - req.responseCb(new ResponseInvalidError("Varbind count in " - + "response '" + pdu.varbinds.length + "' is not a " - + "multiple of repeaters '" + repeaters - + "' plus non-repeaters '" + nonRepeaters + "' in request")); - } else { - while (i < pdu.varbinds.length) { - for (var j = 0; j < repeaters; j++, i++) { - var reqIndex = nonRepeaters + j; - var respIndex = i; - - if (isVarbindError(pdu.varbinds[respIndex])) { - if (!varbinds[reqIndex]) - varbinds[reqIndex] = []; - varbinds[reqIndex].push(pdu.varbinds[respIndex]); - } else if (!oidFollowsOid( - req.message.pdu.varbinds[reqIndex].oid, - pdu.varbinds[respIndex].oid)) { - req.responseCb(new ResponseInvalidError("OID '" - + req.message.pdu.varbinds[reqIndex].oid - + "' in request at positiion '" + (reqIndex) - + "' does not precede OID '" - + pdu.varbinds[respIndex].oid - + "' in response at position '" + (respIndex) + "'")); - return; - } else { - if (!varbinds[reqIndex]) - varbinds[reqIndex] = []; - varbinds[reqIndex].push(pdu.varbinds[respIndex]); - } - } - } - } - - req.responseCb(null, varbinds); - } - - var pduVarbinds = []; - - for (var i = 0; i < oids.length; i++) { - var varbind = { - oid: oids[i] - }; - pduVarbinds.push(varbind); - } - - var options = { - nonRepeaters: nonRepeaters, - maxRepetitions: maxRepetitions - }; - - this.simpleGet(GetBulkRequestPdu, feedCb, pduVarbinds, responseCb, - options); - - return this; -}; - -Session.prototype.getNext = function (oids, responseCb) { - function feedCb(req, message) { - var pdu = message.pdu; - var varbinds = []; - - if (req.message.pdu.varbinds.length != pdu.varbinds.length) { - req.responseCb(new ResponseInvalidError("Requested OIDs do not " - + "match response OIDs")); - } else { - for (var i = 0; i < req.message.pdu.varbinds.length; i++) { - if (isVarbindError(pdu.varbinds[i])) { - varbinds.push(pdu.varbinds[i]); - } else if (!oidFollowsOid(req.message.pdu.varbinds[i].oid, - pdu.varbinds[i].oid)) { - req.responseCb(new ResponseInvalidError("OID '" - + req.message.pdu.varbinds[i].oid + "' in request at " - + "positiion '" + i + "' does not precede " - + "OID '" + pdu.varbinds[i].oid + "' in response " - + "at position '" + i + "'")); - return; - } else { - varbinds.push(pdu.varbinds[i]); - } - } - - req.responseCb(null, varbinds); - } - } - - var pduVarbinds = []; - - for (var i = 0; i < oids.length; i++) { - var varbind = { - oid: oids[i] - }; - pduVarbinds.push(varbind); - } - - this.simpleGet(GetNextRequestPdu, feedCb, pduVarbinds, responseCb); - - return this; -}; - -Session.prototype.inform = function () { - var typeOrOid = arguments[0]; - var varbinds, options = {}, responseCb; - - /** - ** Support the following signatures: - ** - ** typeOrOid, varbinds, options, callback - ** typeOrOid, varbinds, callback - ** typeOrOid, options, callback - ** typeOrOid, callback - **/ - if (arguments.length >= 4) { - varbinds = arguments[1]; - options = arguments[2]; - responseCb = arguments[3]; - } else if (arguments.length >= 3) { - if (arguments[1].constructor != Array) { - varbinds = []; - options = arguments[1]; - responseCb = arguments[2]; - } else { - varbinds = arguments[1]; - responseCb = arguments[2]; - } - } else { - varbinds = []; - responseCb = arguments[1]; - } - - if (this.version == Version1) { - responseCb(new RequestInvalidError("Inform not allowed for SNMPv1")); - return; - } - - function feedCb(req, message) { - var pdu = message.pdu; - var varbinds = []; - - if (req.message.pdu.varbinds.length != pdu.varbinds.length) { - req.responseCb(new ResponseInvalidError("Inform OIDs do not " - + "match response OIDs")); - } else { - for (var i = 0; i < req.message.pdu.varbinds.length; i++) { - if (req.message.pdu.varbinds[i].oid != pdu.varbinds[i].oid) { - req.responseCb(new ResponseInvalidError("OID '" - + req.message.pdu.varbinds[i].oid - + "' in inform at positiion '" + i + "' does not " - + "match OID '" + pdu.varbinds[i].oid + "' in response " - + "at position '" + i + "'")); - return; - } else { - varbinds.push(pdu.varbinds[i]); - } - } - - req.responseCb(null, varbinds); - } - } - - if (typeof typeOrOid != "string") - typeOrOid = "1.3.6.1.6.3.1.1.5." + (typeOrOid + 1); - - var pduVarbinds = [ - { - oid: "1.3.6.1.2.1.1.3.0", - type: ObjectType.TimeTicks, - value: options.upTime || Math.floor(process.uptime() * 100) - }, - { - oid: "1.3.6.1.6.3.1.1.4.1.0", - type: ObjectType.OID, - value: typeOrOid - } - ]; - - for (var i = 0; i < varbinds.length; i++) { - var varbind = { - oid: varbinds[i].oid, - type: varbinds[i].type, - value: varbinds[i].value - }; - pduVarbinds.push(varbind); - } - - options.port = this.trapPort; - - this.simpleGet(InformRequestPdu, feedCb, pduVarbinds, responseCb, options); - - return this; -}; - -Session.prototype.onClose = function () { - this.cancelRequests(new Error("Socket forcibly closed")); - this.emit("close"); -}; - -Session.prototype.onError = function (error) { - this.emit(error); -}; - -Session.prototype.onMsg = function (buffer) { - try { - var message = Message.createFromBuffer(buffer); - - var req = this.unregisterRequest(message.getReqId()); - if (!req) - return; - - if (!message.processIncomingSecurity(this.user, req.responseCb)) - return; - - try { - if (message.version != req.message.version) { - req.responseCb(new ResponseInvalidError("Version in request '" - + req.message.version + "' does not match version in " - + "response '" + message.version + "'")); - } else if (message.community != req.message.community) { - req.responseCb(new ResponseInvalidError("Community '" - + req.message.community + "' in request does not match " - + "community '" + message.community + "' in response")); - } else if (message.pdu.type == PduType.GetResponse) { - req.onResponse(req, message); - } else if (message.pdu.type == PduType.Report) { - if (!req.originalPdu) { - req.responseCb(new ResponseInvalidError("Unexpected Report PDU")); - return; - } - this.msgSecurityParameters = { - msgAuthoritativeEngineID: message.msgSecurityParameters.msgAuthoritativeEngineID, - msgAuthoritativeEngineBoots: message.msgSecurityParameters.msgAuthoritativeEngineBoots, - msgAuthoritativeEngineTime: message.msgSecurityParameters.msgAuthoritativeEngineTime - }; - req.originalPdu.contextName = this.context; - this.sendV3Req(req.originalPdu, req.feedCb, req.responseCb, req.options, req.port); - } else { - req.responseCb(new ResponseInvalidError("Unknown PDU type '" - + message.pdu.type + "' in response")); - } - } catch (error) { - req.responseCb(error); - } - } catch (error) { - this.emit("error", error); - } -}; - -Session.prototype.onSimpleGetResponse = function (req, message) { - var pdu = message.pdu; - - if (pdu.errorStatus > 0) { - var statusString = ErrorStatus[pdu.errorStatus] - || ErrorStatus.GeneralError; - var statusCode = ErrorStatus[statusString] - || ErrorStatus[ErrorStatus.GeneralError]; - - if (pdu.errorIndex <= 0 || pdu.errorIndex > pdu.varbinds.length) { - req.responseCb(new RequestFailedError(statusString, statusCode)); - } else { - var oid = pdu.varbinds[pdu.errorIndex - 1].oid; - var error = new RequestFailedError(statusString + ": " + oid, - statusCode); - req.responseCb(error); - } - } else { - req.feedCb(req, message); - } -}; - -Session.prototype.registerRequest = function (req) { - if (!this.reqs[req.getId()]) { - this.reqs[req.getId()] = req; - if (this.reqCount <= 0) - this.dgram.ref(); - this.reqCount++; - } - var me = this; - req.timer = setTimeout(function () { - if (req.retries-- > 0) { - me.send(req); - } else { - me.unregisterRequest(req.getId()); - req.responseCb(new RequestTimedOutError( - "Request timed out")); - } - }, req.timeout); -}; - -Session.prototype.send = function (req, noWait) { - try { - var me = this; - - var buffer = req.message.toBuffer(); - - this.dgram.send(buffer, 0, buffer.length, req.port, this.target, - function (error, bytes) { - if (error) { - req.responseCb(error); - } else { - if (noWait) { - req.responseCb(null); - } else { - me.registerRequest(req); - } - } - }); - } catch (error) { - req.responseCb(error); - } - - return this; -}; - -Session.prototype.set = function (varbinds, responseCb) { - function feedCb(req, message) { - var pdu = message.pdu; - var varbinds = []; - - if (req.message.pdu.varbinds.length != pdu.varbinds.length) { - req.responseCb(new ResponseInvalidError("Requested OIDs do not " - + "match response OIDs")); - } else { - for (var i = 0; i < req.message.pdu.varbinds.length; i++) { - if (req.message.pdu.varbinds[i].oid != pdu.varbinds[i].oid) { - req.responseCb(new ResponseInvalidError("OID '" - + req.message.pdu.varbinds[i].oid - + "' in request at positiion '" + i + "' does not " - + "match OID '" + pdu.varbinds[i].oid + "' in response " - + "at position '" + i + "'")); - return; - } else { - varbinds.push(pdu.varbinds[i]); - } - } - - req.responseCb(null, varbinds); - } - } - - var pduVarbinds = []; - - for (var i = 0; i < varbinds.length; i++) { - var varbind = { - oid: varbinds[i].oid, - type: varbinds[i].type, - value: varbinds[i].value - }; - pduVarbinds.push(varbind); - } - - this.simpleGet(SetRequestPdu, feedCb, pduVarbinds, responseCb); - - return this; -}; - -Session.prototype.simpleGet = function (pduClass, feedCb, varbinds, - responseCb, options) { - try { - var id = _generateId(this.idBitsSize); - var pdu = SimplePdu.createFromVariables(pduClass, id, varbinds, options); - var message; - var req; - - if (this.version == Version3) { - if (this.msgSecurityParameters) { - this.sendV3Req(pdu, feedCb, responseCb, options, this.port); - } else { - // SNMPv3 discovery - var discoveryPdu = createDiscoveryPdu(this.context); - var discoveryMessage = Message.createDiscoveryV3(discoveryPdu); - var discoveryReq = new Req(this, discoveryMessage, feedCb, responseCb, options); - discoveryReq.originalPdu = pdu; - this.send(discoveryReq); - } - } else { - message = Message.createCommunity(this.version, this.community, pdu); - req = new Req(this, message, feedCb, responseCb, options); - this.send(req); - } - } catch (error) { - if (responseCb) - responseCb(error); - } -} - -function subtreeCb(req, varbinds) { - var done = 0; - - for (var i = varbinds.length; i > 0; i--) { - if (!oidInSubtree(req.baseOid, varbinds[i - 1].oid)) { - done = 1; - varbinds.pop(); - } - } - - if (varbinds.length > 0) - req.feedCb(varbinds); - - if (done) - return true; -} - -Session.prototype.subtree = function () { - var me = this; - var oid = arguments[0]; - var maxRepetitions, feedCb, doneCb; - - if (arguments.length < 4) { - maxRepetitions = 20; - feedCb = arguments[1]; - doneCb = arguments[2]; - } else { - maxRepetitions = arguments[1]; - feedCb = arguments[2]; - doneCb = arguments[3]; - } - - var req = { - feedCb: feedCb, - doneCb: doneCb, - maxRepetitions: maxRepetitions, - baseOid: oid - }; - - this.walk(oid, maxRepetitions, subtreeCb.bind(me, req), doneCb); - - return this; -}; - -function tableColumnsResponseCb(req, error) { - if (error) { - req.responseCb(error); - } else if (req.error) { - req.responseCb(req.error); - } else { - if (req.columns.length > 0) { - var column = req.columns.pop(); - var me = this; - this.subtree(req.rowOid + column, req.maxRepetitions, - tableColumnsFeedCb.bind(me, req), - tableColumnsResponseCb.bind(me, req)); - } else { - req.responseCb(null, req.table); - } - } -} - -function tableColumnsFeedCb(req, varbinds) { - for (var i = 0; i < varbinds.length; i++) { - if (isVarbindError(varbinds[i])) { - req.error = new RequestFailedError(varbindError(varbind[i])); - return true; - } - - var oid = varbinds[i].oid.replace(req.rowOid, ""); - if (oid && oid != varbinds[i].oid) { - var match = oid.match(/^(\d+)\.(.+)$/); - if (match && match[1] > 0) { - if (!req.table[match[2]]) - req.table[match[2]] = {}; - req.table[match[2]][match[1]] = varbinds[i].value; - } - } - } -} - -Session.prototype.tableColumns = function () { - var me = this; - - var oid = arguments[0]; - var columns = arguments[1]; - var maxRepetitions, responseCb; - - if (arguments.length < 4) { - responseCb = arguments[2]; - maxRepetitions = 20; - } else { - maxRepetitions = arguments[2]; - responseCb = arguments[3]; - } - - var req = { - responseCb: responseCb, - maxRepetitions: maxRepetitions, - baseOid: oid, - rowOid: oid + ".1.", - columns: columns.slice(0), - table: {} - }; - - if (req.columns.length > 0) { - var column = req.columns.pop(); - this.subtree(req.rowOid + column, maxRepetitions, - tableColumnsFeedCb.bind(me, req), - tableColumnsResponseCb.bind(me, req)); - } - - return this; -}; - -function tableResponseCb(req, error) { - if (error) - req.responseCb(error); - else if (req.error) - req.responseCb(req.error); - else - req.responseCb(null, req.table); -} - -function tableFeedCb(req, varbinds) { - for (var i = 0; i < varbinds.length; i++) { - if (isVarbindError(varbinds[i])) { - req.error = new RequestFailedError(varbindError(varbind[i])); - return true; - } - - var oid = varbinds[i].oid.replace(req.rowOid, ""); - if (oid && oid != varbinds[i].oid) { - var match = oid.match(/^(\d+)\.(.+)$/); - if (match && match[1] > 0) { - if (!req.table[match[2]]) - req.table[match[2]] = {}; - req.table[match[2]][match[1]] = varbinds[i].value; - } - } - } -} - -Session.prototype.table = function () { - var me = this; - - var oid = arguments[0]; - var maxRepetitions, responseCb; - - if (arguments.length < 3) { - responseCb = arguments[1]; - maxRepetitions = 20; - } else { - maxRepetitions = arguments[1]; - responseCb = arguments[2]; - } - - var req = { - responseCb: responseCb, - maxRepetitions: maxRepetitions, - baseOid: oid, - rowOid: oid + ".1.", - table: {} - }; - - this.subtree(oid, maxRepetitions, tableFeedCb.bind(me, req), - tableResponseCb.bind(me, req)); - - return this; -}; - -Session.prototype.trap = function () { - var req = {}; - - try { - var typeOrOid = arguments[0]; - var varbinds, options = {}, responseCb; - var message; - - /** - ** Support the following signatures: - ** - ** typeOrOid, varbinds, options, callback - ** typeOrOid, varbinds, agentAddr, callback - ** typeOrOid, varbinds, callback - ** typeOrOid, agentAddr, callback - ** typeOrOid, options, callback - ** typeOrOid, callback - **/ - if (arguments.length >= 4) { - varbinds = arguments[1]; - if (typeof arguments[2] == "string") { - options.agentAddr = arguments[2]; - } else if (arguments[2].constructor != Array) { - options = arguments[2]; - } - responseCb = arguments[3]; - } else if (arguments.length >= 3) { - if (typeof arguments[1] == "string") { - varbinds = []; - options.agentAddr = arguments[1]; - } else if (arguments[1].constructor != Array) { - varbinds = []; - options = arguments[1]; - } else { - varbinds = arguments[1]; - agentAddr = null; - } - responseCb = arguments[2]; - } else { - varbinds = []; - responseCb = arguments[1]; - } - - var pdu, pduVarbinds = []; - - for (var i = 0; i < varbinds.length; i++) { - var varbind = { - oid: varbinds[i].oid, - type: varbinds[i].type, - value: varbinds[i].value - }; - pduVarbinds.push(varbind); - } - - var id = _generateId(this.idBitsSize); - - if (this.version == Version2c || this.version == Version3) { - if (typeof typeOrOid != "string") - typeOrOid = "1.3.6.1.6.3.1.1.5." + (typeOrOid + 1); - - pduVarbinds.unshift( - { - oid: "1.3.6.1.2.1.1.3.0", - type: ObjectType.TimeTicks, - value: options.upTime || Math.floor(process.uptime() * 100) - }, - { - oid: "1.3.6.1.6.3.1.1.4.1.0", - type: ObjectType.OID, - value: typeOrOid - } - ); - - pdu = TrapV2Pdu.createFromVariables(id, pduVarbinds, options); - } else { - pdu = TrapPdu.createFromVariables(typeOrOid, pduVarbinds, options); - } - - if (this.version == Version3) { - var msgSecurityParameters = { - msgAuthoritativeEngineID: this.user.engineID, - msgAuthoritativeEngineBoots: 0, - msgAuthoritativeEngineTime: 0 - }; - message = Message.createRequestV3(this.user, msgSecurityParameters, pdu); - } else { - message = Message.createCommunity(this.version, this.community, pdu); - } - - req = { - id: id, - message: message, - responseCb: responseCb, - port: this.trapPort - }; - - this.send(req, true); - } catch (error) { - if (req.responseCb) - req.responseCb(error); - } - - return this; -}; - -Session.prototype.unregisterRequest = function (id) { - var req = this.reqs[id]; - if (req) { - delete this.reqs[id]; - clearTimeout(req.timer); - delete req.timer; - this.reqCount--; - if (this.reqCount <= 0) - this.dgram.unref(); - return req; - } else { - return null; - } -}; - -function walkCb(req, error, varbinds) { - var done = 0; - var oid; - - if (error) { - if (error instanceof RequestFailedError) { - if (error.status != ErrorStatus.NoSuchName) { - req.doneCb(error); - return; - } else { - // signal the version 1 walk code below that it should stop - done = 1; - } - } else { - req.doneCb(error); - return; - } - } - - if (this.version == Version2c || this.version == Version3) { - for (var i = varbinds[0].length; i > 0; i--) { - if (varbinds[0][i - 1].type == ObjectType.EndOfMibView) { - varbinds[0].pop(); - done = 1; - } - } - if (req.feedCb(varbinds[0])) - done = 1; - if (!done) - oid = varbinds[0][varbinds[0].length - 1].oid; - } else { - if (!done) { - if (req.feedCb(varbinds)) { - done = 1; - } else { - oid = varbinds[0].oid; - } - } - } - - if (done) - req.doneCb(null); - else - this.walk(oid, req.maxRepetitions, req.feedCb, req.doneCb, - req.baseOid); -} - -Session.prototype.walk = function () { - var me = this; - var oid = arguments[0]; - var maxRepetitions, feedCb, doneCb, baseOid; - - if (arguments.length < 4) { - maxRepetitions = 20; - feedCb = arguments[1]; - doneCb = arguments[2]; - } else { - maxRepetitions = arguments[1]; - feedCb = arguments[2]; - doneCb = arguments[3]; - } - - var req = { - maxRepetitions: maxRepetitions, - feedCb: feedCb, - doneCb: doneCb - }; - - if (this.version == Version2c || this.version == Version3) - this.getBulk([oid], 0, maxRepetitions, - walkCb.bind(me, req)); - else - this.getNext([oid], walkCb.bind(me, req)); - - return this; -}; - -Session.prototype.sendV3Req = function (pdu, feedCb, responseCb, options, port) { - var message = Message.createRequestV3(this.user, this.msgSecurityParameters, pdu); - var reqOptions = options || {}; - var req = new Req(this, message, feedCb, responseCb, reqOptions); - req.port = port; - this.send(req); -}; - -var Engine = function (engineID, engineBoots, engineTime) { - if (engineID) { - this.engineID = Buffer.from(engineID, 'hex'); - } else { - this.generateEngineID(); - } - this.engineBoots = 0; - this.engineTime = 10; -}; - -Engine.prototype.generateEngineID = function () { - // generate a 17-byte engine ID in the following format: - // 0x80 + 0x00B983 (enterprise OID) | 0x80 (enterprise-specific format) | 12 bytes of random - this.engineID = Buffer.alloc(17); - this.engineID.fill('8000B98380', 'hex', 0, 5); - this.engineID.fill(crypto.randomBytes(12), 5, 17, 'hex'); -} - -var Listener = function (options, receiver) { - this.receiver = receiver; - this.callback = receiver.onMsg; - this.family = options.transport || 'udp4'; - this.port = options.port || 161; - this.disableAuthorization = options.disableAuthorization || false; -}; - -Listener.prototype.startListening = function (receiver) { - var me = this; - this.dgram = dgram.createSocket(this.family); - this.dgram.bind(this.port); - this.dgram.on("message", me.callback.bind(me.receiver)); -}; - -Listener.prototype.send = function (message, rinfo) { - var me = this; - - var buffer = message.toBuffer(); - - this.dgram.send(buffer, 0, buffer.length, rinfo.port, rinfo.address, - function (error, bytes) { - if (error) { - // me.callback (error); - console.error("Error sending: " + error.message); - } else { - // debug ("Listener sent response message"); - } - }); -}; - -Listener.formatCallbackData = function (pdu, rinfo) { - if (pdu.contextEngineID) { - pdu.contextEngineID = pdu.contextEngineID.toString('hex'); - } - delete pdu.nonRepeaters; - delete pdu.maxRepetitions; - return { - pdu: pdu, - rinfo: rinfo - }; -}; - -Listener.processIncoming = function (buffer, authorizer, callback) { - var message = Message.createFromBuffer(buffer); - var community; - - // Authorization - if (message.version == Version3) { - message.user = authorizer.users.filter(localUser => localUser.name == - message.msgSecurityParameters.msgUserName)[0]; - message.disableAuthentication = authorizer.disableAuthorization; - if (!message.user) { - if (message.msgSecurityParameters.msgUserName != "" && !authorizer.disableAuthorization) { - callback(new RequestFailedError("Local user not found for message with user " + - message.msgSecurityParameters.msgUserName)); - return; - } else if (message.hasAuthentication()) { - callback(new RequestFailedError("Local user not found and message requires authentication with user " + - message.msgSecurityParameters.msgUserName)); - return; - } else { - message.user = { - name: "", - level: SecurityLevel.noAuthNoPriv - }; - } - } - if (!message.processIncomingSecurity(message.user, callback)) { - return; - } - } else { - community = authorizer.communities.filter(localCommunity => localCommunity == message.community)[0]; - if (!community && !authorizer.disableAuthorization) { - callback(new RequestFailedError("Local community not found for message with community " + message.community)); - return; - } - } - - return message; -}; - -var Authorizer = function () { - this.communities = []; - this.users = []; -} - -Authorizer.prototype.addCommunity = function (community) { - if (this.getCommunity(community)) { - return; - } else { - this.communities.push(community); - } -}; - -Authorizer.prototype.getCommunity = function (community) { - return this.communities.filter(localCommunity => localCommunity == community)[0] || null; -}; - -Authorizer.prototype.getCommunities = function () { - return this.communities; -}; - -Authorizer.prototype.deleteCommunity = function (community) { - var index = this.communities.indexOf(community); - if (index > -1) { - this.communities.splice(index, 1); - } -}; - -Authorizer.prototype.addUser = function (user) { - if (this.getUser(user.name)) { - this.deleteUser(user.name); - } - this.users.push(user); -}; - -Authorizer.prototype.getUser = function (userName) { - return this.users.filter(localUser => localUser.name == userName)[0] || null; -}; - -Authorizer.prototype.getUsers = function () { - return this.users; -}; - -Authorizer.prototype.deleteUser = function (userName) { - var index = this.users.findIndex(localUser => localUser.name == userName); - if (index > -1) { - this.users.splice(index, 1); - } -}; - - -/***************************************************************************** - ** Receiver class definition - **/ - -var Receiver = function (options, callback) { - DEBUG = options.debug; - this.listener = new Listener(options, this); - this.authorizer = new Authorizer(); - this.engine = new Engine(options.engineID); - - this.engineBoots = 0; - this.engineTime = 10; - this.disableAuthorization = false; - - this.callback = callback; - this.family = options.transport || 'udp4'; - this.port = options.port || 162; - options.port = this.port; - this.disableAuthorization = options.disableAuthorization || false; - this.context = (options && options.context) ? options.context : ""; - this.listener = new Listener(options, this); -}; - -Receiver.prototype.addCommunity = function (community) { - this.authorizer.addCommunity(community); -}; - -Receiver.prototype.getCommunity = function (community) { - return this.authorizer.getCommunity(community); -}; - -Receiver.prototype.getCommunities = function () { - return this.authorizer.getCommunities(); -}; - -Receiver.prototype.deleteCommunity = function (community) { - this.authorizer.deleteCommunities(community); -}; - -Receiver.prototype.addUser = function (user) { - this.authorizer.addUser(user); -}; - -Receiver.prototype.getUser = function (userName) { - return this.authorizer.getUser(userName); -}; - -Receiver.prototype.getUsers = function () { - return this.authorizer.getUsers(); -}; - -Receiver.prototype.deleteUser = function (userName) { - this.authorizer.deleteUser(userName); -}; - -Receiver.prototype.onMsg = function (buffer, rinfo) { - var message = Listener.processIncoming(buffer, this.authorizer, this.callback); - var reportMessage; - - if (!message) { - return; - } - - // The only GetRequest PDUs supported are those used for SNMPv3 discovery - if (message.pdu.type == PduType.GetRequest) { - if (message.version != Version3) { - this.callback(new RequestInvalidError("Only SNMPv3 discovery GetRequests are supported")); - return; - } else if (message.hasAuthentication()) { - this.callback(new RequestInvalidError("Only discovery (noAuthNoPriv) GetRequests are supported but this message has authentication")); - return; - } else if (!message.isReportable()) { - this.callback(new RequestInvalidError("Only discovery GetRequests are supported and this message does not have the reportable flag set")); - return; - } - var reportMessage = message.createReportResponseMessage(this.engine, this.context); - this.listener.send(reportMessage, rinfo); - return; - } - ; - - // Inform/trap processing - debug(JSON.stringify(message.pdu, null, 2)); - if (message.pdu.type == PduType.Trap || message.pdu.type == PduType.TrapV2) { - this.callback(null, this.formatCallbackData(message.pdu, rinfo)); - } else if (message.pdu.type == PduType.InformRequest) { - message.pdu.type = PduType.GetResponse; - message.buffer = null; - message.setReportable(false); - this.listener.send(message, rinfo); - message.pdu.type = PduType.InformRequest; - this.callback(null, this.formatCallbackData(message.pdu, rinfo)); - } else { - this.callback(new RequestInvalidError("Unexpected PDU type " + message.pdu.type + " (" + PduType[message.pdu.type] + ")")); - } -} - -Receiver.prototype.formatCallbackData = function (pdu, rinfo) { - if (pdu.contextEngineID) { - pdu.contextEngineID = pdu.contextEngineID.toString('hex'); - } - delete pdu.nonRepeaters; - delete pdu.maxRepetitions; - return { - pdu: pdu, - rinfo: rinfo - }; -}; - -Receiver.prototype.close = function () { - this.listener.close(); -}; - -Receiver.create = function (options, callback) { - var receiver = new Receiver(options, callback); - receiver.listener.startListening(); - return receiver; -}; - -var MibNode = function (address, parent) { - this.address = address; - this.oid = this.address.join('.'); - ; - this.parent = parent; - this.children = {}; -}; - -MibNode.prototype.child = function (index) { - return this.children[index]; -}; - -MibNode.prototype.listChildren = function (lowest) { - var sorted = []; - - lowest = lowest || 0; - - this.children.forEach(function (c, i) { - if (i >= lowest) - sorted.push(i); - }); - - sorted.sort(function (a, b) { - return (a - b); - }); - - return sorted; -}; - -MibNode.prototype.isDescendant = function (address) { - return MibNode.oidIsDescended(this.address, address); -}; - -MibNode.prototype.isAncestor = function (address) { - return MibNode.oidIsDescended(address, this.address); -}; - -MibNode.prototype.getAncestorProvider = function () { - if (this.provider) { - return this; - } else if (!this.parent) { - return null; - } else { - return this.parent.getAncestorProvider(); - } -}; - -MibNode.prototype.getInstanceNodeForTableRow = function () { - var childCount = Object.keys(this.children).length; - if (childCount == 0) { - if (this.value) { - return this; - } else { - return null; - } - } else if (childCount == 1) { - return this.children[0].getInstanceNodeForTableRow(); - } else if (childCount > 1) { - return null; - } -}; - -MibNode.prototype.getInstanceNodeForTableRowIndex = function (index) { - var childCount = Object.keys(this.children).length; - if (childCount == 0) { - if (this.value) { - return this; - } else { - // not found - return null; - } - } else { - if (index.length == 0) { - return this.getInstanceNodeForTableRow(); - } else { - var nextChildIndexPart = index[0]; - if (!nextChildIndexPart) { - return null; - } - remainingIndex = index.slice(1); - return this.children[nextChildIndexPart].getInstanceNodeForTableRowIndex(remainingIndex); - } - } -}; - -MibNode.prototype.getNextInstanceNode = function () { - - node = this; - if (this.value) { - // Need upwards traversal first - node = this; - while (node) { - siblingIndex = node.address.slice(-1)[0]; - node = node.parent; - if (!node) { - // end of MIB - return null; - } else { - childrenAddresses = Object.keys(node.children).sort((a, b) => a - b); - siblingPosition = childrenAddresses.indexOf(siblingIndex.toString()); - if (siblingPosition + 1 < childrenAddresses.length) { - node = node.children[childrenAddresses[siblingPosition + 1]]; - break; - } - } - } - } - // Descent - while (node) { - if (node.value) { - return node; - } - childrenAddresses = Object.keys(node.children).sort((a, b) => a - b); - node = node.children[childrenAddresses[0]]; - if (!node) { - // unexpected - return null; - } - } -}; - -MibNode.prototype.delete = function () { - if (Object.keys(this.children) > 0) { - throw new Error("Cannot delete non-leaf MIB node"); - } - addressLastPart = this.address.slice(-1)[0]; - delete this.parent.children[addressLastPart]; - this.parent = null; -}; - -MibNode.prototype.pruneUpwards = function () { - if (!this.parent) { - return - } - if (Object.keys(this.children).length == 0) { - var lastAddressPart = this.address.splice(-1)[0].toString(); - delete this.parent.children[lastAddressPart]; - this.parent.pruneUpwards(); - this.parent = null; - } -} - -MibNode.prototype.dump = function (options) { - var valueString; - if ((!options.leavesOnly || options.showProviders) && this.provider) { - console.log(this.oid + " [" + MibProviderType[this.provider.type] + ": " + this.provider.name + "]"); - } else if ((!options.leavesOnly) || Object.keys(this.children).length == 0) { - if (this.value) { - valueString = " = "; - valueString += options.showTypes ? ObjectType[this.valueType] + ": " : ""; - valueString += options.showValues ? this.value : ""; - } else { - valueString = ""; - } - console.log(this.oid + valueString); - } - for (node of Object.keys(this.children).sort((a, b) => a - b)) { - this.children[node].dump(options); - } -}; - -MibNode.oidIsDescended = function (oid, ancestor) { - var ancestorAddress = Mib.convertOidToAddress(ancestor); - var address = Mib.convertOidToAddress(oid); - var isAncestor = true; - - if (address.length <= ancestorAddress.length) { - return false; - } - - ancestorAddress.forEach(function (o, i) { - if (address[i] !== ancestorAddress[i]) { - isAncestor = false; - } - }); - - return isAncestor; -}; - -var Mib = function () { - this.root = new MibNode([], null); - this.providers = {}; - this.providerNodes = {}; -}; - -Mib.prototype.addNodesForOid = function (oidString) { - var address = Mib.convertOidToAddress(oidString); - return this.addNodesForAddress(address); -}; - -Mib.prototype.addNodesForAddress = function (address) { - var address; - var node; - var i; - - node = this.root; - - for (i = 0; i < address.length; i++) { - if (!node.children.hasOwnProperty(address[i])) { - node.children[address[i]] = new MibNode(address.slice(0, i + 1), node); - } - node = node.children[address[i]]; - } - - return node; -}; - -Mib.prototype.lookup = function (oid) { - var address; - var i; - var node; - - address = Mib.convertOidToAddress(oid); - node = this.root; - for (i = 0; i < address.length; i++) { - if (!node.children.hasOwnProperty(address[i])) { - return null - } - node = node.children[address[i]]; - } - - return node; -}; - -Mib.prototype.getProviderNodeForInstance = function (instanceNode) { - if (instanceNode.provider) { - throw new ReferenceError("Instance node has provider which should never happen"); - } - return instanceNode.getAncestorProvider(); -}; - -Mib.prototype.addProviderToNode = function (provider) { - var node = this.addNodesForOid(provider.oid); - - node.provider = provider; - if (provider.type == MibProviderType.Table) { - if (!provider.index) { - provider.index = [1]; - } - } - this.providerNodes[provider.name] = node; - return node; -}; - -Mib.prototype.registerProvider = function (provider) { - this.providers[provider.name] = provider; -}; - -Mib.prototype.unregisterProvider = function (name) { - var providerNode = this.providerNodes[name]; - if (providerNode) { - providerNodeParent = providerNode.parent; - providerNode.delete(); - providerNodeParent.pruneUpwards(); - delete this.providerNodes[name]; - } - delete this.providers[name]; -}; - -Mib.prototype.getProvider = function (name) { - return this.providers[name]; -}; - -Mib.prototype.getProviders = function () { - return this.providers; -}; - -Mib.prototype.getScalarValue = function (scalarName) { - var providerNode = this.providerNodes[scalarName]; - if (!providerNode || !providerNode.provider || providerNode.provider.type != MibProviderType.Scalar) { - throw new ReferenceError("Failed to get node for registered MIB provider " + scalarName); - } - var instanceAddress = providerNode.address.concat([0]); - if (!this.lookup(instanceAddress)) { - throw new Error("Failed created instance node for registered MIB provider " + scalarName); - } - var instanceNode = this.lookup(instanceAddress); - return instanceNode.value; -}; - -Mib.prototype.setScalarValue = function (scalarName, newValue) { - var providerNode; - var instanceNode; - - if (!this.providers[scalarName]) { - throw new ReferenceError("Provider " + scalarName + " not registered with this MIB"); - } - - providerNode = this.providerNodes[scalarName]; - if (!providerNode) { - providerNode = this.addProviderToNode(this.providers[scalarName]); - } - if (!providerNode || !providerNode.provider || providerNode.provider.type != MibProviderType.Scalar) { - throw new ReferenceError("Could not find MIB node for registered provider " + scalarName); - } - var instanceAddress = providerNode.address.concat([0]); - instanceNode = this.lookup(instanceAddress); - if (!instanceNode) { - this.addNodesForAddress(instanceAddress); - instanceNode = this.lookup(instanceAddress); - instanceNode.valueType = providerNode.provider.scalarType; - } - instanceNode.value = newValue; -}; - -Mib.prototype.getProviderNodeForTable = function (table) { - var providerNode; - var provider; - - providerNode = this.providerNodes[table]; - if (!providerNode) { - throw new ReferenceError("No MIB provider registered for " + table); - } - provider = providerNode.provider; - if (!providerNode) { - throw new ReferenceError("No MIB provider definition for registered provider " + table); - } - if (provider.type != MibProviderType.Table) { - throw new TypeError("Registered MIB provider " + table + - " is not of the correct type (is type " + MibProviderType[provider.type] + ")"); - } - return providerNode; -}; - -Mib.prototype.addTableRow = function (table, row) { - var providerNode; - var provider; - var instance = []; - var instanceAddress; - var instanceNode; - - if (this.providers[table] && !this.providerNodes[table]) { - this.addProviderToNode(this.providers[table]); - } - providerNode = this.getProviderNodeForTable(table); - provider = providerNode.provider; - for (var indexPart of provider.index) { - columnPosition = provider.columns.findIndex(column => column.number == indexPart); - instance.push(row[columnPosition]); - } - for (var i = 0; i < providerNode.provider.columns.length; i++) { - var column = providerNode.provider.columns[i]; - instanceAddress = providerNode.address.concat(column.number).concat(instance); - this.addNodesForAddress(instanceAddress); - instanceNode = this.lookup(instanceAddress); - instanceNode.valueType = column.type; - instanceNode.value = row[i]; - } -}; - -Mib.prototype.getTableColumnDefinitions = function (table) { - var providerNode; - var provider; - - providerNode = this.getProviderNodeForTable(table); - provider = providerNode.provider; - return provider.columns; -}; - -Mib.prototype.getTableColumnCells = function (table, columnNumber) { - providerNode = this.getProviderNodeForTable(table); - columnNode = providerNode.children[columnNumber]; - column = [] - for (var row of Object.keys(columnNode.children)) { - instanceNode = columnNode.children[row].getInstanceNodeForTableRow(); - column.push(instanceNode.value); - } - return column; -}; - -Mib.prototype.getTableRowCells = function (table, rowIndex) { - var providerNode; - var columnNode; - var instanceNode; - var row = []; - - providerNode = this.getProviderNodeForTable(table); - for (var columnNumber of Object.keys(providerNode.children)) { - columnNode = providerNode.children[columnNumber]; - instanceNode = columnNode.getInstanceNodeForTableRowIndex(rowIndex); - row.push(instanceNode.value); - } - return row; -}; - -Mib.prototype.getTableCells = function (table, byRows) { - var providerNode; - var columnNode; - var data = []; - - providerNode = this.getProviderNodeForTable(table); - for (var columnNumber of Object.keys(providerNode.children)) { - columnNode = providerNode.children[columnNumber]; - column = []; - data.push(column); - for (var row of Object.keys(columnNode.children)) { - instanceNode = columnNode.children[row].getInstanceNodeForTableRow(); - column.push(instanceNode.value); - } - } - - if (byRows) { - return Object.keys(data[0]).map(function (c) { - return data.map(function (r) { - return r[c]; - }); - }); - } else { - return data; - } - -}; - -Mib.prototype.getTableSingleCell = function (table, columnNumber, rowIndex) { - var providerNode; - var columnNode; - var instanceNode; - - providerNode = this.getProviderNodeForTable(table); - columnNode = providerNode.children[columnNumber]; - instanceNode = columnNode.getInstanceNodeForTableRowIndex(rowIndex); - return instanceNode.value; -}; - -Mib.prototype.setTableSingleCell = function (table, columnNumber, rowIndex, value) { - var providerNode; - var columnNode; - var instanceNode; - - providerNode = this.getProviderNodeForTable(table); - columnNode = providerNode.children[columnNumber]; - instanceNode = columnNode.getInstanceNodeForTableRowIndex(rowIndex); - instanceNode.value = value; -}; - -Mib.prototype.deleteTableRow = function (table, rowIndex) { - var providerNode; - var columnNode; - var instanceNode; - var row = []; - - providerNode = this.getProviderNodeForTable(table); - for (var columnNumber of Object.keys(providerNode.children)) { - columnNode = providerNode.children[columnNumber]; - instanceNode = columnNode.getInstanceNodeForTableRowIndex(rowIndex); - if (instanceNode) { - instanceParentNode = instanceNode.parent; - instanceNode.delete(); - instanceParentNode.pruneUpwards(); - } else { - throw new ReferenceError("Cannot find row for index " + rowIndex + " at registered provider " + table); - } - } - return row; -}; - -Mib.prototype.dump = function (options) { - if (!options) { - options = {}; - } - var completedOptions = { - leavesOnly: options.leavesOnly || true, - showProviders: options.leavesOnly || true, - showValues: options.leavesOnly || true, - showTypes: options.leavesOnly || true - }; - this.root.dump(completedOptions); -}; - -Mib.convertOidToAddress = function (oid) { - var address; - var oidArray; - var i; - - if (typeof (oid) === 'object' && util.isArray(oid)) { - address = oid; - } else if (typeof (oid) === 'string') { - address = oid.split('.'); - } else { - throw new TypeError('oid (string or array) is required'); - } - - if (address.length < 3) - throw new RangeError('object identifier is too short'); - - oidArray = []; - for (i = 0; i < address.length; i++) { - var n; - - if (address[i] === '') - continue; - - if (address[i] === true || address[i] === false) { - throw new TypeError('object identifier component ' + - address[i] + ' is malformed'); - } - - n = Number(address[i]); - - if (isNaN(n)) { - throw new TypeError('object identifier component ' + - address[i] + ' is malformed'); - } - if (n % 1 !== 0) { - throw new TypeError('object identifier component ' + - address[i] + ' is not an integer'); - } - if (i === 0 && n > 2) { - throw new RangeError('object identifier does not ' + - 'begin with 0, 1, or 2'); - } - if (i === 1 && n > 39) { - throw new RangeError('object identifier second ' + - 'component ' + n + ' exceeds encoding limit of 39'); - } - if (n < 0) { - throw new RangeError('object identifier component ' + - address[i] + ' is negative'); - } - if (n > MAX_INT32) { - throw new RangeError('object identifier component ' + - address[i] + ' is too large'); - } - oidArray.push(n); - } - - return oidArray; - -}; - -var MibRequest = function (requestDefinition) { - this.operation = requestDefinition.operation; - this.address = Mib.convertOidToAddress(requestDefinition.oid); - this.oid = this.address.join('.'); - this.providerNode = requestDefinition.providerNode; - this.instanceNode = requestDefinition.instanceNode; -}; - -MibRequest.prototype.isScalar = function () { - return this.providerNode && this.providerNode.provider && - this.providerNode.provider.type == MibProviderType.Scalar; -}; - -MibRequest.prototype.isTabular = function () { - return this.providerNode && this.providerNode.provider && - this.providerNode.provider.type == MibProviderType.Table; -}; - -var Agent = function (options, callback) { - DEBUG = options.debug; - this.listener = new Listener(options, this); - this.engine = new Engine(options.engineID); - this.authorizer = new Authorizer(); - this.mib = new Mib(); - this.callback = callback || function () { - }; - this.context = ""; -}; - -Agent.prototype.getMib = function () { - return this.mib; -}; - -Agent.prototype.getAuthorizer = function () { - return this.authorizer; -}; - -Agent.prototype.registerProvider = function (provider) { - this.mib.registerProvider(provider); -}; - -Agent.prototype.unregisterProvider = function (provider) { - this.mib.unregisterProvider(provider); -}; - -Agent.prototype.getProvider = function (provider) { - return this.mib.getProvider(provider); -}; - -Agent.prototype.getProviders = function () { - return this.mib.getProviders(); -}; - -Agent.prototype.onMsg = function (buffer, rinfo) { - var message = Listener.processIncoming(buffer, this.authorizer, this.callback); - var reportMessage; - var responseMessage; - - if (!message) { - return; - } - - // SNMPv3 discovery - if (message.version == Version3 && message.pdu.type == PduType.GetRequest && - !message.hasAuthoritativeEngineID() && message.isReportable()) { - reportMessage = message.createReportResponseMessage(this.engine, this.context); - this.listener.send(reportMessage, rinfo); - return; - } - - // Request processing - debug(JSON.stringify(message.pdu, null, 2)); - if (message.pdu.type == PduType.GetRequest) { - responseMessage = this.request(message, rinfo); - } else if (message.pdu.type == PduType.SetRequest) { - responseMessage = this.request(message, rinfo); - } else if (message.pdu.type == PduType.GetNextRequest) { - responseMessage = this.getNextRequest(message, rinfo); - } else if (message.pdu.type == PduType.GetBulkRequest) { - responseMessage = this.getBulkRequest(message, rinfo); - } else { - this.callback(new RequestInvalidError("Unexpected PDU type " + - message.pdu.type + " (" + PduType[message.pdu.type] + ")")); - } - -}; - -Agent.prototype.request = function (requestMessage, rinfo) { - var me = this; - var varbindsCompleted = 0; - var requestPdu = requestMessage.pdu; - var varbindsLength = requestPdu.varbinds.length; - var responsePdu = requestPdu.getResponsePduForRequest(); - - for (var i = 0; i < requestPdu.varbinds.length; i++) { - var requestVarbind = requestPdu.varbinds[i]; - var instanceNode = this.mib.lookup(requestVarbind.oid); - var providerNode; - var mibRequest; - var handler; - var responseVarbindType; - - if (!instanceNode) { - mibRequest = new MibRequest({ - operation: requestPdu.type, - oid: requestVarbind.oid - }); - handler = function getNsoHandler(mibRequestForNso) { - mibRequestForNso.done({ - errorStatus: ErrorStatus.NoSuchName, - errorIndex: i - }); - }; - } else { - providerNode = this.mib.getProviderNodeForInstance(instanceNode); - mibRequest = new MibRequest({ - operation: requestPdu.type, - providerNode: providerNode, - instanceNode: instanceNode, - oid: requestVarbind.oid - }); - handler = providerNode.provider.handler; - } - - mibRequest.done = function (error) { - if (error) { - responsePdu.errorStatus = error.errorStatus; - responsePdu.errorIndex = error.errorIndex; - responseVarbind = { - oid: mibRequest.oid, - type: ObjectType.Null, - value: null - }; - } else { - if (requestPdu.type == PduType.SetRequest) { - mibRequest.instanceNode.value = requestVarbind.value; - } - if (requestPdu.type == PduType.GetNextRequest && requestVarbind.type == ObjectType.EndOfMibView) { - responseVarbindType = ObjectType.EndOfMibView; - } else { - responseVarbindType = mibRequest.instanceNode.valueType; - } - responseVarbind = { - oid: mibRequest.oid, - type: responseVarbindType, - value: mibRequest.instanceNode.value - }; - } - me.setSingleVarbind(responsePdu, i, responseVarbind); - if (++varbindsCompleted == varbindsLength) { - me.sendResponse.call(me, rinfo, requestMessage, responsePdu); - } - }; - if (handler) { - handler(mibRequest); - } else { - mibRequest.done(); - } - } - ; -}; - -Agent.prototype.addGetNextVarbind = function (targetVarbinds, startOid) { - var startNode = this.mib.lookup(startOid); - var getNextNode; - - if (!startNode) { - // Off-tree start specified - targetVarbinds.push({ - oid: requestVarbind.oid, - type: ObjectType.Null, - value: null - }); - } else { - getNextNode = startNode.getNextInstanceNode(); - if (!getNextNode) { - // End of MIB - targetVarbinds.push({ - oid: requestVarbind.oid, - type: ObjectType.EndOfMibView, - value: null - }); - } else { - // Normal response - targetVarbinds.push({ - oid: getNextNode.oid, - type: getNextNode.valueType, - value: getNextNode.value - }); - } - } - return getNextNode; -}; - -Agent.prototype.getNextRequest = function (requestMessage, rinfo) { - var requestPdu = requestMessage.pdu; - var varbindsLength = requestPdu.varbinds.length; - var getNextVarbinds = []; - - for (var i = 0; i < varbindsLength; i++) { - this.addGetNextVarbind(getNextVarbinds, requestPdu.varbinds[i].oid); - } - - requestMessage.pdu.varbinds = getNextVarbinds; - this.request(requestMessage, rinfo); -}; - -Agent.prototype.getBulkRequest = function (requestMessage, rinfo) { - var requestPdu = requestMessage.pdu; - var requestVarbinds = requestPdu.varbinds; - var getBulkVarbinds = []; - var startOid = []; - var getNextNode; - - for (var n = 0; n < requestPdu.nonRepeaters; n++) { - this.addGetNextVarbind(getBulkVarbinds, requestVarbinds[n].oid); - } - - for (var v = requestPdu.nonRepeaters; v < requestVarbinds.length; v++) { - startOid.push(requestVarbinds[v].oid); - } - - for (var r = 0; r < requestPdu.maxRepetitions; r++) { - for (var v = requestPdu.nonRepeaters; v < requestVarbinds.length; v++) { - getNextNode = this.addGetNextVarbind(getBulkVarbinds, startOid[v - requestPdu.nonRepeaters]); - if (getNextNode) { - startOid[v - requestPdu.nonRepeaters] = getNextNode.oid; - } - } - } - - requestMessage.pdu.varbinds = getBulkVarbinds; - this.request(requestMessage, rinfo); -}; - -Agent.prototype.setSingleVarbind = function (responsePdu, index, responseVarbind) { - responsePdu.varbinds[index] = responseVarbind; -}; - -Agent.prototype.sendResponse = function (rinfo, requestMessage, responsePdu) { - var responseMessage = requestMessage.createResponseForRequest(responsePdu); - this.listener.send(responseMessage, rinfo); - this.callback(null, Listener.formatCallbackData(responseMessage.pdu, rinfo)); -}; - -Agent.create = function (options, callback) { - var agent = new Agent(options, callback); - agent.listener.startListening(); - return agent; -}; - -/***************************************************************************** - ** Exports - **/ - -exports.Session = Session; - -exports.createSession = function (target, community, options) { - if (options.version && !(options.version == Version1 || options.version == Version2c)) { - throw new ResponseInvalidError("SNMP community session requested but version '" + options.version + "' specified in options not valid"); - } else { - return new Session(target, community, options); - } -}; - -exports.createV3Session = function (target, user, options) { - if (options.version && options.version != Version3) { - throw new ResponseInvalidError("SNMPv3 session requested but version '" + options.version + "' specified in options"); - } else { - options.version = Version3; - } - return new Session(target, user, options); -}; - -exports.createReceiver = Receiver.create; -exports.createAgent = Agent.create; - -exports.isVarbindError = isVarbindError; -exports.varbindError = varbindError; - -exports.Version1 = Version1; -exports.Version2c = Version2c; -exports.Version3 = Version3; -exports.Version = Version; - -exports.ErrorStatus = ErrorStatus; -exports.TrapType = TrapType; -exports.ObjectType = ObjectType; -exports.PduType = PduType; -exports.MibProviderType = MibProviderType; -exports.SecurityLevel = SecurityLevel; -exports.AuthProtocols = AuthProtocols; -exports.PrivProtocols = PrivProtocols; - -exports.ResponseInvalidError = ResponseInvalidError; -exports.RequestInvalidError = RequestInvalidError; -exports.RequestFailedError = RequestFailedError; -exports.RequestTimedOutError = RequestTimedOutError; - -/** - ** We've added this for testing. - **/ -exports.ObjectParser = { - readInt: readInt, - readUint: readUint -}; -exports.Authentication = Authentication; -exports.Encryption = Encryption; diff --git a/collectors/node.d.plugin/node_modules/netdata.js b/collectors/node.d.plugin/node_modules/netdata.js deleted file mode 100644 index 603922c6e..000000000 --- a/collectors/node.d.plugin/node_modules/netdata.js +++ /dev/null @@ -1,654 +0,0 @@ -'use strict'; - -// netdata -// real-time performance and health monitoring, done right! -// (C) 2016 Costa Tsaousis <costa@tsaousis.gr> -// SPDX-License-Identifier: GPL-3.0-or-later - -var url = require('url'); -var http = require('http'); -var util = require('util'); - -/* -var netdata = require('netdata'); - -var example_chart = { - id: 'id', // the unique id of the chart - name: 'name', // the name of the chart - title: 'title', // the title of the chart - units: 'units', // the units of the chart dimensions - family: 'family', // the family of the chart - context: 'context', // the context of the chart - type: netdata.chartTypes.line, // the type of the chart - priority: 0, // the priority relative to others in the same family - update_every: 1, // the expected update frequency of the chart - dimensions: { - 'dim1': { - id: 'dim1', // the unique id of the dimension - name: 'name', // the name of the dimension - algorithm: netdata.chartAlgorithms.absolute, // the id of the netdata algorithm - multiplier: 1, // the multiplier - divisor: 1, // the divisor - hidden: false, // is hidden (boolean) - }, - 'dim2': { - id: 'dim2', // the unique id of the dimension - name: 'name', // the name of the dimension - algorithm: 'absolute', // the id of the netdata algorithm - multiplier: 1, // the multiplier - divisor: 1, // the divisor - hidden: false, // is hidden (boolean) - } - // add as many dimensions as needed - } -}; -*/ - -var netdata = { - options: { - filename: __filename, - DEBUG: false, - update_every: 1 - }, - - chartAlgorithms: { - incremental: 'incremental', - absolute: 'absolute', - percentage_of_absolute_row: 'percentage-of-absolute-row', - percentage_of_incremental_row: 'percentage-of-incremental-row' - }, - - chartTypes: { - line: 'line', - area: 'area', - stacked: 'stacked' - }, - - services: new Array(), - modules_configuring: 0, - charts: {}, - - processors: { - http: { - name: 'http', - - process: function(service, callback) { - var __DEBUG = netdata.options.DEBUG; - - if(__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': making ' + this.name + ' request: ' + netdata.stringify(service.request)); - - var req = http.request(service.request, function(response) { - if(__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': got server response...'); - - var end = false; - var data = ''; - response.setEncoding('utf8'); - - if(response.statusCode !== 200) { - if(end === false) { - service.error('Got HTTP code ' + response.statusCode + ', failed to get data.'); - end = true; - return callback(null); - } - } - - response.on('data', function(chunk) { - if(end === false) data += chunk; - }); - - response.on('error', function() { - if(end === false) { - service.error(': Read error, failed to get data.'); - end = true; - return callback(null); - } - }); - - response.on('end', function() { - if(end === false) { - if(__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': read completed.'); - end = true; - return callback(data); - } - }); - }); - - req.on('error', function(e) { - if(__DEBUG === true) netdata.debug('Failed to make request: ' + netdata.stringify(service.request) + ', message: ' + e.message); - service.error('Failed to make request, message: ' + e.message); - return callback(null); - }); - - // write data to request body - if(typeof service.postData !== 'undefined' && service.request.method === 'POST') { - if(__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': posting data: ' + service.postData); - req.write(service.postData); - } - - req.end(); - } - } - }, - - stringify: function(obj) { - return util.inspect(obj, {depth: 10}); - }, - - zeropad2: function(s) { - return ("00" + s).slice(-2); - }, - - logdate: function(d) { - if(typeof d === 'undefined') d = new Date(); - return d.getFullYear().toString() + '-' + this.zeropad2(d.getMonth() + 1) + '-' + this.zeropad2(d.getDate()) - + ' ' + this.zeropad2(d.getHours()) + ':' + this.zeropad2(d.getMinutes()) + ':' + this.zeropad2(d.getSeconds()); - }, - - // show debug info, if debug is enabled - debug: function(msg) { - if(this.options.DEBUG === true) { - console.error(this.logdate() + ': ' + netdata.options.filename + ': DEBUG: ' + ((typeof(msg) === 'object')?netdata.stringify(msg):msg).toString()); - } - }, - - // log an error - error: function(msg) { - console.error(this.logdate() + ': ' + netdata.options.filename + ': ERROR: ' + ((typeof(msg) === 'object')?netdata.stringify(msg):msg).toString()); - }, - - // send data to netdata - send: function(msg) { - console.log(msg.toString()); - }, - - service: function(service) { - if(typeof service === 'undefined') - service = {}; - - var now = Date.now(); - - service._current_chart = null; // the current chart we work on - service._queue = ''; // data to be sent to netdata - - service.error_reported = false; // error log flood control - - service.added = false; // added to netdata.services - service.enabled = true; - service.updates = 0; - service.running = false; - service.started = 0; - service.ended = 0; - - if(typeof service.module === 'undefined') { - service.module = { name: 'not-defined-module' }; - service.error('Attempted to create service without a module.'); - service.enabled = false; - } - - if(typeof service.name === 'undefined') { - service.name = 'unnamed@' + service.module.name + '/' + now; - } - - if(typeof service.processor === 'undefined') - service.processor = netdata.processors.http; - - if(typeof service.update_every === 'undefined') - service.update_every = service.module.update_every; - - if(typeof service.update_every === 'undefined') - service.update_every = netdata.options.update_every; - - if(service.update_every < netdata.options.update_every) - service.update_every = netdata.options.update_every; - - // align the runs - service.next_run = now - (now % (service.update_every * 1000)) + (service.update_every * 1000); - - service.commit = function() { - if(this.added !== true) { - this.added = true; - - var now = Date.now(); - this.next_run = now - (now % (service.update_every * 1000)) + (service.update_every * 1000); - - netdata.services.push(this); - if(netdata.options.DEBUG === true) netdata.debug(this.module.name + ': ' + this.name + ': service committed.'); - } - }; - - service.execute = function(responseProcessor) { - var __DEBUG = netdata.options.DEBUG; - - if(service.enabled === false) - return responseProcessor(null); - - this.module.active++; - this.running = true; - this.started = Date.now(); - this.updates++; - - if(__DEBUG === true) - netdata.debug(this.module.name + ': ' + this.name + ': making ' + this.processor.name + ' request: ' + netdata.stringify(this)); - - this.processor.process(this, function(response) { - service.ended = Date.now(); - service.duration = service.ended - service.started; - - if(typeof response === 'undefined') - response = null; - - if(response !== null) - service.errorClear(); - - if(__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': processing ' + service.processor.name + ' response (received in ' + (service.ended - service.started).toString() + ' ms)'); - - try { - responseProcessor(service, response); - } - catch(e) { - netdata.error(e); - service.error("responseProcessor failed process response data."); - } - - service.running = false; - service.module.active--; - if(service.module.active < 0) { - service.module.active = 0; - if(__DEBUG === true) - netdata.debug(service.module.name + ': active module counter below zero.'); - } - - if(service.module.active === 0) { - // check if we run under configure - if(service.module.configure_callback !== null) { - if(__DEBUG === true) - netdata.debug(service.module.name + ': configuration finish callback called from processResponse().'); - - var configure_callback = service.module.configure_callback; - service.module.configure_callback = null; - configure_callback(); - } - } - }); - }; - - service.update = function() { - if(netdata.options.DEBUG === true) - netdata.debug(this.module.name + ': ' + this.name + ': starting data collection...'); - - this.module.update(this, function() { - if(netdata.options.DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': data collection ended in ' + service.duration.toString() + ' ms.'); - }); - }; - - service.error = function(message) { - if(this.error_reported === false) { - netdata.error(this.module.name + ': ' + this.name + ': ' + message); - this.error_reported = true; - } - else if(netdata.options.DEBUG === true) - netdata.debug(this.module.name + ': ' + this.name + ': ' + message); - }; - - service.errorClear = function() { - this.error_reported = false; - }; - - service.queue = function(txt) { - this._queue += txt + '\n'; - }; - - service._send_chart_to_netdata = function(chart) { - // internal function to send a chart to netdata - this.queue('CHART "' + chart.id + '" "' + chart.name + '" "' + chart.title + '" "' + chart.units + '" "' + chart.family + '" "' + chart.context + '" "' + chart.type + '" ' + chart.priority.toString() + ' ' + chart.update_every.toString()); - - if(typeof(chart.dimensions) !== 'undefined') { - var dims = Object.keys(chart.dimensions); - var len = dims.length; - while(len--) { - var d = chart.dimensions[dims[len]]; - - this.queue('DIMENSION "' + d.id + '" "' + d.name + '" "' + d.algorithm + '" ' + d.multiplier.toString() + ' ' + d.divisor.toString() + ' ' + ((d.hidden === true) ? 'hidden' : '').toString()); - d._created = true; - d._updated = false; - } - } - - chart._created = true; - chart._updated = false; - }; - - // begin data collection for a chart - service.begin = function(chart) { - if(this._current_chart !== null && this._current_chart !== chart) { - this.error('Called begin() for chart ' + chart.id + ' while chart ' + this._current_chart.id + ' is still open. Closing it.'); - this.end(); - } - - if(typeof(chart.id) === 'undefined' || netdata.charts[chart.id] !== chart) { - this.error('Called begin() for chart ' + chart.id + ' that is not mine. Where did you find it? Ignoring it.'); - return false; - } - - if(netdata.options.DEBUG === true) netdata.debug('setting current chart to ' + chart.id); - this._current_chart = chart; - this._current_chart._began = true; - - if(this._current_chart._dimensions_count !== 0) { - if(this._current_chart._created === false || this._current_chart._updated === true) - this._send_chart_to_netdata(this._current_chart); - - var now = this.ended; - this.queue('BEGIN ' + this._current_chart.id + ' ' + ((this._current_chart._last_updated > 0)?((now - this._current_chart._last_updated) * 1000):'').toString()); - } - // else this.error('Called begin() for chart ' + chart.id + ' which is empty.'); - - this._current_chart._last_updated = now; - this._current_chart._began = true; - this._current_chart._counter++; - - return true; - }; - - // set a collected value for a chart - // we do most things on the first value we attempt to set - service.set = function(dimension, value) { - if(this._current_chart === null) { - this.error('Called set(' + dimension + ', ' + value + ') without an open chart.'); - return false; - } - - if(typeof(this._current_chart.dimensions[dimension]) === 'undefined') { - this.error('Called set(' + dimension + ', ' + value + ') but dimension "' + dimension + '" does not exist in chart "' + this._current_chart.id + '".'); - return false; - } - - if(typeof value === 'undefined' || value === null) - return false; - - if(this._current_chart._dimensions_count !== 0) - this.queue('SET ' + dimension + ' = ' + value.toString()); - - return true; - }; - - // end data collection for the current chart - after calling begin() - service.end = function() { - if(this._current_chart !== null && this._current_chart._began === false) { - this.error('Called end() without an open chart.'); - return false; - } - - if(this._current_chart._dimensions_count !== 0) { - this.queue('END'); - netdata.send(this._queue); - } - - this._queue = ''; - this._current_chart._began = false; - if(netdata.options.DEBUG === true) netdata.debug('sent chart ' + this._current_chart.id); - this._current_chart = null; - return true; - }; - - // discard the collected values for the current chart - after calling begin() - service.flush = function() { - if(this._current_chart === null || this._current_chart._began === false) { - this.error('Called flush() without an open chart.'); - return false; - } - - this._queue = ''; - this._current_chart._began = false; - this._current_chart = null; - return true; - }; - - // create a netdata chart - service.chart = function(id, chart) { - var __DEBUG = netdata.options.DEBUG; - - if(typeof(netdata.charts[id]) === 'undefined') { - netdata.charts[id] = { - _created: false, - _updated: true, - _began: false, - _counter: 0, - _last_updated: 0, - _dimensions_count: 0, - id: id, - name: id, - title: 'untitled chart', - units: 'a unit', - family: '', - context: '', - type: netdata.chartTypes.line, - priority: 50000, - update_every: netdata.options.update_every, - dimensions: {} - }; - } - - var c = netdata.charts[id]; - - if(typeof(chart.name) !== 'undefined' && chart.name !== c.name) { - if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its name'); - c.name = chart.name; - c._updated = true; - } - - if(typeof(chart.title) !== 'undefined' && chart.title !== c.title) { - if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its title'); - c.title = chart.title; - c._updated = true; - } - - if(typeof(chart.units) !== 'undefined' && chart.units !== c.units) { - if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its units'); - c.units = chart.units; - c._updated = true; - } - - if(typeof(chart.family) !== 'undefined' && chart.family !== c.family) { - if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its family'); - c.family = chart.family; - c._updated = true; - } - - if(typeof(chart.context) !== 'undefined' && chart.context !== c.context) { - if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its context'); - c.context = chart.context; - c._updated = true; - } - - if(typeof(chart.type) !== 'undefined' && chart.type !== c.type) { - if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its type'); - c.type = chart.type; - c._updated = true; - } - - if(typeof(chart.priority) !== 'undefined' && chart.priority !== c.priority) { - if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its priority'); - c.priority = chart.priority; - c._updated = true; - } - - if(typeof(chart.update_every) !== 'undefined' && chart.update_every !== c.update_every) { - if(__DEBUG === true) netdata.debug('chart ' + id + ' updated its update_every from ' + c.update_every + ' to ' + chart.update_every); - c.update_every = chart.update_every; - c._updated = true; - } - - if(typeof(chart.dimensions) !== 'undefined') { - var dims = Object.keys(chart.dimensions); - var len = dims.length; - while(len--) { - var x = dims[len]; - - if(typeof(c.dimensions[x]) === 'undefined') { - c._dimensions_count++; - - c.dimensions[x] = { - _created: false, - _updated: false, - id: x, // the unique id of the dimension - name: x, // the name of the dimension - algorithm: netdata.chartAlgorithms.absolute, // the id of the netdata algorithm - multiplier: 1, // the multiplier - divisor: 1, // the divisor - hidden: false // is hidden (boolean) - }; - - if(__DEBUG === true) netdata.debug('chart ' + id + ' created dimension ' + x); - c._updated = true; - } - - var dim = chart.dimensions[x]; - var d = c.dimensions[x]; - - if(typeof(dim.name) !== 'undefined' && d.name !== dim.name) { - if(__DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its name'); - d.name = dim.name; - d._updated = true; - } - - if(typeof(dim.algorithm) !== 'undefined' && d.algorithm !== dim.algorithm) { - if(__DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its algorithm from ' + d.algorithm + ' to ' + dim.algorithm); - d.algorithm = dim.algorithm; - d._updated = true; - } - - if(typeof(dim.multiplier) !== 'undefined' && d.multiplier !== dim.multiplier) { - if(__DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its multiplier'); - d.multiplier = dim.multiplier; - d._updated = true; - } - - if(typeof(dim.divisor) !== 'undefined' && d.divisor !== dim.divisor) { - if(__DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its divisor'); - d.divisor = dim.divisor; - d._updated = true; - } - - if(typeof(dim.hidden) !== 'undefined' && d.hidden !== dim.hidden) { - if(__DEBUG === true) netdata.debug('chart ' + id + ', dimension ' + x + ' updated its hidden status'); - d.hidden = dim.hidden; - d._updated = true; - } - - if(d._updated) c._updated = true; - } - } - - //if(netdata.options.DEBUG === true) netdata.debug(netdata.charts); - return netdata.charts[id]; - }; - - return service; - }, - - runAllServices: function() { - if(netdata.options.DEBUG === true) netdata.debug('runAllServices()'); - - var now = Date.now(); - var len = netdata.services.length; - while(len--) { - var service = netdata.services[len]; - - if(service.enabled === false || service.running === true) continue; - if(now <= service.next_run) continue; - - service.update(); - - now = Date.now(); - service.next_run = now - (now % (service.update_every * 1000)) + (service.update_every * 1000); - } - - // 1/10th of update_every in pause - setTimeout(netdata.runAllServices, netdata.options.update_every * 100); - }, - - start: function() { - if(netdata.options.DEBUG === true) this.debug('started, services: ' + netdata.stringify(this.services)); - - if(this.services.length === 0) { - this.disableNodePlugin(); - - // eslint suggested way to exit - var exit = process.exit; - exit(1); - } - else this.runAllServices(); - }, - - // disable the whole node.js plugin - disableNodePlugin: function() { - this.send('DISABLE'); - - // eslint suggested way to exit - var exit = process.exit; - exit(1); - }, - - requestFromParams: function(protocol, hostname, port, path, method) { - return { - protocol: protocol, - hostname: hostname, - port: port, - path: path, - //family: 4, - method: method, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - 'Connection': 'keep-alive' - }, - agent: new http.Agent({ - keepAlive: true, - keepAliveMsecs: netdata.options.update_every * 1000, - maxSockets: 2, // it must be 2 to work - maxFreeSockets: 1 - }) - }; - }, - - requestFromURL: function(a_url) { - var u = url.parse(a_url); - return netdata.requestFromParams(u.protocol, u.hostname, u.port, u.path, 'GET'); - }, - - configure: function(module, config, callback) { - if(netdata.options.DEBUG === true) this.debug(module.name + ': configuring (update_every: ' + this.options.update_every + ')...'); - - module.active = 0; - module.update_every = this.options.update_every; - - if(typeof config.update_every !== 'undefined') - module.update_every = config.update_every; - - module.enable_autodetect = (config.enable_autodetect)?true:false; - - if(typeof(callback) === 'function') - module.configure_callback = callback; - else - module.configure_callback = null; - - var added = module.configure(config); - - if(netdata.options.DEBUG === true) this.debug(module.name + ': configured, reporting ' + added + ' eligible services.'); - - if(module.configure_callback !== null && added === 0) { - if(netdata.options.DEBUG === true) this.debug(module.name + ': configuration finish callback called from configure().'); - var configure_callback = module.configure_callback; - module.configure_callback = null; - configure_callback(); - } - - return added; - } -}; - -if(netdata.options.DEBUG === true) netdata.debug('loaded netdata from:', __filename); -module.exports = netdata; diff --git a/collectors/node.d.plugin/node_modules/pixl-xml.js b/collectors/node.d.plugin/node_modules/pixl-xml.js deleted file mode 100644 index 48de89e77..000000000 --- a/collectors/node.d.plugin/node_modules/pixl-xml.js +++ /dev/null @@ -1,607 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - JavaScript XML Library - Plus a bunch of object utility functions - - Usage: - var XML = require('pixl-xml'); - var myxmlstring = '<?xml version="1.0"?><Document>' + - '<Simple>Hello</Simple>' + - '<Node Key="Value">Content</Node>' + - '</Document>'; - - var tree = XML.parse( myxmlstring, { preserveAttributes: true }); - console.log( tree ); - - tree.Simple = "Hello2"; - tree.Node._Attribs.Key = "Value2"; - tree.Node._Data = "Content2"; - tree.New = "I added this"; - - console.log( XML.stringify( tree, 'Document' ) ); - - Copyright (c) 2004 - 2015 Joseph Huckaby - Released under the MIT License - This version is for Node.JS, converted in 2012. -*/ - -var fs = require('fs'); - -var indent_string = "\t"; -var xml_header = '<?xml version="1.0"?>'; -var sort_args = null; -var re_valid_tag_name = /^\w[\w\-\:]*$/; - -var XML = exports.XML = function XML(args) { - // class constructor for XML parser class - // pass in args hash or text to parse - if (!args) args = ''; - if (isa_hash(args)) { - for (var key in args) this[key] = args[key]; - } - else this.text = args || ''; - - // stringify buffers - if (this.text instanceof Buffer) { - this.text = this.text.toString(); - } - - if (!this.text.match(/^\s*</)) { - // try as file path - var file = this.text; - this.text = fs.readFileSync(file, { encoding: 'utf8' }); - if (!this.text) throw new Error("File not found: " + file); - } - - this.tree = {}; - this.errors = []; - this.piNodeList = []; - this.dtdNodeList = []; - this.documentNodeName = ''; - - if (this.lowerCase) { - this.attribsKey = this.attribsKey.toLowerCase(); - this.dataKey = this.dataKey.toLowerCase(); - } - - this.patTag.lastIndex = 0; - if (this.text) this.parse(); -} - -XML.prototype.preserveAttributes = false; -XML.prototype.lowerCase = false; - -XML.prototype.patTag = /([^<]*?)<([^>]+)>/g; -XML.prototype.patSpecialTag = /^\s*([\!\?])/; -XML.prototype.patPITag = /^\s*\?/; -XML.prototype.patCommentTag = /^\s*\!--/; -XML.prototype.patDTDTag = /^\s*\!DOCTYPE/; -XML.prototype.patCDATATag = /^\s*\!\s*\[\s*CDATA/; -XML.prototype.patStandardTag = /^\s*(\/?)([\w\-\:\.]+)\s*(.*)$/; -XML.prototype.patSelfClosing = /\/\s*$/; -XML.prototype.patAttrib = new RegExp("([\\w\\-\\:\\.]+)\\s*=\\s*([\\\"\\'])([^\\2]*?)\\2", "g"); -XML.prototype.patPINode = /^\s*\?\s*([\w\-\:]+)\s*(.*)$/; -XML.prototype.patEndComment = /--$/; -XML.prototype.patNextClose = /([^>]*?)>/g; -XML.prototype.patExternalDTDNode = new RegExp("^\\s*\\!DOCTYPE\\s+([\\w\\-\\:]+)\\s+(SYSTEM|PUBLIC)\\s+\\\"([^\\\"]+)\\\""); -XML.prototype.patInlineDTDNode = /^\s*\!DOCTYPE\s+([\w\-\:]+)\s+\[/; -XML.prototype.patEndDTD = /\]$/; -XML.prototype.patDTDNode = /^\s*\!DOCTYPE\s+([\w\-\:]+)\s+\[(.*)\]/; -XML.prototype.patEndCDATA = /\]\]$/; -XML.prototype.patCDATANode = /^\s*\!\s*\[\s*CDATA\s*\[([^]*)\]\]/; - -XML.prototype.attribsKey = '_Attribs'; -XML.prototype.dataKey = '_Data'; - -XML.prototype.parse = function(branch, name) { - // parse text into XML tree, recurse for nested nodes - if (!branch) branch = this.tree; - if (!name) name = null; - var foundClosing = false; - var matches = null; - - // match each tag, plus preceding text - while ( matches = this.patTag.exec(this.text) ) { - var before = matches[1]; - var tag = matches[2]; - - // text leading up to tag = content of parent node - if (before.match(/\S/)) { - if (typeof(branch[this.dataKey]) != 'undefined') branch[this.dataKey] += ' '; else branch[this.dataKey] = ''; - branch[this.dataKey] += trim(decode_entities(before)); - } - - // parse based on tag type - if (tag.match(this.patSpecialTag)) { - // special tag - if (tag.match(this.patPITag)) tag = this.parsePINode(tag); - else if (tag.match(this.patCommentTag)) tag = this.parseCommentNode(tag); - else if (tag.match(this.patDTDTag)) tag = this.parseDTDNode(tag); - else if (tag.match(this.patCDATATag)) { - tag = this.parseCDATANode(tag); - if (typeof(branch[this.dataKey]) != 'undefined') branch[this.dataKey] += ' '; else branch[this.dataKey] = ''; - branch[this.dataKey] += trim(decode_entities(tag)); - } // cdata - else { - this.throwParseError( "Malformed special tag", tag ); - break; - } // error - - if (tag == null) break; - continue; - } // special tag - else { - // Tag is standard, so parse name and attributes (if any) - var matches = tag.match(this.patStandardTag); - if (!matches) { - this.throwParseError( "Malformed tag", tag ); - break; - } - - var closing = matches[1]; - var nodeName = this.lowerCase ? matches[2].toLowerCase() : matches[2]; - var attribsRaw = matches[3]; - - // If this is a closing tag, make sure it matches its opening tag - if (closing) { - if (nodeName == (name || '')) { - foundClosing = 1; - break; - } - else { - this.throwParseError( "Mismatched closing tag (expected </" + name + ">)", tag ); - break; - } - } // closing tag - else { - // Not a closing tag, so parse attributes into hash. If tag - // is self-closing, no recursive parsing is needed. - var selfClosing = !!attribsRaw.match(this.patSelfClosing); - var leaf = {}; - var attribs = leaf; - - // preserve attributes means they go into a sub-hash named "_Attribs" - // the XML composer honors this for restoring the tree back into XML - if (this.preserveAttributes) { - leaf[this.attribsKey] = {}; - attribs = leaf[this.attribsKey]; - } - - // parse attributes - this.patAttrib.lastIndex = 0; - while ( matches = this.patAttrib.exec(attribsRaw) ) { - var key = this.lowerCase ? matches[1].toLowerCase() : matches[1]; - attribs[ key ] = decode_entities( matches[3] ); - } // foreach attrib - - // if no attribs found, but we created the _Attribs subhash, clean it up now - if (this.preserveAttributes && !num_keys(attribs)) { - delete leaf[this.attribsKey]; - } - - // Recurse for nested nodes - if (!selfClosing) { - this.parse( leaf, nodeName ); - if (this.error()) break; - } - - // Compress into simple node if text only - var num_leaf_keys = num_keys(leaf); - if ((typeof(leaf[this.dataKey]) != 'undefined') && (num_leaf_keys == 1)) { - leaf = leaf[this.dataKey]; - } - else if (!num_leaf_keys) { - leaf = ''; - } - - // Add leaf to parent branch - if (typeof(branch[nodeName]) != 'undefined') { - if (isa_array(branch[nodeName])) { - branch[nodeName].push( leaf ); - } - else { - var temp = branch[nodeName]; - branch[nodeName] = [ temp, leaf ]; - } - } - else { - branch[nodeName] = leaf; - } - - if (this.error() || (branch == this.tree)) break; - } // not closing - } // standard tag - } // main reg exp - - // Make sure we found the closing tag - if (name && !foundClosing) { - this.throwParseError( "Missing closing tag (expected </" + name + ">)", name ); - } - - // If we are the master node, finish parsing and setup our doc node - if (branch == this.tree) { - if (typeof(this.tree[this.dataKey]) != 'undefined') delete this.tree[this.dataKey]; - - if (num_keys(this.tree) > 1) { - this.throwParseError( 'Only one top-level node is allowed in document', first_key(this.tree) ); - return; - } - - this.documentNodeName = first_key(this.tree); - if (this.documentNodeName) { - this.tree = this.tree[this.documentNodeName]; - } - } -}; - -XML.prototype.throwParseError = function(key, tag) { - // log error and locate current line number in source XML document - var parsedSource = this.text.substring(0, this.patTag.lastIndex); - var eolMatch = parsedSource.match(/\n/g); - var lineNum = (eolMatch ? eolMatch.length : 0) + 1; - lineNum -= tag.match(/\n/) ? tag.match(/\n/g).length : 0; - - this.errors.push({ - type: 'Parse', - key: key, - text: '<' + tag + '>', - line: lineNum - }); - - // Throw actual error (must wrap parse in try/catch) - throw new Error( this.getLastError() ); -}; - -XML.prototype.error = function() { - // return number of errors - return this.errors.length; -}; - -XML.prototype.getError = function(error) { - // get formatted error - var text = ''; - if (!error) return ''; - - text = (error.type || 'General') + ' Error'; - if (error.code) text += ' ' + error.code; - text += ': ' + error.key; - - if (error.line) text += ' on line ' + error.line; - if (error.text) text += ': ' + error.text; - - return text; -}; - -XML.prototype.getLastError = function() { - // Get most recently thrown error in plain text format - if (!this.error()) return ''; - return this.getError( this.errors[this.errors.length - 1] ); -}; - -XML.prototype.parsePINode = function(tag) { - // Parse Processor Instruction Node, e.g. <?xml version="1.0"?> - if (!tag.match(this.patPINode)) { - this.throwParseError( "Malformed processor instruction", tag ); - return null; - } - - this.piNodeList.push( tag ); - return tag; -}; - -XML.prototype.parseCommentNode = function(tag) { - // Parse Comment Node, e.g. <!-- hello --> - var matches = null; - this.patNextClose.lastIndex = this.patTag.lastIndex; - - while (!tag.match(this.patEndComment)) { - if (matches = this.patNextClose.exec(this.text)) { - tag += '>' + matches[1]; - } - else { - this.throwParseError( "Unclosed comment tag", tag ); - return null; - } - } - - this.patTag.lastIndex = this.patNextClose.lastIndex; - return tag; -}; - -XML.prototype.parseDTDNode = function(tag) { - // Parse Document Type Descriptor Node, e.g. <!DOCTYPE ... > - var matches = null; - - if (tag.match(this.patExternalDTDNode)) { - // tag is external, and thus self-closing - this.dtdNodeList.push( tag ); - } - else if (tag.match(this.patInlineDTDNode)) { - // Tag is inline, so check for nested nodes. - this.patNextClose.lastIndex = this.patTag.lastIndex; - - while (!tag.match(this.patEndDTD)) { - if (matches = this.patNextClose.exec(this.text)) { - tag += '>' + matches[1]; - } - else { - this.throwParseError( "Unclosed DTD tag", tag ); - return null; - } - } - - this.patTag.lastIndex = this.patNextClose.lastIndex; - - // Make sure complete tag is well-formed, and push onto DTD stack. - if (tag.match(this.patDTDNode)) { - this.dtdNodeList.push( tag ); - } - else { - this.throwParseError( "Malformed DTD tag", tag ); - return null; - } - } - else { - this.throwParseError( "Malformed DTD tag", tag ); - return null; - } - - return tag; -}; - -XML.prototype.parseCDATANode = function(tag) { - // Parse CDATA Node, e.g. <![CDATA[Brooks & Shields]]> - var matches = null; - this.patNextClose.lastIndex = this.patTag.lastIndex; - - while (!tag.match(this.patEndCDATA)) { - if (matches = this.patNextClose.exec(this.text)) { - tag += '>' + matches[1]; - } - else { - this.throwParseError( "Unclosed CDATA tag", tag ); - return null; - } - } - - this.patTag.lastIndex = this.patNextClose.lastIndex; - - if (matches = tag.match(this.patCDATANode)) { - return matches[1]; - } - else { - this.throwParseError( "Malformed CDATA tag", tag ); - return null; - } -}; - -XML.prototype.getTree = function() { - // get reference to parsed XML tree - return this.tree; -}; - -XML.prototype.compose = function() { - // compose tree back into XML - var raw = compose_xml( this.tree, this.documentNodeName ); - var body = raw.substring( raw.indexOf("\n") + 1, raw.length ); - var xml = ''; - - if (this.piNodeList.length) { - for (var idx = 0, len = this.piNodeList.length; idx < len; idx++) { - xml += '<' + this.piNodeList[idx] + '>' + "\n"; - } - } - else { - xml += xml_header + "\n"; - } - - if (this.dtdNodeList.length) { - for (var idx = 0, len = this.dtdNodeList.length; idx < len; idx++) { - xml += '<' + this.dtdNodeList[idx] + '>' + "\n"; - } - } - - xml += body; - return xml; -}; - -// -// Static Utility Functions: -// - -var parse_xml = exports.parse = function parse_xml(text, opts) { - // turn text into XML tree quickly - if (!opts) opts = {}; - opts.text = text; - var parser = new XML(opts); - return parser.error() ? parser.getLastError() : parser.getTree(); -}; - -var trim = exports.trim = function trim(text) { - // strip whitespace from beginning and end of string - if (text == null) return ''; - - if (text && text.replace) { - text = text.replace(/^\s+/, ""); - text = text.replace(/\s+$/, ""); - } - - return text; -}; - -var encode_entities = exports.encodeEntities = function encode_entities(text) { - // Simple entitize exports.for = function for composing XML - if (text == null) return ''; - - if (text && text.replace) { - text = text.replace(/\&/g, "&"); // MUST BE FIRST - text = text.replace(/</g, "<"); - text = text.replace(/>/g, ">"); - } - - return text; -}; - -var encode_attrib_entities = exports.encodeAttribEntities = function encode_attrib_entities(text) { - // Simple entitize exports.for = function for composing XML attributes - if (text == null) return ''; - - if (text && text.replace) { - text = text.replace(/\&/g, "&"); // MUST BE FIRST - text = text.replace(/</g, "<"); - text = text.replace(/>/g, ">"); - text = text.replace(/\"/g, """); - text = text.replace(/\'/g, "'"); - } - - return text; -}; - -var decode_entities = exports.decodeEntities = function decode_entities(text) { - // Decode XML entities into raw ASCII - if (text == null) return ''; - - if (text && text.replace && text.match(/\&/)) { - text = text.replace(/\<\;/g, "<"); - text = text.replace(/\>\;/g, ">"); - text = text.replace(/\"\;/g, '"'); - text = text.replace(/\&apos\;/g, "'"); - text = text.replace(/\&\;/g, "&"); // MUST BE LAST - } - - return text; -}; - -var compose_xml = exports.stringify = function compose_xml(node, name, indent) { - // Compose node into XML including attributes - // Recurse for child nodes - var xml = ""; - - // If this is the root node, set the indent to 0 - // and setup the XML header (PI node) - if (!indent) { - indent = 0; - xml = xml_header + "\n"; - - if (!name) { - // no name provided, assume content is wrapped in it - name = first_key(node); - node = node[name]; - } - } - - // Setup the indent text - var indent_text = ""; - for (var k = 0; k < indent; k++) indent_text += indent_string; - - if ((typeof(node) == 'object') && (node != null)) { - // node is object -- now see if it is an array or hash - if (!node.length) { // what about zero-length array? - // node is hash - xml += indent_text + "<" + name; - - var num_keys = 0; - var has_attribs = 0; - for (var key in node) num_keys++; // there must be a better way... - - if (node["_Attribs"]) { - has_attribs = 1; - var sorted_keys = hash_keys_to_array(node["_Attribs"]).sort(); - for (var idx = 0, len = sorted_keys.length; idx < len; idx++) { - var key = sorted_keys[idx]; - xml += " " + key + "=\"" + encode_attrib_entities(node["_Attribs"][key]) + "\""; - } - } // has attribs - - if (num_keys > has_attribs) { - // has child elements - xml += ">"; - - if (node["_Data"]) { - // simple text child node - xml += encode_entities(node["_Data"]) + "</" + name + ">\n"; - } // just text - else { - xml += "\n"; - - var sorted_keys = hash_keys_to_array(node).sort(); - for (var idx = 0, len = sorted_keys.length; idx < len; idx++) { - var key = sorted_keys[idx]; - if ((key != "_Attribs") && key.match(re_valid_tag_name)) { - // recurse for node, with incremented indent value - xml += compose_xml( node[key], key, indent + 1 ); - } // not _Attribs key - } // foreach key - - xml += indent_text + "</" + name + ">\n"; - } // real children - } - else { - // no child elements, so self-close - xml += "/>\n"; - } - } // standard node - else { - // node is array - for (var idx = 0; idx < node.length; idx++) { - // recurse for node in array with same indent - xml += compose_xml( node[idx], name, indent ); - } - } // array of nodes - } // complex node - else { - // node is simple string - xml += indent_text + "<" + name + ">" + encode_entities(node) + "</" + name + ">\n"; - } // simple text node - - return xml; -}; - -var always_array = exports.alwaysArray = function always_array(obj, key) { - // if object is not array, return array containing object - // if key is passed, work like XMLalwaysarray() instead - if (key) { - if ((typeof(obj[key]) != 'object') || (typeof(obj[key].length) == 'undefined')) { - var temp = obj[key]; - delete obj[key]; - obj[key] = new Array(); - obj[key][0] = temp; - } - return null; - } - else { - if ((typeof(obj) != 'object') || (typeof(obj.length) == 'undefined')) { return [ obj ]; } - else return obj; - } -}; - -var hash_keys_to_array = exports.hashKeysToArray = function hash_keys_to_array(hash) { - // convert hash keys to array (discard values) - var array = []; - for (var key in hash) array.push(key); - return array; -}; - -var isa_hash = exports.isaHash = function isa_hash(arg) { - // determine if arg is a hash - return( !!arg && (typeof(arg) == 'object') && (typeof(arg.length) == 'undefined') ); -}; - -var isa_array = exports.isaArray = function isa_array(arg) { - // determine if arg is an array or is array-like - if (typeof(arg) == 'array') return true; - return( !!arg && (typeof(arg) == 'object') && (typeof(arg.length) != 'undefined') ); -}; - -var first_key = exports.firstKey = function first_key(hash) { - // return first key from hash (unordered) - for (var key in hash) return key; - return null; // no keys in hash -}; - -var num_keys = exports.numKeys = function num_keys(hash) { - // count the number of keys in a hash - var count = 0; - for (var a in hash) count++; - return count; -}; diff --git a/collectors/node.d.plugin/snmp/Makefile.inc b/collectors/node.d.plugin/snmp/Makefile.inc deleted file mode 100644 index 26448a1ce..000000000 --- a/collectors/node.d.plugin/snmp/Makefile.inc +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-3.0-or-later - -# THIS IS NOT A COMPLETE Makefile -# IT IS INCLUDED BY ITS PARENT'S Makefile.am -# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT - -# install these files -dist_node_DATA += snmp/snmp.node.js -# dist_nodeconfig_DATA += snmp/snmp.conf - -# do not install these files, but include them in the distribution -dist_noinst_DATA += snmp/README.md snmp/Makefile.inc - diff --git a/collectors/node.d.plugin/snmp/README.md b/collectors/node.d.plugin/snmp/README.md deleted file mode 100644 index 2df94c7b5..000000000 --- a/collectors/node.d.plugin/snmp/README.md +++ /dev/null @@ -1,445 +0,0 @@ -<!-- -title: "SNMP device monitoring with Netdata" -custom_edit_url: https://github.com/netdata/netdata/edit/master/collectors/node.d.plugin/snmp/README.md -sidebar_label: "SNMP" ---> - -# SNMP device monitoring with Netdata - -Collects data from any SNMP device and uses the [net-snmp](https://github.com/markabrahams/node-net-snmp) module. - -It supports: - -- all SNMP versions: SNMPv1, SNMPv2c and SNMPv3 -- any number of SNMP devices -- each SNMP device can be used to collect data for any number of charts -- each chart may have any number of dimensions -- each SNMP device may have a different update frequency -- each SNMP device will accept one or more batches to report values (you can set `max_request_size` per SNMP server, to control the size of batches). - -## Requirements - -- `nodejs` minimum required version 4 - -## Configuration - -You will need to create the file `/etc/netdata/node.d/snmp.conf` with data like the following. - -In this example: - -- the SNMP device is `10.11.12.8`. -- the SNMP community is `public`. -- we will update the values every 10 seconds (`update_every: 10` under the server `10.11.12.8`). -- we define 2 charts `snmp_switch.bandwidth_port1` and `snmp_switch.bandwidth_port2`, each having 2 dimensions: `in` and `out`. Note that the charts and dimensions must not contain any white space or special characters, other than `.` and `_`. - -```json -{ - "enable_autodetect": false, - "update_every": 5, - "max_request_size": 100, - "servers": [ - { - "hostname": "10.11.12.8", - "community": "public", - "update_every": 10, - "max_request_size": 50, - "options": { - "timeout": 10000 - }, - "charts": { - "snmp_switch.bandwidth_port1": { - "title": "Switch Bandwidth for port 1", - "units": "kilobits/s", - "type": "area", - "priority": 1, - "family": "ports", - "dimensions": { - "in": { - "oid": "1.3.6.1.2.1.2.2.1.10.1", - "algorithm": "incremental", - "multiplier": 8, - "divisor": 1024, - "offset": 0 - }, - "out": { - "oid": "1.3.6.1.2.1.2.2.1.16.1", - "algorithm": "incremental", - "multiplier": -8, - "divisor": 1024, - "offset": 0 - } - } - }, - "snmp_switch.bandwidth_port2": { - "title": "Switch Bandwidth for port 2", - "units": "kilobits/s", - "type": "area", - "priority": 1, - "family": "ports", - "dimensions": { - "in": { - "oid": "1.3.6.1.2.1.2.2.1.10.2", - "algorithm": "incremental", - "multiplier": 8, - "divisor": 1024, - "offset": 0 - }, - "out": { - "oid": "1.3.6.1.2.1.2.2.1.16.2", - "algorithm": "incremental", - "multiplier": -8, - "divisor": 1024, - "offset": 0 - } - } - } - } - } - ] -} -``` - -`update_every` is the update frequency for each server, in seconds. - -`max_request_size` limits the maximum number of OIDs that will be requested in a single call. The default is 50. Lower this number of you get `TooBig` errors in Netdata's `error.log`. - -`family` sets the name of the submenu of the dashboard each chart will appear under. - -`multiplier` and `divisor` are passed by the plugin to the Netdata daemon and are applied to the metric to convert it properly to `units`. For incremental counters with the exception of Counter64 type metrics, `offset` is added to the metric from within the SNMP plugin. This means that the value you will see in debug mode in the `DEBUG: setting current chart to... SET` line for a metric will not have been multiplied or divided, but it will have had the offset added to it. - -<details markdown="1"><summary><b>Caution: Counter64 metrics do not support `offset` (issue #5028).</b></summary> -The SNMP plugin supports Counter64 metrics with the only limitation that the `offset` parameter should not be defined. Due to the way Javascript handles large numbers and the fact that the offset is applied to metrics inside the plugin, the offset will be ignored silently. -</details> - -If you need to define many charts using incremental OIDs, you can use something like this: - -```json -{ - "enable_autodetect": false, - "update_every": 10, - "servers": [ - { - "hostname": "10.11.12.8", - "community": "public", - "update_every": 10, - "options": { - "timeout": 20000 - }, - "charts": { - "snmp_switch.bandwidth_port": { - "title": "Switch Bandwidth for port ", - "units": "kilobits/s", - "type": "area", - "priority": 1, - "family": "ports", - "multiply_range": [ - 1, - 24 - ], - "dimensions": { - "in": { - "oid": "1.3.6.1.2.1.2.2.1.10.", - "algorithm": "incremental", - "multiplier": 8, - "divisor": 1024, - "offset": 0 - }, - "out": { - "oid": "1.3.6.1.2.1.2.2.1.16.", - "algorithm": "incremental", - "multiplier": -8, - "divisor": 1024, - "offset": 0 - } - } - } - } - } - ] -} -``` - -This is like the previous, but the option `multiply_range` given, will multiply the current chart from `1` to `24` inclusive, producing 24 charts in total for the 24 ports of the switch `10.11.12.8`. - -Each of the 24 new charts will have its id (1-24) appended at: - -1. its chart unique id, i.e. `snmp_switch.bandwidth_port1` to `snmp_switch.bandwidth_port24` -2. its `title`, i.e. `Switch Bandwidth for port 1` to `Switch Bandwidth for port 24` -3. its `oid` (for all dimensions), i.e. dimension `in` will be `1.3.6.1.2.1.2.2.1.10.1` to `1.3.6.1.2.1.2.2.1.10.24` -4. its priority (which will be incremented for each chart so that the charts will appear on the dashboard in this order) - -The `options` given for each server, are: - -- `port` - UDP port to send requests too. Defaults to `161`. -- `retries` - number of times to re-send a request. Defaults to `1`. -- `sourceAddress` - IP address from which SNMP requests should originate, there is no default for this option, the operating system will select an appropriate source address when the SNMP request is sent. -- `sourcePort` - UDP port from which SNMP requests should originate, defaults to an ephemeral port selected by the operation system. -- `timeout` - number of milliseconds to wait for a response before re-trying or failing. Defaults to `5000`. -- `transport` - specify the transport to use, can be either `udp4` or `udp6`. Defaults to `udp4`. -- `version` - either `0` (v1) or `1` (v2) or `3` (v3). Defaults to `0`. -- `idBitsSize` - either `16` or `32`. Defaults to `32`. Used to reduce the size of the generated id for compatibility with some older devices. - -## SNMPv3 - -To use SNMPv3: - -- use `user` instead of `community` -- set `version` to 3 - -User syntax: - -```json -{ - "enable_autodetect": false, - "update_every": 10, - "servers": [ - { - "hostname": "10.11.12.8", - "user": { - "name": "userName", - "level": 3, - "authProtocol": "3", - "authKey": "authKey", - "privProtocol": "2", - "privKey": "privKey" - }, - "update_every": 10, - "options": { - "version": 3 - }, - "charts": { - } - } - ] -} -``` - -Security levels (`level`): - -- 1 is `noAuthNoPriv` -- 2 is `authNoPriv` -- 3 is `authPriv` - -Authentication protocols (`authProtocol`): - -- "1" is `none` -- "2" is `md5` -- "3" is `sha` - -Privacy protocols (`privProtocol`): - -- "1" is `none` -- "2" is `des` - -For additional details please see [net-snmp module readme](https://github.com/markabrahams/node-net-snmp#snmpcreatev3session-target-user-options). - -## Retrieving names from snmp - -You can append a value retrieved from SNMP to the title, by adding `titleoid` to the chart. - -You can set a dimension name to a value retrieved from SNMP, by adding `oidname` to the dimension. - -Both of the above will participate in `multiply_range`. - -## Testing the configuration - -To test it, you can run: - -```sh -/usr/libexec/netdata/plugins.d/node.d.plugin 1 snmp -``` - -The above will run it on your console and you will be able to see what Netdata sees, but also errors. You can get a very detailed output by appending `debug` to the command line. - -If it works, restart Netdata to activate the snmp collector and refresh the dashboard (if your SNMP device responds with a delay, you may need to refresh the dashboard in a few seconds). - -## Data collection speed - -Keep in mind that many SNMP switches and routers are very slow. They may not be able to report values per second. If you run `node.d.plugin` in `debug` mode, it will report the time it took for the SNMP device to respond. My switch, for example, needs 7-8 seconds to respond for the traffic on 24 ports (48 OIDs, in/out). - -Also, if you use many SNMP clients on the same SNMP device at the same time, values may be skipped. This is a problem of the SNMP device, not this collector. - -## Finding OIDs - -Use `snmpwalk`, like this: - -```sh -snmpwalk -t 20 -v 1 -O fn -c public 10.11.12.8 -``` - -- `-t 20` is the timeout in seconds -- `-v 1` is the SNMP version -- `-O fn` will display full OIDs in numeric format (you may want to run it also without this option to see human readable output of OIDs) -- `-c public` is the SNMP community -- `10.11.12.8` is the SNMP device - -Keep in mind that `snmpwalk` outputs the OIDs with a dot in front them. You should remove this dot when adding OIDs to the configuration file of this collector. - -## Example: Linksys SRW2024P - -This is what I use for my Linksys SRW2024P. It creates: - -1. A chart for power consumption (it is a PoE switch) -2. Two charts for packets received (total packets received and packets received with errors) -3. One chart for packets output -4. 24 charts, one for each port of the switch. It also appends the port names, as defined at the switch, to the chart titles. - -This switch also reports various other metrics, like snmp, packets per port, etc. Unfortunately it does not report CPU utilization or backplane utilization. - -This switch has a very slow SNMP processors. To respond, it needs about 8 seconds, so I have set the refresh frequency (`update_every`) to 15 seconds. - -```json -{ - "enable_autodetect": false, - "update_every": 5, - "servers": [ - { - "hostname": "10.11.12.8", - "community": "public", - "update_every": 15, - "options": { - "timeout": 20000, - "version": 1 - }, - "charts": { - "snmp_switch.power": { - "title": "Switch Power Supply", - "units": "watts", - "type": "line", - "priority": 10, - "family": "power", - "dimensions": { - "supply": { - "oid": ".1.3.6.1.2.1.105.1.3.1.1.2.1", - "algorithm": "absolute", - "multiplier": 1, - "divisor": 1, - "offset": 0 - }, - "used": { - "oid": ".1.3.6.1.2.1.105.1.3.1.1.4.1", - "algorithm": "absolute", - "multiplier": 1, - "divisor": 1, - "offset": 0 - } - } - }, - "snmp_switch.input": { - "title": "Switch Packets Input", - "units": "packets/s", - "type": "area", - "priority": 20, - "family": "IP", - "dimensions": { - "receives": { - "oid": ".1.3.6.1.2.1.4.3.0", - "algorithm": "incremental", - "multiplier": 1, - "divisor": 1, - "offset": 0 - }, - "discards": { - "oid": ".1.3.6.1.2.1.4.8.0", - "algorithm": "incremental", - "multiplier": 1, - "divisor": 1, - "offset": 0 - } - } - }, - "snmp_switch.input_errors": { - "title": "Switch Received Packets with Errors", - "units": "packets/s", - "type": "line", - "priority": 30, - "family": "IP", - "dimensions": { - "bad_header": { - "oid": ".1.3.6.1.2.1.4.4.0", - "algorithm": "incremental", - "multiplier": 1, - "divisor": 1, - "offset": 0 - }, - "bad_address": { - "oid": ".1.3.6.1.2.1.4.5.0", - "algorithm": "incremental", - "multiplier": 1, - "divisor": 1, - "offset": 0 - }, - "unknown_protocol": { - "oid": ".1.3.6.1.2.1.4.7.0", - "algorithm": "incremental", - "multiplier": 1, - "divisor": 1, - "offset": 0 - } - } - }, - "snmp_switch.output": { - "title": "Switch Output Packets", - "units": "packets/s", - "type": "line", - "priority": 40, - "family": "IP", - "dimensions": { - "requests": { - "oid": ".1.3.6.1.2.1.4.10.0", - "algorithm": "incremental", - "multiplier": 1, - "divisor": 1, - "offset": 0 - }, - "discards": { - "oid": ".1.3.6.1.2.1.4.11.0", - "algorithm": "incremental", - "multiplier": -1, - "divisor": 1, - "offset": 0 - }, - "no_route": { - "oid": ".1.3.6.1.2.1.4.12.0", - "algorithm": "incremental", - "multiplier": -1, - "divisor": 1, - "offset": 0 - } - } - }, - "snmp_switch.bandwidth_port": { - "title": "Switch Bandwidth for port ", - "titleoid": ".1.3.6.1.2.1.31.1.1.1.18.", - "units": "kilobits/s", - "type": "area", - "priority": 100, - "family": "ports", - "multiply_range": [ - 1, - 24 - ], - "dimensions": { - "in": { - "oid": ".1.3.6.1.2.1.2.2.1.10.", - "algorithm": "incremental", - "multiplier": 8, - "divisor": 1024, - "offset": 0 - }, - "out": { - "oid": ".1.3.6.1.2.1.2.2.1.16.", - "algorithm": "incremental", - "multiplier": -8, - "divisor": 1024, - "offset": 0 - } - } - } - } - } - ] -} -``` - - diff --git a/collectors/node.d.plugin/snmp/snmp.node.js b/collectors/node.d.plugin/snmp/snmp.node.js deleted file mode 100644 index 9e874586e..000000000 --- a/collectors/node.d.plugin/snmp/snmp.node.js +++ /dev/null @@ -1,527 +0,0 @@ -'use strict'; -// SPDX-License-Identifier: GPL-3.0-or-later -// netdata snmp module -// This program will connect to one or more SNMP Agents -// - -// example configuration in /etc/netdata/node.d/snmp.conf -/* -{ - "enable_autodetect": false, - "update_every": 5, - "max_request_size": 50, - "servers": [ - { - "hostname": "10.11.12.8", - "community": "public", - "update_every": 10, - "max_request_size": 50, - "options": { "timeout": 10000 }, - "charts": { - "snmp_switch.bandwidth_port1": { - "title": "Switch Bandwidth for port 1", - "units": "kilobits/s", - "type": "area", - "priority": 1, - "dimensions": { - "in": { - "oid": ".1.3.6.1.2.1.2.2.1.10.1", - "algorithm": "incremental", - "multiplier": 8, - "divisor": 1024, - "offset": 0 - }, - "out": { - "oid": ".1.3.6.1.2.1.2.2.1.16.1", - "algorithm": "incremental", - "multiplier": -8, - "divisor": 1024, - "offset": 0 - } - } - }, - "snmp_switch.bandwidth_port2": { - "title": "Switch Bandwidth for port 2", - "units": "kilobits/s", - "type": "area", - "priority": 1, - "dimensions": { - "in": { - "oid": ".1.3.6.1.2.1.2.2.1.10.2", - "algorithm": "incremental", - "multiplier": 8, - "divisor": 1024, - "offset": 0 - }, - "out": { - "oid": ".1.3.6.1.2.1.2.2.1.16.2", - "algorithm": "incremental", - "multiplier": -8, - "divisor": 1024, - "offset": 0 - } - } - } - } - } - ] -} -*/ - -// You can also give ranges of charts like the following. -// This will append 1-24 to id, title, oid (on each dimension) -// so that 24 charts will be created. -/* -{ - "enable_autodetect": false, - "update_every": 10, - "max_request_size": 50, - "servers": [ - { - "hostname": "10.11.12.8", - "community": "public", - "update_every": 10, - "max_request_size": 50, - "options": { "timeout": 20000 }, - "charts": { - "snmp_switch.bandwidth_port": { - "title": "Switch Bandwidth for port ", - "units": "kilobits/s", - "type": "area", - "priority": 1, - "multiply_range": [ 1, 24 ], - "dimensions": { - "in": { - "oid": ".1.3.6.1.2.1.2.2.1.10.", - "algorithm": "incremental", - "multiplier": 8, - "divisor": 1024, - "offset": 0 - }, - "out": { - "oid": ".1.3.6.1.2.1.2.2.1.16.", - "algorithm": "incremental", - "multiplier": -8, - "divisor": 1024, - "offset": 0 - } - } - } - } - } - ] -} -*/ - -var net_snmp = require('net-snmp'); -var extend = require('extend'); -var netdata = require('netdata'); - -if (netdata.options.DEBUG === true) netdata.debug('loaded', __filename, ' plugin'); - -netdata.processors.snmp = { - name: 'snmp', - - fixoid: function (oid) { - if (typeof oid !== 'string') - return oid; - - if (oid.charAt(0) === '.') - return oid.substring(1, oid.length); - - return oid; - }, - - prepare: function (service) { - var __DEBUG = netdata.options.DEBUG; - - if (typeof service.snmp_oids === 'undefined' || service.snmp_oids === null || service.snmp_oids.length === 0) { - // this is the first time we see this service - - if (__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': preparing ' + this.name + ' OIDs'); - - // build an index of all OIDs - service.snmp_oids_index = {}; - var chart_keys = Object.keys(service.request.charts); - var chart_keys_len = chart_keys.length; - while (chart_keys_len--) { - var c = chart_keys[chart_keys_len]; - var chart = service.request.charts[c]; - - // for each chart - - if (__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c); - - if (typeof chart.titleoid !== 'undefined') { - service.snmp_oids_index[this.fixoid(chart.titleoid)] = { - type: 'title', - link: chart - }; - } - - var dim_keys = Object.keys(chart.dimensions); - var dim_keys_len = dim_keys.length; - while (dim_keys_len--) { - var d = dim_keys[dim_keys_len]; - var dim = chart.dimensions[d]; - - // for each dimension in the chart - - var oid = this.fixoid(dim.oid); - var oidname = this.fixoid(dim.oidname); - - if (__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c + ', dimension: ' + d + ', OID: ' + oid + ", OID name: " + oidname); - - // link it to the point we need to set the value to - service.snmp_oids_index[oid] = { - type: 'value', - link: dim - }; - - if (typeof oidname !== 'undefined') - service.snmp_oids_index[oidname] = { - type: 'name', - link: dim - }; - - // and set the value to null - dim.value = null; - } - } - - if (__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': indexed ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids_index)); - - // now create the array of OIDs needed by net-snmp - service.snmp_oids = Object.keys(service.snmp_oids_index); - - if (__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': final list of ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids)); - - service.snmp_oids_cleaned = 0; - } else if (service.snmp_oids_cleaned === 0) { - service.snmp_oids_cleaned = 1; - - // the second time, keep only values - - service.snmp_oids = new Array(); - var oid_keys = Object.keys(service.snmp_oids_index); - var oid_keys_len = oid_keys.length; - while (oid_keys_len--) { - if (service.snmp_oids_index[oid_keys[oid_keys_len]].type === 'value') - service.snmp_oids.push(oid_keys[oid_keys_len]); - } - } - }, - - getdata: function (service, index, ok, failed, callback) { - var __DEBUG = netdata.options.DEBUG; - var that = this; - - if (index >= service.snmp_oids.length) { - callback((ok > 0) ? {ok: ok, failed: failed} : null); - return; - } - - var slice; - if (service.snmp_oids.length <= service.request.max_request_size) { - slice = service.snmp_oids; - index = service.snmp_oids.length; - } else if (service.snmp_oids.length - index <= service.request.max_request_size) { - slice = service.snmp_oids.slice(index, service.snmp_oids.length); - index = service.snmp_oids.length; - } else { - slice = service.snmp_oids.slice(index, index + service.request.max_request_size); - index += service.request.max_request_size; - } - - if (__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': making ' + slice.length + ' entries request, max is: ' + service.request.max_request_size); - - service.snmp_session.get(slice, function (error, varbinds) { - if (error) { - service.error('Received error = ' + netdata.stringify(error) + ' varbinds = ' + netdata.stringify(varbinds)); - - // make all values null - var len = slice.length; - while (len--) - service.snmp_oids_index[slice[len]].value = null; - } else { - if (__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': got valid ' + service.module.name + ' response: ' + netdata.stringify(varbinds)); - - var varbinds_len = varbinds.length; - for (var i = 0; i < varbinds_len; i++) { - var value = null; - - if (net_snmp.isVarbindError(varbinds[i])) { - if (__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': failed ' + service.module.name + ' get for OIDs ' + varbinds[i].oid); - - service.error('OID ' + varbinds[i].oid + ' gave error: ' + net_snmp.varbindError(varbinds[i])); - value = null; - failed++; - } else { - // test fom Counter64 - // varbinds[i].type = net_snmp.ObjectType.Counter64; - // varbinds[i].value = new Buffer([0x34, 0x49, 0x2e, 0xdc, 0xd1]); - - switch (varbinds[i].type) { - case net_snmp.ObjectType.OctetString: - if (service.snmp_oids_index[varbinds[i].oid].type !== 'title' && service.snmp_oids_index[varbinds[i].oid].type !== 'name') { - // parse floating point values, exposed as strings - value = parseFloat(varbinds[i].value) * 1000; - if (__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + ", ObjectType " + net_snmp.ObjectType[varbinds[i].type] + " (" + netdata.stringify(varbinds[i].type) + "), typeof(" + typeof (varbinds[i].value) + "), in JSON: " + netdata.stringify(varbinds[i].value) + ", value = " + value.toString() + " (parsed as float in string)"); - } else { - // just use the string - value = varbinds[i].value; - if (__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + ", ObjectType " + net_snmp.ObjectType[varbinds[i].type] + " (" + netdata.stringify(varbinds[i].type) + "), typeof(" + typeof (varbinds[i].value) + "), in JSON: " + netdata.stringify(varbinds[i].value) + ", value = " + value.toString() + " (parsed as string)"); - } - break; - - case net_snmp.ObjectType.Counter64: - // copy the buffer - value = '0x' + varbinds[i].value.toString('hex'); - if (__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + ", ObjectType " + net_snmp.ObjectType[varbinds[i].type] + " (" + netdata.stringify(varbinds[i].type) + "), typeof(" + typeof (varbinds[i].value) + "), in JSON: " + netdata.stringify(varbinds[i].value) + ", value = " + value.toString() + " (parsed as buffer)"); - break; - - case net_snmp.ObjectType.Integer: - case net_snmp.ObjectType.Counter: - case net_snmp.ObjectType.Gauge: - default: - value = varbinds[i].value; - if (__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + ", ObjectType " + net_snmp.ObjectType[varbinds[i].type] + " (" + netdata.stringify(varbinds[i].type) + "), typeof(" + typeof (varbinds[i].value) + "), in JSON: " + netdata.stringify(varbinds[i].value) + ", value = " + value.toString() + " (parsed as number)"); - break; - } - - ok++; - } - - if (value !== null) { - switch (service.snmp_oids_index[varbinds[i].oid].type) { - case 'title': - service.snmp_oids_index[varbinds[i].oid].link.title += ' ' + value; - break; - case 'name' : - service.snmp_oids_index[varbinds[i].oid].link.name = value.toString().replace(/\W/g, '_'); - break; - case 'value': - service.snmp_oids_index[varbinds[i].oid].link.value = value; - break; - } - } - } - - if (__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': finished ' + service.module.name + ' with ' + ok + ' successful and ' + failed + ' failed values'); - } - that.getdata(service, index, ok, failed, callback); - }); - }, - - process: function (service, callback) { - var __DEBUG = netdata.options.DEBUG; - - this.prepare(service); - - if (service.snmp_oids.length === 0) { - // no OIDs found for this service - - if (__DEBUG === true) - service.error('no OIDs to process.'); - - callback(null); - return; - } - - if (typeof service.snmp_session === 'undefined' || service.snmp_session === null) { - // no SNMP session has been created for this service - // the SNMP session is just the initialization of NET-SNMP - - var snmp_version = (service.request.options && service.request.options.version) - ? service.request.options.version - : net_snmp.Version1; - - if (snmp_version === net_snmp.Version3) { - if (__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': opening ' + this.name + ' session on ' + service.request.hostname + ' user ' + service.request.user + ' options ' + netdata.stringify(service.request.options)); - - // create the SNMP session - service.snmp_session = net_snmp.createV3Session(service.request.hostname, service.request.user, service.request.options); - } else { - if (__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': opening ' + this.name + ' session on ' + service.request.hostname + ' community ' + service.request.community + ' options ' + netdata.stringify(service.request.options)); - - // create the SNMP session - service.snmp_session = net_snmp.createSession(service.request.hostname, service.request.community, service.request.options); - } - - if (__DEBUG === true) - netdata.debug(service.module.name + ': ' + service.name + ': got ' + this.name + ' session: ' + netdata.stringify(service.snmp_session)); - - // if we later need traps, this is how to do it: - //service.snmp_session.trap(net_snmp.TrapType.LinkDown, function(error) { - // if(error) console.error('trap error: ' + netdata.stringify(error)); - //}); - } - - // do it, get the SNMP values for the sessions we need - this.getdata(service, 0, 0, 0, callback); - } -}; - -var snmp = { - name: __filename, - enable_autodetect: true, - update_every: 1, - base_priority: 50000, - - charts: {}, - - processResponse: function (service, data) { - if (data !== null) { - if (service.added !== true) - service.commit(); - - var chart_keys = Object.keys(service.request.charts); - var chart_keys_len = chart_keys.length; - for (var i = 0; i < chart_keys_len; i++) { - var c = chart_keys[i]; - - var chart = snmp.charts[c]; - if (typeof chart === 'undefined') { - chart = service.chart(c, service.request.charts[c]); - snmp.charts[c] = chart; - } - - service.begin(chart); - - var dimensions = service.request.charts[c].dimensions; - var dim_keys = Object.keys(dimensions); - var dim_keys_len = dim_keys.length; - for (var j = 0; j < dim_keys_len; j++) { - var d = dim_keys[j]; - - if (dimensions[d].value !== null) { - if (typeof dimensions[d].offset === 'number' && typeof dimensions[d].value === 'number') - service.set(d, dimensions[d].value + dimensions[d].offset); - else - service.set(d, dimensions[d].value); - } - } - - service.end(); - } - } - }, - - // module.serviceExecute() - // this function is called only from this module - // its purpose is to prepare the request and call - // netdata.serviceExecute() - serviceExecute: function (conf) { - var __DEBUG = netdata.options.DEBUG; - - if (__DEBUG === true) - netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', update_every: ' + conf.update_every); - - var service = netdata.service({ - name: conf.hostname, - request: conf, - update_every: conf.update_every, - module: this, - processor: netdata.processors.snmp - }); - - // multiply the charts, if required - var chart_keys = Object.keys(service.request.charts); - var chart_keys_len = chart_keys.length; - for (var i = 0; i < chart_keys_len; i++) { - var c = chart_keys[i]; - var service_request_chart = service.request.charts[c]; - - if (__DEBUG === true) - netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', examining chart: ' + c); - - if (typeof service_request_chart.update_every === 'undefined') - service_request_chart.update_every = service.update_every; - - if (typeof service_request_chart.multiply_range !== 'undefined') { - var from = service_request_chart.multiply_range[0]; - var to = service_request_chart.multiply_range[1]; - var prio = service_request_chart.priority || 1; - - if (prio < snmp.base_priority) prio += snmp.base_priority; - - while (from <= to) { - var id = c + from.toString(); - var chart = extend(true, {}, service_request_chart); - chart.title += from.toString(); - - if (typeof chart.titleoid !== 'undefined') - chart.titleoid += from.toString(); - - chart.priority = prio++; - - var dim_keys = Object.keys(chart.dimensions); - var dim_keys_len = dim_keys.length; - for (var j = 0; j < dim_keys_len; j++) { - var d = dim_keys[j]; - - chart.dimensions[d].oid += from.toString(); - - if (typeof chart.dimensions[d].oidname !== 'undefined') - chart.dimensions[d].oidname += from.toString(); - } - service.request.charts[id] = chart; - from++; - } - - delete service.request.charts[c]; - } else { - if (service.request.charts[c].priority < snmp.base_priority) - service.request.charts[c].priority += snmp.base_priority; - } - } - - service.execute(this.processResponse); - }, - - configure: function (config) { - var added = 0; - - if (typeof config.max_request_size === 'undefined') - config.max_request_size = 50; - - if (typeof (config.servers) !== 'undefined') { - var len = config.servers.length; - while (len--) { - if (typeof config.servers[len].update_every === 'undefined') - config.servers[len].update_every = this.update_every; - - if (typeof config.servers[len].max_request_size === 'undefined') - config.servers[len].max_request_size = config.max_request_size; - - this.serviceExecute(config.servers[len]); - added++; - } - } - - return added; - }, - - // module.update() - // this is called repeatedly to collect data, by calling - // service.execute() - update: function (service, callback) { - service.execute(function (serv, data) { - service.module.processResponse(serv, data); - callback(); - }); - } -}; - -module.exports = snmp; |