diff --git a/io/snmp/package.json b/io/snmp/package.json index f812391e..e8d1472b 100644 --- a/io/snmp/package.json +++ b/io/snmp/package.json @@ -1,9 +1,9 @@ { "name" : "node-red-node-snmp", - "version" : "0.0.26", + "version" : "0.1.0", "description" : "A Node-RED node that looks for SNMP oids.", "dependencies" : { - "net-snmp" : "2.9.6" + "net-snmp" : "3.6.2" }, "repository" : { "type":"git", @@ -24,6 +24,7 @@ "contributors": [ { "name": "Mika Karaila" }, { "name": "Bryan Malyn" }, + { "name": "Steve-Mcl" }, { "name": "Andres" } ] } diff --git a/io/snmp/snmp.html b/io/snmp/snmp.html index 0df25340..f25eec46 100644 --- a/io/snmp/snmp.html +++ b/io/snmp/snmp.html @@ -1,3 +1,47 @@ + + @@ -123,49 +172,49 @@ Timeout  S -
+
-
+
-
- +
+
-
- +
+ - Priv.Prot. +
+
+ + +
+
+
-
- - -
-
- +
+
-
@@ -179,18 +228,18 @@

Simple snmp Set node. Trigger by any input

msg.host may contain the host.

msg.community may contain the community.

-

msg.username may contain the username.

-

msg.authkey may contain the digest security key.

-

msg.privkey may contain the encryption security key.

+

msg.username may contain the username. (V3 only)

+

msg.authkey may contain the digest security key. (V3 only)

+

msg.privkey may contain the encryption security key. (V3 only)

msg.varbinds may contain varbinds as an array of json objects containing multiple oids, types and values. -

[
-    {
-        "oid":   "1.3.6.1.2.1.1.5.0",
-        "type":  "OctetString",
-        "value": "host1"
-    },
-    {   "oid":   ... }
-]
+
[
+  {
+    "oid": "1.3.6.1.2.1.1.5.0",
+    "type": "OctetString",
+    "value": "host1"
+  },
+  { "oid": ... }
+]

Any numeric inputs must be numbers, not strings, e.g. 1 not "1".

OIDs must be numeric. iso. is the same a 1.

@@ -205,15 +254,24 @@ version: { value: "v1", required: true }, timeout: { value: 5 }, community: { value: "public" }, - username: { value: "" }, auth: { value: "noAuthNoPriv", required: true }, - authprot: { value: "None", required: true }, - privprot: { value: "None", required: true }, - authkey: { value: "" }, - privkey: { value: "" }, - varbinds: { value: "" }, + authprot: { value: "MD5", required: true }, + privprot: { value: "DES", required: true }, + oids: { value: "" }, + varbinds: { value: "", validate:function(v) { + try { + return !v || !!JSON.parse(v); + } catch(e) { + return false; + } + }}, name: { value: "" } }, + credentials: { + username: { type: "text" }, + authkey: { type: "password" }, + privkey: { type: "password" } + }, inputs: 1, outputs: 0, icon: "snmp.png", @@ -222,6 +280,9 @@ }, labelStyle: function () { return this.name ? "node_label_italic" : ""; + }, + oneditprepare: function () { + node_snmp_common.oneditprepare(this); } }); @@ -243,43 +304,43 @@ Timeout  S
-
+
-
+
-
- +
+
-
- +
+ - Priv.Prot. +
+
+ + +
+
+
-
- - -
-
- +
+
@@ -298,9 +359,9 @@

Simple SNMP oid table fetcher. Triggered by any input.

msg.host may contain the host.

msg.community may contain the community.

-

msg.username may contain the username.

-

msg.authkey may contain the digest security key.

-

msg.privkey may contain the encryption security key.

+

msg.username may contain the username. (V3 only)

+

msg.authkey may contain the digest security key. (V3 only)

+

msg.privkey may contain the encryption security key. (V3 only)

msg.oid may contain the oid of a table to request.

OID must be numeric. iso. is the same a 1.

The node will output msg.payload and msg.oid.

@@ -315,15 +376,17 @@ version: { value: "v1", required: true }, timeout: { value: 5 }, community: { value: "public" }, - username: { value: "" }, auth: { value: "noAuthNoPriv", required: true }, - authprot: { value: "None", required: true }, - privprot: { value: "None", required: true }, - authkey: { value: "" }, - privkey: { value: "" }, + authprot: { value: "MD5", required: true }, + privprot: { value: "DES", required: true }, oids: { value: "" }, name: { value: "" } }, + credentials: { + username: { type: "text" }, + authkey: { type: "password" }, + privkey: { type: "password" } + }, inputs: 1, outputs: 1, icon: "snmp.png", @@ -332,6 +395,9 @@ }, labelStyle: function () { return this.name ? "node_label_italic" : ""; + }, + oneditprepare: function () { + node_snmp_common.oneditprepare(this); } }); @@ -353,43 +419,43 @@ Timeout  S
-
+
-
+
-
- +
+
-
- +
+ - Priv.Prot. +
+
+ + +
+
+
-
- - -
-
- +
+
@@ -408,9 +474,9 @@

Simple SNMP oid subtree fetcher. Triggered by any input. Reads all OIDS at and below the current base OID.

msg.host may contain the host.

msg.community may contain the community.

-

msg.username may contain the username.

-

msg.authkey may contain the digest security key.

-

msg.privkey may contain the encryption security key.

+

msg.username may contain the username. (V3 only)

+

msg.authkey may contain the digest security key. (V3 only)

+

msg.privkey may contain the encryption security key. (V3 only)

msg.oid may contain the oid of a table to request.

OID must be numeric. iso. is the same a 1.

The node will output msg.payload and msg.oid.

@@ -425,15 +491,17 @@ version: { value: "v1", required: true }, timeout: { value: 5 }, community: { value: "public" }, - username: { value: "" }, auth: { value: "noAuthNoPriv", required: true }, - authprot: { value: "None", required: true }, - privprot: { value: "None", required: true }, - authkey: { value: "" }, - privkey: { value: "" }, + authprot: { value: "MD5", required: true }, + privprot: { value: "DES", required: true }, oids: { value: "" }, name: { value: "" } }, + credentials: { + username: { type: "text" }, + authkey: { type: "password" }, + privkey: { type: "password" } + }, inputs: 1, outputs: 1, icon: "snmp.png", @@ -442,6 +510,9 @@ }, labelStyle: function () { return this.name ? "node_label_italic" : ""; + }, + oneditprepare: function () { + node_snmp_common.oneditprepare(this); } }); @@ -464,43 +535,43 @@ Timeout  S
-
+
-
+
-
- +
+
-
- +
+ - Priv.Prot. +
+
+ + +
+
+
-
- - -
-
- +
+
@@ -520,9 +591,9 @@ Fetches all nodes from this OID to the end of the table.

msg.host may contain the host.

msg.community may contain the community.

-

msg.username may contain the username.

-

msg.authkey may contain the digest security key.

-

msg.privkey may contain the encryption security key.

+

msg.username may contain the username. (V3 only)

+

msg.authkey may contain the digest security key. (V3 only)

+

msg.privkey may contain the encryption security key. (V3 only)

msg.oid may contain the oid of a table to request.

OID must be numeric. iso. is the same a 1.

The node will output msg.payload and msg.oid.

@@ -539,15 +610,17 @@ version: { value: "v1", required: true }, timeout: { value: 5 }, community: { value: "public" }, - username: { value: "" }, auth: { value: "noAuthNoPriv", required: true }, - authprot: { value: "None", required: true }, - privprot: { value: "None", required: true }, - authkey: { value: "" }, - privkey: { value: "" }, + authprot: { value: "MD5", required: true }, + privprot: { value: "DES", required: true }, oids: { value: "" }, name: { value: "" } }, + credentials: { + username: { type: "text" }, + authkey: { type: "password" }, + privkey: { type: "password" } + }, inputs: 1, outputs: 1, icon: "snmp.png", @@ -556,6 +629,9 @@ }, labelStyle: function () { return this.name ? "node_label_italic" : ""; + }, + oneditprepare: function () { + node_snmp_common.oneditprepare(this); } }); diff --git a/io/snmp/snmp.js b/io/snmp/snmp.js index 29fd102e..501b4af9 100644 --- a/io/snmp/snmp.js +++ b/io/snmp/snmp.js @@ -1,429 +1,479 @@ module.exports = function (RED) { "use strict"; - var snmp = require("net-snmp"); - - var sessions = {}; - - function openSession(host, data, options) { - //console.log({data}); - //console.log({options}); - var sessionid = data.sessionid; - options.port = 161; - if (host.indexOf(":") !== -1) { - options.port = host.split(":")[1]; - host = host.split(":")[0]; - } - // SNMPv3 call - if (options.version === "v3"){ - var user = {}; - options.version = snmp.Version3; - user.name = data.name || ""; - user.level = snmp.SecurityLevel.noAuthNoPriv; - if (data.auth === "authNoPriv" || data.auth === "authPriv" ) { - user.level = snmp.SecurityLevel.authNoPriv; - user.authKey = data.authkey || ""; - user.authProtocol = (data.authprot === "SHA") ? snmp.AuthProtocols.sha : snmp.AuthProtocols.md5; - if (data.auth === "authPriv" ) { - user.level = snmp.SecurityLevel.authPriv; - if (data.privprot === "DES" || data.privprot === "AES"){ - user.privProtocol = (data.privprot === "AES") ? snmp.PrivProtocols.aes : snmp.PrivProtocols.des; - user.privKey = data.privkey || ""; - } - } + const SNMP = require("net-snmp"); + const sessions = {}; + function generateUUID() { + let d = Date.now(); + let d2 = ((typeof performance !== 'undefined') && performance.now && (performance.now() * 1000)) || (Date.now() * Math.random() * 100000);//Time in microseconds since load + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + let r = Math.random() * 16;//random number between 0 and 16 + if (d > 0) {//Use timestamp until depleted + r = (d + r) % 16 | 0; + d = Math.floor(d / 16); + } else {//Use microseconds since page-load if supported + r = (d2 + r) % 16 | 0; + d2 = Math.floor(d2 / 16); } - sessions[sessionid] = snmp.createV3Session(host, user, options); + return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); + }); + } + function openSession(sessionid, host, user, options) { + // SNMPv3 call + if (options.version === SNMP.Version3) { + sessions[sessionid] = SNMP.createV3Session(host, user, options); } // SNMPv1 or SNMPv2c call - else{ - var community = data.community; - options.version = (options.version === "v2c") ? snmp.Version2c : snmp.Version1; - sessions[sessionid] = snmp.createSession(host, community, options); + else { + sessions[sessionid] = SNMP.createSession(host, user.community, options); } return sessions[sessionid]; } // Any session needs to be closed after completion function closeSession(sessionid) { - //console.log("closing session"); - sessions[sessionid].close(); + try { + sessions[sessionid].removeAllListeners(); + } catch (e) { } + try { + sessions[sessionid].close(); + } catch (e) { } + delete sessions[sessionid]; } - function SnmpNode(n) { - RED.nodes.createNode(this, n); - this.community = n.community; - this.host = n.host; - this.version = n.version; - this.username = n.username; - this.auth = n.auth; - this.authprot = n.authprot; - this.privprot = n.privprot; - this.authkey = n.authkey; - this.privkey = n.privkey; - this.oids = n.oids.replace(/\s/g, ""); - this.timeout = Number(n.timeout || 5) * 1000; - var node = this; + function initSnmpNode(node, config) { + node.community = config.community; + node.host = config.host; + node.version = config.version; + node.auth = config.auth; + node.authprot = config.authprot; + node.privprot = config.privprot; + if (node.credentials) { + node.username = node.credentials.username; + node.authkey = node.credentials.authkey; + node.privkey = node.credentials.privkey; + } + node.timeout = Number(config.timeout || 5) * 1000; + } - this.on("input", function (msg) { - var host = node.host || msg.host; - var version = node.version; - var community = node.community || msg.community; - var username = node.username || msg.username; - var auth = node.auth; - var authprot = node.authprot; - var privprot = node.privprot; - var authkey = node.authkey || msg.authkey; - var privkey = node.privkey || msg.privkey; - var oids = node.oids || msg.oid; - var sessionid = Date.now(); // Create an unique session ID for each call - var data = {}; - data.community = community; - data.name = username; - data.auth = auth; - data.authprot = authprot; - data.privprot = privprot; - data.authkey = authkey; - data.privkey = privkey; - data.sessionid = sessionid; - var options = {}; - options.version = version; - options.timeout = node.timeout; + function prepareSnmpOptions(node, msg) { + let host = node.host || msg.host; + const sessionid = generateUUID(); + const user = {} + const options = {}; + + options.version = node.version; + if (node.version === "v1") { + options.version = SNMP.Version1; + user.community = node.community || msg.community; + } else if (node.version === "v2c") { + options.version = SNMP.Version2c; + user.community = node.community || msg.community; + } else if (node.version === "v3") { + user.name = node.username || msg.username || ""; + user.level = SNMP.SecurityLevel.noAuthNoPriv; + user.authProtocol = SNMP.AuthProtocols.none; + user.authKey = ""; + user.privProtocol = SNMP.PrivProtocols.none; + user.privKey = ""; + options.version = SNMP.Version3; + if (node.auth === "authNoPriv" || node.auth === "authPriv") { + user.level = SNMP.SecurityLevel.authNoPriv; + user.authProtocol = (node.authprot === "SHA") ? SNMP.AuthProtocols.sha : SNMP.AuthProtocols.md5; + user.authKey = node.authkey || msg.authkey || ""; + if (node.auth === "authPriv") { + user.level = SNMP.SecurityLevel.authPriv; + if (node.privprot === "DES" || node.privprot === "AES") { + user.privProtocol = (node.privprot === "AES") ? SNMP.PrivProtocols.aes : SNMP.PrivProtocols.des; + user.privKey = node.privkey || msg.privkey || ""; + } + } + } + } + + options.timeout = node.timeout; + options.debug = msg.debug || undefined; + options.port = options.port || 161; + options.retries = options.retries || 1; + + if (msg.engineID) { + options.engineID = msg.engineID;//The engineID used for SNMPv3 communications, given as a hex string - defaults to a system-generated engineID containing elements of random + } + if (msg.backoff) { + options.backoff = msg.backoff;//The factor by which to increase the timeout for every retry, defaults to 1 for no increase + } + if (msg.backwardsGetNexts) { + options.backwardsGetNexts = msg.backwardsGetNexts;//boolean to allow GetNext operations to retrieve lexicographically preceding OIDs + } + if (msg.idBitsSize === 16 || msg.idBitsSize === 32) { + options.idBitsSize = msg.idBitsSize;//Either 16 or 32, defaults to 32. Used to reduce the size of the generated id for compatibility with some older devices. + } + const ipv = parseIP(host); + if (ipv.version === 4) { + host = ipv.ip; + options.port = ipv.port || options.port; + options.transport = 'udp4'; + } else if (ipv.version === 6) { + host = ipv.ip; + options.port = ipv.port || options.port; + options.transport = 'udp6'; + } else { + //probably a host name + if (host.indexOf(":") > 0) { + host = host.split(":")[0]; + options.port = host.split(":")[1]; + } + } + return { + host: host, + sessionid: sessionid, + user: user, + options: options, + } + } + function parseIP(ip) { + const IPV4_PAT = /^(\d+)\.(\d+)\.(\d+)\.(\d+)(?::(\d+)){0,1}$/g; + const IPV6_DOUBLE_COL_PAT = /^\[{0,1}([0-9a-f:]*)::([0-9a-f:]*)(?:\]:(\d+)){0,1}$/g; + const ipv4Matcher = IPV4_PAT.exec(ip); + let hex = ""; + let port = undefined; + let ipOnly = []; + try { + + if (ipv4Matcher && ipv4Matcher.length) { + for (let i = 1; i <= 4; i++) { + ipOnly.push(ipv4Matcher[i]); + hex += toHex4(ipv4Matcher[i]); + } + if (ipv4Matcher[5]) { + port = parseInt(ipv4Matcher[5]); + } + return { ip: ipOnly.join("."), hex, port, version: 4 }; + } + + // IPV6 Must be colons format (a:b:c:d:e:A.B.C.D not currently supported) + let ipv6Pattern = "^\\[{0,1}"; + for (let i = 1; i <= 7; i++) { + ipv6Pattern += "([0-9a-f]+):"; + } + ipv6Pattern += "([0-9a-f]+)(?:\\]:(\\d+)){0,1}$"; + const IPV6_PAT = new RegExp(ipv6Pattern); + + + // IPV6, double colon + const ipv6DoubleColonMatcher = IPV6_DOUBLE_COL_PAT.exec(ip); + if (ipv6DoubleColonMatcher && ipv6DoubleColonMatcher.length) { + let p1 = ipv6DoubleColonMatcher[1]; + if (!p1) { + p1 = "0"; + } + let p2 = ipv6DoubleColonMatcher[2]; + if (!p2) { + p2 = "0"; + } + p1 = p1.padStart(4, "0"); + p2 = p2.padStart(4, "0"); + ip = p1 + getZeros(8 - numCount(p1) - numCount(p2)) + p2; + if (ipv6DoubleColonMatcher[3]) { + ip = "[" + ip + "]:" + ipv6DoubleColonMatcher[3]; + } + } + + // IPV6 + const ipv6Matcher = IPV6_PAT.exec(ip); + if (ipv6Matcher && ipv6Matcher.length) { + for (let i = 1; i <= 8; i++) { + const p = toHex6(ipv6Matcher[i]).padStart(4, "0"); + ipOnly.push(p); + hex += p; + } + if (ipv6Matcher[9]) { + port = parseInt(ipv6Matcher[9]); + } + return { ip: ipOnly.join(":"), hex, port, version: 6 }; + } + + throw new Error("Unknown address: " + ip); + } catch (error) { + return { ip, hex, port, version: null, error: error }; + } + + function numCount(/** @type {string} */s) { + return s.split(":").length; + } + function getZeros(/** @type {number} */ count) { + const sb = [":"]; + while (count > 0) { + sb.push("0000:"); + count--; + } + return sb.join(""); + } + function toHex4(/** @type {string} */ s) { + const val = parseInt(s); + if (val < 0 || val > 255) { + throw new Error("Invalid value : " + s); + } + return val.toString(16).padStart(2, "0"); + } + function toHex6(/** @type {string} */ s) { + const val = parseInt(s, 16); + if (val < 0 || val > 65536) { + throw new Error("Invalid hex value : " + s); + } + return s; + } + } + function SnmpNode(n) { + const node = this; + RED.nodes.createNode(node, n); + initSnmpNode(node, n); + node.oids = n.oids ? n.oids.replace(/\s/g, "") : ""; + + node.on("input", function (msg) { + const oids = node.oids || msg.oid; + const { host, sessionid, user, options } = prepareSnmpOptions(node, msg); if (oids) { - openSession(host, data, options).get(oids.split(","), function (error, varbinds) { + let sess = openSession(sessionid, host, user, options); + sess.on("error", function (err) { + node.error(err, msg); + }) + sess.get(oids.split(","), function (error, varbinds) { if (error) { node.error(error.toString(), msg); - } - else { - for (var i = 0; i < varbinds.length; i++) { - if (snmp.isVarbindError(varbinds[i])) { - node.error(snmp.varbindError(varbinds[i]), msg); + } else { + for (let i = 0; i < varbinds.length; i++) { + let vb = varbinds[i]; + if (SNMP.isVarbindError(vb)) { + node.error(SNMP.varbindError(vb), msg); + vb._error = SNMP.varbindError(vb); //add _error to msg so users can determine the varbind is not valid } else { - if (varbinds[i].type == 4) { varbinds[i].value = varbinds[i].value.toString(); } - varbinds[i].tstr = snmp.ObjectType[varbinds[i].type]; - // node.log(varbinds[i].oid + "|" + varbinds[i].tstr + "|" + varbinds[i].value); + if (vb.type == 4) { vb.value = vb.value.toString(); } } + vb.tstr = SNMP.ObjectType[vb.type]; } - msg.oid = oids; msg.payload = varbinds; + msg.oid = oids; node.send(msg); } closeSession(sessionid); // Needed to close the session else a bad or good read could affect future readings }); - } - else { + } else { node.warn("No oid(s) to search for"); } }); } - RED.nodes.registerType("snmp", SnmpNode); + RED.nodes.registerType("snmp", SnmpNode, { + credentials: { + username: { type: "text" }, + authkey: { type: "password" }, + privkey: { type: "password" } + } + }); function SnmpSNode(n) { - RED.nodes.createNode(this, n); - this.community = n.community; - this.host = n.host; - this.version = n.version; - this.username = n.username; - this.auth = n.auth; - this.authprot = n.authprot; - this.privprot = n.privprot; - this.authkey = n.authkey; - this.privkey = n.privkey; - this.timeout = Number(n.timeout || 5) * 1000; - this.varbinds = n.varbinds; - if (this.varbinds && this.varbinds.trim().length === 0) { delete this.varbinds; } - var node = this; - this.on("input", function (msg) { - var host = node.host || msg.host; - var version = node.version; - var community = node.community || msg.community; - var username = node.username || msg.username; - var auth = node.auth; - var authprot = node.authprot; - var privprot = node.privprot; - var authkey = node.authkey || msg.authkey; - var privkey = node.privkey || msg.privkey; - var sessionid = Date.now(); - var data = {}; - data.community = community; - data.name = username; - data.auth = auth; - data.authprot = authprot; - data.privprot = privprot; - data.authkey = authkey; - data.privkey = privkey; - data.sessionid = sessionid; - var options = {}; - options.version = version; - options.timeout = node.timeout; - var varbinds = (node.varbinds) ? JSON.parse(node.varbinds) : msg.varbinds; + const node = this; + RED.nodes.createNode(node, n); + initSnmpNode(node, n); + node.varbinds = n.varbinds; + if (node.varbinds && node.varbinds.trim().length === 0) { delete node.varbinds; } + node.on("input", function (msg) { + const { host, sessionid, user, options } = prepareSnmpOptions(node, msg); + const varbinds = (node.varbinds) ? JSON.parse(node.varbinds) : msg.varbinds; if (varbinds) { - for (var i = 0; i < varbinds.length; i++) { - varbinds[i].type = snmp.ObjectType[varbinds[i].type]; + for (let i = 0; i < varbinds.length; i++) { + varbinds[i].type = SNMP.ObjectType[varbinds[i].type]; } - openSession(host, data, options).set(varbinds, function (error, varbinds) { + let sess = openSession(sessionid, host, user, options); + sess.on("error", function (err) { + node.error(err, msg); + }) + sess.set(varbinds, function (error, varbinds) { if (error) { node.error(error.toString(), msg); - } - else { - for (var i = 0; i < varbinds.length; i++) { + } else { + for (let i = 0; i < varbinds.length; i++) { // for version 2c we must check each OID for an error condition - if (snmp.isVarbindError(varbinds[i])) { - node.error(snmp.varbindError(varbinds[i]), msg); + if (SNMP.isVarbindError(varbinds[i])) { + node.error(SNMP.varbindError(varbinds[i]), msg); } } } closeSession(sessionid); }); - } - else { + } else { node.warn("No varbinds to set"); } }); } - RED.nodes.registerType("snmp set", SnmpSNode); + RED.nodes.registerType("snmp set", SnmpSNode, { + credentials: { + username: { type: "text" }, + authkey: { type: "password" }, + privkey: { type: "password" } + } + }); function SnmpTNode(n) { - RED.nodes.createNode(this, n); - this.community = n.community; - this.host = n.host; - this.version = n.version; - this.username = n.username; - this.auth = n.auth; - this.authprot = n.authprot; - this.privprot = n.privprot; - this.authkey = n.authkey; - this.privkey = n.privkey; - this.oids = n.oids.replace(/\s/g, ""); - this.timeout = Number(n.timeout || 5) * 1000; - var node = this; - var maxRepetitions = 20; + const node = this; + RED.nodes.createNode(node, n); + initSnmpNode(node, n); + node.oids = n.oids ? n.oids.replace(/\s/g, "") : "" + const maxRepetitions = 20; function sortInt(a, b) { if (a > b) { return 1; } - else if (b > a) { return -1; } - else { return 0; } + else if (b > a) { return -1; } else { return 0; } } - this.on("input", function (msg) { - var host = node.host || msg.host; - var version = node.version; - var community = node.community || msg.community; - var username = node.username || msg.username; - var auth = node.auth; - var authprot = node.authprot; - var privprot = node.privprot; - var authkey = node.authkey || msg.authkey; - var privkey = node.privkey || msg.privkey; - var oids = node.oids || msg.oid; - var sessionid = Date.now(); - var data = {}; - data.community = community; - data.name = username; - data.auth = auth; - data.authprot = authprot; - data.privprot = privprot; - data.authkey = authkey; - data.privkey = privkey; - data.sessionid = sessionid; - var options = {}; - options.version = version; - options.timeout = node.timeout; - node.log({options}); + node.on("input", function (msg) { + const oids = node.oids || msg.oid; + const { host, sessionid, user, options } = prepareSnmpOptions(node, msg); if (oids) { msg.oid = oids; - openSession(host, data, options).table(oids, maxRepetitions, function (error, table) { + let sess = openSession(sessionid, host, user, options); + sess.on("error", function (err) { + node.error(err, msg); + }) + sess.table(oids, maxRepetitions, function (error, table) { if (error) { node.error(error.toString(), msg); - } - else { - var indexes = []; - for (var index in table) { + } else { + const indexes = []; + for (let index in table) { if (table.hasOwnProperty(index)) { indexes.push(parseInt(index)); } } indexes.sort(sortInt); - for (var i = 0; i < indexes.length; i++) { - var columns = []; - for (var column in table[indexes[i]]) { + for (let i = 0; i < indexes.length; i++) { + const columns = []; + for (let column in table[indexes[i]]) { if (table[indexes[i]].hasOwnProperty(column)) { columns.push(parseInt(column)); } } columns.sort(sortInt); - // console.log("row index = " + indexes[i]); - // for (var j = 0; j < columns.length; j++) { - // console.log(" column " + columns[j] + " = " + table[indexes[i]][columns[j]]); - // } } msg.payload = table; node.send(msg); } closeSession(sessionid); }); - } - else { + } else { node.warn("No oid to search for"); } }); } - RED.nodes.registerType("snmp table", SnmpTNode); + RED.nodes.registerType("snmp table", SnmpTNode, { + credentials: { + username: { type: "text" }, + authkey: { type: "password" }, + privkey: { type: "password" } + } + }); function SnmpSubtreeNode(n) { - RED.nodes.createNode(this, n); - this.community = n.community; - this.host = n.host; - this.version = n.version; - this.username = n.username; - this.auth = n.auth; - this.authprot = n.authprot; - this.privprot = n.privprot; - this.authkey = n.authkey; - this.privkey = n.privkey; - this.oids = n.oids.replace(/\s/g, ""); - this.timeout = Number(n.timeout || 5) * 1000; - var node = this; - var maxRepetitions = 20; - var response = []; + const node = this; + RED.nodes.createNode(node, n); + initSnmpNode(node, n); + node.oids = n.oids ? n.oids.replace(/\s/g, "") : "" + const maxRepetitions = 20; - function feedCb(varbinds) { - for (var i = 0; i < varbinds.length; i++) { - if (snmp.isVarbindError(varbinds[i])) { - node.error(snmp.varbindError(varbinds[i]), msg); - } - else { - //console.log(varbinds[i].oid + "|" + varbinds[i].value); - response.push({ oid: varbinds[i].oid, value: varbinds[i].value }); - } - } - } - - this.on("input", function (msg) { - var host = node.host || msg.host; - var version = node.version; - var community = node.community || msg.community; - var username = node.username || msg.username; - var auth = node.auth; - var authprot = node.authprot; - var privprot = node.privprot; - var authkey = node.authkey || msg.authkey; - var privkey = node.privkey || msg.privkey; - var oids = node.oids || msg.oid; - var sessionid = Date.now(); - var data = {}; - data.community = community; - data.name = username; - data.auth = auth; - data.authprot = authprot; - data.privprot = privprot; - data.authkey = authkey; - data.privkey = privkey; - data.sessionid = sessionid; - var options = {}; - options.version = version; - options.timeout = node.timeout; + node.on("input", function (msg) { + const oids = node.oids || msg.oid; + const { host, sessionid, user, options } = prepareSnmpOptions(node, msg); if (oids) { msg.oid = oids; - openSession(host, data, options).subtree(msg.oid, maxRepetitions, feedCb, function (error) { + let sess = openSession(sessionid, host, user, options); + sess.on("error", function (err) { + node.error(err, msg); + }) + //move response array & feedCb to inside `node.on("input",` to avoid subsequent + // calls overwriting results from previous operations (each call gets own result/response) + const response = []; + function feedCb(varbinds) { + for (let i = 0; i < varbinds.length; i++) { + if (SNMP.isVarbindError(varbinds[i])) { + node.error(SNMP.varbindError(varbinds[i]), msg); + } else { + response.push({ oid: varbinds[i].oid, value: varbinds[i].value }); + } + } + } + sess.subtree(msg.oid, maxRepetitions, feedCb, function (error) { if (error) { node.error(error.toString(), msg); - } - else { - // Clone the array - msg.payload = response.slice(0); + } else { + msg.payload = response; node.send(msg); - //Clears response - response.length = 0; } closeSession(sessionid); }); - } - else { + } else { node.warn("No oid to search for"); } }); } - RED.nodes.registerType("snmp subtree", SnmpSubtreeNode); - + RED.nodes.registerType("snmp subtree", SnmpSubtreeNode, { + credentials: { + username: { type: "text" }, + authkey: { type: "password" }, + privkey: { type: "password" } + } + }); function SnmpWalkerNode(n) { - RED.nodes.createNode(this, n); - this.community = n.community; - this.host = n.host; - this.version = n.version; - this.username = n.username; - this.auth = n.auth; - this.authprot = n.authprot; - this.privprot = n.privprot; - this.authkey = n.authkey; - this.privkey = n.privkey; - this.oids = n.oids.replace(/\s/g, ""); - this.timeout = Number(n.timeout || 5) * 1000; - var node = this; - var maxRepetitions = 20; - var response = []; + const node = this; + RED.nodes.createNode(node, n); + initSnmpNode(node, n); + node.oids = n.oids ? n.oids.replace(/\s/g, "") : "" + const maxRepetitions = 20; - function feedCb(varbinds) { - for (var i = 0; i < varbinds.length; i++) { - if (snmp.isVarbindError(varbinds[i])) { - node.error(snmp.varbindError(varbinds[i]), msg); - } - else { - //console.log(varbinds[i].oid + "|" + varbinds[i].value); - response.push({ oid: varbinds[i].oid, value: varbinds[i].value }); - } - } - } - - this.on("input", function (msg) { - node.msg = msg; - var host = node.host || msg.host; - var version = node.version; - var community = node.community || msg.community; - var username = node.username || msg.username; - var auth = node.auth; - var authprot = node.authprot; - var privprot = node.privprot; - var authkey = node.authkey || msg.authkey; - var privkey = node.privkey || msg.privkey; - var oids = node.oids || msg.oid; - var sessionid = Date.now(); - var data = {}; - data.community = community; - data.name = username; - data.auth = auth; - data.authprot = authprot; - data.privprot = privprot; - data.authkey = authkey; - data.privkey = privkey; - data.sessionid = sessionid; - var options = {}; - options.version = version; - options.timeout = node.timeout; + node.on("input", function (msg) { + const oids = node.oids || msg.oid; + const { host, sessionid, user, options } = prepareSnmpOptions(node, msg); if (oids) { msg.oid = oids; - openSession(host, data, options).walk(msg.oid, maxRepetitions, feedCb, function (error) { + let sess = openSession(sessionid, host, user, options); + sess.on("error", function (err) { + node.error(err, msg); + }) + //move response array & feedCb to inside `node.on("input",` to avoid subsequent + // calls overwriting results from previous operations (each call gets own result/response) + const response = []; + function feedCb(varbinds) { + for (let i = 0; i < varbinds.length; i++) { + if (SNMP.isVarbindError(varbinds[i])) { + node.error(SNMP.varbindError(varbinds[i]), msg); + } else { + response.push({ oid: varbinds[i].oid, value: varbinds[i].value }); + } + } + } + sess.walk(msg.oid, maxRepetitions, feedCb, function (error) { if (error) { node.error(error.toString(), msg); - } - else { - // Clone the array - msg.payload = response.slice(0); + } else { + msg.payload = response; node.send(msg); - //Clears response - response.length = 0; } closeSession(sessionid); }); - } - else { + } else { node.warn("No oid to search for"); } }); } - RED.nodes.registerType("snmp walker", SnmpWalkerNode); + RED.nodes.registerType("snmp walker", SnmpWalkerNode, { + credentials: { + username: { type: "text" }, + authkey: { type: "password" }, + privkey: { type: "password" } + } + }); };