Comparing version 1.0.0 to 1.1.0
@@ -7,3 +7,3 @@ | ||
if (process.argv.length < 5) { | ||
console.log ("usage: snmp-get-next <target> <community> <oid>"); | ||
console.log ("usage: snmp-get-next <target> <community> <version> <oid>"); | ||
process.exit (1); | ||
@@ -14,6 +14,7 @@ } | ||
var community = process.argv[3]; | ||
var version = (process.argv[4] == "2c") ? snmp.Version2c : snmp.Version1; | ||
var oids = [process.argv[4]]; | ||
var oids = [process.argv[5]]; | ||
var session = snmp.createSession (target, community); | ||
var session = snmp.createSession (target, community, {version: version}); | ||
@@ -24,5 +25,9 @@ session.getNext (oids, function (error, varbinds) { | ||
} else { | ||
for (var i = 0; i < varbinds.length; i++) | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
for (var i = 0; i < varbinds.length; i++) { | ||
if (snmp.isVarbindError (varbinds[i])) | ||
console.error (snmp.varbindError (varbinds[i])); | ||
else | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
} | ||
} | ||
}); |
@@ -6,4 +6,4 @@ | ||
if (process.argv.length < 5) { | ||
console.log ("usage: snmp-get-next <target> <community> <oid>"); | ||
if (process.argv.length < 6) { | ||
console.log ("usage: snmp-get <target> <community> <version> <oid>"); | ||
process.exit (1); | ||
@@ -14,6 +14,7 @@ } | ||
var community = process.argv[3]; | ||
var version = (process.argv[4] == "2c") ? snmp.Version2c : snmp.Version1; | ||
var oids = [process.argv[4]]; | ||
var oids = [process.argv[5]]; | ||
var session = snmp.createSession (target, community); | ||
var session = snmp.createSession (target, community, {version: version}); | ||
@@ -24,5 +25,9 @@ session.get (oids, function (error, varbinds) { | ||
} else { | ||
for (var i = 0; i < varbinds.length; i++) | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
for (var i = 0; i < varbinds.length; i++) { | ||
if (snmp.isVarbindError (varbinds[i])) | ||
console.error (snmp.varbindError (varbinds[i])); | ||
else | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
} | ||
} | ||
}); |
@@ -6,4 +6,5 @@ | ||
if (process.argv.length < 7) { | ||
console.log ("usage: snmp-set <target> <community> <oid> <type> <value>"); | ||
if (process.argv.length < 8) { | ||
console.log ("usage: snmp-set <target> <community> <version> <oid> <type> " | ||
+ "<value>"); | ||
process.exit (1); | ||
@@ -14,13 +15,12 @@ } | ||
var community = process.argv[3]; | ||
var version = (process.argv[4] == "2c") ? snmp.Version2c : snmp.Version1; | ||
var varbinds = [{ | ||
oid: process.argv[4], | ||
type: snmp.ObjectType[process.argv[5]], | ||
value: process.argv[6] | ||
oid: process.argv[5], | ||
type: snmp.ObjectType[process.argv[6]], | ||
value: process.argv[7] | ||
}]; | ||
var hostname = "hostname-" + new Date ().getTime ().toString (); | ||
var session = snmp.createSession (target, community, {version: version}); | ||
var session = snmp.createSession (target, community); | ||
session.set (varbinds, function (error, varbinds) { | ||
@@ -27,0 +27,0 @@ if (error) { |
@@ -8,4 +8,4 @@ | ||
if (process.argv.length < 5) { | ||
console.log ("usage: node snmp-get <target> <community> <typeOrOid>"); | ||
if (process.argv.length < 6) { | ||
console.log ("usage: node snmp-trap <target> <community> <version> <typeOrOid>"); | ||
process.exit (1); | ||
@@ -16,7 +16,7 @@ } | ||
var community = process.argv[3]; | ||
var typeOrOid = process.argv[4]; | ||
var version = (process.argv[4] == "2c") ? snmp.Version2c : snmp.Version1; | ||
var hostname = "hostname-" + new Date ().getTime ().toString (); | ||
var typeOrOid = process.argv[5]; | ||
var session = snmp.createSession (target, community); | ||
var session = snmp.createSession (target, community, {version: version}); | ||
@@ -27,2 +27,3 @@ dns.lookup (os.hostname (), function (error, address) { | ||
} else { | ||
// address will be ignored for version 2c | ||
session.trap (snmp.TrapType[typeOrOid] || typeOrOid, | ||
@@ -29,0 +30,0 @@ address, function (error) { |
@@ -6,4 +6,4 @@ | ||
if (process.argv.length < 5) { | ||
console.log ("usage: snmp-walk <target> <community> <oid>"); | ||
if (process.argv.length < 6) { | ||
console.log ("usage: snmp-walk <target> <community> <version> <oid>"); | ||
process.exit (1); | ||
@@ -14,6 +14,7 @@ } | ||
var community = process.argv[3]; | ||
var version = (process.argv[4] == "2c") ? snmp.Version2c : snmp.Version1; | ||
var oids = [process.argv[4]]; | ||
var oids = [process.argv[5]]; | ||
var session = snmp.createSession (target, community); | ||
var session = snmp.createSession (target, community, {version: version}); | ||
@@ -31,15 +32,32 @@ function cb (error, varbinds) { | ||
var oids = []; | ||
for (var i = 0; i < varbinds.length; i++) { | ||
console.log (varbinds[i].oid + "|" + varbinds[i].type + "|" | ||
+ varbinds[i].value); | ||
oids.push (varbinds[i].oid); | ||
if (version == snmp.Version2c) { | ||
for (var i = 0; i < varbinds.length; i++) { | ||
for (var j = 0; j < varbinds[i].length; j++) { | ||
if (! snmp.isVarbindError (varbinds[i][j])) { | ||
console.log (varbinds[i][j].oid + "|" + varbinds[i][j].type + "|" | ||
+ varbinds[i][j].value); | ||
} | ||
} | ||
if (! snmp.isVarbindError (varbinds[i][varbinds[i].length - 1])) | ||
oids.push (varbinds[i][varbinds[i].length - 1].oid); | ||
} | ||
} else { | ||
for (var i = 0; i < varbinds.length; i++) { | ||
console.log (varbinds[i].oid + "|" + varbinds[i].type + "|" | ||
+ varbinds[i].value); | ||
oids.push (varbinds[i].oid); | ||
} | ||
} | ||
getNext (oids, cb); | ||
if (oids.length) | ||
walk (oids, cb); | ||
} | ||
} | ||
function getNext (oids, cb) { | ||
session.getNext (oids, cb); | ||
function walk (oids, cb) { | ||
if (version == snmp.Version2c) | ||
session.getBulk (oids, 0, 20, cb); | ||
else | ||
session.getNext (oids, cb); | ||
} | ||
getNext (oids, cb); | ||
walk (oids, cb); |
449
index.js
@@ -8,14 +8,2 @@ | ||
/** | ||
** To help with navigation and parsing this module is organised as follows: | ||
** | ||
** - Constants | ||
** - Exception class definitions | ||
** - OID and varbind helper functions | ||
** - PDU class definitions | ||
** - Message class definitions | ||
** - Session class definition | ||
** - Exports | ||
**/ | ||
/***************************************************************************** | ||
@@ -25,2 +13,10 @@ ** 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 = { | ||
@@ -32,14 +28,19 @@ 0: "NoError", | ||
4: "ReadOnly", | ||
5: "GeneralError" | ||
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" | ||
}; | ||
var TrapType = { | ||
0: "ColdStart", | ||
1: "WarmStart", | ||
2: "LinkDown", | ||
3: "LinkUp", | ||
4: "AuthenticationFailure", | ||
5: "EgpNeighborLoss", | ||
6: "EnterpriseSpecific" | ||
}; | ||
_expandConstantObject (ErrorStatus); | ||
@@ -56,5 +57,16 @@ var ObjectType = { | ||
67: "TimeTicks", | ||
68: "Opaque" | ||
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 = { | ||
@@ -65,6 +77,25 @@ 160: "GetRequest", | ||
163: "SetRequest", | ||
164: "Trap" | ||
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; | ||
@@ -104,14 +135,14 @@ /***************************************************************************** | ||
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]); | ||
function isVarbindError (varbind) { | ||
if (varbind.type == ObjectType.NoSuchObject | ||
|| varbind.type == ObjectType.NoSuchInstance | ||
|| varbind.type == ObjectType.EndOfMibView) | ||
return true; | ||
else | ||
return false; | ||
} | ||
expandConstantObject (ErrorStatus); | ||
expandConstantObject (TrapType); | ||
expandConstantObject (ObjectType); | ||
expandConstantObject (PduType); | ||
function varbindError (varbind) { | ||
return (ObjectType[varbind.type] || "NotAnError") + ": " + varbind.oid; | ||
} | ||
@@ -157,2 +188,11 @@ function oidFollowsOid (oidString, nextString) { | ||
function readInt (buffer) { | ||
var value = readUint (buffer); | ||
if (value & 0x80000000) | ||
value = 0 - (value & 0x7fffffff); | ||
return value; | ||
} | ||
function readUint (buffer) { | ||
buffer.readByte (); | ||
@@ -166,2 +206,3 @@ var length = buffer.readByte (); | ||
throw new RangeError ("Integer too long '" + length + "'"); | ||
length = 4; | ||
} | ||
@@ -178,2 +219,12 @@ | ||
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) { | ||
@@ -212,9 +263,23 @@ buffer.readSequence (); | ||
} else if (type == ObjectType.Counter) { | ||
value = readInt (buffer); | ||
value = readUint (buffer); | ||
} else if (type == ObjectType.Gauge) { | ||
value = readInt (buffer); | ||
value = readUint (buffer); | ||
} else if (type == ObjectType.TimeTicks) { | ||
value = readInt (buffer); | ||
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 { | ||
@@ -233,2 +298,15 @@ throw new ResponseInvalidError ("Unknown type '" + type | ||
function writeUint (buffer, type, value) { | ||
var b = new Buffer (4); | ||
b.writeUInt32BE (value); | ||
buffer.writeBuffer (b, type); | ||
} | ||
function writeUint64 (buffer, value) { | ||
if (value.length > 8) | ||
throw new RequestInvalidError ("64 bit unsigned integer too long '" | ||
+ value.length + "'") | ||
buffer.writeBuffer (value, ObjectType.Counter64); | ||
} | ||
function writeVarbinds (buffer, varbinds) { | ||
@@ -246,6 +324,9 @@ buffer.startSequence (); | ||
buffer.writeBoolean (value ? true : false); | ||
} else if (type == ObjectType.Integer) { | ||
} else if (type == ObjectType.Integer) { // also Integer32 | ||
buffer.writeInt (value); | ||
} else if (type == ObjectType.OctetString) { | ||
buffer.writeString (value); | ||
if (typeof value == "string") | ||
buffer.writeString (value); | ||
else | ||
buffer.writeBuffer (value, ObjectType.OctetString); | ||
} else if (type == ObjectType.Null) { | ||
@@ -261,10 +342,12 @@ buffer.writeNull (); | ||
buffer.writeBuffer (new Buffer (bytes), 64); | ||
} else if (type == ObjectType.Counter) { | ||
buffer.writeInt (value, ObjectType.Counter); | ||
} else if (type == ObjectType.Gauge) { | ||
buffer.writeInt (value, ObjectType.Gauge); | ||
} 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) { | ||
buffer.writeInt (value, 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 { | ||
@@ -287,5 +370,6 @@ throw new RequestInvalidError ("Unknown type '" + type | ||
var SimplePdu = function (id, varbinds) { | ||
var SimplePdu = function (id, varbinds, options) { | ||
this.id = id; | ||
this.varbinds = varbinds; | ||
this.options = options || {}; | ||
}; | ||
@@ -297,4 +381,8 @@ | ||
buffer.writeInt (this.id); | ||
buffer.writeInt (0); | ||
buffer.writeInt (0); | ||
buffer.writeInt ((this.type == PduType.GetBulkRequest) | ||
? (this.options.nonRepeaters || 0) | ||
: 0); | ||
buffer.writeInt ((this.type == PduType.GetBulkRequest) | ||
? (this.options.maxRepetitions || 0) | ||
: 0); | ||
@@ -306,2 +394,9 @@ writeVarbinds (buffer, this.varbinds); | ||
var GetBulkRequestPdu = function () { | ||
this.type = PduType.GetBulkRequest; | ||
GetBulkRequestPdu.super_.apply (this, arguments); | ||
}; | ||
util.inherits (GetBulkRequestPdu, SimplePdu); | ||
var GetNextRequestPdu = function () { | ||
@@ -336,2 +431,9 @@ this.type = PduType.GetNextRequest; | ||
var InformRequestPdu = function () { | ||
this.type = PduType.InformRequest; | ||
InformRequestPdu.super_.apply (this, arguments); | ||
}; | ||
util.inherits (InformRequestPdu, SimplePdu); | ||
var SetRequestPdu = function () { | ||
@@ -377,2 +479,9 @@ this.type = PduType.SetRequest; | ||
var TrapV2Pdu = function () { | ||
this.type = PduType.TrapV2; | ||
TrapV2Pdu.super_.apply (this, arguments); | ||
}; | ||
util.inherits (TrapV2Pdu, SimplePdu); | ||
/***************************************************************************** | ||
@@ -430,7 +539,7 @@ ** Message class definitions | ||
var Session = function (target, community, version, options) { | ||
var Session = function (target, community, options) { | ||
this.target = target || "127.0.0.1"; | ||
this.community = community || "public"; | ||
this.version = (version && version == Version2c) ? Version2c : Version1; | ||
this.version = (options && options.version) ? options.version : Version1; | ||
@@ -446,6 +555,9 @@ this.port = (options && options.port ) ? options.port : 161; | ||
function _generateId () { | ||
return Math.floor (Math.random () + Math.random () * 10000000) | ||
} | ||
Session.prototype.get = function (oids, responseCb) { | ||
function feedCb (req, message) { | ||
var pdu = message.pdu; | ||
var oids = {}; | ||
var varbinds = []; | ||
@@ -488,10 +600,113 @@ | ||
function _generateId () { | ||
return Math.floor (Math.random () + Math.random () * 10000000) | ||
} | ||
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 oids = {}; | ||
var varbinds = []; | ||
@@ -504,3 +719,5 @@ | ||
for (var i = 0; i < req.message.pdu.varbinds.length; i++) { | ||
if (! oidFollowsOid (req.message.pdu.varbinds[i].oid, | ||
if (isVarbindError (pdu.varbinds[i])) { | ||
varbinds.push (pdu.varbinds[i]); | ||
} else if (! oidFollowsOid (req.message.pdu.varbinds[i].oid, | ||
pdu.varbinds[i].oid)) { | ||
@@ -536,2 +753,73 @@ req.responseCb (new ResponseInvalidError ("OID '" | ||
Session.prototype.inform = function () { | ||
var typeOrOid = arguments[0];; | ||
var varbinds, responseCb; | ||
if (arguments.length >= 3) { | ||
varbinds = arguments[1]; | ||
responseCb = arguments[2]; | ||
} else { | ||
varbinds = []; | ||
responseCb = arguments[1]; | ||
} | ||
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: 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); | ||
} | ||
var options = { | ||
port: this.trapPort | ||
}; | ||
this.simpleGet (InformRequestPdu, feedCb, pduVarbinds, responseCb, options); | ||
return this; | ||
}; | ||
Session.prototype.onMsg = function (req, buffer, remote) { | ||
@@ -550,3 +838,7 @@ try { | ||
if (message.version != req.message.version) { | ||
if (message.pdu.id != req.message.pdu.id) { | ||
cbError (req, new ResponseInvalidError ("ID in request '" | ||
+ req.message.pdu.id + "' does not match ID in " | ||
+ "response '" + message.pdu.id)); | ||
} else if (message.version != req.message.version) { | ||
cbError (req, new ResponseInvalidError ("Version in request '" | ||
@@ -627,3 +919,2 @@ + req.message.version + "' does not match version in " | ||
var pdu = message.pdu; | ||
var oids = {}; | ||
var varbinds = []; | ||
@@ -669,7 +960,7 @@ | ||
Session.prototype.simpleGet = function (pduClass, feedCb, varbinds, | ||
responseCb) { | ||
responseCb, options) { | ||
var req = {} | ||
try { | ||
var pdu = new pduClass (_generateId (), varbinds); | ||
var pdu = new pduClass (_generateId (), varbinds, options); | ||
var message = new RequestMessage (this.version, this.community, pdu); | ||
@@ -684,3 +975,3 @@ | ||
feedCb: feedCb, | ||
port: this.port | ||
port: (options && options.port) ? options.port : this.port | ||
}; | ||
@@ -727,3 +1018,35 @@ | ||
var pdu = new TrapPdu (typeOrOid, varbinds, agentAddr); | ||
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); | ||
} | ||
if (this.version == Version2c) { | ||
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: process.uptime () * 100 | ||
}, | ||
{ | ||
oid: "1.3.6.1.6.3.1.1.4.1.0", | ||
type: ObjectType.OID, | ||
value: typeOrOid | ||
} | ||
); | ||
pdu = new TrapV2Pdu (_generateId (), pduVarbinds); | ||
} else { | ||
pdu = new TrapPdu (typeOrOid, pduVarbinds, agentAddr); | ||
} | ||
var message = new RequestMessage (this.version, this.community, pdu); | ||
@@ -760,3 +1083,7 @@ | ||
exports.isVarbindError = isVarbindError; | ||
exports.varbindError = varbindError; | ||
exports.Version1 = Version1; | ||
exports.Version2c = Version2c; | ||
@@ -763,0 +1090,0 @@ exports.ErrorStatus = ErrorStatus; |
{ | ||
"name": "net-snmp", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "Native implementation of the Simple Network Management Protocol (SNMP)", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
901
README.md
# net-snmp - [homepage](http://re-tool.org) | ||
# net-snmp - [homepage][homepage] | ||
This module implements version 1 of the [Simple Network Management Protocol | ||
(SNMP)](http://en.wikipedia.org/wiki/Simple_Network_Management_Protocol). | ||
Version 2c support will be available shortly. | ||
This module implements version 1 and 2c of the [Simple Network Management | ||
Protocol (SNMP)][SNMP]. | ||
This module is installed using [Node Package Manager | ||
(NPM)](https://npmjs.org/): | ||
This module is installed using [Node Package Manager (NPM)][NPM]: | ||
npm install net-snmp | ||
npm install net-snmp | ||
It then can be loaded using the `require()` function: | ||
It is loaded using the `require()` function: | ||
var snmp = require ("snmp"); | ||
var snmp = require ("snmp"); | ||
Sessions to remote hosts can then be created: | ||
Sessions to remote hosts can then be created and used to perform SNMP requests | ||
and send SNMP traps or informs: | ||
var session = snmp.createSession ("127.0.0.1", "public"); | ||
var session = snmp.createSession ("127.0.0.1", "public"); | ||
Use the session to make SNMP get, get-next and set requests, and send SNMP | ||
traps: | ||
var oids = ["1.3.6.1.2.1.1.5.0", "1.3.6.1.2.1.1.6.0"]; | ||
session.get (oids, function (error, varbinds) { | ||
if (error) { | ||
console.error (error); | ||
} else { | ||
for (var i = 0; i < varbinds.length; i++) | ||
if (snmp.isVarbindError (varbinds[i]) | ||
console.error (snmp.varbindError (varbinds[i]) | ||
else | ||
console.log (varbinds[i].oid + " = " + varbinds[i].value); | ||
} | ||
}); | ||
var oids = ["1.3.6.1.2.1.1.5.0", "1.3.6.1.2.1.1.6.0"]; | ||
session.get (oids, function (error, varbinds) { | ||
if (error) { | ||
console.error (error); | ||
} else { | ||
for (var i = 0; i < varbinds.length; i++) | ||
console.log (varbinds[i].oid + " = " + varbinds[i].value); | ||
} | ||
}); | ||
session.trap (snmp.TrapType.LinkDown, function (error) { | ||
if (error) | ||
console.error (error); | ||
}); | ||
session.trap (snmp.TrapType.LinkDown, function (error) { | ||
if (error) | ||
console.error (error); | ||
}); | ||
[homepage]: http://re-tool.org "Homepage" | ||
[SNMP]: http://en.wikipedia.org/wiki/Simple_Network_Management_Protocol "SNMP" | ||
[NPM]: https://npmjs.org/ "NPM" | ||
# RFC & Standards Compliance | ||
This module aims to be fully compliant with the following RFCs: | ||
* [1065][1065] - Structure and Identification of Management Information | ||
* [1067][1067] - A Simple Network Management Protocol (version 1) | ||
* [2578][2578] - Structure of Management Information Version 2 (SMIv2) | ||
* [3416][3416] - Simple Network Management Protocol (SNMP) (version 2c) | ||
However, this module does not implement or export any method to help implement | ||
the report request type. | ||
[1065]: https://tools.ietf.org/rfc/rfc1065.txt "RFC 1065" | ||
[1067]: https://tools.ietf.org/rfc/rfc1067.txt "RFC 1067" | ||
[2578]: https://tools.ietf.org/rfc/rfc2578.txt "RFC 2578" | ||
[3416]: https://tools.ietf.org/rfc/rfc3416.txt "RFC 3416" | ||
# Constants | ||
The following sections describe constants exported by this module. | ||
The following sections describe constants exported and used by this module. | ||
## snmp.Version1 & snmp.Version2c | ||
These constants are used to specify which of the two versions supported by | ||
this module should be used. | ||
## snmp.ErrorStatus | ||
This object contains constants for all valid values the error-status field in | ||
response PDUs could hold. When parsing a PDU the error-index field contains a | ||
value not defined in this object the constant `snmp.ErrorStatus.GeneralError` | ||
will be used instead. | ||
response PDUs can hold. If when parsing a PDU the error-index field contains | ||
a value not defined in this object the constant `snmp.ErrorStatus.GeneralError` | ||
will be used instead of the value of the error-status field. The following | ||
constants are defined in this object: | ||
The following constants are defined in this object: | ||
* `NoError` | ||
@@ -59,18 +83,16 @@ * `TooBig` | ||
* `GeneralError` | ||
* `NoAccess` | ||
* `WrongType` | ||
* `WrongLength` | ||
* `WrongEncoding` | ||
* `WrongValue` | ||
* `NoCreation` | ||
* `InconsistentValue` | ||
* `ResourceUnavailable` | ||
* `CommitFailed` | ||
* `UndoFailed` | ||
* `AuthorizationError` | ||
* `NotWritable` | ||
* `InconsistentName` | ||
## snmp.TrapType | ||
This object contains constants used to specify a type of SNMP trap. Currently | ||
this is only used by the `trap()` method exposed by the `Session` class. | ||
The following constants are defined in this object: | ||
* `ColdStart` | ||
* `WarmStart` | ||
* `LinkDown` | ||
* `LinkUp` | ||
* `AuthenticationFailure` | ||
* `EgpNeighborLoss` | ||
* `EnterpriseSpecific` | ||
## snmp.ObjectType | ||
@@ -81,7 +103,7 @@ | ||
var varbind = { | ||
oid: "1.3.6.1.2.1.1.4.0", | ||
type: snmp.ObjectType.OctetString, | ||
value: "user.name@domain.name" | ||
}; | ||
var varbind = { | ||
oid: "1.3.6.1.2.1.1.4.0", | ||
type: snmp.ObjectType.OctetString, | ||
value: "user.name@domain.name" | ||
}; | ||
@@ -100,49 +122,179 @@ The following constants are defined in this object: | ||
* `Opaque` | ||
* `Integer32` | ||
* `Counter32` | ||
* `Gauge32` | ||
* `Unsigned32` | ||
* `Counter64` | ||
* `NoSuchObject` | ||
* `NoSuchInstance` | ||
* `EndOfMibView` | ||
## snmp.TrapType | ||
This object contains constants used to specify a type of SNMP trap. These | ||
constants are passed to the `trap()` and `inform()` methods exposed by the | ||
`Session` class. The following constants are defined in this object: | ||
* `ColdStart` | ||
* `WarmStart` | ||
* `LinkDown` | ||
* `LinkUp` | ||
* `AuthenticationFailure` | ||
* `EgpNeighborLoss` | ||
* `EnterpriseSpecific` | ||
# OID Strings & Varbinds | ||
Some parts of the API accept simple OID strings, e.g.: | ||
Some parts of this module accept simple OID strings, e.g.: | ||
var oid = "1.3.6.1.2.1.1.5.0"; | ||
var oid = "1.3.6.1.2.1.1.5.0"; | ||
OID strings are typically referred as "OID" or "OIDs". | ||
Other parts take an OID string, it's type and value. This is collectively | ||
referred to as a varbind, and is specified as an object, e.g.: | ||
var varbind = { | ||
oid: "1.3.6.1.2.1.1.5.0", | ||
type: snmp.ObjectType.OctetString, | ||
value: "host1" | ||
}; | ||
var varbind = { | ||
oid: "1.3.6.1.2.1.1.5.0", | ||
type: snmp.ObjectType.OctetString, | ||
value: new Buffer ("host1") | ||
}; | ||
# Error Handling | ||
The `type` parameter is one of the constants defined in the `snmp.ObjectType` | ||
object. | ||
SNMP request and trap functions take a mandatory callback function. This | ||
function is called once a request has been processed. This could be because | ||
an error occurred when processing the request, a trap has been dispatched or a | ||
successful response was received. | ||
The JavaScript `true` and `false` keywords are used for the values of varbinds | ||
with type `Boolean`. | ||
All integer based types are specified as expected (this includes `Integer`, | ||
`Counter`, `Gauge`, `TimeTicks`, `Integer32`, `Counter32`, `Gauge32`, and | ||
`Unsigned32`), e.g. `-128` or `100`. | ||
Since JavaScript does not offer full 64 bit integer support objects with type | ||
`Counter64` cannot be supported in the same way as other integer types, | ||
instead [Node.js][nodejs] `Buffer` objects are used. Users are responsible for | ||
producing (i.e. for `set()` requests) and consuming (i.e. the varbinds passed | ||
to callback functions) `Buffer` objects. That is, this module does no work | ||
with 64 bit integers, it simply treats them as opaque `Buffer` objects. | ||
Dotted decimal strings are used for the values of varbinds with type `OID`, | ||
e.g. `1.3.6.1.2.1.1.5.0`. | ||
Dotted quad formatted strings are used for the values of varbinds with type | ||
`IpAddress`, e.g. `192.168.1.1`. | ||
[Node.js][nodejs] `Buffer` objects are used for the values of varbinds with | ||
type `Opaque` and `OctetString`. For varbinds with type `OctetString` this | ||
module will accept JavaScript strings, but will always give back `Buffer` | ||
objects. | ||
The `NoSuchObject`, `NoSuchInstance` and `EndOfMibView` types are used to | ||
indicate an error condition. Currently there is no reason for users of this | ||
module to to build varbinds using these types. | ||
[nodejs]: http://nodejs.org "Node.js" | ||
# Callback Functions & Error Handling | ||
Most of the request methods exposed by this module require a mandatory | ||
callback function. This function is called once a request has been processed. | ||
This could be because an error occurred when processing the request, a trap | ||
has been dispatched or a successful response was received. | ||
The first parameter to every callback is an error object. In the case no | ||
error occurred this parameter will be "null" indicating no error, e.g.: | ||
function responseCb (error, varbinds) { | ||
if (error) { | ||
console.error (error); | ||
} else { | ||
// no error, do something with varbinds | ||
} | ||
} | ||
function responseCb (error, varbinds) { | ||
if (error) { | ||
console.error (error); | ||
} else { | ||
// no error, do something with varbinds | ||
} | ||
} | ||
When defined, the error parameter is always an instance of the Error class, or | ||
a sub-class described in one of the following sections. | ||
a sub-class described in one of the sub-sections contained in this section. | ||
The semantics of error handling is slightly different between SNMP version | ||
1 and 2c. In SNMP version 1 if an error occurs when calculating the value for | ||
one OID the request as a whole will fail, i.e. no OIDs will have a value. | ||
This failure manifests itself within the error-status and error-index fields | ||
of the response. When the error-status field in the response is non-zero, | ||
i.e. not `snmp.ErrorStatus.NoError` the `callback` will be called with `error` | ||
defined detailing the error. | ||
Requests made with SNMP version 1 can simply assume all OIDs have a value when | ||
no error object is passed to the `callback`, i.e.: | ||
var oids = ["1.3.6.1.2.1.1.5.0", "1.3.6.1.2.1.1.6.0"]; | ||
session.get (oids, function (error, varbinds) { | ||
if (error) { | ||
console.error (error.toString ()); | ||
} else { | ||
var sysName = varbinds[0].value; // this WILL have a value | ||
} | ||
}); | ||
In SNMP version 2c instead of using the error-status and error-index fields of | ||
the response to signal an error, the value for the varbind placed in the | ||
response for an OID will have an object syntax describing an error. The | ||
error-status and error-index fields of the response will indicate the request | ||
was successul, i.e. `snmp.ErrorStatus.NoError`. | ||
This changes the way in which error checking is performed in the `callback`. | ||
When using SNMP version 2c each varbind must be checked to see if its value | ||
was computed and returned successfully: | ||
var oids = ["1.3.6.1.2.1.1.5.0", "1.3.6.1.2.1.1.6.0"]; | ||
session.get (oids, function (error, varbinds) { | ||
if (error) { | ||
console.error (error.toString ()); | ||
} else { | ||
if (varbinds[0].type != snmp.ErrorStatus.NoSuchObject | ||
&& varbinds[0].type != snmp.ErrorStatus.NoSuchInstance | ||
&& varbinds[0].type != snmp.ErrorStatus.EndOfMibView) { | ||
var sysName = varbinds[0].value; | ||
} else { | ||
console.error (snmp.ObjectType[varbinds[0].type] + ": " | ||
+ varbinds[0].oid); | ||
} | ||
} | ||
}); | ||
This module exports two functions and promotes a specifc pattern to make error | ||
checking a little simpler. Firstly, regardless of version in use varbinds can | ||
always be checked. This results in a generic `callback` that can be used for | ||
both versions. | ||
The `isVarbindError()` function can be used to determine if a varbind has an | ||
error condition. This function takes a single `varbind` parameter and returns | ||
`true` if the varbind has an error condition, otherwise `false`. The exported | ||
`varbindError()` function can then be used to obtain the error string | ||
describing the error, which will include the OID for the varbind: | ||
session.get (oids, function (error, varbinds) { | ||
if (error) { | ||
console.error (error.toString ()); | ||
} else { | ||
if (snmp.isVarbindError (varbinds[0])) { | ||
console.error (snmp.varbindError (varbinds[0])); | ||
} else { | ||
var sysName = varbinds[0].value; | ||
} | ||
} | ||
}); | ||
If the `varbindError` function is called with a varbind for which | ||
`isVarbindError` would return false, the string `NotAnError` will be returned | ||
appended with the related OID. | ||
The sections following defines the error classes used by this module. | ||
## snmp.RequestFailedError | ||
This error indicates the remote host failed to process the request. The | ||
exposed `message` attribute will contain a detailed string indicating what the | ||
error was. | ||
This error also exposes a `status` attribute which contains the error-index | ||
value from a response PDU. This will be one of the constants defined in the | ||
This error indicates a remote host failed to process a request. The exposed | ||
`message` attribute will contain a detailed error message. This error also | ||
exposes a `status` attribute which contains the error-index value from a | ||
response. This will be one of the constants defined in the | ||
`snmp.ErrorStatus` object. | ||
@@ -152,18 +304,15 @@ | ||
This error indicates a failure to render a request message or PDU before it | ||
could be sent. The error can also indicate that a parameter provided was | ||
invalid. The exposed `message` attribute will contain a detailed string | ||
indicating what the error was. | ||
This error indicates a failure to render a request message before it could be | ||
sent. The error can also indicate that a parameter provided was invalid. | ||
The exposed `message` attribute will contain a detailed error message. | ||
## snmp.RequestTimdOutError | ||
## snmp.RequestTimedOutError | ||
This error states that no response was received for a particular request. The | ||
exposed `message` attribute will typically contain the value `Request timed | ||
out`. | ||
exposed `message` attribute will contain the value `Request timed out`. | ||
## snmp.ResponseInvalidError | ||
This error indicates a failure to parse a received response message or PDU. | ||
The exposed `message` attribute will contain a detailed string indicating what | ||
the error was. | ||
This error indicates a failure to parse a response message. The exposed | ||
`message` attribute will contain a detailed error message. | ||
@@ -173,4 +322,4 @@ # Using This Module | ||
All SNMP requests are made using an instance of the `Session` class. This | ||
module exports the `createSession()` function, which is used to create new | ||
`Session` objects. | ||
module exports the `createSession()` function which is used to create | ||
instances of the `Session` class. | ||
@@ -182,10 +331,11 @@ ## snmp.createSession ([target], [community], [options]) | ||
var options = { | ||
retries: 1, | ||
timeout: 5000, | ||
port: 161, | ||
trapPort: 162 | ||
}; | ||
var session = snmp.createSession ("127.0.0.1", "public", options); | ||
var options = { | ||
version: snmp.Version1, | ||
retries: 1, | ||
timeout: 5000, | ||
port: 161, | ||
trapPort: 162 | ||
}; | ||
var session = snmp.createSession ("127.0.0.1", "public", options); | ||
@@ -196,18 +346,17 @@ The optional `target` parameter defaults to `127.0.0.1`. The optional | ||
* `retries` - Number of times to re-send a request, defaults to 1 | ||
* `version` - Either `snmp.Version1` or `snmp.Version2c`, defaults to | ||
`snmp.Version1` | ||
* `retries` - Number of times to re-send a request, defaults to `1` | ||
* `timeout` - Number of milliseconds to wait for a response before re-trying | ||
or failing, defaults to 5000 | ||
* `port` - UDP port to send requests too, defaults to 161 | ||
* `trapPort` - UDP port to send traps too, defaults to 162 | ||
or failing, defaults to `5000` | ||
* `port` - UDP port to send requests too, defaults to `161` | ||
* `trapPort` - UDP port to send traps and informs too, defaults to `162` | ||
The returned object can be used to perform SNMP requests and send traps to a | ||
remote host. | ||
## session.get (oids, callback) | ||
The `get()` method fetches the value for one or more OIDs from a remote host. | ||
The `oids` parameter is an array of OID strings. | ||
The `callback` function is called once the request is complete. The following | ||
arguments will be passed to the `callback` function: | ||
The `oids` parameter is an array of OID strings. The `callback` function is | ||
called once the request is complete. The following arguments will be passed | ||
to the `callback` function: | ||
@@ -221,24 +370,35 @@ * `error` - Instance of the Error class or a sub-class, or `null` if no error | ||
The following example fetches values for the sysName (1.3.6.1.2.1.1.5.0) and | ||
sysLocation (1.3.6.1.2.1.1.6.0) OIDs: | ||
Each varbind must be checked for an error condition using the | ||
`snmp.isVarbindError()` function when using SNMP version 2c. | ||
var oids = ["1.3.6.1.2.1.1.5.0", "1.3.6.1.2.1.1.6.0"]; | ||
session.get (oids, function (error, varbinds) { | ||
if (error) { | ||
console.error (error.toString ()); | ||
} else { | ||
for (var i = 0; i < varbinds.length; i++) | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
} | ||
}); | ||
The following example fetches values for the sysName (`1.3.6.1.2.1.1.5.0`) and | ||
sysLocation (`1.3.6.1.2.1.1.6.0`) OIDs: | ||
var oids = ["1.3.6.1.2.1.1.5.0", "1.3.6.1.2.1.1.6.0"]; | ||
session.get (oids, function (error, varbinds) { | ||
if (error) { | ||
console.error (error.toString ()); | ||
} else { | ||
for (var i = 0; i < varbinds.length; i++) { | ||
// for version 1 we can assume all OIDs were successful | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
// for version 2c we must check each OID for an error condition | ||
if (snmp.isVarbindError (varbinds[i])) | ||
console.error (snmp.varbindError (varbinds[i])); | ||
else | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
} | ||
} | ||
}); | ||
## session.getNext (oids, callback) | ||
The `getNext()` method fetches the value for the OIDs lexicographically | ||
following one or more OIDs in the MIB tree from a remote host. The `oids` | ||
parameter is an array of OID strings. | ||
following one or more OIDs in the MIB tree from a remote host. | ||
The `callback` function is called once the request is complete. The following | ||
arguments will be passed to the `callback` function: | ||
The `oids` parameter is an array of OID strings. The `callback` function is | ||
called once the request is complete. The following arguments will be passed | ||
to the `callback` function: | ||
@@ -252,24 +412,42 @@ * `error` - Instance of the Error class or a sub-class, or `null` if no error | ||
Each varbind must be checked for an error condition using the | ||
`snmp.isVarbindError()` function when using SNMP version 2c. | ||
The following example fetches values for the next OIDs following the | ||
sysObjectID (1.3.6.1.2.1.1.1.0) and sysName (1.3.6.1.2.1.1.4.0) OIDs: | ||
sysObjectID (`1.3.6.1.2.1.1.1.0`) and sysName (`1.3.6.1.2.1.1.4.0`) OIDs: | ||
var oids = [ | ||
"1.3.6.1.2.1.1.1.0", | ||
"1.3.6.1.2.1.1.4.0" | ||
]; | ||
session.getNext (oids, function (error, varbinds) { | ||
if (error) { | ||
console.error (error.toString ()); | ||
} else { | ||
for (var i = 0; i < varbinds.length; i++) | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
} | ||
}); | ||
var oids = [ | ||
"1.3.6.1.2.1.1.1.0", | ||
"1.3.6.1.2.1.1.4.0" | ||
]; | ||
session.getNext (oids, function (error, varbinds) { | ||
if (error) { | ||
console.error (error.toString ()); | ||
} else { | ||
for (var i = 0; i < varbinds.length; i++) { | ||
// for version 1 we can assume all OIDs were successful | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
// for version 2c we must check each OID for an error condition | ||
if (snmp.isVarbindError (varbinds[i])) | ||
console.error (snmp.varbindError (varbinds[i])); | ||
else | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
} | ||
} | ||
}); | ||
## session.set (varbinds, callback) | ||
## session.getBulk (oids, [nonRepeaters], [maxRepetitions], callback) | ||
The `set()` method sets the value of one or more OIDs on a remote host. The | ||
`varbinds` parameter is an array of varbind objects. | ||
The `getBulk()` method fetches the value for the OIDs lexicographically | ||
following one or more OIDs in the MIB tree from a remote host. | ||
The `oids` parameter is an array of OID strings. The optional `nonRepeaters` | ||
parameter specifies the number of OIDs in the `oids` parameter for which only | ||
1 varbind should be returned, and defaults to `0`. For each remaining OID | ||
in the `oids` parameter the optional `maxRepetitions` parameter specifies how | ||
many OIDs lexicographically following an OID for which varbinds should be | ||
fetched, and defaults to `20`. | ||
The `callback` function is called once the request is complete. The following | ||
@@ -282,39 +460,119 @@ arguments will be passed to the `callback` function: | ||
The varbind in position N in the `varbinds` array will correspond to the OID | ||
in position N in the `oids` array in the request. | ||
For for the first `nonRepeaters` items in `varbinds` each item will be a | ||
single varbind. For all remaining items in `varbinds` each item will be an | ||
array of varbinds - this makes it easy to tie response varbinds with requested | ||
OIDs since response varbinds are grouped and placed in the same position in | ||
`varbinds`. | ||
Each varbind must be checked for an error condition using the | ||
`snmp.isVarbindError()` function when using SNMP version 2c. | ||
The following example fetches values for the OIDs following the sysContact | ||
(`1.3.6.1.2.1.1.4.0`) and sysName (`1.3.6.1.2.1.1.5.0`) OIDs, and up to the | ||
first 20 OIDs in the ifDescr (`1.3.6.1.2.1.2.2.1.2`) and ifType | ||
(`1.3.6.1.2.1.2.2.1.3`) columns from the ifTable (`1.3.6.1.2.1.2.2`) table: | ||
var oids = [ | ||
"1.3.6.1.2.1.1.4.0", | ||
"1.3.6.1.2.1.1.5.0", | ||
"1.3.6.1.2.1.2.2.1.2", | ||
"1.3.6.1.2.1.2.2.1.3" | ||
]; | ||
var nonRepeaters = 2; | ||
session.getNext (oids, nonRepeaters, function (error, varbinds) { | ||
if (error) { | ||
console.error (error.toString ()); | ||
} else { | ||
// step through the non-repeaters which are single varbinds | ||
for (var i = 0; i < nonRepeaters; i++) { | ||
if (i >= varbinds.length) | ||
break; | ||
if (snmp.isVarbindError (varbinds[i])) | ||
console.error (snmp.varbindError (varbinds[i])); | ||
else | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
} | ||
// then step through the repeaters which are varbind arrays | ||
for (var i = nonRepeaters; i < varbinds.length; i++) { | ||
for (var j = 0; j < varbinds[i].length; j++) { | ||
if (snmp.isVarbindError (varbinds[i][j])) | ||
console.error (snmp.varbindError (varbinds[i][j])); | ||
else | ||
console.log (varbinds[i][j].oid + "|" | ||
+ varbinds[i][j].value); | ||
} | ||
} | ||
}); | ||
## session.set (varbinds, callback) | ||
The `set()` method sets the value of one or more OIDs on a remote host. | ||
The `varbinds` parameter is an array of varbind objects. The `callback` | ||
function is called once the request is complete. The following arguments will | ||
be passed to the `callback` function: | ||
* `error` - Instance of the Error class or a sub-class, or `null` if no error | ||
occurred | ||
* `varbinds` - Array of varbinds, will not be provided if an error occurred | ||
The varbind in position N in the `varbinds` array will correspond to the | ||
varbind in position N in the `varbinds` array in the request. The remote host | ||
should echo back varbinds and their values as specified in the request, and | ||
the `varbinds` array will contain each varbind as sent back by the remote host. | ||
should echo back varbinds and their values as specified in the request unless | ||
an error occurred. The `varbinds` array will contain each varbind as sent | ||
back by the remote host. | ||
The following example sets the value of the sysName (1.3.6.1.2.1.1.4.0) and | ||
sysLocation (1.3.6.1.2.1.1.6.0) OIDs: | ||
Each varbind must be checked for an error condition using the | ||
`snmp.isVarbindError()` function when using SNMP version 2c. | ||
var varbinds = [ | ||
{ | ||
oid: "1.3.6.1.2.1.1.5.0", | ||
type: snmp.ObjectType.OctetString, | ||
value: "host1" | ||
}, { | ||
oid: "1.3.6.1.2.1.1.6.0", | ||
type: snmp.ObjectType.OctetString, | ||
value: "somewhere" | ||
} | ||
]; | ||
session.set (varbinds, function (error, varbinds) { | ||
if (error) { | ||
console.error (error.toString ()); | ||
} else { | ||
for (var i = 0; i < varbinds.length; i++) | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
} | ||
}); | ||
The following example sets the value of the sysName (`1.3.6.1.2.1.1.4.0`) and | ||
sysLocation (`1.3.6.1.2.1.1.6.0`) OIDs: | ||
var varbinds = [ | ||
{ | ||
oid: "1.3.6.1.2.1.1.5.0", | ||
type: snmp.ObjectType.OctetString, | ||
value: "host1" | ||
}, { | ||
oid: "1.3.6.1.2.1.1.6.0", | ||
type: snmp.ObjectType.OctetString, | ||
value: "somewhere" | ||
} | ||
]; | ||
session.set (varbinds, function (error, varbinds) { | ||
if (error) { | ||
console.error (error.toString ()); | ||
} else { | ||
for (var i = 0; i < varbinds.length; i++) { | ||
// for version 1 we can assume all OIDs were successful | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
// for version 2c we must check each OID for an error condition | ||
if (snmp.isVarbindError (varbinds[i])) | ||
console.error (snmp.varbindError (varbinds[i])); | ||
else | ||
console.log (varbinds[i].oid + "|" + varbinds[i].value); | ||
} | ||
} | ||
}); | ||
## session.trap (typeOrOid, [varbinds], [agentAddr], callback) | ||
The `trap()` method sends a SNMP trap to a remote host. The `typeOrOid` | ||
parameter can be one of two types; one of the constants defined in the | ||
`snmp.TrapType` object (excluding the `snmp.TrapType.EnterpriseSpecific` | ||
constant), or an OID string. When a constant is specified the following | ||
fields are set in the trap: | ||
The `trap()` method sends a SNMP trap to a remote host. | ||
The `typeOrOid` parameter can be one of two types; one of the constants | ||
defined in the `snmp.TrapType` object (excluding the | ||
`snmp.TrapType.EnterpriseSpecific` constant), or an OID string. | ||
For SNMP version 1 when a constant is specified the following fields are set in | ||
the trap: | ||
* The enterprise field is set to the OID `1.3.6.1.4.1` | ||
@@ -335,6 +593,21 @@ * The generic-trap field is set to the constant specified | ||
The `varbinds` parameter is an optional array of varbinds to include in the | ||
trap, and defaults to the empty array `[]`. The `agentAddr` parameter is | ||
optional, and defaults to `127.0.0.1`. | ||
SNMP version 2c messages are quite different in comparison with version 1. | ||
The version 2c trap has a much simpler format, simply a sequence of varbinds. | ||
The first varbind to be placed in the trap message will be for the | ||
`sysUptime.0` OID (`1.3.6.1.6.3.1.1.4.1.0`). The value for this varbind will | ||
be the value returned by the `process.uptime ()` function multiplied by 100. | ||
This will be followed by a second varbind for the `snmpTrapOID.0` OID | ||
(`1.3.6.1.6.3.1.1.4.1.0`). The value for this will depend on the `typeOrOid` | ||
parameter. If a constant is specified the trap OID for the constant | ||
will be used as supplied for the varbinds value, otherwise the OID string | ||
specified will be used as is for the value of the varbind. | ||
The optional `varbinds` parameter is an array of varbinds to include in the | ||
trap, and defaults to the empty array `[]`. | ||
The optional `agentAddr` parameter is the IP address used to populate the | ||
agent-addr field for SNMP version 1 type traps, and defaults to `127.0.0.1`. | ||
When using SNMP version 2c the `agentAddr` parameter is ignored if specified | ||
since version 2c trap messages do not have an agent-addr field. | ||
The `callback` function is called once the trap has been sent, or an error | ||
@@ -346,88 +619,198 @@ occurred. The following arguments will be passed to the `callback` function: | ||
The following example sends an enterprise specific trap to a remote host, and | ||
includes the sysName (1.3.6.1.2.1.1.5.0) varbind in the trap. Before the trap | ||
is sent the `agentAddr` field is calculated using DNS to resolve the hostname | ||
of the local host: | ||
The following example sends an enterprise specific trap to a remote host using | ||
a SNMP version 1 trap, and includes the sysName (`1.3.6.1.2.1.1.5.0`) varbind | ||
in the trap. Before the trap is sent the `agentAddr` field is calculated using | ||
DNS to resolve the hostname of the local host: | ||
var enterpriseOid = "1.3.6.1.4.1.2000.1"; // we made this up, but it may be | ||
valid | ||
var varbinds = [ | ||
{ | ||
oid: "1.3.6.1.2.1.1.5.0", | ||
type: snmp.Type.OctetString, | ||
value: "host1" | ||
} | ||
]; | ||
dns.lookup (os.hostname (), function (error, agentAddress) { | ||
if (error) { | ||
console.error (error); | ||
} else { | ||
session.trap (enterpriseOid, varbinds, agentAddress, | ||
function (error) { | ||
if (error) | ||
console.error (error); | ||
}); | ||
} | ||
}); | ||
var enterpriseOid = "1.3.6.1.4.1.2000.1"; // made up, but it may be valid | ||
var varbinds = [ | ||
{ | ||
oid: "1.3.6.1.2.1.1.5.0", | ||
type: snmp.Type.OctetString, | ||
value: "host1" | ||
} | ||
]; | ||
dns.lookup (os.hostname (), function (error, agentAddress) { | ||
if (error) { | ||
console.error (error); | ||
} else { | ||
session.trap (enterpriseOid, varbinds, agentAddress, | ||
function (error) { | ||
if (error) | ||
console.error (error); | ||
}); | ||
} | ||
}); | ||
The following example sends a generic link-down trap to a remote host, it does | ||
not include any varbinds or specify the `agentAddr` parameter: | ||
The following example sends a generic link-down trap to a remote host using a | ||
SNMP version 1 trap, it does not include any varbinds or specify the | ||
`agentAddr` parameter: | ||
session.trap (snmp.TrapType.LinkDown, function (error) { | ||
if (error) | ||
console.error (error); | ||
}); | ||
session.trap (snmp.TrapType.LinkDown, function (error) { | ||
if (error) | ||
console.error (error); | ||
}); | ||
The following example sends an enterprise specific trap to a remote host using | ||
a SNMP version 2c trap, and includes two enterprise specific varbinds: | ||
var trapOid = "1.3.6.1.4.1.2000.1"; | ||
var varbinds = [ | ||
{ | ||
oid: "1.3.6.1.4.1.2000.2", | ||
type: snmp.Type.OctetString, | ||
value: "Hardware health status changed" | ||
}, | ||
{ | ||
oid: "1.3.6.1.4.1.2000.3", | ||
type: snmp.Type.OctetString, | ||
value: "status-error" | ||
} | ||
]; | ||
// version 2c should have been specified when creating the session | ||
session.trap (trapOid, varbinds, function (error) { | ||
if (error) | ||
console.error (error); | ||
}); | ||
## session.inform (typeOrOid, [varbinds], callback) | ||
The `inform()` method sends a SNMP inform to a remote host. | ||
The `typeOrOid` parameter can be one of two types; one of the constants | ||
defined in the `snmp.TrapType` object (excluding the | ||
`snmp.TrapType.EnterpriseSpecific` constant), or an OID string. | ||
The first varbind to be placed in the request message will be for the | ||
`sysUptime.0` OID (`1.3.6.1.6.3.1.1.4.1.0`). The value for this varbind will | ||
be the value returned by the `process.uptime ()` function multiplied by 100. | ||
This will be followed by a second varbind for the `snmpTrapOID.0` OID | ||
(`1.3.6.1.6.3.1.1.4.1.0`). The value for this will depend on the `typeOrOid` | ||
parameter. If a constant is specified the trap OID for the constant will be | ||
used as supplied for the varbinds value, otherwise the OID string specified | ||
will be used as is for the value of the varbind. | ||
The optional `varbinds` parameter is an array of varbinds to include in the | ||
inform request, and defaults to the empty array `[]`. | ||
The `callback` function is called once the trap has been sent, or an error | ||
occurred. The following arguments will be passed to the `callback` function: | ||
* `error` - Instance of the Error class or a sub-class, or `null` if no error | ||
occurred | ||
* `varbinds` - Array of varbinds, will not be provided if an error occurred | ||
The varbind in position N in the `varbinds` array will correspond to the | ||
varbind in position N in the `varbinds` array in the request. The remote host | ||
should echo back varbinds and their values as specified in the request, and | ||
the `varbinds` array will contain each varbind as sent back by the remote host. | ||
Normally there is no reason to use the contents of the `varbinds` parameter | ||
since the varbinds are as they were sent in the request. | ||
The following example sends a generic cold-start inform to a remote host, | ||
it does not include any varbinds: | ||
session.inform (snmp.TrapType.ColdStart, function (error) { | ||
if (error) | ||
console.error (error); | ||
}); | ||
The following example sends an enterprise specific inform to a remote host, | ||
and includes two enterprise specific varbinds: | ||
var informOid = "1.3.6.1.4.1.2000.1"; | ||
var varbinds = [ | ||
{ | ||
oid: "1.3.6.1.4.1.2000.2", | ||
type: snmp.Type.OctetString, | ||
value: "Periodic hardware self-check" | ||
}, | ||
{ | ||
oid: "1.3.6.1.4.1.2000.3", | ||
type: snmp.Type.OctetString, | ||
value: "hardware-ok" | ||
} | ||
]; | ||
session.inform (informOid, varbinds, function (error) { | ||
if (error) | ||
console.error (error); | ||
}); | ||
## session.walk (oids, callback) | ||
This `walk()` method is not actually implemented by the API. The main reason | ||
being that the semantics of the callback function when more than one OID is | ||
specified in the request is ambiguous. | ||
This `walk()` method is not actually implemented by this module. The main | ||
reason being that the semantics of the callback function when more than one | ||
OID is specified in the request is ambiguous. | ||
Instead of exposing a `walk()` method an example implementation which supports | ||
walking a single OID is provided: | ||
Instead an example implementation which supports walking a single OID using | ||
both SNMP version 1 and 2c is provided, with comments: | ||
var oid = "1.3.6.1"; | ||
function responseCb (error, varbinds) { | ||
if (error) { | ||
// When we reach the end of the MIB view the remote host will respond | ||
// with the error-index field set to NoSuchName, this will be passed | ||
// to this callback as a RequestFailedError with status set to the | ||
// constant snmp.ErrorStatus.NoSuchName, this indicates we can stop | ||
// performing get-next-requests: | ||
if (error instanceof snmp.RequestFailedError) { | ||
if (error.status != snmp.ErrorStatus.NoSuchName) { | ||
console.error (error.toString ()); | ||
} | ||
} else { | ||
console.error (error.toString ()); | ||
} | ||
} else { | ||
var oids = []; | ||
for (var i = 0; i < varbinds.length; i++) { | ||
console.log (varbinds[i].oid + "|" + varbinds[i].type + "|" | ||
+ varbinds[i].value); | ||
// Use the varbinds returned to work out which OIDs to specify in | ||
// the next get-next-request: | ||
oids.push (varbinds[i].oid); | ||
} | ||
walk (oids, cb); | ||
} | ||
} | ||
function walk (oids, responseCb) { | ||
// We only support a single OID so the first call to this function will | ||
// be performed using an OID string, the getNext() method wants an array | ||
// so we'll implicitly convert it here for the initial request, all | ||
// other requests made by the responseCb() callback above will be | ||
// performed using OID arrays | ||
if (typeof oids == "string") | ||
oids = [oids]; | ||
session.getNext (oids, responseCb); | ||
} | ||
walk (oid, responseCb); | ||
var oid = "1.3.6.1"; | ||
function responseCb (error, varbinds) { | ||
if (error) { | ||
// When we reach the end of the MIB view the remote host will | ||
// respond with the error-index field set to NoSuchName, this | ||
// will be passed to this callback as a RequestFailedError with | ||
// status set to the constant snmp.ErrorStatus.NoSuchName, this | ||
// indicates we can stop performing get-next-requests, this will | ||
// work for version 1 only, for version 2c we will end the walk by | ||
// looking for a varbind with a value of type | ||
// `snmp.ObjectType.EndOfMibView` which will be checked later: | ||
if (error instanceof snmp.RequestFailedError) { | ||
if (error.status != snmp.ErrorStatus.NoSuchName) { | ||
console.error (error.toString ()); | ||
} | ||
} else { | ||
console.error (error.toString ()); | ||
} | ||
} else { | ||
var oids; | ||
if (session.version == snmp.Version2c) { | ||
// Use the last varbind returned to work out which OID to | ||
// specify in the next get-bulk-request, remember the | ||
// semantics of the getBulk() callback, our first and only | ||
// varbind item will be an array of varbinds: | ||
if (! snmp.isVarbindError (varbinds[0][varbinds[0].length - 0])) | ||
oids = varbinds[0][varbinds[0].length - 0].oid; | ||
for (var i = 0; i < varbinds[0].length; i++) { | ||
console.log (varbinds[0][i].oid + "|" + varbinds[0][i].type | ||
+ "|" + varbinds[0][i].value); | ||
} | ||
} else { | ||
// Use the only varbind returned to work out which OID to | ||
// specify in the next get-next-request: | ||
oids = [varbinds[0].oid]; | ||
console.log (varbinds[0].oid + "|" + varbinds[0].type + "|" | ||
+ varbinds[0].value); | ||
} | ||
} | ||
walk (oids, cb); | ||
} | ||
function walk (version, oids, responseCb) { | ||
// We only support a single OID so the first call to this function will | ||
// be performed using an OID string, the getNext() and getBulk() | ||
// methods want an arrays so we'll implicitly convert it here for the | ||
// initial request, all other requests made by the responseCb() | ||
// callback above will be performed using OID arrays | ||
if (typeof oids == "string") | ||
oids = [oids]; | ||
if (session.version == snmp.Version2c) | ||
session.getBulk (oids, 0, 20, responseCb); | ||
else | ||
session.getNext (oids, responseCb); | ||
} | ||
walk (oid, responseCb); | ||
@@ -442,2 +825,12 @@ # Example Programs | ||
Please report bugs to <stephen.vickers.sv@gmail.com>. | ||
# Roadmap | ||
In no particular order: | ||
* Helper functions (`getTable()`, `getSubtree()`, `walk()`) | ||
* Extensible SNMP agent | ||
* SNMP version 3 | ||
# License | ||
@@ -444,0 +837,0 @@ |
Sorry, the diff of this file is not supported yet
483029
19
1096
842