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/node_modules | |
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/node_modules')
-rw-r--r-- | collectors/node.d.plugin/node_modules/asn1-ber.js | 7 | ||||
-rw-r--r-- | collectors/node.d.plugin/node_modules/extend.js | 88 | ||||
-rw-r--r-- | collectors/node.d.plugin/node_modules/lib/ber/errors.js | 10 | ||||
-rw-r--r-- | collectors/node.d.plugin/node_modules/lib/ber/index.js | 18 | ||||
-rw-r--r-- | collectors/node.d.plugin/node_modules/lib/ber/reader.js | 270 | ||||
-rw-r--r-- | collectors/node.d.plugin/node_modules/lib/ber/types.js | 35 | ||||
-rw-r--r-- | collectors/node.d.plugin/node_modules/lib/ber/writer.js | 318 | ||||
-rw-r--r-- | collectors/node.d.plugin/node_modules/net-snmp.js | 3452 | ||||
-rw-r--r-- | collectors/node.d.plugin/node_modules/netdata.js | 654 | ||||
-rw-r--r-- | collectors/node.d.plugin/node_modules/pixl-xml.js | 607 |
10 files changed, 0 insertions, 5459 deletions
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; -}; |