summaryrefslogtreecommitdiffstats
path: root/node.d
diff options
context:
space:
mode:
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>2016-02-05 02:02:12 +0200
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>2016-02-05 02:02:12 +0200
commitcac53fd155c250599871b12ebc1e7f83e1616777 (patch)
treee6c9a2ffe4ac588fb2b7da72f387d8437288e4e8 /node.d
parentccb789708de8b8126ddd17cfaf8e2c3623e4c073 (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.am12
-rwxr-xr-xnode.d/named.node.js12
-rw-r--r--node.d/node_modules/asn1.js20
-rw-r--r--node.d/node_modules/ber/errors.js13
-rw-r--r--node.d/node_modules/ber/index.js27
-rw-r--r--node.d/node_modules/ber/reader.js261
-rw-r--r--node.d/node_modules/ber/types.js36
-rw-r--r--node.d/node_modules/ber/writer.js316
-rw-r--r--node.d/node_modules/net-snmp.js1466
-rwxr-xr-xnode.d/node_modules/netdata.js187
-rwxr-xr-xnode.d/sma_webbox.node.js14
-rwxr-xr-xnode.d/snmp.node.js327
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