diff options
author | Costa Tsaousis (ktsaou) <costa@tsaousis.gr> | 2016-02-05 02:02:12 +0200 |
---|---|---|
committer | Costa Tsaousis (ktsaou) <costa@tsaousis.gr> | 2016-02-05 02:02:12 +0200 |
commit | cac53fd155c250599871b12ebc1e7f83e1616777 (patch) | |
tree | e6c9a2ffe4ac588fb2b7da72f387d8437288e4e8 /node.d | |
parent | ccb789708de8b8126ddd17cfaf8e2c3623e4c073 (diff) |
added SNMP node.js data collector; node.d.plugin now supports multiple processors (http, snmp at the ones currently implemented)
Diffstat (limited to 'node.d')
-rw-r--r-- | node.d/Makefile.am | 12 | ||||
-rwxr-xr-x | node.d/named.node.js | 12 | ||||
-rw-r--r-- | node.d/node_modules/asn1.js | 20 | ||||
-rw-r--r-- | node.d/node_modules/ber/errors.js | 13 | ||||
-rw-r--r-- | node.d/node_modules/ber/index.js | 27 | ||||
-rw-r--r-- | node.d/node_modules/ber/reader.js | 261 | ||||
-rw-r--r-- | node.d/node_modules/ber/types.js | 36 | ||||
-rw-r--r-- | node.d/node_modules/ber/writer.js | 316 | ||||
-rw-r--r-- | node.d/node_modules/net-snmp.js | 1466 | ||||
-rwxr-xr-x | node.d/node_modules/netdata.js | 187 | ||||
-rwxr-xr-x | node.d/sma_webbox.node.js | 14 | ||||
-rwxr-xr-x | node.d/snmp.node.js | 327 |
12 files changed, 2594 insertions, 97 deletions
diff --git a/node.d/Makefile.am b/node.d/Makefile.am index 5e8ec6ad7f..ae7eeac522 100644 --- a/node.d/Makefile.am +++ b/node.d/Makefile.am @@ -4,6 +4,7 @@ dist_node_SCRIPTS = \ README.md \ named.node.js \ sma_webbox.node.js \ + snmp.node.js \ $(NULL) nodemodulesdir=$(nodedir)/node_modules @@ -11,4 +12,15 @@ dist_nodemodules_DATA = \ node_modules/netdata.js \ node_modules/extend.js \ node_modules/pixl-xml.js \ + node_modules/net-snmp.js \ + node_modules/asn1.js \ + $(NULL) + +nodemodulesberdir=$(nodedir)/node_modules/ber +dist_nodemodulesber_DATA = \ + node_modules/ber/index.js \ + node_modules/ber/errors.js \ + node_modules/ber/reader.js \ + node_modules/ber/types.js \ + node_modules/ber/writer.js \ $(NULL) diff --git a/node.d/named.node.js b/node.d/named.node.js index 67426beadf..4348fbaa6f 100755 --- a/node.d/named.node.js +++ b/node.d/named.node.js @@ -46,7 +46,7 @@ if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plug var named = { name: __filename, enable_autodetect: true, - update_every: 1000, + update_every: 1, charts: {}, @@ -60,7 +60,7 @@ var named = { category: category_prefix + '_' + service.name, // the category of the chart type: type, // the type of the chart priority: priority, // the priority relative to others in the same family and category - update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart + update_every: service.update_every, // the expected update frequency of the chart dimensions: {} } @@ -338,7 +338,7 @@ var named = { category: 'named', // the category of the chart type: netdata.chartTypes.line, // the type of the chart priority: 150, // the priority relative to others in the same family and category - update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart + update_every: service.update_every, // the expected update frequency of the chart dimensions: { 'clients': { id: 'clients', // the unique id of the dimension @@ -442,7 +442,7 @@ var named = { category: 'named', // the category of the chart type: netdata.chartTypes.line, // the type of the chart priority: 5000, // the priority relative to others in the same family and category - update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart + update_every: service.update_every, // the expected update frequency of the chart dimensions: { 'queries': { id: 'queries', // the unique id of the dimension @@ -486,7 +486,7 @@ var named = { category: 'named', // the category of the chart type: netdata.chartTypes.area, // the type of the chart priority: 8000, // the priority relative to others in the same family and category - update_every: Math.round(service.update_every / 1000), // the expected update frequency of the chart + update_every: service.update_every, // the expected update frequency of the chart dimensions: { 'CacheHits': { id: 'CacheHits', // the unique id of the dimension @@ -563,8 +563,6 @@ var named = { while(len--) { if(typeof config.servers[len].update_every === 'undefined') config.servers[len].update_every = this.update_every; - else - config.servers[len].update_every = config.servers[len].update_every * 1000; this.serviceExecute(config.servers[len].name, config.servers[len].url, config.servers[len].update_every); added++; diff --git a/node.d/node_modules/asn1.js b/node.d/node_modules/asn1.js new file mode 100644 index 0000000000..d1766e7a6d --- /dev/null +++ b/node.d/node_modules/asn1.js @@ -0,0 +1,20 @@ +// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved. + +// If you have no idea what ASN.1 or BER is, see this: +// ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc + +var Ber = require('./ber/index'); + + + +///--- Exported API + +module.exports = { + + Ber: Ber, + + BerReader: Ber.Reader, + + BerWriter: Ber.Writer + +}; diff --git a/node.d/node_modules/ber/errors.js b/node.d/node_modules/ber/errors.js new file mode 100644 index 0000000000..ff21d4fab3 --- /dev/null +++ b/node.d/node_modules/ber/errors.js @@ -0,0 +1,13 @@ +// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved. + + +module.exports = { + + newInvalidAsn1Error: function(msg) { + var e = new Error(); + e.name = 'InvalidAsn1Error'; + e.message = msg || ''; + return e; + } + +}; diff --git a/node.d/node_modules/ber/index.js b/node.d/node_modules/ber/index.js new file mode 100644 index 0000000000..4fb90aea9a --- /dev/null +++ b/node.d/node_modules/ber/index.js @@ -0,0 +1,27 @@ +// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved. + +var errors = require('./errors'); +var types = require('./types'); + +var Reader = require('./reader'); +var Writer = require('./writer'); + + +///--- Exports + +module.exports = { + + Reader: Reader, + + Writer: Writer + +}; + +for (var t in types) { + if (types.hasOwnProperty(t)) + module.exports[t] = types[t]; +} +for (var e in errors) { + if (errors.hasOwnProperty(e)) + module.exports[e] = errors[e]; +} diff --git a/node.d/node_modules/ber/reader.js b/node.d/node_modules/ber/reader.js new file mode 100644 index 0000000000..0a00e98e33 --- /dev/null +++ b/node.d/node_modules/ber/reader.js @@ -0,0 +1,261 @@ +// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved. + +var assert = require('assert'); + +var ASN1 = require('./types'); +var errors = require('./errors'); + + +///--- Globals + +var newInvalidAsn1Error = errors.newInvalidAsn1Error; + + + +///--- 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 newInvalidAsn1Error('Indefinite length not supported'); + + if (lenB > 4) + throw newInvalidAsn1Error('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 newInvalidAsn1Error('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() { + return this._readTag(ASN1.Integer); +}; + + +Reader.prototype.readBoolean = function() { + return (this._readTag(ASN1.Boolean) === 0 ? false : true); +}; + + +Reader.prototype.readEnumeration = function() { + 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 newInvalidAsn1Error('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); + 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 newInvalidAsn1Error('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 newInvalidAsn1Error('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/node.d/node_modules/ber/types.js b/node.d/node_modules/ber/types.js new file mode 100644 index 0000000000..8aea000137 --- /dev/null +++ b/node.d/node_modules/ber/types.js @@ -0,0 +1,36 @@ +// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved. + + +module.exports = { + EOC: 0, + Boolean: 1, + Integer: 2, + BitString: 3, + OctetString: 4, + Null: 5, + OID: 6, + ObjectDescriptor: 7, + External: 8, + Real: 9, // float + 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/node.d/node_modules/ber/writer.js b/node.d/node_modules/ber/writer.js new file mode 100644 index 0000000000..d9d99af680 --- /dev/null +++ b/node.d/node_modules/ber/writer.js @@ -0,0 +1,316 @@ +// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved. + +var assert = require('assert'); +var ASN1 = require('./types'); +var errors = require('./errors'); + + +///--- Globals + +var newInvalidAsn1Error = errors.newInvalidAsn1Error; + +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 (typeof(tag) !== 'number') + throw new TypeError('tag must be a number'); + if (!Buffer.isBuffer(buf)) + throw new TypeError('argument must be a buffer'); + + 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) { + if ((!strings instanceof Array)) + throw new TypeError('argument must be an Array[String]'); + + var self = this; + strings.forEach(function(s) { + self.writeString(s); + }); +}; + +// 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/node.d/node_modules/net-snmp.js b/node.d/node_modules/net-snmp.js new file mode 100644 index 0000000000..95692c1606 --- /dev/null +++ b/node.d/node_modules/net-snmp.js @@ -0,0 +1,1466 @@ + +// Copyright 2013 Stephen Vickers <stephen.vickers.sv@gmail.com> + +var ber = require ("asn1").Ber; +var dgram = require ("dgram"); +var events = require ("events"); +var util = require ("util"); + +/***************************************************************************** + ** Constants + **/ + +function _expandConstantObject (object) { + var keys = []; + for (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 Version1 = 0; +var Version2c = 1; + +/***************************************************************************** + ** 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) { + if (varbind.type == ObjectType.NoSuchObject + || varbind.type == ObjectType.NoSuchInstance + || varbind.type == ObjectType.EndOfMibView) + return true; + else + return false; +} + +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 readUint (buffer, isSigned) { + buffer.readByte (); + var length = buffer.readByte (); + + 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; + } + + value = 0, signedBitSet = false; + + 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); + + if (value.length > 8) + throw new RequestInvalidError ("64 bit unsigned integer too long '" + + value.length + "'") + + return value; +} + +function readVarbinds (buffer, varbinds) { + buffer.readSequence (); + + while (1) { + buffer.readSequence (); + 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 |