@cryptotaxi247 / netdata-1 / commits / b93aaad43

node.d/snmp: snmpv3 support (#7802)

* node.d.plugin/node_modules: update net-snmp.js to the latest (snmp v3 support) * node.d/snmp.node.js: create v3 session if snmp version is 3 * node.d/snmp/README.md: update

Ilya Mashchenko committed Jan 22, 2020 at 18:05 UTC b93aaad43c5861d1ba47df62cd07ca0e3223455a
3 files changed +3419 -1357
collectors/node.d.plugin/node_modules/net-snmp.js
+3199 -1212
@@ -1,66 +1,77 @@
1 -
1 // Copyright 2013 Stephen Vickers <stephen.vickers.sv@gmail.com>
2 // SPDX-License-Identifier: MIT
3
5 -var ber = require ("asn1-ber").Ber;
6 -var dgram = require ("dgram");
7 -var events = require ("events");
8 -var util = require ("util");
4 +var ber = require("asn1-ber").Ber;
5 +var dgram = require("dgram");
6 +var events = require("events");
7 +var util = require("util");
8 +var crypto = require("crypto");
9 +
10 +var DEBUG = false;
11 +
12 +var MAX_INT32 = 2147483647;
13 +
14 +function debug(line) {
15 + if (DEBUG) {
16 + console.debug(line);
17 + }
18 +}
19
20 /*****************************************************************************
21 ** Constants
22 **/
23
14 -function _expandConstantObject (object) {
15 - var keys = [];
16 - for (var key in object)
17 - keys.push (key);
18 - for (var i = 0; i < keys.length; i++)
19 - object[object[keys[i]]] = parseInt (keys[i]);
24 +
25 +function _expandConstantObject(object) {
26 + var keys = [];
27 + for (var key in object)
28 + keys.push(key);
29 + for (var i = 0; i < keys.length; i++)
30 + object[object[keys[i]]] = parseInt(keys[i]);
31 }
32
33 var ErrorStatus = {
23 - 0: "NoError",
24 - 1: "TooBig",
25 - 2: "NoSuchName",
26 - 3: "BadValue",
27 - 4: "ReadOnly",
28 - 5: "GeneralError",
29 - 6: "NoAccess",
30 - 7: "WrongType",
31 - 8: "WrongLength",
32 - 9: "WrongEncoding",
33 - 10: "WrongValue",
34 - 11: "NoCreation",
35 - 12: "InconsistentValue",
36 - 13: "ResourceUnavailable",
37 - 14: "CommitFailed",
38 - 15: "UndoFailed",
39 - 16: "AuthorizationError",
40 - 17: "NotWritable",
41 - 18: "InconsistentName"
42 -};
43 -
44 -_expandConstantObject (ErrorStatus);
34 + 0: "NoError",
35 + 1: "TooBig",
36 + 2: "NoSuchName",
37 + 3: "BadValue",
38 + 4: "ReadOnly",
39 + 5: "GeneralError",
40 + 6: "NoAccess",
41 + 7: "WrongType",
42 + 8: "WrongLength",
43 + 9: "WrongEncoding",
44 + 10: "WrongValue",
45 + 11: "NoCreation",
46 + 12: "InconsistentValue",
47 + 13: "ResourceUnavailable",
48 + 14: "CommitFailed",
49 + 15: "UndoFailed",
50 + 16: "AuthorizationError",
51 + 17: "NotWritable",
52 + 18: "InconsistentName"
53 +};
54 +
55 +_expandConstantObject(ErrorStatus);
56
57 var ObjectType = {
47 - 1: "Boolean",
48 - 2: "Integer",
49 - 4: "OctetString",
50 - 5: "Null",
51 - 6: "OID",
52 - 64: "IpAddress",
53 - 65: "Counter",
54 - 66: "Gauge",
55 - 67: "TimeTicks",
56 - 68: "Opaque",
57 - 70: "Counter64",
58 - 128: "NoSuchObject",
59 - 129: "NoSuchInstance",
60 - 130: "EndOfMibView"
61 -};
62 -
63 -_expandConstantObject (ObjectType);
58 + 1: "Boolean",
59 + 2: "Integer",
60 + 4: "OctetString",
61 + 5: "Null",
62 + 6: "OID",
63 + 64: "IpAddress",
64 + 65: "Counter",
65 + 66: "Gauge",
66 + 67: "TimeTicks",
67 + 68: "Opaque",
68 + 70: "Counter64",
69 + 128: "NoSuchObject",
70 + 129: "NoSuchInstance",
71 + 130: "EndOfMibView"
72 +};
73 +
74 +_expandConstantObject(ObjectType);
75
76 ObjectType.Integer32 = ObjectType.Integer;
77 ObjectType.Counter32 = ObjectType.Counter;
@@ -68,132 +79,173 @@ ObjectType.Gauge32 = ObjectType.Gauge;
79 ObjectType.Unsigned32 = ObjectType.Gauge32;
80
81 var PduType = {
71 - 160: "GetRequest",
72 - 161: "GetNextRequest",
73 - 162: "GetResponse",
74 - 163: "SetRequest",
75 - 164: "Trap",
76 - 165: "GetBulkRequest",
77 - 166: "InformRequest",
78 - 167: "TrapV2",
79 - 168: "Report"
82 + 160: "GetRequest",
83 + 161: "GetNextRequest",
84 + 162: "GetResponse",
85 + 163: "SetRequest",
86 + 164: "Trap",
87 + 165: "GetBulkRequest",
88 + 166: "InformRequest",
89 + 167: "TrapV2",
90 + 168: "Report"
91 };
92
82 -_expandConstantObject (PduType);
93 +_expandConstantObject(PduType);
94
95 var TrapType = {
85 - 0: "ColdStart",
86 - 1: "WarmStart",
87 - 2: "LinkDown",
88 - 3: "LinkUp",
89 - 4: "AuthenticationFailure",
90 - 5: "EgpNeighborLoss",
91 - 6: "EnterpriseSpecific"
96 + 0: "ColdStart",
97 + 1: "WarmStart",
98 + 2: "LinkDown",
99 + 3: "LinkUp",
100 + 4: "AuthenticationFailure",
101 + 5: "EgpNeighborLoss",
102 + 6: "EnterpriseSpecific"
103 +};
104 +
105 +_expandConstantObject(TrapType);
106 +
107 +var SecurityLevel = {
108 + 1: "noAuthNoPriv",
109 + 2: "authNoPriv",
110 + 3: "authPriv"
111 +};
112 +
113 +_expandConstantObject(SecurityLevel);
114 +
115 +var AuthProtocols = {
116 + "1": "none",
117 + "2": "md5",
118 + "3": "sha"
119 +};
120 +
121 +_expandConstantObject(AuthProtocols);
122 +
123 +var PrivProtocols = {
124 + "1": "none",
125 + "2": "des"
126 +};
127 +
128 +_expandConstantObject(PrivProtocols);
129 +
130 +var MibProviderType = {
131 + "1": "Scalar",
132 + "2": "Table"
133 };
134
94 -_expandConstantObject (TrapType);
135 +_expandConstantObject(MibProviderType);
136
137 var Version1 = 0;
138 var Version2c = 1;
139 +var Version3 = 3;
140 +
141 +var Version = {
142 + "1": Version1,
143 + "2c": Version2c,
144 + "3": Version3
145 +};
146
147 /*****************************************************************************
148 ** Exception class definitions
149 **/
150
103 -function ResponseInvalidError (message) {
104 - this.name = "ResponseInvalidError";
105 - this.message = message;
106 - Error.captureStackTrace(this, ResponseInvalidError);
151 +function ResponseInvalidError(message) {
152 + this.name = "ResponseInvalidError";
153 + this.message = message;
154 + Error.captureStackTrace(this, ResponseInvalidError);
155 }
108 -util.inherits (ResponseInvalidError, Error);
156
110 -function RequestInvalidError (message) {
111 - this.name = "RequestInvalidError";
112 - this.message = message;
113 - Error.captureStackTrace(this, RequestInvalidError);
157 +util.inherits(ResponseInvalidError, Error);
158 +
159 +function RequestInvalidError(message) {
160 + this.name = "RequestInvalidError";
161 + this.message = message;
162 + Error.captureStackTrace(this, RequestInvalidError);
163 }
115 -util.inherits (RequestInvalidError, Error);
164
117 -function RequestFailedError (message, status) {
118 - this.name = "RequestFailedError";
119 - this.message = message;
120 - this.status = status;
121 - Error.captureStackTrace(this, RequestFailedError);
165 +util.inherits(RequestInvalidError, Error);
166 +
167 +function RequestFailedError(message, status) {
168 + this.name = "RequestFailedError";
169 + this.message = message;
170 + this.status = status;
171 + Error.captureStackTrace(this, RequestFailedError);
172 }
123 -util.inherits (RequestFailedError, Error);
173
125 -function RequestTimedOutError (message) {
126 - this.name = "RequestTimedOutError";
127 - this.message = message;
128 - Error.captureStackTrace(this, RequestTimedOutError);
174 +util.inherits(RequestFailedError, Error);
175 +
176 +function RequestTimedOutError(message) {
177 + this.name = "RequestTimedOutError";
178 + this.message = message;
179 + Error.captureStackTrace(this, RequestTimedOutError);
180 }
130 -util.inherits (RequestTimedOutError, Error);
181 +
182 +util.inherits(RequestTimedOutError, Error);
183
184 /*****************************************************************************
185 ** OID and varbind helper functions
186 **/
187
136 -function isVarbindError (varbind) {
137 - return !!(varbind.type == ObjectType.NoSuchObject
138 - || varbind.type == ObjectType.NoSuchInstance
139 - || varbind.type == ObjectType.EndOfMibView);
188 +function isVarbindError(varbind) {
189 + return !!(varbind.type == ObjectType.NoSuchObject
190 + || varbind.type == ObjectType.NoSuchInstance
191 + || varbind.type == ObjectType.EndOfMibView);
192 }
193
142 -function varbindError (varbind) {
143 - return (ObjectType[varbind.type] || "NotAnError") + ": " + varbind.oid;
194 +function varbindError(varbind) {
195 + return (ObjectType[varbind.type] || "NotAnError") + ": " + varbind.oid;
196 }
197
146 -function oidFollowsOid (oidString, nextString) {
147 - var oid = {str: oidString, len: oidString.length, idx: 0};
148 - var next = {str: nextString, len: nextString.length, idx: 0};
149 - var dotCharCode = ".".charCodeAt (0);
150 -
151 - function getNumber (item) {
152 - var n = 0;
153 - if (item.idx >= item.len)
154 - return null;
155 - while (item.idx < item.len) {
156 - var charCode = item.str.charCodeAt (item.idx++);
157 - if (charCode == dotCharCode)
158 - return n;
159 - n = (n ? (n * 10) : n) + (charCode - 48);
160 - }
161 - return n;
162 - }
163 -
164 - while (1) {
165 - var oidNumber = getNumber (oid);
166 - var nextNumber = getNumber (next);
167 -
168 - if (oidNumber !== null) {
169 - if (nextNumber !== null) {
170 - if (nextNumber > oidNumber) {
171 - return true;
172 - } else if (nextNumber < oidNumber) {
173 - return false;
174 - }
175 - } else {
176 - return true;
177 - }
178 - } else {
179 - return true;
180 - }
181 - }
198 +function oidFollowsOid(oidString, nextString) {
199 + var oid = {str: oidString, len: oidString.length, idx: 0};
200 + var next = {str: nextString, len: nextString.length, idx: 0};
201 + var dotCharCode = ".".charCodeAt(0);
202 +
203 + function getNumber(item) {
204 + var n = 0;
205 + if (item.idx >= item.len)
206 + return null;
207 + while (item.idx < item.len) {
208 + var charCode = item.str.charCodeAt(item.idx++);
209 + if (charCode == dotCharCode)
210 + return n;
211 + n = (n ? (n * 10) : n) + (charCode - 48);
212 + }
213 + return n;
214 + }
215 +
216 + while (1) {
217 + var oidNumber = getNumber(oid);
218 + var nextNumber = getNumber(next);
219 +
220 + if (oidNumber !== null) {
221 + if (nextNumber !== null) {
222 + if (nextNumber > oidNumber) {
223 + return true;
224 + } else if (nextNumber < oidNumber) {
225 + return false;
226 + }
227 + } else {
228 + return true;
229 + }
230 + } else {
231 + return true;
232 + }
233 + }
234 }
235
184 -function oidInSubtree (oidString, nextString) {
185 - var oid = oidString.split (".");
186 - var next = nextString.split (".");
236 +function oidInSubtree(oidString, nextString) {
237 + var oid = oidString.split(".");
238 + var next = nextString.split(".");
239
188 - if (oid.length > next.length)
189 - return false;
240 + if (oid.length > next.length)
241 + return false;
242
191 - for (var i = 0; i < oid.length; i++) {
192 - if (next[i] != oid[i])
193 - return false;
194 - }
243 + for (var i = 0; i < oid.length; i++) {
244 + if (next[i] != oid[i])
245 + return false;
246 + }
247
196 - return true;
248 + return true;
249 }
250
251 /**
@@ -207,1228 +259,3138 @@ function oidInSubtree (oidString, nextString) {
259 ** an error since the integer is too large.
260 **/
261
210 -function readInt (buffer) {
211 - return readUint (buffer, true);
262 +function readInt(buffer) {
263 + return readUint(buffer, true);
264 +}
265 +
266 +function readIpAddress(buffer) {
267 + var bytes = buffer.readString(ObjectType.IpAddress, true);
268 + if (bytes.length != 4)
269 + throw new ResponseInvalidError("Length '" + bytes.length
270 + + "' of IP address '" + bytes.toString("hex")
271 + + "' is not 4");
272 + var value = bytes[0] + "." + bytes[1] + "." + bytes[2] + "." + bytes[3];
273 + return value;
274 }
275
214 -function readUint (buffer, isSigned) {
215 - buffer.readByte ();
216 - var length = buffer.readByte ();
217 - var value = 0;
218 - var signedBitSet = false;
219 -
220 - if (length > 5) {
221 - throw new RangeError ("Integer too long '" + length + "'");
222 - } else if (length == 5) {
223 - if (buffer.readByte () !== 0)
224 - throw new RangeError ("Integer too long '" + length + "'");
225 - length = 4;
226 - }
227 -
228 - for (var i = 0; i < length; i++) {
229 - value *= 256;
230 - value += buffer.readByte ();
231 -
232 - if (isSigned && i <= 0) {
233 - if ((value & 0x80) == 0x80)
234 - signedBitSet = true;
235 - }
236 - }
237 -
238 - if (signedBitSet)
239 - value -= (1 << (i * 8));
240 -
241 - return value;
276 +function readUint(buffer, isSigned) {
277 + buffer.readByte();
278 + var length = buffer.readByte();
279 + var value = 0;
280 + var signedBitSet = false;
281 +
282 + if (length > 5) {
283 + throw new RangeError("Integer too long '" + length + "'");
284 + } else if (length == 5) {
285 + if (buffer.readByte() !== 0)
286 + throw new RangeError("Integer too long '" + length + "'");
287 + length = 4;
288 + }
289 +
290 + for (var i = 0; i < length; i++) {
291 + value *= 256;
292 + value += buffer.readByte();
293 +
294 + if (isSigned && i <= 0) {
295 + if ((value & 0x80) == 0x80)
296 + signedBitSet = true;
297 + }
298 + }
299 +
300 + if (signedBitSet)
301 + value -= (1 << (i * 8));
302 +
303 + return value;
304 }
305
244 -function readUint64 (buffer) {
245 - var value = buffer.readString (ObjectType.Counter64, true);
306 +function readUint64(buffer) {
307 + var value = buffer.readString(ObjectType.Counter64, true);
308
247 - return value;
309 + return value;
310 }
311
250 -function readVarbinds (buffer, varbinds) {
251 - buffer.readSequence ();
252 -
253 - while (1) {
254 - buffer.readSequence ();
255 - var oid = buffer.readOID ();
256 - var type = buffer.peek ();
257 -
258 - if (type == null)
259 - break;
260 -
261 - var value;
262 -
263 - if (type == ObjectType.Boolean) {
264 - value = buffer.readBoolean ();
265 - } else if (type == ObjectType.Integer) {
266 - value = readInt (buffer);
267 - } else if (type == ObjectType.OctetString) {
268 - value = buffer.readString (null, true);
269 - } else if (type == ObjectType.Null) {
270 - buffer.readByte ();
271 - buffer.readByte ();
272 - value = null;
273 - } else if (type == ObjectType.OID) {
274 - value = buffer.readOID ();
275 - } else if (type == ObjectType.IpAddress) {
276 - var bytes = buffer.readString (ObjectType.IpAddress, true);
277 - if (bytes.length != 4)
278 - throw new ResponseInvalidError ("Length '" + bytes.length
279 - + "' of IP address '" + bytes.toString ("hex")
280 - + "' is not 4");
281 - value = bytes[0] + "." + bytes[1] + "." + bytes[2] + "." + bytes[3];
282 - } else if (type == ObjectType.Counter) {
283 - value = readUint (buffer);
284 - } else if (type == ObjectType.Gauge) {
285 - value = readUint (buffer);
286 - } else if (type == ObjectType.TimeTicks) {
287 - value = readUint (buffer);
288 - } else if (type == ObjectType.Opaque) {
289 - value = buffer.readString (ObjectType.Opaque, true);
290 - } else if (type == ObjectType.Counter64) {
291 - value = readUint64 (buffer);
292 - } else if (type == ObjectType.NoSuchObject) {
293 - buffer.readByte ();
294 - buffer.readByte ();
295 - value = null;
296 - } else if (type == ObjectType.NoSuchInstance) {
297 - buffer.readByte ();
298 - buffer.readByte ();
299 - value = null;
300 - } else if (type == ObjectType.EndOfMibView) {
301 - buffer.readByte ();
302 - buffer.readByte ();
303 - value = null;
304 - } else {
305 - throw new ResponseInvalidError ("Unknown type '" + type
306 - + "' in response");
307 - }
308 -
309 - varbinds.push ({
310 - oid: oid,
311 - type: type,
312 - value: value
313 - });
314 - }
312 +function readVarbinds(buffer, varbinds) {
313 + buffer.readSequence();
314 +
315 + while (1) {
316 + buffer.readSequence();
317 + if (buffer.peek() != ObjectType.OID)
318 + break;
319 + var oid = buffer.readOID();
320 + var type = buffer.peek();
321 +
322 + if (type == null)
323 + break;
324 +
325 + var value;
326 +
327 + if (type == ObjectType.Boolean) {
328 + value = buffer.readBoolean();
329 + } else if (type == ObjectType.Integer) {
330 + value = readInt(buffer);
331 + } else if (type == ObjectType.OctetString) {
332 + value = buffer.readString(null, true);
333 + } else if (type == ObjectType.Null) {
334 + buffer.readByte();
335 + buffer.readByte();
336 + value = null;
337 + } else if (type == ObjectType.OID) {
338 + value = buffer.readOID();
339 + } else if (type == ObjectType.IpAddress) {
340 + var bytes = buffer.readString(ObjectType.IpAddress, true);
341 + if (bytes.length != 4)
342 + throw new ResponseInvalidError("Length '" + bytes.length
343 + + "' of IP address '" + bytes.toString("hex")
344 + + "' is not 4");
345 + value = bytes[0] + "." + bytes[1] + "." + bytes[2] + "." + bytes[3];
346 + } else if (type == ObjectType.Counter) {
347 + value = readUint(buffer);
348 + } else if (type == ObjectType.Gauge) {
349 + value = readUint(buffer);
350 + } else if (type == ObjectType.TimeTicks) {
351 + value = readUint(buffer);
352 + } else if (type == ObjectType.Opaque) {
353 + value = buffer.readString(ObjectType.Opaque, true);
354 + } else if (type == ObjectType.Counter64) {
355 + value = readUint64(buffer);
356 + } else if (type == ObjectType.NoSuchObject) {
357 + buffer.readByte();
358 + buffer.readByte();
359 + value = null;
360 + } else if (type == ObjectType.NoSuchInstance) {
361 + buffer.readByte();
362 + buffer.readByte();
363 + value = null;
364 + } else if (type == ObjectType.EndOfMibView) {
365 + buffer.readByte();
366 + buffer.readByte();
367 + value = null;
368 + } else {
369 + throw new ResponseInvalidError("Unknown type '" + type
370 + + "' in response");
371 + }
372 +
373 + varbinds.push({
374 + oid: oid,
375 + type: type,
376 + value: value
377 + });
378 + }
379 }
380
317 -function writeUint (buffer, type, value) {
318 - var b = new Buffer (4);
319 - b.writeUInt32BE (value, 0);
320 - buffer.writeBuffer (b, type);
381 +function writeUint(buffer, type, value) {
382 + var b = Buffer.alloc(4);
383 + b.writeUInt32BE(value, 0);
384 + buffer.writeBuffer(b, type);
385 }
386
323 -function writeUint64 (buffer, value) {
324 - buffer.writeBuffer (value, ObjectType.Counter64);
387 +function writeUint64(buffer, value) {
388 + buffer.writeBuffer(value, ObjectType.Counter64);
389 }
390
327 -function writeVarbinds (buffer, varbinds) {
328 - buffer.startSequence ();
329 - for (var i = 0; i < varbinds.length; i++) {
330 - buffer.startSequence ();
331 - buffer.writeOID (varbinds[i].oid);
332 -
333 - if (varbinds[i].type && varbinds[i].hasOwnProperty("value")) {
334 - var type = varbinds[i].type;
335 - var value = varbinds[i].value;
336 -
337 - if (type == ObjectType.Boolean) {
338 - buffer.writeBoolean (value ? true : false);
339 - } else if (type == ObjectType.Integer) { // also Integer32
340 - buffer.writeInt (value);
341 - } else if (type == ObjectType.OctetString) {
342 - if (typeof value == "string")
343 - buffer.writeString (value);
344 - else
345 - buffer.writeBuffer (value, ObjectType.OctetString);
346 - } else if (type == ObjectType.Null) {
347 - buffer.writeNull ();
348 - } else if (type == ObjectType.OID) {
349 - buffer.writeOID (value);
350 - } else if (type == ObjectType.IpAddress) {
351 - var bytes = value.split (".");
352 - if (bytes.length != 4)
353 - throw new RequestInvalidError ("Invalid IP address '"
354 - + value + "'");
355 - buffer.writeBuffer (new Buffer (bytes), 64);
356 - } else if (type == ObjectType.Counter) { // also Counter32
357 - writeUint (buffer, ObjectType.Counter, value);
358 - } else if (type == ObjectType.Gauge) { // also Gauge32 & Unsigned32
359 - writeUint (buffer, ObjectType.Gauge, value);
360 - } else if (type == ObjectType.TimeTicks) {
361 - writeUint (buffer, ObjectType.TimeTicks, value);
362 - } else if (type == ObjectType.Opaque) {
363 - buffer.writeBuffer (value, ObjectType.Opaque);
364 - } else if (type == ObjectType.Counter64) {
365 - writeUint64 (buffer, value);
366 - } else {
367 - throw new RequestInvalidError ("Unknown type '" + type
368 - + "' in request");
369 - }
370 - } else {
371 - buffer.writeNull ();
372 - }
373 -
374 - buffer.endSequence ();
375 - }
376 - buffer.endSequence ();
391 +function writeVarbinds(buffer, varbinds) {
392 + buffer.startSequence();
393 + for (var i = 0; i < varbinds.length; i++) {
394 + buffer.startSequence();
395 + buffer.writeOID(varbinds[i].oid);
396 +
397 + if (varbinds[i].type && varbinds[i].hasOwnProperty("value")) {
398 + var type = varbinds[i].type;
399 + var value = varbinds[i].value;
400 +
401 + if (type == ObjectType.Boolean) {
402 + buffer.writeBoolean(value ? true : false);
403 + } else if (type == ObjectType.Integer) { // also Integer32
404 + buffer.writeInt(value);
405 + } else if (type == ObjectType.OctetString) {
406 + if (typeof value == "string")
407 + buffer.writeString(value);
408 + else
409 + buffer.writeBuffer(value, ObjectType.OctetString);
410 + } else if (type == ObjectType.Null) {
411 + buffer.writeNull();
412 + } else if (type == ObjectType.OID) {
413 + buffer.writeOID(value);
414 + } else if (type == ObjectType.IpAddress) {
415 + var bytes = value.split(".");
416 + if (bytes.length != 4)
417 + throw new RequestInvalidError("Invalid IP address '"
418 + + value + "'");
419 + buffer.writeBuffer(Buffer.from(bytes), 64);
420 + } else if (type == ObjectType.Counter) { // also Counter32
421 + writeUint(buffer, ObjectType.Counter, value);
422 + } else if (type == ObjectType.Gauge) { // also Gauge32 & Unsigned32
423 + writeUint(buffer, ObjectType.Gauge, value);
424 + } else if (type == ObjectType.TimeTicks) {
425 + writeUint(buffer, ObjectType.TimeTicks, value);
426 + } else if (type == ObjectType.Opaque) {
427 + buffer.writeBuffer(value, ObjectType.Opaque);
428 + } else if (type == ObjectType.Counter64) {
429 + writeUint64(buffer, value);
430 + } else if (type == ObjectType.EndOfMibView) {
431 + buffer.writeByte(130);
432 + buffer.writeByte(0);
433 + } else {
434 + throw new RequestInvalidError("Unknown type '" + type
435 + + "' in request");
436 + }
437 + } else {
438 + buffer.writeNull();
439 + }
440 +
441 + buffer.endSequence();
442 + }
443 + buffer.endSequence();
444 }
445
446 /*****************************************************************************
447 ** PDU class definitions
448 **/
449
383 -var SimplePdu = function (id, varbinds, options) {
384 - this.id = id;
385 - this.varbinds = varbinds;
386 - this.options = options || {};
450 +var SimplePdu = function () {
451 };
452
453 SimplePdu.prototype.toBuffer = function (buffer) {
390 - buffer.startSequence (this.type);
454 + buffer.startSequence(this.type);
455
392 - buffer.writeInt (this.id);
393 - buffer.writeInt ((this.type == PduType.GetBulkRequest)
394 - ? (this.options.nonRepeaters || 0)
395 - : 0);
396 - buffer.writeInt ((this.type == PduType.GetBulkRequest)
397 - ? (this.options.maxRepetitions || 0)
398 - : 0);
456 + buffer.writeInt(this.id);
457 + buffer.writeInt((this.type == PduType.GetBulkRequest)
458 + ? (this.options.nonRepeaters || 0)
459 + : 0);
460 + buffer.writeInt((this.type == PduType.GetBulkRequest)
461 + ? (this.options.maxRepetitions || 0)
462 + : 0);
463
400 - writeVarbinds (buffer, this.varbinds);
464 + writeVarbinds(buffer, this.varbinds);
465
402 - buffer.endSequence ();
466 + buffer.endSequence();
467 };
468
405 -var GetBulkRequestPdu = function () {
406 - this.type = PduType.GetBulkRequest;
407 - GetBulkRequestPdu.super_.apply (this, arguments);
408 -};
469 +SimplePdu.prototype.initializeFromVariables = function (id, varbinds, options) {
470 + this.id = id;
471 + this.varbinds = varbinds;
472 + this.options = options || {};
473 + this.contextName = (options && options.context) ? options.context : "";
474 +}
475
410 -util.inherits (GetBulkRequestPdu, SimplePdu);
476 +SimplePdu.prototype.initializeFromBuffer = function (reader) {
477 + this.type = reader.peek();
478 + reader.readSequence();
479 +
480 + this.id = reader.readInt();
481 + this.nonRepeaters = reader.readInt();
482 + this.maxRepetitions = reader.readInt();
483 +
484 + this.varbinds = [];
485 + readVarbinds(reader, this.varbinds);
486
412 -var GetNextRequestPdu = function () {
413 - this.type = PduType.GetNextRequest;
414 - GetNextRequestPdu.super_.apply (this, arguments);
487 };
488
417 -util.inherits (GetNextRequestPdu, SimplePdu);
489 +SimplePdu.prototype.getResponsePduForRequest = function () {
490 + var responsePdu = GetResponsePdu.createFromVariables(this.id, [], {});
491 + if (this.contextEngineID) {
492 + responsePdu.contextEngineID = this.contextEngineID;
493 + responsePdu.contextName = this.contextName;
494 + }
495 + return responsePdu;
496 +};
497 +
498 +SimplePdu.createFromVariables = function (pduClass, id, varbinds, options) {
499 + var pdu = new pduClass(id, varbinds, options);
500 + pdu.id = id;
501 + pdu.varbinds = varbinds;
502 + pdu.options = options || {};
503 + pdu.contextName = (options && options.context) ? options.context : "";
504 + return pdu;
505 +};
506
419 -var GetResponsePdu = function (buffer) {
420 - this.type = PduType.GetResponse;
507 +var GetBulkRequestPdu = function () {
508 + this.type = PduType.GetBulkRequest;
509 + GetBulkRequestPdu.super_.apply(this, arguments);
510 +};
511
422 - buffer.readSequence (this.type);
512 +util.inherits(GetBulkRequestPdu, SimplePdu);
513
424 - this.id = buffer.readInt ();
514 +GetBulkRequestPdu.createFromBuffer = function (reader) {
515 + var pdu = new GetBulkRequestPdu();
516 + pdu.initializeFromBuffer(reader);
517 + return pdu;
518 +};
519
426 - this.errorStatus = buffer.readInt ();
427 - this.errorIndex = buffer.readInt ();
520 +var GetNextRequestPdu = function () {
521 + this.type = PduType.GetNextRequest;
522 + GetNextRequestPdu.super_.apply(this, arguments);
523 +};
524
429 - this.varbinds = [];
525 +util.inherits(GetNextRequestPdu, SimplePdu);
526
431 - readVarbinds (buffer, this.varbinds);
527 +GetNextRequestPdu.createFromBuffer = function (reader) {
528 + var pdu = new GetNextRequestPdu();
529 + pdu.initializeFromBuffer(reader);
530 + return pdu;
531 };
532
533 var GetRequestPdu = function () {
435 - this.type = PduType.GetRequest;
436 - GetRequestPdu.super_.apply (this, arguments);
534 + this.type = PduType.GetRequest;
535 + GetRequestPdu.super_.apply(this, arguments);
536 +};
537 +
538 +util.inherits(GetRequestPdu, SimplePdu);
539 +
540 +GetRequestPdu.createFromBuffer = function (reader) {
541 + var pdu = new GetRequestPdu();
542 + pdu.initializeFromBuffer(reader);
543 + return pdu;
544 };
545
439 -util.inherits (GetRequestPdu, SimplePdu);
546 +GetRequestPdu.createFromVariables = function (id, varbinds, options) {
547 + var pdu = new GetRequestPdu();
548 + pdu.initializeFromVariables(id, varbinds, options);
549 + return pdu;
550 +};
551
552 var InformRequestPdu = function () {
442 - this.type = PduType.InformRequest;
443 - InformRequestPdu.super_.apply (this, arguments);
553 + this.type = PduType.InformRequest;
554 + InformRequestPdu.super_.apply(this, arguments);
555 };
556
446 -util.inherits (InformRequestPdu, SimplePdu);
557 +util.inherits(InformRequestPdu, SimplePdu);
558 +
559 +InformRequestPdu.createFromBuffer = function (reader) {
560 + var pdu = new InformRequestPdu();
561 + pdu.initializeFromBuffer(reader);
562 + return pdu;
563 +};
564
565 var SetRequestPdu = function () {
449 - this.type = PduType.SetRequest;
450 - SetRequestPdu.super_.apply (this, arguments);
566 + this.type = PduType.SetRequest;
567 + SetRequestPdu.super_.apply(this, arguments);
568 +};
569 +
570 +util.inherits(SetRequestPdu, SimplePdu);
571 +
572 +SetRequestPdu.createFromBuffer = function (reader) {
573 + var pdu = new SetRequestPdu();
574 + pdu.initializeFromBuffer(reader);
575 + return pdu;
576 };
577
453 -util.inherits (SetRequestPdu, SimplePdu);
578 +var TrapPdu = function () {
579 + this.type = PduType.Trap;
580 +};
581
455 -var TrapPdu = function (typeOrOid, varbinds, options) {
456 - this.type = PduType.Trap;
582 +TrapPdu.prototype.toBuffer = function (buffer) {
583 + buffer.startSequence(this.type);
584
458 - this.agentAddr = options.agentAddr || "127.0.0.1";
459 - this.upTime = options.upTime;
585 + buffer.writeOID(this.enterprise);
586 + buffer.writeBuffer(Buffer.from(this.agentAddr.split(".")),
587 + ObjectType.IpAddress);
588 + buffer.writeInt(this.generic);
589 + buffer.writeInt(this.specific);
590 + writeUint(buffer, ObjectType.TimeTicks,
591 + this.upTime || Math.floor(process.uptime() * 100));
592
461 - if (typeof typeOrOid == "string") {
462 - this.generic = TrapType.EnterpriseSpecific;
463 - this.specific = parseInt (typeOrOid.match (/\.(\d+)$/)[1]);
464 - this.enterprise = typeOrOid.replace (/\.(\d+)$/, "");
465 - } else {
466 - this.generic = typeOrOid;
467 - this.specific = 0;
468 - this.enterprise = "1.3.6.1.4.1";
469 - }
593 + writeVarbinds(buffer, this.varbinds);
594
471 - this.varbinds = varbinds;
595 + buffer.endSequence();
596 };
597
474 -TrapPdu.prototype.toBuffer = function (buffer) {
475 - buffer.startSequence (this.type);
598 +TrapPdu.createFromBuffer = function (reader) {
599 + var pdu = new TrapPdu();
600 + reader.readSequence();
601 +
602 + pdu.enterprise = reader.readOID();
603 + pdu.agentAddr = readIpAddress(reader);
604 + pdu.generic = reader.readInt();
605 + pdu.specific = reader.readInt();
606 + pdu.upTime = readUint(reader)
607 +
608 + pdu.varbinds = [];
609 + readVarbinds(reader, pdu.varbinds);
610 +
611 + return pdu;
612 +};
613
477 - buffer.writeOID (this.enterprise);
478 - buffer.writeBuffer (new Buffer (this.agentAddr.split (".")),
479 - ObjectType.IpAddress);
480 - buffer.writeInt (this.generic);
481 - buffer.writeInt (this.specific);
482 - writeUint (buffer, ObjectType.TimeTicks,
483 - this.upTime || Math.floor (process.uptime () * 100));
614 +TrapPdu.createFromVariables = function (typeOrOid, varbinds, options) {
615 + var pdu = new TrapPdu();
616 + pdu.agentAddr = options.agentAddr || "127.0.0.1";
617 + pdu.upTime = options.upTime;
618
485 - writeVarbinds (buffer, this.varbinds);
619 + if (typeof typeOrOid == "string") {
620 + pdu.generic = TrapType.EnterpriseSpecific;
621 + pdu.specific = parseInt(typeOrOid.match(/\.(\d+)$/)[1]);
622 + pdu.enterprise = typeOrOid.replace(/\.(\d+)$/, "");
623 + } else {
624 + pdu.generic = typeOrOid;
625 + pdu.specific = 0;
626 + pdu.enterprise = "1.3.6.1.4.1";
627 + }
628
487 - buffer.endSequence ();
629 + pdu.varbinds = varbinds;
630 +
631 + return pdu;
632 };
633
634 var TrapV2Pdu = function () {
491 - this.type = PduType.TrapV2;
492 - TrapV2Pdu.super_.apply (this, arguments);
635 + this.type = PduType.TrapV2;
636 + TrapV2Pdu.super_.apply(this, arguments);
637 +};
638 +
639 +util.inherits(TrapV2Pdu, SimplePdu);
640 +
641 +TrapV2Pdu.createFromBuffer = function (reader) {
642 + var pdu = new TrapV2Pdu();
643 + pdu.initializeFromBuffer(reader);
644 + return pdu;
645 +};
646 +
647 +TrapV2Pdu.createFromVariables = function (id, varbinds, options) {
648 + var pdu = new TrapV2Pdu();
649 + pdu.initializeFromVariables(id, varbinds, options);
650 + return pdu;
651 +};
652 +
653 +var SimpleResponsePdu = function () {
654 +};
655 +
656 +SimpleResponsePdu.prototype.toBuffer = function (writer) {
657 + writer.startSequence(this.type);
658 +
659 + writer.writeInt(this.id);
660 + writer.writeInt(this.errorStatus || 0);
661 + writer.writeInt(this.errorIndex || 0);
662 + writeVarbinds(writer, this.varbinds);
663 + writer.endSequence();
664 +
665 };
666
495 -util.inherits (TrapV2Pdu, SimplePdu);
667 +SimpleResponsePdu.prototype.initializeFromBuffer = function (reader) {
668 + reader.readSequence(this.type);
669 +
670 + this.id = reader.readInt();
671 + this.errorStatus = reader.readInt();
672 + this.errorIndex = reader.readInt();
673 +
674 + this.varbinds = [];
675 + readVarbinds(reader, this.varbinds);
676 +};
677 +
678 +SimpleResponsePdu.prototype.initializeFromVariables = function (id, varbinds, options) {
679 + this.id = id;
680 + this.varbinds = varbinds;
681 + this.options = options || {};
682 +};
683 +
684 +var GetResponsePdu = function () {
685 + this.type = PduType.GetResponse;
686 + GetResponsePdu.super_.apply(this, arguments);
687 +};
688 +
689 +util.inherits(GetResponsePdu, SimpleResponsePdu);
690 +
691 +GetResponsePdu.createFromBuffer = function (reader) {
692 + var pdu = new GetResponsePdu();
693 + pdu.initializeFromBuffer(reader);
694 + return pdu;
695 +};
696 +
697 +GetResponsePdu.createFromVariables = function (id, varbinds, options) {
698 + var pdu = new GetResponsePdu();
699 + pdu.initializeFromVariables(id, varbinds, options);
700 + return pdu;
701 +};
702 +
703 +var ReportPdu = function () {
704 + this.type = PduType.Report;
705 + ReportPdu.super_.apply(this, arguments);
706 +};
707 +
708 +util.inherits(ReportPdu, SimpleResponsePdu);
709 +
710 +ReportPdu.createFromBuffer = function (reader) {
711 + var pdu = new ReportPdu();
712 + pdu.initializeFromBuffer(reader);
713 + return pdu;
714 +};
715 +
716 +ReportPdu.createFromVariables = function (id, varbinds, options) {
717 + var pdu = new ReportPdu();
718 + pdu.initializeFromVariables(id, varbinds, options);
719 + return pdu;
720 +};
721 +
722 +var readPdu = function (reader, scoped) {
723 + var pdu;
724 + var contextEngineID;
725 + var contextName;
726 + if (scoped) {
727 + reader.readSequence();
728 + contextEngineID = reader.readString(ber.OctetString, true);
729 + contextName = reader.readString();
730 + }
731 + var type = reader.peek();
732 +
733 + if (type == PduType.GetResponse) {
734 + pdu = GetResponsePdu.createFromBuffer(reader);
735 + } else if (type == PduType.Report) {
736 + pdu = ReportPdu.createFromBuffer(reader);
737 + } else if (type == PduType.Trap) {
738 + pdu = TrapPdu.createFromBuffer(reader);
739 + } else if (type == PduType.TrapV2) {
740 + pdu = TrapV2Pdu.createFromBuffer(reader);
741 + } else if (type == PduType.InformRequest) {
742 + pdu = InformRequestPdu.createFromBuffer(reader);
743 + } else if (type == PduType.GetRequest) {
744 + pdu = GetRequestPdu.createFromBuffer(reader);
745 + } else if (type == PduType.SetRequest) {
746 + pdu = SetRequestPdu.createFromBuffer(reader);
747 + } else if (type == PduType.GetNextRequest) {
748 + pdu = GetNextRequestPdu.createFromBuffer(reader);
749 + } else if (type == PduType.GetBulkRequest) {
750 + pdu = GetBulkRequestPdu.createFromBuffer(reader);
751 + } else {
752 + throw new ResponseInvalidError("Unknown PDU type '" + type
753 + + "' in response");
754 + }
755 + if (scoped) {
756 + pdu.contextEngineID = contextEngineID;
757 + pdu.contextName = contextName;
758 + }
759 + pdu.scoped = scoped;
760 + return pdu;
761 +};
762 +
763 +var createDiscoveryPdu = function (context) {
764 + return GetRequestPdu.createFromVariables(_generateId(), [], {context: context});
765 +};
766 +
767 +var Authentication = {};
768 +
769 +Authentication.HMAC_BUFFER_SIZE = 1024 * 1024;
770 +Authentication.HMAC_BLOCK_SIZE = 64;
771 +Authentication.AUTHENTICATION_CODE_LENGTH = 12;
772 +Authentication.AUTH_PARAMETERS_PLACEHOLDER = Buffer.from('8182838485868788898a8b8c', 'hex');
773 +
774 +Authentication.algorithms = {};
775 +
776 +Authentication.algorithms[AuthProtocols.md5] = {
777 + // KEY_LENGTH: 16,
778 + CRYPTO_ALGORITHM: 'md5'
779 +};
780 +
781 +Authentication.algorithms[AuthProtocols.sha] = {
782 + // KEY_LENGTH: 20,
783 + CRYPTO_ALGORITHM: 'sha1'
784 +};
785 +
786 +// Adapted from RFC3414 Appendix A.2.1. Password to Key Sample Code for MD5
787 +Authentication.passwordToKey = function (authProtocol, authPasswordString, engineID) {
788 + var hashAlgorithm;
789 + var firstDigest;
790 + var finalDigest;
791 + var buf = Buffer.alloc(Authentication.HMAC_BUFFER_SIZE);
792 + var bufOffset = 0;
793 + var passwordIndex = 0;
794 + var count = 0;
795 + var password = Buffer.from(authPasswordString);
796 + var cryptoAlgorithm = Authentication.algorithms[authProtocol].CRYPTO_ALGORITHM;
797 +
798 + while (count < Authentication.HMAC_BUFFER_SIZE) {
799 + for (var i = 0; i < Authentication.HMAC_BLOCK_SIZE; i++) {
800 + buf.writeUInt8(password[passwordIndex++ % password.length], bufOffset++);
801 + }
802 + count += Authentication.HMAC_BLOCK_SIZE;
803 + }
804 + hashAlgorithm = crypto.createHash(cryptoAlgorithm);
805 + hashAlgorithm.update(buf);
806 + firstDigest = hashAlgorithm.digest();
807 + // debug ("First digest: " + firstDigest.toString('hex'));
808 +
809 + hashAlgorithm = crypto.createHash(cryptoAlgorithm);
810 + hashAlgorithm.update(firstDigest);
811 + hashAlgorithm.update(engineID);
812 + hashAlgorithm.update(firstDigest);
813 + finalDigest = hashAlgorithm.digest();
814 + debug("Localized key: " + finalDigest.toString('hex'));
815 +
816 + return finalDigest;
817 +};
818 +
819 +Authentication.addParametersToMessageBuffer = function (messageBuffer, authProtocol, authPassword, engineID) {
820 + var authenticationParametersOffset;
821 + var digestToAdd;
822 +
823 + // clear the authenticationParameters field in message
824 + authenticationParametersOffset = messageBuffer.indexOf(Authentication.AUTH_PARAMETERS_PLACEHOLDER);
825 + messageBuffer.fill(0, authenticationParametersOffset, authenticationParametersOffset + Authentication.AUTHENTICATION_CODE_LENGTH);
826 +
827 + digestToAdd = Authentication.calculateDigest(messageBuffer, authProtocol, authPassword, engineID);
828 + digestToAdd.copy(messageBuffer, authenticationParametersOffset, 0, Authentication.AUTHENTICATION_CODE_LENGTH);
829 + debug("Added Auth Parameters: " + digestToAdd.toString('hex'));
830 +};
831 +
832 +Authentication.isAuthentic = function (messageBuffer, authProtocol, authPassword, engineID, digestInMessage) {
833 + var authenticationParametersOffset;
834 + var calculatedDigest;
835 +
836 + // clear the authenticationParameters field in message
837 + authenticationParametersOffset = messageBuffer.indexOf(digestInMessage);
838 + messageBuffer.fill(0, authenticationParametersOffset, authenticationParametersOffset + Authentication.AUTHENTICATION_CODE_LENGTH);
839 +
840 + calculatedDigest = Authentication.calculateDigest(messageBuffer, authProtocol, authPassword, engineID);
841 +
842 + // replace previously cleared authenticationParameters field in message
843 + digestInMessage.copy(messageBuffer, authenticationParametersOffset, 0, Authentication.AUTHENTICATION_CODE_LENGTH);
844 +
845 + debug("Digest in message: " + digestInMessage.toString('hex'));
846 + debug("Calculated digest: " + calculatedDigest.toString('hex'));
847 + return calculatedDigest.equals(digestInMessage, Authentication.AUTHENTICATION_CODE_LENGTH);
848 +};
849 +
850 +Authentication.calculateDigest = function (messageBuffer, authProtocol, authPassword, engineID) {
851 + var authKey = Authentication.passwordToKey(authProtocol, authPassword, engineID);
852 +
853 + // Adapted from RFC3147 Section 6.3.1. Processing an Outgoing Message
854 + var hashAlgorithm;
855 + var kIpad;
856 + var kOpad;
857 + var firstDigest;
858 + var finalDigest;
859 + var truncatedDigest;
860 + var i;
861 + var cryptoAlgorithm = Authentication.algorithms[authProtocol].CRYPTO_ALGORITHM;
862 +
863 + if (authKey.length > Authentication.HMAC_BLOCK_SIZE) {
864 + hashAlgorithm = crypto.createHash(cryptoAlgorithm);
865 + hashAlgorithm.update(authKey);
866 + authKey = hashAlgorithm.digest();
867 + }
868 +
869 + // MD(K XOR opad, MD(K XOR ipad, msg))
870 + kIpad = Buffer.alloc(Authentication.HMAC_BLOCK_SIZE);
871 + kOpad = Buffer.alloc(Authentication.HMAC_BLOCK_SIZE);
872 + for (i = 0; i < authKey.length; i++) {
873 + kIpad[i] = authKey[i] ^ 0x36;
874 + kOpad[i] = authKey[i] ^ 0x5c;
875 + }
876 + kIpad.fill(0x36, authKey.length);
877 + kOpad.fill(0x5c, authKey.length);
878 +
879 + // inner MD
880 + hashAlgorithm = crypto.createHash(cryptoAlgorithm);
881 + hashAlgorithm.update(kIpad);
882 + hashAlgorithm.update(messageBuffer);
883 + firstDigest = hashAlgorithm.digest();
884 + // outer MD
885 + hashAlgorithm = crypto.createHash(cryptoAlgorithm);
886 + hashAlgorithm.update(kOpad);
887 + hashAlgorithm.update(firstDigest);
888 + finalDigest = hashAlgorithm.digest();
889 +
890 + truncatedDigest = Buffer.alloc(Authentication.AUTHENTICATION_CODE_LENGTH);
891 + finalDigest.copy(truncatedDigest, 0, 0, Authentication.AUTHENTICATION_CODE_LENGTH);
892 + return truncatedDigest;
893 +};
894 +
895 +var Encryption = {};
896 +
897 +Encryption.INPUT_KEY_LENGTH = 16;
898 +Encryption.DES_KEY_LENGTH = 8;
899 +Encryption.DES_BLOCK_LENGTH = 8;
900 +Encryption.CRYPTO_DES_ALGORITHM = 'des-cbc';
901 +Encryption.PRIV_PARAMETERS_PLACEHOLDER = Buffer.from('9192939495969798', 'hex');
902 +
903 +Encryption.encryptPdu = function (scopedPdu, privProtocol, privPassword, authProtocol, engineID) {
904 + var privLocalizedKey;
905 + var encryptionKey;
906 + var preIv;
907 + var salt;
908 + var iv;
909 + var i;
910 + var paddedScopedPduLength;
911 + var paddedScopedPdu;
912 + var encryptedPdu;
913 + var cbcProtocol = Encryption.CRYPTO_DES_ALGORITHM;
914 +
915 + privLocalizedKey = Authentication.passwordToKey(authProtocol, privPassword, engineID);
916 + encryptionKey = Buffer.alloc(Encryption.DES_KEY_LENGTH);
917 + privLocalizedKey.copy(encryptionKey, 0, 0, Encryption.DES_KEY_LENGTH);
918 + preIv = Buffer.alloc(Encryption.DES_BLOCK_LENGTH);
919 + privLocalizedKey.copy(preIv, 0, Encryption.DES_KEY_LENGTH, Encryption.DES_KEY_LENGTH + Encryption.DES_BLOCK_LENGTH);
920 +
921 + salt = Buffer.alloc(Encryption.DES_BLOCK_LENGTH);
922 + // set local SNMP engine boots part of salt to 1, as we have no persistent engine state
923 + salt.fill('00000001', 0, 4, 'hex');
924 + // set local integer part of salt to random
925 + salt.fill(crypto.randomBytes(4), 4, 8);
926 + iv = Buffer.alloc(Encryption.DES_BLOCK_LENGTH);
927 + for (i = 0; i < iv.length; i++) {
928 + iv[i] = preIv[i] ^ salt[i];
929 + }
930 +
931 + if (scopedPdu.length % Encryption.DES_BLOCK_LENGTH == 0) {
932 + paddedScopedPdu = scopedPdu;
933 + } else {
934 + paddedScopedPduLength = Encryption.DES_BLOCK_LENGTH * (Math.floor(scopedPdu.length / Encryption.DES_BLOCK_LENGTH) + 1);
935 + paddedScopedPdu = Buffer.alloc(paddedScopedPduLength);
936 + scopedPdu.copy(paddedScopedPdu, 0, 0, scopedPdu.length);
937 + }
938 + cipher = crypto.createCipheriv(cbcProtocol, encryptionKey, iv);
939 + encryptedPdu = cipher.update(paddedScopedPdu);
940 + encryptedPdu = Buffer.concat([encryptedPdu, cipher.final()]);
941 + debug("Key: " + encryptionKey.toString('hex'));
942 + debug("IV: " + iv.toString('hex'));
943 + debug("Plain: " + paddedScopedPdu.toString('hex'));
944 + debug("Encrypted: " + encryptedPdu.toString('hex'));
945 +
946 + return {
947 + encryptedPdu: encryptedPdu,
948 + msgPrivacyParameters: salt
949 + };
950 +};
951 +
952 +Encryption.decryptPdu = function (encryptedPdu, privProtocol, privParameters, privPassword, authProtocol, engineID, forceAutoPaddingDisable) {
953 + var privLocalizedKey;
954 + var decryptionKey;
955 + var preIv;
956 + var salt;
957 + var iv;
958 + var i;
959 + var decryptedPdu;
960 + var cbcProtocol = Encryption.CRYPTO_DES_ALGORITHM;
961 + ;
962 +
963 + privLocalizedKey = Authentication.passwordToKey(authProtocol, privPassword, engineID);
964 + decryptionKey = Buffer.alloc(Encryption.DES_KEY_LENGTH);
965 + privLocalizedKey.copy(decryptionKey, 0, 0, Encryption.DES_KEY_LENGTH);
966 + preIv = Buffer.alloc(Encryption.DES_BLOCK_LENGTH);
967 + privLocalizedKey.copy(preIv, 0, Encryption.DES_KEY_LENGTH, Encryption.DES_KEY_LENGTH + Encryption.DES_BLOCK_LENGTH);
968 +
969 + salt = privParameters;
970 + iv = Buffer.alloc(Encryption.DES_BLOCK_LENGTH);
971 + for (i = 0; i < iv.length; i++) {
972 + iv[i] = preIv[i] ^ salt[i];
973 + }
974 +
975 + decipher = crypto.createDecipheriv(cbcProtocol, decryptionKey, iv);
976 + if (forceAutoPaddingDisable) {
977 + decipher.setAutoPadding(false);
978 + }
979 + decryptedPdu = decipher.update(encryptedPdu);
980 + // This try-catch is a workaround for a seemingly incorrect error condition
981 + // - where sometimes a decrypt error is thrown with decipher.final()
982 + // It replaces this line which should have been sufficient:
983 + // decryptedPdu = Buffer.concat ([decryptedPdu, decipher.final()]);
984 + try {
985 + decryptedPdu = Buffer.concat([decryptedPdu, decipher.final()]);
986 + } catch (error) {
987 + // debug("Decrypt error: " + error);
988 + decipher = crypto.createDecipheriv(cbcProtocol, decryptionKey, iv);
989 + decipher.setAutoPadding(false);
990 + decryptedPdu = decipher.update(encryptedPdu);
991 + decryptedPdu = Buffer.concat([decryptedPdu, decipher.final()]);
992 + }
993 + debug("Key: " + decryptionKey.toString('hex'));
994 + debug("IV: " + iv.toString('hex'));
995 + debug("Encrypted: " + encryptedPdu.toString('hex'));
996 + debug("Plain: " + decryptedPdu.toString('hex'));
997 +
998 + return decryptedPdu;
999 +
1000 +};
1001 +
1002 +Encryption.addParametersToMessageBuffer = function (messageBuffer, msgPrivacyParameters) {
1003 + privacyParametersOffset = messageBuffer.indexOf(Encryption.PRIV_PARAMETERS_PLACEHOLDER);
1004 + msgPrivacyParameters.copy(messageBuffer, privacyParametersOffset, 0, Encryption.DES_IV_LENGTH);
1005 +};
1006
1007 /*****************************************************************************
498 - ** Message class definitions
1008 + ** Message class definition
1009 **/
1010
501 -var RequestMessage = function (version, community, pdu) {
502 - this.version = version;
503 - this.community = community;
504 - this.pdu = pdu;
1011 +var Message = function () {
1012 +}
1013 +
1014 +Message.prototype.getReqId = function () {
1015 + return this.version == Version3 ? this.msgGlobalData.msgID : this.pdu.id;
1016 +};
1017 +
1018 +Message.prototype.toBuffer = function () {
1019 + if (this.version == Version3) {
1020 + return this.toBufferV3();
1021 + } else {
1022 + return this.toBufferCommunity();
1023 + }
1024 +}
1025 +
1026 +Message.prototype.toBufferCommunity = function () {
1027 + if (this.buffer)
1028 + return this.buffer;
1029 +
1030 + var writer = new ber.Writer();
1031 +
1032 + writer.startSequence();
1033 +
1034 + writer.writeInt(this.version);
1035 + writer.writeString(this.community);
1036 +
1037 + this.pdu.toBuffer(writer);
1038 +
1039 + writer.endSequence();
1040 +
1041 + this.buffer = writer.buffer;
1042 +
1043 + return this.buffer;
1044 +};
1045 +
1046 +Message.prototype.toBufferV3 = function () {
1047 + var encryptionResult;
1048 +
1049 + if (this.buffer)
1050 + return this.buffer;
1051 +
1052 + var writer = new ber.Writer();
1053 +
1054 + writer.startSequence();
1055 +
1056 + writer.writeInt(this.version);
1057 +
1058 + // HeaderData
1059 + writer.startSequence();
1060 + writer.writeInt(this.msgGlobalData.msgID);
1061 + writer.writeInt(this.msgGlobalData.msgMaxSize);
1062 + writer.writeByte(ber.OctetString);
1063 + writer.writeByte(1);
1064 + writer.writeByte(this.msgGlobalData.msgFlags);
1065 + writer.writeInt(this.msgGlobalData.msgSecurityModel);
1066 + writer.endSequence();
1067 +
1068 + // msgSecurityParameters
1069 + var msgSecurityParametersWriter = new ber.Writer();
1070 + msgSecurityParametersWriter.startSequence();
1071 + //msgSecurityParametersWriter.writeString (this.msgSecurityParameters.msgAuthoritativeEngineID);
1072 + // writing a zero-length buffer fails - should fix asn1-ber for this condition
1073 + if (this.msgSecurityParameters.msgAuthoritativeEngineID.length == 0) {
1074 + msgSecurityParametersWriter.writeString("");
1075 + } else {
1076 + msgSecurityParametersWriter.writeBuffer(this.msgSecurityParameters.msgAuthoritativeEngineID, ber.OctetString);
1077 + }
1078 + msgSecurityParametersWriter.writeInt(this.msgSecurityParameters.msgAuthoritativeEngineBoots);
1079 + msgSecurityParametersWriter.writeInt(this.msgSecurityParameters.msgAuthoritativeEngineTime);
1080 + msgSecurityParametersWriter.writeString(this.msgSecurityParameters.msgUserName);
1081 +
1082 + if (this.hasAuthentication()) {
1083 + msgSecurityParametersWriter.writeBuffer(Authentication.AUTH_PARAMETERS_PLACEHOLDER, ber.OctetString);
1084 + // should never happen where msgFlags has no authentication but authentication parameters still present
1085 + } else if (this.msgSecurityParameters.msgAuthenticationParameters.length > 0) {
1086 + msgSecurityParametersWriter.writeBuffer(this.msgSecurityParameters.msgAuthenticationParameters, ber.OctetString);
1087 + } else {
1088 + msgSecurityParametersWriter.writeString("");
1089 + }
1090 +
1091 + if (this.hasPrivacy()) {
1092 + msgSecurityParametersWriter.writeBuffer(Encryption.PRIV_PARAMETERS_PLACEHOLDER, ber.OctetString);
1093 + // should never happen where msgFlags has no privacy but privacy parameters still present
1094 + } else if (this.msgSecurityParameters.msgPrivacyParameters.length > 0) {
1095 + msgSecurityParametersWriter.writeBuffer(this.msgSecurityParameters.msgPrivacyParameters, ber.OctetString);
1096 + } else {
1097 + msgSecurityParametersWriter.writeString("");
1098 + }
1099 + msgSecurityParametersWriter.endSequence();
1100 +
1101 + writer.writeBuffer(msgSecurityParametersWriter.buffer, ber.OctetString);
1102 +
1103 + // ScopedPDU
1104 + var scopedPduWriter = new ber.Writer();
1105 + scopedPduWriter.startSequence();
1106 + var contextEngineID = this.pdu.contextEngineID ? this.pdu.contextEngineID : this.msgSecurityParameters.msgAuthoritativeEngineID;
1107 + if (contextEngineID.length == 0) {
1108 + scopedPduWriter.writeString("");
1109 + } else {
1110 + scopedPduWriter.writeBuffer(contextEngineID, ber.OctetString);
1111 + }
1112 + scopedPduWriter.writeString(this.pdu.contextName);
1113 + this.pdu.toBuffer(scopedPduWriter);
1114 + scopedPduWriter.endSequence();
1115 +
1116 + if (this.hasPrivacy()) {
1117 + encryptionResult = Encryption.encryptPdu(scopedPduWriter.buffer, this.user.privProtocol, this.user.privKey, this.user.authProtocol, this.msgSecurityParameters.msgAuthoritativeEngineID);
1118 + writer.writeBuffer(encryptionResult.encryptedPdu, ber.OctetString);
1119 + } else {
1120 + writer.writeBuffer(scopedPduWriter.buffer);
1121 + }
1122 +
1123 + writer.endSequence();
1124 +
1125 + this.buffer = writer.buffer;
1126 +
1127 + if (this.hasPrivacy()) {
1128 + Encryption.addParametersToMessageBuffer(this.buffer, encryptionResult.msgPrivacyParameters);
1129 + }
1130 +
1131 + if (this.hasAuthentication()) {
1132 + Authentication.addParametersToMessageBuffer(this.buffer, this.user.authProtocol, this.user.authKey,
1133 + this.msgSecurityParameters.msgAuthoritativeEngineID);
1134 + }
1135 +
1136 + return this.buffer;
1137 +};
1138 +
1139 +Message.prototype.processIncomingSecurity = function (user, responseCb) {
1140 + if (this.hasPrivacy()) {
1141 + if (!this.decryptPdu(user, responseCb)) {
1142 + return false;
1143 + }
1144 + }
1145 +
1146 + if (this.hasAuthentication() && !this.isAuthenticationDisabled()) {
1147 + return this.checkAuthentication(user, responseCb);
1148 + } else {
1149 + return true;
1150 + }
1151 +};
1152 +
1153 +Message.prototype.decryptPdu = function (user, responseCb) {
1154 + var decryptedPdu;
1155 + var decryptedPduReader;
1156 + try {
1157 + decryptedPdu = Encryption.decryptPdu(this.encryptedPdu, user.privProtocol,
1158 + this.msgSecurityParameters.msgPrivacyParameters, user.privKey, user.authProtocol,
1159 + this.msgSecurityParameters.msgAuthoritativeEngineID);
1160 + decryptedPduReader = new ber.Reader(decryptedPdu);
1161 + this.pdu = readPdu(decryptedPduReader, true);
1162 + return true;
1163 + // really really occasionally the decrypt truncates a single byte
1164 + // causing an ASN read failure in readPdu()
1165 + // in this case, disabling auto padding decrypts the PDU correctly
1166 + // this try-catch provides the workaround for this condition
1167 + } catch (possibleTruncationError) {
1168 + try {
1169 + decryptedPdu = Encryption.decryptPdu(this.encryptedPdu, user.privProtocol,
1170 + this.msgSecurityParameters.msgPrivacyParameters, user.privKey, user.authProtocol,
1171 + this.msgSecurityParameters.msgAuthoritativeEngineID, true);
1172 + decryptedPduReader = new ber.Reader(decryptedPdu);
1173 + this.pdu = readPdu(decryptedPduReader, true);
1174 + return true;
1175 + } catch (error) {
1176 + responseCb(new ResponseInvalidError("Failed to decrypt PDU: " + error));
1177 + return false;
1178 + }
1179 + }
1180 +
1181 +};
1182 +
1183 +Message.prototype.checkAuthentication = function (user, responseCb) {
1184 + if (Authentication.isAuthentic(this.buffer, user.authProtocol, user.authKey,
1185 + this.msgSecurityParameters.msgAuthoritativeEngineID, this.msgSecurityParameters.msgAuthenticationParameters)) {
1186 + return true;
1187 + } else {
1188 + responseCb(new ResponseInvalidError("Authentication digest "
1189 + + this.msgSecurityParameters.msgAuthenticationParameters.toString('hex')
1190 + + " received in message does not match digest "
1191 + + Authentication.calculateDigest(buffer, user.authProtocol, user.authKey,
1192 + this.msgSecurityParameters.msgAuthoritativeEngineID).toString('hex')
1193 + + " calculated for message"));
1194 + return false;
1195 + }
1196 +
1197 +};
1198 +
1199 +Message.prototype.hasAuthentication = function () {
1200 + return this.msgGlobalData && this.msgGlobalData.msgFlags && this.msgGlobalData.msgFlags & 1;
1201 };
1202
507 -RequestMessage.prototype.toBuffer = function () {
508 - if (this.buffer)
509 - return this.buffer;
1203 +Message.prototype.hasPrivacy = function () {
1204 + return this.msgGlobalData && this.msgGlobalData.msgFlags && this.msgGlobalData.msgFlags & 2;
1205 +};
1206 +
1207 +Message.prototype.isReportable = function () {
1208 + return this.msgGlobalData && this.msgGlobalData.msgFlags && this.msgGlobalData.msgFlags & 4;
1209 +};
1210
511 - var writer = new ber.Writer ();
1211 +Message.prototype.setReportable = function (flag) {
1212 + if (this.msgGlobalData && this.msgGlobalData.msgFlags) {
1213 + if (flag) {
1214 + this.msgGlobalData.msgFlags = this.msgGlobalData.msgFlags | 4;
1215 + } else {
1216 + this.msgGlobalData.msgFlags = this.msgGlobalData.msgFlags & (255 - 4);
1217 + }
1218 + }
1219 +};
1220
513 - writer.startSequence ();
1221 +Message.prototype.isAuthenticationDisabled = function () {
1222 + return this.disableAuthentication;
1223 +};
1224
515 - writer.writeInt (this.version);
516 - writer.writeString (this.community);
1225 +Message.prototype.hasAuthoritativeEngineID = function () {
1226 + return this.msgSecurityParameters && this.msgSecurityParameters.msgAuthoritativeEngineID &&
1227 + this.msgSecurityParameters.msgAuthoritativeEngineID != "";
1228 +};
1229
518 - this.pdu.toBuffer (writer);
1230 +Message.prototype.createReportResponseMessage = function (engine, context) {
1231 + var user = {
1232 + name: "",
1233 + level: SecurityLevel.noAuthNoPriv
1234 + };
1235 + var responseSecurityParameters = {
1236 + msgAuthoritativeEngineID: engine.engineID,
1237 + msgAuthoritativeEngineBoots: engine.engineBoots,
1238 + msgAuthoritativeEngineTime: engine.engineTime,
1239 + msgUserName: user.name,
1240 + msgAuthenticationParameters: "",
1241 + msgPrivacyParameters: ""
1242 + };
1243 + var reportPdu = ReportPdu.createFromVariables(this.pdu.id, [], {});
1244 + reportPdu.contextName = context;
1245 + var responseMessage = Message.createRequestV3(user, responseSecurityParameters, reportPdu);
1246 + responseMessage.msgGlobalData.msgID = this.msgGlobalData.msgID;
1247 + return responseMessage;
1248 +};
1249
520 - writer.endSequence ();
1250 +Message.prototype.createResponseForRequest = function (responsePdu) {
1251 + if (this.version == Version3) {
1252 + return this.createV3ResponseFromRequest(responsePdu);
1253 + } else {
1254 + return this.createCommunityResponseFromRequest(responsePdu);
1255 + }
1256 +};
1257
522 - this.buffer = writer.buffer;
1258 +Message.prototype.createCommunityResponseFromRequest = function (responsePdu) {
1259 + return Message.createCommunity(this.version, this.community, responsePdu);
1260 +};
1261
524 - return this.buffer;
1262 +Message.prototype.createV3ResponseFromRequest = function (responsePdu) {
1263 + var responseUser = {
1264 + name: this.user.name,
1265 + level: this.user.name,
1266 + authProtocol: this.user.authProtocol,
1267 + authKey: this.user.authKey,
1268 + privProtocol: this.user.privProtocol,
1269 + privKey: this.user.privKey
1270 + };
1271 + var responseSecurityParameters = {
1272 + msgAuthoritativeEngineID: this.msgSecurityParameters.msgAuthoritativeEngineID,
1273 + msgAuthoritativeEngineBoots: this.msgSecurityParameters.msgAuthoritativeEngineBoots,
1274 + msgAuthoritativeEngineTime: this.msgSecurityParameters.msgAuthoritativeEngineTime,
1275 + msgUserName: this.msgSecurityParameters.msgUserName,
1276 + msgAuthenticationParameters: "",
1277 + msgPrivacyParameters: ""
1278 + };
1279 + var responseGlobalData = {
1280 + msgID: this.msgGlobalData.msgID,
1281 + msgMaxSize: 65507,
1282 + msgFlags: this.msgGlobalData.msgFlags & (255 - 4),
1283 + msgSecurityModel: 3
1284 + };
1285 + return Message.createV3(responseUser, responseGlobalData, responseSecurityParameters, responsePdu);
1286 };
1287
527 -var ResponseMessage = function (buffer) {
528 - var reader = new ber.Reader (buffer);
1288 +Message.createCommunity = function (version, community, pdu) {
1289 + var message = new Message();
1290 +
1291 + message.version = version;
1292 + message.community = community;
1293 + message.pdu = pdu;
1294 +
1295 + return message;
1296 +};
1297
530 - reader.readSequence ();
1298 +Message.createRequestV3 = function (user, msgSecurityParameters, pdu) {
1299 + var authFlag = user.level == SecurityLevel.authNoPriv || user.level == SecurityLevel.authPriv ? 1 : 0;
1300 + var privFlag = user.level == SecurityLevel.authPriv ? 1 : 0;
1301 + var reportableFlag = (pdu.type == PduType.GetResponse || pdu.type == PduType.TrapV2) ? 0 : 1;
1302 + var msgGlobalData = {
1303 + msgID: _generateId(), // random ID
1304 + msgMaxSize: 65507,
1305 + msgFlags: reportableFlag * 4 | privFlag * 2 | authFlag * 1,
1306 + msgSecurityModel: 3
1307 + };
1308 + return Message.createV3(user, msgGlobalData, msgSecurityParameters, pdu);
1309 +};
1310
532 - this.version = reader.readInt ();
533 - this.community = reader.readString ();
1311 +Message.createV3 = function (user, msgGlobalData, msgSecurityParameters, pdu) {
1312 + var message = new Message();
1313 +
1314 + message.version = 3;
1315 + message.user = user;
1316 + message.msgGlobalData = msgGlobalData;
1317 + message.msgSecurityParameters = {
1318 + msgAuthoritativeEngineID: msgSecurityParameters.msgAuthoritativeEngineID || Buffer.from(""),
1319 + msgAuthoritativeEngineBoots: msgSecurityParameters.msgAuthoritativeEngineBoots || 0,
1320 + msgAuthoritativeEngineTime: msgSecurityParameters.msgAuthoritativeEngineTime || 0,
1321 + msgUserName: user.name || "",
1322 + msgAuthenticationParameters: "",
1323 + msgPrivacyParameters: ""
1324 + };
1325 + message.pdu = pdu;
1326 +
1327 + return message;
1328 +};
1329
535 - var type = reader.peek ();
1330 +Message.createDiscoveryV3 = function (pdu) {
1331 + var msgSecurityParameters = {
1332 + msgAuthoritativeEngineID: Buffer.from(""),
1333 + msgAuthoritativeEngineBoots: 0,
1334 + msgAuthoritativeEngineTime: 0
1335 + };
1336 + var emptyUser = {
1337 + name: "",
1338 + level: SecurityLevel.noAuthNoPriv
1339 + };
1340 + return Message.createRequestV3(emptyUser, msgSecurityParameters, pdu);
1341 +}
1342
537 - if (type == PduType.GetResponse) {
538 - this.pdu = new GetResponsePdu (reader);
539 - } else {
540 - throw new ResponseInvalidError ("Unknown PDU type '" + type
541 - + "' in response");
542 - }
1343 +Message.createFromBuffer = function (buffer, user) {
1344 + var reader = new ber.Reader(buffer);
1345 + var message = new Message();
1346 +
1347 + reader.readSequence();
1348 +
1349 + message.version = reader.readInt();
1350 +
1351 + if (message.version != 3) {
1352 + message.community = reader.readString();
1353 + message.pdu = readPdu(reader, false);
1354 + } else {
1355 + // HeaderData
1356 + message.msgGlobalData = {};
1357 + reader.readSequence();
1358 + message.msgGlobalData.msgID = reader.readInt();
1359 + message.msgGlobalData.msgMaxSize = reader.readInt();
1360 + message.msgGlobalData.msgFlags = reader.readString(ber.OctetString, true)[0];
1361 + message.msgGlobalData.msgSecurityModel = reader.readInt();
1362 +
1363 + // msgSecurityParameters
1364 + message.msgSecurityParameters = {};
1365 + var msgSecurityParametersReader = new ber.Reader(reader.readString(ber.OctetString, true));
1366 + msgSecurityParametersReader.readSequence();
1367 + message.msgSecurityParameters.msgAuthoritativeEngineID = msgSecurityParametersReader.readString(ber.OctetString, true);
1368 + message.msgSecurityParameters.msgAuthoritativeEngineBoots = msgSecurityParametersReader.readInt();
1369 + message.msgSecurityParameters.msgAuthoritativeEngineTime = msgSecurityParametersReader.readInt();
1370 + message.msgSecurityParameters.msgUserName = msgSecurityParametersReader.readString();
1371 + message.msgSecurityParameters.msgAuthenticationParameters = Buffer.from(msgSecurityParametersReader.readString(ber.OctetString, true));
1372 + message.msgSecurityParameters.msgPrivacyParameters = Buffer.from(msgSecurityParametersReader.readString(ber.OctetString, true));
1373 + scopedPdu = true;
1374 +
1375 + if (message.hasPrivacy()) {
1376 + message.encryptedPdu = reader.readString(ber.OctetString, true);
1377 + message.pdu = null;
1378 + } else {
1379 + message.pdu = readPdu(reader, true);
1380 + }
1381 + }
1382 +
1383 + message.buffer = buffer;
1384 +
1385 + return message;
1386 };
1387
1388 +
1389 +var Req = function (session, message, feedCb, responseCb, options) {
1390 +
1391 + this.message = message;
1392 + this.responseCb = responseCb;
1393 + this.retries = session.retries;
1394 + this.timeout = session.timeout;
1395 + this.onResponse = session.onSimpleGetResponse;
1396 + this.feedCb = feedCb;
1397 + this.port = (options && options.port) ? options.port : session.port;
1398 + this.context = session.context;
1399 +};
1400 +
1401 +Req.prototype.getId = function () {
1402 + return this.message.getReqId();
1403 +};
1404 +
1405 +
1406 /*****************************************************************************
1407 ** Session class definition
1408 **/
1409
549 -var Session = function (target, community, options) {
550 - this.target = target || "127.0.0.1";
551 - this.community = community || "public";
552 -
553 - this.version = (options && options.version)
554 - ? options.version
555 - : Version1;
556 -
557 - this.transport = (options && options.transport)
558 - ? options.transport
559 - : "udp4";
560 - this.port = (options && options.port )
561 - ? options.port
562 - : 161;
563 - this.trapPort = (options && options.trapPort )
564 - ? options.trapPort
565 - : 162;
566 -
567 - this.retries = (options && (options.retries || options.retries == 0))
568 - ? options.retries
569 - : 1;
570 - this.timeout = (options && options.timeout)
571 - ? options.timeout
572 - : 5000;
573 -
574 - this.sourceAddress = (options && options.sourceAddress )
575 - ? options.sourceAddress
576 - : undefined;
577 - this.sourcePort = (options && options.sourcePort )
578 - ? parseInt(options.sourcePort)
579 - : undefined;
580 -
581 - this.idBitsSize = (options && options.idBitsSize)
582 - ? parseInt(options.idBitsSize)
583 - : 32;
584 -
585 - this.reqs = {};
586 - this.reqCount = 0;
587 -
588 - this.dgram = dgram.createSocket (this.transport);
589 - this.dgram.unref();
590 -
591 - var me = this;
592 - this.dgram.on ("message", me.onMsg.bind (me));
593 - this.dgram.on ("close", me.onClose.bind (me));
594 - this.dgram.on ("error", me.onError.bind (me));
595 -
596 - if (this.sourceAddress || this.sourcePort)
597 - this.dgram.bind (this.sourcePort, this.sourceAddress);
598 -};
599 -
600 -util.inherits (Session, events.EventEmitter);
1410 +var Session = function (target, authenticator, options) {
1411 + this.target = target || "127.0.0.1";
1412 +
1413 + this.version = (options && options.version)
1414 + ? options.version
1415 + : Version1;
1416 +
1417 + if (this.version == Version3) {
1418 + this.user = authenticator;
1419 + } else {
1420 + this.community = authenticator || "public";
1421 + }
1422 +
1423 + this.transport = (options && options.transport)
1424 + ? options.transport
1425 + : "udp4";
1426 + this.port = (options && options.port)
1427 + ? options.port
1428 + : 161;
1429 + this.trapPort = (options && options.trapPort)
1430 + ? options.trapPort
1431 + : 162;
1432 +
1433 + this.retries = (options && (options.retries || options.retries == 0))
1434 + ? options.retries
1435 + : 1;
1436 + this.timeout = (options && options.timeout)
1437 + ? options.timeout
1438 + : 5000;
1439 +
1440 + this.sourceAddress = (options && options.sourceAddress)
1441 + ? options.sourceAddress
1442 + : undefined;
1443 + this.sourcePort = (options && options.sourcePort)
1444 + ? parseInt(options.sourcePort)
1445 + : undefined;
1446 +
1447 + this.idBitsSize = (options && options.idBitsSize)
1448 + ? parseInt(options.idBitsSize)
1449 + : 32;
1450 +
1451 + this.context = (options && options.context) ? options.context : "";
1452 +
1453 + DEBUG = options.debug;
1454 +
1455 + this.reqs = {};
1456 + this.reqCount = 0;
1457 +
1458 + this.dgram = dgram.createSocket(this.transport);
1459 + this.dgram.unref();
1460 +
1461 + var me = this;
1462 + this.dgram.on("message", me.onMsg.bind(me));
1463 + this.dgram.on("close", me.onClose.bind(me));
1464 + this.dgram.on("error", me.onError.bind(me));
1465 +
1466 + if (this.sourceAddress || this.sourcePort)
1467 + this.dgram.bind(this.sourcePort, this.sourceAddress);
1468 +};
1469 +
1470 +util.inherits(Session, events.EventEmitter);
1471
1472 Session.prototype.close = function () {
603 - this.dgram.close ();
604 - return this;
1473 + this.dgram.close();
1474 + return this;
1475 };
1476
1477 Session.prototype.cancelRequests = function (error) {
608 - var id;
609 - for (id in this.reqs) {
610 - var req = this.reqs[id];
611 - this.unregisterRequest (req.id);
612 - req.responseCb (error);
613 - }
614 -};
615 -
616 -function _generateId (bitSize) {
617 - if (bitSize === 16) {
618 - return Math.floor(Math.random() * 10000) % 65535;
619 - }
620 - return Math.floor(Math.random() * 100000000) % 4294967295;
1478 + var id;
1479 + for (id in this.reqs) {
1480 + var req = this.reqs[id];
1481 + this.unregisterRequest(req.getId());
1482 + req.responseCb(error);
1483 + }
1484 +};
1485 +
1486 +function _generateId(bitSize) {
1487 + if (bitSize === 16) {
1488 + return Math.floor(Math.random() * 10000) % 65535;
1489 + }
1490 + return Math.floor(Math.random() * 100000000) % 4294967295;
1491 }
1492
1493 Session.prototype.get = function (oids, responseCb) {
624 - function feedCb (req, message) {
625 - var pdu = message.pdu;
626 - var varbinds = [];
627 -
628 - if (req.message.pdu.varbinds.length != pdu.varbinds.length) {
629 - req.responseCb (new ResponseInvalidError ("Requested OIDs do not "
630 - + "match response OIDs"));
631 - } else {
632 - for (var i = 0; i < req.message.pdu.varbinds.length; i++) {
633 - if (req.message.pdu.varbinds[i].oid != pdu.varbinds[i].oid) {
634 - req.responseCb (new ResponseInvalidError ("OID '"
635 - + req.message.pdu.varbinds[i].oid
636 - + "' in request at positiion '" + i + "' does not "
637 - + "match OID '" + pdu.varbinds[i].oid + "' in response "
638 - + "at position '" + i + "'"));
639 - return;
640 - } else {
641 - varbinds.push (pdu.varbinds[i]);
642 - }
643 - }
644 -
645 - req.responseCb (null, varbinds);
646 - }
647 - }
648 -
649 - var pduVarbinds = [];
650 -
651 - for (var i = 0; i < oids.length; i++) {
652 - var varbind = {
653 - oid: oids[i]
654 - };
655 - pduVarbinds.push (varbind);
656 - }
657 -
658 - this.simpleGet (GetRequestPdu, feedCb, pduVarbinds, responseCb);
659 -
660 - return this;
1494 + function feedCb(req, message) {
1495 + var pdu = message.pdu;
1496 + var varbinds = [];
1497 +
1498 + if (req.message.pdu.varbinds.length != pdu.varbinds.length) {
1499 + req.responseCb(new ResponseInvalidError("Requested OIDs do not "
1500 + + "match response OIDs"));
1501 + } else {
1502 + for (var i = 0; i < req.message.pdu.varbinds.length; i++) {
1503 + if (req.message.pdu.varbinds[i].oid != pdu.varbinds[i].oid) {
1504 + req.responseCb(new ResponseInvalidError("OID '"
1505 + + req.message.pdu.varbinds[i].oid
1506 + + "' in request at positiion '" + i + "' does not "
1507 + + "match OID '" + pdu.varbinds[i].oid + "' in response "
1508 + + "at position '" + i + "'"));
1509 + return;
1510 + } else {
1511 + varbinds.push(pdu.varbinds[i]);
1512 + }
1513 + }
1514 +
1515 + req.responseCb(null, varbinds);
1516 + }
1517 + }
1518 +
1519 + var pduVarbinds = [];
1520 +
1521 + for (var i = 0; i < oids.length; i++) {
1522 + var varbind = {
1523 + oid: oids[i]
1524 + };
1525 + pduVarbinds.push(varbind);
1526 + }
1527 +
1528 + this.simpleGet(GetRequestPdu, feedCb, pduVarbinds, responseCb);
1529 +
1530 + return this;
1531 };
1532
1533 Session.prototype.getBulk = function () {
664 - var oids, nonRepeaters, maxRepetitions, responseCb;
665 -
666 - if (arguments.length >= 4) {
667 - oids = arguments[0];
668 - nonRepeaters = arguments[1];
669 - maxRepetitions = arguments[2];
670 - responseCb = arguments[3];
671 - } else if (arguments.length >= 3) {
672 - oids = arguments[0];
673 - nonRepeaters = arguments[1];
674 - maxRepetitions = 10;
675 - responseCb = arguments[2];
676 - } else {
677 - oids = arguments[0];
678 - nonRepeaters = 0;
679 - maxRepetitions = 10;
680 - responseCb = arguments[1];
681 - }
682 -
683 - function feedCb (req, message) {
684 - var pdu = message.pdu;
685 - var varbinds = [];
686 - var i = 0;
687 -
688 - // first walk through and grab non-repeaters
689 - if (pdu.varbinds.length < nonRepeaters) {
690 - req.responseCb (new ResponseInvalidError ("Varbind count in "
691 - + "response '" + pdu.varbinds.length + "' is less than "
692 - + "non-repeaters '" + nonRepeaters + "' in request"));
693 - } else {
694 - for ( ; i < nonRepeaters; i++) {
695 - if (isVarbindError (pdu.varbinds[i])) {
696 - varbinds.push (pdu.varbinds[i]);
697 - } else if (! oidFollowsOid (req.message.pdu.varbinds[i].oid,
698 - pdu.varbinds[i].oid)) {
699 - req.responseCb (new ResponseInvalidError ("OID '"
700 - + req.message.pdu.varbinds[i].oid + "' in request at "
701 - + "positiion '" + i + "' does not precede "
702 - + "OID '" + pdu.varbinds[i].oid + "' in response "
703 - + "at position '" + i + "'"));
704 - return;
705 - } else {
706 - varbinds.push (pdu.varbinds[i]);
707 - }
708 - }
709 - }
710 -
711 - var repeaters = req.message.pdu.varbinds.length - nonRepeaters;
712 -
713 - // secondly walk through and grab repeaters
714 - if (pdu.varbinds.length % (repeaters)) {
715 - req.responseCb (new ResponseInvalidError ("Varbind count in "
716 - + "response '" + pdu.varbinds.length + "' is not a "
717 - + "multiple of repeaters '" + repeaters
718 - + "' plus non-repeaters '" + nonRepeaters + "' in request"));
719 - } else {
720 - while (i < pdu.varbinds.length) {
721 - for (var j = 0; j < repeaters; j++, i++) {
722 - var reqIndex = nonRepeaters + j;
723 - var respIndex = i;
724 -
725 - if (isVarbindError (pdu.varbinds[respIndex])) {
726 - if (! varbinds[reqIndex])
727 - varbinds[reqIndex] = [];
728 - varbinds[reqIndex].push (pdu.varbinds[respIndex]);
729 - } else if (! oidFollowsOid (
730 - req.message.pdu.varbinds[reqIndex].oid,
731 - pdu.varbinds[respIndex].oid)) {
732 - req.responseCb (new ResponseInvalidError ("OID '"
733 - + req.message.pdu.varbinds[reqIndex].oid
734 - + "' in request at positiion '" + (reqIndex)
735 - + "' does not precede OID '"
736 - + pdu.varbinds[respIndex].oid
737 - + "' in response at position '" + (respIndex) + "'"));
738 - return;
739 - } else {
740 - if (! varbinds[reqIndex])
741 - varbinds[reqIndex] = [];
742 - varbinds[reqIndex].push (pdu.varbinds[respIndex]);
743 - }
744 - }
745 - }
746 - }
747 -
748 - req.responseCb (null, varbinds);
749 - }
750 -
751 - var pduVarbinds = [];
752 -
753 - for (var i = 0; i < oids.length; i++) {
754 - var varbind = {
755 - oid: oids[i]
756 - };
757 - pduVarbinds.push (varbind);
758 - }
759 -
760 - var options = {
761 - nonRepeaters: nonRepeaters,
762 - maxRepetitions: maxRepetitions
763 - };
764 -
765 - this.simpleGet (GetBulkRequestPdu, feedCb, pduVarbinds, responseCb,
766 - options);
767 -
768 - return this;
1534 + var oids, nonRepeaters, maxRepetitions, responseCb;
1535 +
1536 + if (arguments.length >= 4) {
1537 + oids = arguments[0];
1538 + nonRepeaters = arguments[1];
1539 + maxRepetitions = arguments[2];
1540 + responseCb = arguments[3];
1541 + } else if (arguments.length >= 3) {
1542 + oids = arguments[0];
1543 + nonRepeaters = arguments[1];
1544 + maxRepetitions = 10;
1545 + responseCb = arguments[2];
1546 + } else {
1547 + oids = arguments[0];
1548 + nonRepeaters = 0;
1549 + maxRepetitions = 10;
1550 + responseCb = arguments[1];
1551 + }
1552 +
1553 + function feedCb(req, message) {
1554 + var pdu = message.pdu;
1555 + var varbinds = [];
1556 + var i = 0;
1557 +
1558 + // first walk through and grab non-repeaters
1559 + if (pdu.varbinds.length < nonRepeaters) {
1560 + req.responseCb(new ResponseInvalidError("Varbind count in "
1561 + + "response '" + pdu.varbinds.length + "' is less than "
1562 + + "non-repeaters '" + nonRepeaters + "' in request"));
1563 + } else {
1564 + for (; i < nonRepeaters; i++) {
1565 + if (isVarbindError(pdu.varbinds[i])) {
1566 + varbinds.push(pdu.varbinds[i]);
1567 + } else if (!oidFollowsOid(req.message.pdu.varbinds[i].oid,
1568 + pdu.varbinds[i].oid)) {
1569 + req.responseCb(new ResponseInvalidError("OID '"
1570 + + req.message.pdu.varbinds[i].oid + "' in request at "
1571 + + "positiion '" + i + "' does not precede "
1572 + + "OID '" + pdu.varbinds[i].oid + "' in response "
1573 + + "at position '" + i + "'"));
1574 + return;
1575 + } else {
1576 + varbinds.push(pdu.varbinds[i]);
1577 + }
1578 + }
1579 + }
1580 +
1581 + var repeaters = req.message.pdu.varbinds.length - nonRepeaters;
1582 +
1583 + // secondly walk through and grab repeaters
1584 + if (pdu.varbinds.length % (repeaters)) {
1585 + req.responseCb(new ResponseInvalidError("Varbind count in "
1586 + + "response '" + pdu.varbinds.length + "' is not a "
1587 + + "multiple of repeaters '" + repeaters
1588 + + "' plus non-repeaters '" + nonRepeaters + "' in request"));
1589 + } else {
1590 + while (i < pdu.varbinds.length) {
1591 + for (var j = 0; j < repeaters; j++, i++) {
1592 + var reqIndex = nonRepeaters + j;
1593 + var respIndex = i;
1594 +
1595 + if (isVarbindError(pdu.varbinds[respIndex])) {
1596 + if (!varbinds[reqIndex])
1597 + varbinds[reqIndex] = [];
1598 + varbinds[reqIndex].push(pdu.varbinds[respIndex]);
1599 + } else if (!oidFollowsOid(
1600 + req.message.pdu.varbinds[reqIndex].oid,
1601 + pdu.varbinds[respIndex].oid)) {
1602 + req.responseCb(new ResponseInvalidError("OID '"
1603 + + req.message.pdu.varbinds[reqIndex].oid
1604 + + "' in request at positiion '" + (reqIndex)
1605 + + "' does not precede OID '"
1606 + + pdu.varbinds[respIndex].oid
1607 + + "' in response at position '" + (respIndex) + "'"));
1608 + return;
1609 + } else {
1610 + if (!varbinds[reqIndex])
1611 + varbinds[reqIndex] = [];
1612 + varbinds[reqIndex].push(pdu.varbinds[respIndex]);
1613 + }
1614 + }
1615 + }
1616 + }
1617 +
1618 + req.responseCb(null, varbinds);
1619 + }
1620 +
1621 + var pduVarbinds = [];
1622 +
1623 + for (var i = 0; i < oids.length; i++) {
1624 + var varbind = {
1625 + oid: oids[i]
1626 + };
1627 + pduVarbinds.push(varbind);
1628 + }
1629 +
1630 + var options = {
1631 + nonRepeaters: nonRepeaters,
1632 + maxRepetitions: maxRepetitions
1633 + };
1634 +
1635 + this.simpleGet(GetBulkRequestPdu, feedCb, pduVarbinds, responseCb,
1636 + options);
1637 +
1638 + return this;
1639 };
1640
1641 Session.prototype.getNext = function (oids, responseCb) {
772 - function feedCb (req, message) {
773 - var pdu = message.pdu;
774 - var varbinds = [];
775 -
776 - if (req.message.pdu.varbinds.length != pdu.varbinds.length) {
777 - req.responseCb (new ResponseInvalidError ("Requested OIDs do not "
778 - + "match response OIDs"));
779 - } else {
780 - for (var i = 0; i < req.message.pdu.varbinds.length; i++) {
781 - if (isVarbindError (pdu.varbinds[i])) {
782 - varbinds.push (pdu.varbinds[i]);
783 - } else if (! oidFollowsOid (req.message.pdu.varbinds[i].oid,
784 - pdu.varbinds[i].oid)) {
785 - req.responseCb (new ResponseInvalidError ("OID '"
786 - + req.message.pdu.varbinds[i].oid + "' in request at "
787 - + "positiion '" + i + "' does not precede "
788 - + "OID '" + pdu.varbinds[i].oid + "' in response "
789 - + "at position '" + i + "'"));
790 - return;
791 - } else {
792 - varbinds.push (pdu.varbinds[i]);
793 - }
794 - }
795 -
796 - req.responseCb (null, varbinds);
797 - }
798 - }
799 -
800 - var pduVarbinds = [];
801 -
802 - for (var i = 0; i < oids.length; i++) {
803 - var varbind = {
804 - oid: oids[i]
805 - };
806 - pduVarbinds.push (varbind);
807 - }
808 -
809 - this.simpleGet (GetNextRequestPdu, feedCb, pduVarbinds, responseCb);
810 -
811 - return this;
1642 + function feedCb(req, message) {
1643 + var pdu = message.pdu;
1644 + var varbinds = [];
1645 +
1646 + if (req.message.pdu.varbinds.length != pdu.varbinds.length) {
1647 + req.responseCb(new ResponseInvalidError("Requested OIDs do not "
1648 + + "match response OIDs"));
1649 + } else {
1650 + for (var i = 0; i < req.message.pdu.varbinds.length; i++) {
1651 + if (isVarbindError(pdu.varbinds[i])) {
1652 + varbinds.push(pdu.varbinds[i]);
1653 + } else if (!oidFollowsOid(req.message.pdu.varbinds[i].oid,
1654 + pdu.varbinds[i].oid)) {
1655 + req.responseCb(new ResponseInvalidError("OID '"
1656 + + req.message.pdu.varbinds[i].oid + "' in request at "
1657 + + "positiion '" + i + "' does not precede "
1658 + + "OID '" + pdu.varbinds[i].oid + "' in response "
1659 + + "at position '" + i + "'"));
1660 + return;
1661 + } else {
1662 + varbinds.push(pdu.varbinds[i]);
1663 + }
1664 + }
1665 +
1666 + req.responseCb(null, varbinds);
1667 + }
1668 + }
1669 +
1670 + var pduVarbinds = [];
1671 +
1672 + for (var i = 0; i < oids.length; i++) {
1673 + var varbind = {
1674 + oid: oids[i]
1675 + };
1676 + pduVarbinds.push(varbind);
1677 + }
1678 +
1679 + this.simpleGet(GetNextRequestPdu, feedCb, pduVarbinds, responseCb);
1680 +
1681 + return this;
1682 };
1683
1684 Session.prototype.inform = function () {
815 - var typeOrOid = arguments[0];
816 - var varbinds, options = {}, responseCb;
817 -
818 - /**
819 - ** Support the following signatures:
820 - **
821 - ** typeOrOid, varbinds, options, callback
822 - ** typeOrOid, varbinds, callback
823 - ** typeOrOid, options, callback
824 - ** typeOrOid, callback
825 - **/
826 - if (arguments.length >= 4) {
827 - varbinds = arguments[1];
828 - options = arguments[2];
829 - responseCb = arguments[3];
830 - } else if (arguments.length >= 3) {
831 - if (arguments[1].constructor != Array) {
832 - varbinds = [];
833 - options = arguments[1];
834 - responseCb = arguments[2];
835 - } else {
836 - varbinds = arguments[1];
837 - responseCb = arguments[2];
838 - }
839 - } else {
840 - varbinds = [];
841 - responseCb = arguments[1];
842 - }
843 -
844 - function feedCb (req, message) {
845 - var pdu = message.pdu;
846 - var varbinds = [];
847 -
848 - if (req.message.pdu.varbinds.length != pdu.varbinds.length) {
849 - req.responseCb (new ResponseInvalidError ("Inform OIDs do not "
850 - + "match response OIDs"));
851 - } else {
852 - for (var i = 0; i < req.message.pdu.varbinds.length; i++) {
853 - if (req.message.pdu.varbinds[i].oid != pdu.varbinds[i].oid) {
854 - req.responseCb (new ResponseInvalidError ("OID '"
855 - + req.message.pdu.varbinds[i].oid
856 - + "' in inform at positiion '" + i + "' does not "
857 - + "match OID '" + pdu.varbinds[i].oid + "' in response "
858 - + "at position '" + i + "'"));
859 - return;
860 - } else {
861 - varbinds.push (pdu.varbinds[i]);
862 - }
863 - }
864 -
865 - req.responseCb (null, varbinds);
866 - }
867 - }
868 -
869 - if (typeof typeOrOid != "string")
870 - typeOrOid = "1.3.6.1.6.3.1.1.5." + (typeOrOid + 1);
871 -
872 - var pduVarbinds = [
873 - {
874 - oid: "1.3.6.1.2.1.1.3.0",
875 - type: ObjectType.TimeTicks,
876 - value: options.upTime || Math.floor (process.uptime () * 100)
877 - },
878 - {
879 - oid: "1.3.6.1.6.3.1.1.4.1.0",
880 - type: ObjectType.OID,
881 - value: typeOrOid
882 - }
883 - ];
884 -
885 - for (var i = 0; i < varbinds.length; i++) {
886 - var varbind = {
887 - oid: varbinds[i].oid,
888 - type: varbinds[i].type,
889 - value: varbinds[i].value
890 - };
891 - pduVarbinds.push (varbind);
892 - }
893 -
894 - options.port = this.trapPort;
895 -
896 - this.simpleGet (InformRequestPdu, feedCb, pduVarbinds, responseCb, options);
897 -
898 - return this;
1685 + var typeOrOid = arguments[0];
1686 + var varbinds, options = {}, responseCb;
1687 +
1688 + /**
1689 + ** Support the following signatures:
1690 + **
1691 + ** typeOrOid, varbinds, options, callback
1692 + ** typeOrOid, varbinds, callback
1693 + ** typeOrOid, options, callback
1694 + ** typeOrOid, callback
1695 + **/
1696 + if (arguments.length >= 4) {
1697 + varbinds = arguments[1];
1698 + options = arguments[2];
1699 + responseCb = arguments[3];
1700 + } else if (arguments.length >= 3) {
1701 + if (arguments[1].constructor != Array) {
1702 + varbinds = [];
1703 + options = arguments[1];
1704 + responseCb = arguments[2];
1705 + } else {
1706 + varbinds = arguments[1];
1707 + responseCb = arguments[2];
1708 + }
1709 + } else {
1710 + varbinds = [];
1711 + responseCb = arguments[1];
1712 + }
1713 +
1714 + if (this.version == Version1) {
1715 + responseCb(new RequestInvalidError("Inform not allowed for SNMPv1"));
1716 + return;
1717 + }
1718 +
1719 + function feedCb(req, message) {
1720 + var pdu = message.pdu;
1721 + var varbinds = [];
1722 +
1723 + if (req.message.pdu.varbinds.length != pdu.varbinds.length) {
1724 + req.responseCb(new ResponseInvalidError("Inform OIDs do not "
1725 + + "match response OIDs"));
1726 + } else {
1727 + for (var i = 0; i < req.message.pdu.varbinds.length; i++) {
1728 + if (req.message.pdu.varbinds[i].oid != pdu.varbinds[i].oid) {
1729 + req.responseCb(new ResponseInvalidError("OID '"
1730 + + req.message.pdu.varbinds[i].oid
1731 + + "' in inform at positiion '" + i + "' does not "
1732 + + "match OID '" + pdu.varbinds[i].oid + "' in response "
1733 + + "at position '" + i + "'"));
1734 + return;
1735 + } else {
1736 + varbinds.push(pdu.varbinds[i]);
1737 + }
1738 + }
1739 +
1740 + req.responseCb(null, varbinds);
1741 + }
1742 + }
1743 +
1744 + if (typeof typeOrOid != "string")
1745 + typeOrOid = "1.3.6.1.6.3.1.1.5." + (typeOrOid + 1);
1746 +
1747 + var pduVarbinds = [
1748 + {
1749 + oid: "1.3.6.1.2.1.1.3.0",
1750 + type: ObjectType.TimeTicks,
1751 + value: options.upTime || Math.floor(process.uptime() * 100)
1752 + },
1753 + {
1754 + oid: "1.3.6.1.6.3.1.1.4.1.0",
1755 + type: ObjectType.OID,
1756 + value: typeOrOid
1757 + }
1758 + ];
1759 +
1760 + for (var i = 0; i < varbinds.length; i++) {
1761 + var varbind = {
1762 + oid: varbinds[i].oid,
1763 + type: varbinds[i].type,
1764 + value: varbinds[i].value
1765 + };
1766 + pduVarbinds.push(varbind);
1767 + }
1768 +
1769 + options.port = this.trapPort;
1770 +
1771 + this.simpleGet(InformRequestPdu, feedCb, pduVarbinds, responseCb, options);
1772 +
1773 + return this;
1774 };
1775
1776 Session.prototype.onClose = function () {
902 - this.cancelRequests (new Error ("Socket forcibly closed"));
903 - this.emit ("close");
1777 + this.cancelRequests(new Error("Socket forcibly closed"));
1778 + this.emit("close");
1779 };
1780
1781 Session.prototype.onError = function (error) {
907 - this.emit (error);
908 -};
909 -
910 -Session.prototype.onMsg = function (buffer, remote) {
911 - try {
912 - var message = new ResponseMessage (buffer);
913 -
914 - var req = this.unregisterRequest (message.pdu.id);
915 - if (! req)
916 - return;
917 -
918 - try {
919 - if (message.version != req.message.version) {
920 - req.responseCb (new ResponseInvalidError ("Version in request '"
921 - + req.message.version + "' does not match version in "
922 - + "response '" + message.version));
923 - } else if (message.community != req.message.community) {
924 - req.responseCb (new ResponseInvalidError ("Community '"
925 - + req.message.community + "' in request does not match "
926 - + "community '" + message.community + "' in response"));
927 - } else if (message.pdu.type == PduType.GetResponse) {
928 - req.onResponse (req, message);
929 - } else {
930 - req.responseCb (new ResponseInvalidError ("Unknown PDU type '"
931 - + message.pdu.type + "' in response"));
932 - }
933 - } catch (error) {
934 - req.responseCb (error);
935 - }
936 - } catch (error) {
937 - this.emit("error", error);
938 - }
1782 + this.emit(error);
1783 +};
1784 +
1785 +Session.prototype.onMsg = function (buffer) {
1786 + try {
1787 + var message = Message.createFromBuffer(buffer);
1788 +
1789 + var req = this.unregisterRequest(message.getReqId());
1790 + if (!req)
1791 + return;
1792 +
1793 + if (!message.processIncomingSecurity(this.user, req.responseCb))
1794 + return;
1795 +
1796 + try {
1797 + if (message.version != req.message.version) {
1798 + req.responseCb(new ResponseInvalidError("Version in request '"
1799 + + req.message.version + "' does not match version in "
1800 + + "response '" + message.version + "'"));
1801 + } else if (message.community != req.message.community) {
1802 + req.responseCb(new ResponseInvalidError("Community '"
1803 + + req.message.community + "' in request does not match "
1804 + + "community '" + message.community + "' in response"));
1805 + } else if (message.pdu.type == PduType.GetResponse) {
1806 + req.onResponse(req, message);
1807 + } else if (message.pdu.type == PduType.Report) {
1808 + if (!req.originalPdu) {
1809 + req.responseCb(new ResponseInvalidError("Unexpected Report PDU"));
1810 + return;
1811 + }
1812 + this.msgSecurityParameters = {
1813 + msgAuthoritativeEngineID: message.msgSecurityParameters.msgAuthoritativeEngineID,
1814 + msgAuthoritativeEngineBoots: message.msgSecurityParameters.msgAuthoritativeEngineBoots,
1815 + msgAuthoritativeEngineTime: message.msgSecurityParameters.msgAuthoritativeEngineTime
1816 + };
1817 + req.originalPdu.contextName = this.context;
1818 + this.sendV3Req(req.originalPdu, req.feedCb, req.responseCb, req.options, req.port);
1819 + } else {
1820 + req.responseCb(new ResponseInvalidError("Unknown PDU type '"
1821 + + message.pdu.type + "' in response"));
1822 + }
1823 + } catch (error) {
1824 + req.responseCb(error);
1825 + }
1826 + } catch (error) {
1827 + this.emit("error", error);
1828 + }
1829 };
1830
1831 Session.prototype.onSimpleGetResponse = function (req, message) {
942 - var pdu = message.pdu;
943 -
944 - if (pdu.errorStatus > 0) {
945 - var statusString = ErrorStatus[pdu.errorStatus]
946 - || ErrorStatus.GeneralError;
947 - var statusCode = ErrorStatus[statusString]
948 - || ErrorStatus[ErrorStatus.GeneralError];
949 -
950 - if (pdu.errorIndex <= 0 || pdu.errorIndex > pdu.varbinds.length) {
951 - req.responseCb (new RequestFailedError (statusString, statusCode));
952 - } else {
953 - var oid = pdu.varbinds[pdu.errorIndex - 1].oid;
954 - var error = new RequestFailedError (statusString + ": " + oid,
955 - statusCode);
956 - req.responseCb (error);
957 - }
958 - } else {
959 - req.feedCb (req, message);
960 - }
1832 + var pdu = message.pdu;
1833 +
1834 + if (pdu.errorStatus > 0) {
1835 + var statusString = ErrorStatus[pdu.errorStatus]
1836 + || ErrorStatus.GeneralError;
1837 + var statusCode = ErrorStatus[statusString]
1838 + || ErrorStatus[ErrorStatus.GeneralError];
1839 +
1840 + if (pdu.errorIndex <= 0 || pdu.errorIndex > pdu.varbinds.length) {
1841 + req.responseCb(new RequestFailedError(statusString, statusCode));
1842 + } else {
1843 + var oid = pdu.varbinds[pdu.errorIndex - 1].oid;
1844 + var error = new RequestFailedError(statusString + ": " + oid,
1845 + statusCode);
1846 + req.responseCb(error);
1847 + }
1848 + } else {
1849 + req.feedCb(req, message);
1850 + }
1851 };
1852
1853 Session.prototype.registerRequest = function (req) {
964 - if (! this.reqs[req.id]) {
965 - this.reqs[req.id] = req;
966 - if (this.reqCount <= 0)
967 - this.dgram.ref();
968 - this.reqCount++;
969 - }
970 - var me = this;
971 - req.timer = setTimeout (function () {
972 - if (req.retries-- > 0) {
973 - me.send (req);
974 - } else {
975 - me.unregisterRequest (req.id);
976 - req.responseCb (new RequestTimedOutError (
977 - "Request timed out"));
978 - }
979 - }, req.timeout);
1854 + if (!this.reqs[req.getId()]) {
1855 + this.reqs[req.getId()] = req;
1856 + if (this.reqCount <= 0)
1857 + this.dgram.ref();
1858 + this.reqCount++;
1859 + }
1860 + var me = this;
1861 + req.timer = setTimeout(function () {
1862 + if (req.retries-- > 0) {
1863 + me.send(req);
1864 + } else {
1865 + me.unregisterRequest(req.getId());
1866 + req.responseCb(new RequestTimedOutError(
1867 + "Request timed out"));
1868 + }
1869 + }, req.timeout);
1870 };
1871
1872 Session.prototype.send = function (req, noWait) {
983 - try {
984 - var me = this;
985 -
986 - var buffer = req.message.toBuffer ();
987 -
988 - this.dgram.send (buffer, 0, buffer.length, req.port, this.target,
989 - function (error, bytes) {
990 - if (error) {
991 - req.responseCb (error);
992 - } else {
993 - if (noWait) {
994 - req.responseCb (null);
995 - } else {
996 - me.registerRequest (req);
997 - }
998 - }
999 - });
1000 - } catch (error) {
1001 - req.responseCb (error);
1002 - }
1003 -
1004 - return this;
1873 + try {
1874 + var me = this;
1875 +
1876 + var buffer = req.message.toBuffer();
1877 +
1878 + this.dgram.send(buffer, 0, buffer.length, req.port, this.target,
1879 + function (error, bytes) {
1880 + if (error) {
1881 + req.responseCb(error);
1882 + } else {
1883 + if (noWait) {
1884 + req.responseCb(null);
1885 + } else {
1886 + me.registerRequest(req);
1887 + }
1888 + }
1889 + });
1890 + } catch (error) {
1891 + req.responseCb(error);
1892 + }
1893 +
1894 + return this;
1895 };
1896
1897 Session.prototype.set = function (varbinds, responseCb) {
1008 - function feedCb (req, message) {
1009 - var pdu = message.pdu;
1010 - var varbinds = [];
1011 -
1012 - if (req.message.pdu.varbinds.length != pdu.varbinds.length) {
1013 - req.responseCb (new ResponseInvalidError ("Requested OIDs do not "
1014 - + "match response OIDs"));
1015 - } else {
1016 - for (var i = 0; i < req.message.pdu.varbinds.length; i++) {
1017 - if (req.message.pdu.varbinds[i].oid != pdu.varbinds[i].oid) {
1018 - req.responseCb (new ResponseInvalidError ("OID '"
1019 - + req.message.pdu.varbinds[i].oid
1020 - + "' in request at positiion '" + i + "' does not "
1021 - + "match OID '" + pdu.varbinds[i].oid + "' in response "
1022 - + "at position '" + i + "'"));
1023 - return;
1024 - } else {
1025 - varbinds.push (pdu.varbinds[i]);
1026 - }
1027 - }
1028 -
1029 - req.responseCb (null, varbinds);
1030 - }
1031 - }
1032 -
1033 - var pduVarbinds = [];
1034 -
1035 - for (var i = 0; i < varbinds.length; i++) {
1036 - var varbind = {
1037 - oid: varbinds[i].oid,
1038 - type: varbinds[i].type,
1039 - value: varbinds[i].value
1040 - };
1041 - pduVarbinds.push (varbind);
1042 - }
1043 -
1044 - this.simpleGet (SetRequestPdu, feedCb, pduVarbinds, responseCb);
1045 -
1046 - return this;
1898 + function feedCb(req, message) {
1899 + var pdu = message.pdu;
1900 + var varbinds = [];
1901 +
1902 + if (req.message.pdu.varbinds.length != pdu.varbinds.length) {
1903 + req.responseCb(new ResponseInvalidError("Requested OIDs do not "
1904 + + "match response OIDs"));
1905 + } else {
1906 + for (var i = 0; i < req.message.pdu.varbinds.length; i++) {
1907 + if (req.message.pdu.varbinds[i].oid != pdu.varbinds[i].oid) {
1908 + req.responseCb(new ResponseInvalidError("OID '"
1909 + + req.message.pdu.varbinds[i].oid
1910 + + "' in request at positiion '" + i + "' does not "
1911 + + "match OID '" + pdu.varbinds[i].oid + "' in response "
1912 + + "at position '" + i + "'"));
1913 + return;
1914 + } else {
1915 + varbinds.push(pdu.varbinds[i]);
1916 + }
1917 + }
1918 +
1919 + req.responseCb(null, varbinds);
1920 + }
1921 + }
1922 +
1923 + var pduVarbinds = [];
1924 +
1925 + for (var i = 0; i < varbinds.length; i++) {
1926 + var varbind = {
1927 + oid: varbinds[i].oid,
1928 + type: varbinds[i].type,
1929 + value: varbinds[i].value
1930 + };
1931 + pduVarbinds.push(varbind);
1932 + }
1933 +
1934 + this.simpleGet(SetRequestPdu, feedCb, pduVarbinds, responseCb);
1935 +
1936 + return this;
1937 };
1938
1939 Session.prototype.simpleGet = function (pduClass, feedCb, varbinds,
1050 - responseCb, options) {
1051 - var req = {};
1052 -
1053 - try {
1054 - var id = _generateId (this.idBitsSize);
1055 - var pdu = new pduClass (id, varbinds, options);
1056 - var message = new RequestMessage (this.version, this.community, pdu);
1057 -
1058 - req = {
1059 - id: id,
1060 - message: message,
1061 - responseCb: responseCb,
1062 - retries: this.retries,
1063 - timeout: this.timeout,
1064 - onResponse: this.onSimpleGetResponse,
1065 - feedCb: feedCb,
1066 - port: (options && options.port) ? options.port : this.port
1067 - };
1068 -
1069 - this.send (req);
1070 - } catch (error) {
1071 - if (req.responseCb)
1072 - req.responseCb (error);
1073 - }
1074 -};
1075 -
1076 -function subtreeCb (req, varbinds) {
1077 - var done = 0;
1078 -
1079 - for (var i = varbinds.length; i > 0; i--) {
1080 - if (! oidInSubtree (req.baseOid, varbinds[i - 1].oid)) {
1081 - done = 1;
1082 - varbinds.pop ();
1083 - }
1084 - }
1085 -
1086 - if (varbinds.length > 0)
1087 - req.feedCb (varbinds);
1088 -
1089 - if (done)
1090 - return true;
1940 + responseCb, options) {
1941 + try {
1942 + var id = _generateId(this.idBitsSize);
1943 + var pdu = SimplePdu.createFromVariables(pduClass, id, varbinds, options);
1944 + var message;
1945 + var req;
1946 +
1947 + if (this.version == Version3) {
1948 + if (this.msgSecurityParameters) {
1949 + this.sendV3Req(pdu, feedCb, responseCb, options, this.port);
1950 + } else {
1951 + // SNMPv3 discovery
1952 + var discoveryPdu = createDiscoveryPdu(this.context);
1953 + var discoveryMessage = Message.createDiscoveryV3(discoveryPdu);
1954 + var discoveryReq = new Req(this, discoveryMessage, feedCb, responseCb, options);
1955 + discoveryReq.originalPdu = pdu;
1956 + this.send(discoveryReq);
1957 + }
1958 + } else {
1959 + message = Message.createCommunity(this.version, this.community, pdu);
1960 + req = new Req(this, message, feedCb, responseCb, options);
1961 + this.send(req);
1962 + }
1963 + } catch (error) {
1964 + if (responseCb)
1965 + responseCb(error);
1966 + }
1967 }
1968
1093 -Session.prototype.subtree = function () {
1094 - var me = this;
1095 - var oid = arguments[0];
1096 - var maxRepetitions, feedCb, doneCb;
1097 -
1098 - if (arguments.length < 4) {
1099 - maxRepetitions = 20;
1100 - feedCb = arguments[1];
1101 - doneCb = arguments[2];
1102 - } else {
1103 - maxRepetitions = arguments[1];
1104 - feedCb = arguments[2];
1105 - doneCb = arguments[3];
1106 - }
1107 -
1108 - var req = {
1109 - feedCb: feedCb,
1110 - doneCb: doneCb,
1111 - maxRepetitions: maxRepetitions,
1112 - baseOid: oid
1113 - };
1114 -
1115 - this.walk (oid, maxRepetitions, subtreeCb.bind (me, req), doneCb);
1116 -
1117 - return this;
1118 -};
1119 -
1120 -function tableColumnsResponseCb (req, error) {
1121 - if (error) {
1122 - req.responseCb (error);
1123 - } else if (req.error) {
1124 - req.responseCb (req.error);
1125 - } else {
1126 - if (req.columns.length > 0) {
1127 - var column = req.columns.pop ();
1128 - var me = this;
1129 - this.subtree (req.rowOid + column, req.maxRepetitions,
1130 - tableColumnsFeedCb.bind (me, req),
1131 - tableColumnsResponseCb.bind (me, req));
1132 - } else {
1133 - req.responseCb (null, req.table);
1134 - }
1135 - }
1969 +function subtreeCb(req, varbinds) {
1970 + var done = 0;
1971 +
1972 + for (var i = varbinds.length; i > 0; i--) {
1973 + if (!oidInSubtree(req.baseOid, varbinds[i - 1].oid)) {
1974 + done = 1;
1975 + varbinds.pop();
1976 + }
1977 + }
1978 +
1979 + if (varbinds.length > 0)
1980 + req.feedCb(varbinds);
1981 +
1982 + if (done)
1983 + return true;
1984 +}
1985 +
1986 +Session.prototype.subtree = function () {
1987 + var me = this;
1988 + var oid = arguments[0];
1989 + var maxRepetitions, feedCb, doneCb;
1990 +
1991 + if (arguments.length < 4) {
1992 + maxRepetitions = 20;
1993 + feedCb = arguments[1];
1994 + doneCb = arguments[2];
1995 + } else {
1996 + maxRepetitions = arguments[1];
1997 + feedCb = arguments[2];
1998 + doneCb = arguments[3];
1999 + }
2000 +
2001 + var req = {
2002 + feedCb: feedCb,
2003 + doneCb: doneCb,
2004 + maxRepetitions: maxRepetitions,
2005 + baseOid: oid
2006 + };
2007 +
2008 + this.walk(oid, maxRepetitions, subtreeCb.bind(me, req), doneCb);
2009 +
2010 + return this;
2011 +};
2012 +
2013 +function tableColumnsResponseCb(req, error) {
2014 + if (error) {
2015 + req.responseCb(error);
2016 + } else if (req.error) {
2017 + req.responseCb(req.error);
2018 + } else {
2019 + if (req.columns.length > 0) {
2020 + var column = req.columns.pop();
2021 + var me = this;
2022 + this.subtree(req.rowOid + column, req.maxRepetitions,
2023 + tableColumnsFeedCb.bind(me, req),
2024 + tableColumnsResponseCb.bind(me, req));
2025 + } else {
2026 + req.responseCb(null, req.table);
2027 + }
2028 + }
2029 }
2030
1138 -function tableColumnsFeedCb (req, varbinds) {
1139 - for (var i = 0; i < varbinds.length; i++) {
1140 - if (isVarbindError (varbinds[i])) {
1141 - req.error = new RequestFailedError (varbindError (varbind[i]));
1142 - return true;
1143 - }
1144 -
1145 - var oid = varbinds[i].oid.replace (req.rowOid, "");
1146 - if (oid && oid != varbinds[i].oid) {
1147 - var match = oid.match (/^(\d+)\.(.+)$/);
1148 - if (match && match[1] > 0) {
1149 - if (! req.table[match[2]])
1150 - req.table[match[2]] = {};
1151 - req.table[match[2]][match[1]] = varbinds[i].value;
1152 - }
1153 - }
1154 - }
2031 +function tableColumnsFeedCb(req, varbinds) {
2032 + for (var i = 0; i < varbinds.length; i++) {
2033 + if (isVarbindError(varbinds[i])) {
2034 + req.error = new RequestFailedError(varbindError(varbind[i]));
2035 + return true;
2036 + }
2037 +
2038 + var oid = varbinds[i].oid.replace(req.rowOid, "");
2039 + if (oid && oid != varbinds[i].oid) {
2040 + var match = oid.match(/^(\d+)\.(.+)$/);
2041 + if (match && match[1] > 0) {
2042 + if (!req.table[match[2]])
2043 + req.table[match[2]] = {};
2044 + req.table[match[2]][match[1]] = varbinds[i].value;
2045 + }
2046 + }
2047 + }
2048 }
2049
2050 Session.prototype.tableColumns = function () {
1158 - var me = this;
1159 -
1160 - var oid = arguments[0];
1161 - var columns = arguments[1];
1162 - var maxRepetitions, responseCb;
1163 -
1164 - if (arguments.length < 4) {
1165 - responseCb = arguments[2];
1166 - maxRepetitions = 20;
1167 - } else {
1168 - maxRepetitions = arguments[2];
1169 - responseCb = arguments[3];
1170 - }
1171 -
1172 - var req = {
1173 - responseCb: responseCb,
1174 - maxRepetitions: maxRepetitions,
1175 - baseOid: oid,
1176 - rowOid: oid + ".1.",
1177 - columns: columns.slice(0),
1178 - table: {}
1179 - };
1180 -
1181 - if (req.columns.length > 0) {
1182 - var column = req.columns.pop ();
1183 - this.subtree (req.rowOid + column, maxRepetitions,
1184 - tableColumnsFeedCb.bind (me, req),
1185 - tableColumnsResponseCb.bind (me, req));
1186 - }
1187 -
1188 - return this;
1189 -};
1190 -
1191 -function tableResponseCb (req, error) {
1192 - if (error)
1193 - req.responseCb (error);
1194 - else if (req.error)
1195 - req.responseCb (req.error);
1196 - else
1197 - req.responseCb (null, req.table);
2051 + var me = this;
2052 +
2053 + var oid = arguments[0];
2054 + var columns = arguments[1];
2055 + var maxRepetitions, responseCb;
2056 +
2057 + if (arguments.length < 4) {
2058 + responseCb = arguments[2];
2059 + maxRepetitions = 20;
2060 + } else {
2061 + maxRepetitions = arguments[2];
2062 + responseCb = arguments[3];
2063 + }
2064 +
2065 + var req = {
2066 + responseCb: responseCb,
2067 + maxRepetitions: maxRepetitions,
2068 + baseOid: oid,
2069 + rowOid: oid + ".1.",
2070 + columns: columns.slice(0),
2071 + table: {}
2072 + };
2073 +
2074 + if (req.columns.length > 0) {
2075 + var column = req.columns.pop();
2076 + this.subtree(req.rowOid + column, maxRepetitions,
2077 + tableColumnsFeedCb.bind(me, req),
2078 + tableColumnsResponseCb.bind(me, req));
2079 + }
2080 +
2081 + return this;
2082 +};
2083 +
2084 +function tableResponseCb(req, error) {
2085 + if (error)
2086 + req.responseCb(error);
2087 + else if (req.error)
2088 + req.responseCb(req.error);
2089 + else
2090 + req.responseCb(null, req.table);
2091 }
2092
1200 -function tableFeedCb (req, varbinds) {
1201 - for (var i = 0; i < varbinds.length; i++) {
1202 - if (isVarbindError (varbinds[i])) {
1203 - req.error = new RequestFailedError (varbindError (varbind[i]));
1204 - return true;
1205 - }
1206 -
1207 - var oid = varbinds[i].oid.replace (req.rowOid, "");
1208 - if (oid && oid != varbinds[i].oid) {
1209 - var match = oid.match (/^(\d+)\.(.+)$/);
1210 - if (match && match[1] > 0) {
1211 - if (! req.table[match[2]])
1212 - req.table[match[2]] = {};
1213 - req.table[match[2]][match[1]] = varbinds[i].value;
1214 - }
1215 - }
1216 - }
2093 +function tableFeedCb(req, varbinds) {
2094 + for (var i = 0; i < varbinds.length; i++) {
2095 + if (isVarbindError(varbinds[i])) {
2096 + req.error = new RequestFailedError(varbindError(varbind[i]));
2097 + return true;
2098 + }
2099 +
2100 + var oid = varbinds[i].oid.replace(req.rowOid, "");
2101 + if (oid && oid != varbinds[i].oid) {
2102 + var match = oid.match(/^(\d+)\.(.+)$/);
2103 + if (match && match[1] > 0) {
2104 + if (!req.table[match[2]])
2105 + req.table[match[2]] = {};
2106 + req.table[match[2]][match[1]] = varbinds[i].value;
2107 + }
2108 + }
2109 + }
2110 }
2111
2112 Session.prototype.table = function () {
1220 - var me = this;
2113 + var me = this;
2114 +
2115 + var oid = arguments[0];
2116 + var maxRepetitions, responseCb;
2117 +
2118 + if (arguments.length < 3) {
2119 + responseCb = arguments[1];
2120 + maxRepetitions = 20;
2121 + } else {
2122 + maxRepetitions = arguments[1];
2123 + responseCb = arguments[2];
2124 + }
2125 +
2126 + var req = {
2127 + responseCb: responseCb,
2128 + maxRepetitions: maxRepetitions,
2129 + baseOid: oid,
2130 + rowOid: oid + ".1.",
2131 + table: {}
2132 + };
2133 +
2134 + this.subtree(oid, maxRepetitions, tableFeedCb.bind(me, req),
2135 + tableResponseCb.bind(me, req));
2136 +
2137 + return this;
2138 +};
2139
1222 - var oid = arguments[0];
1223 - var maxRepetitions, responseCb;
2140 +Session.prototype.trap = function () {
2141 + var req = {};
2142 +
2143 + try {
2144 + var typeOrOid = arguments[0];
2145 + var varbinds, options = {}, responseCb;
2146 + var message;
2147 +
2148 + /**
2149 + ** Support the following signatures:
2150 + **
2151 + ** typeOrOid, varbinds, options, callback
2152 + ** typeOrOid, varbinds, agentAddr, callback
2153 + ** typeOrOid, varbinds, callback
2154 + ** typeOrOid, agentAddr, callback
2155 + ** typeOrOid, options, callback
2156 + ** typeOrOid, callback
2157 + **/
2158 + if (arguments.length >= 4) {
2159 + varbinds = arguments[1];
2160 + if (typeof arguments[2] == "string") {
2161 + options.agentAddr = arguments[2];
2162 + } else if (arguments[2].constructor != Array) {
2163 + options = arguments[2];
2164 + }
2165 + responseCb = arguments[3];
2166 + } else if (arguments.length >= 3) {
2167 + if (typeof arguments[1] == "string") {
2168 + varbinds = [];
2169 + options.agentAddr = arguments[1];
2170 + } else if (arguments[1].constructor != Array) {
2171 + varbinds = [];
2172 + options = arguments[1];
2173 + } else {
2174 + varbinds = arguments[1];
2175 + agentAddr = null;
2176 + }
2177 + responseCb = arguments[2];
2178 + } else {
2179 + varbinds = [];
2180 + responseCb = arguments[1];
2181 + }
2182 +
2183 + var pdu, pduVarbinds = [];
2184 +
2185 + for (var i = 0; i < varbinds.length; i++) {
2186 + var varbind = {
2187 + oid: varbinds[i].oid,
2188 + type: varbinds[i].type,
2189 + value: varbinds[i].value
2190 + };
2191 + pduVarbinds.push(varbind);
2192 + }
2193 +
2194 + var id = _generateId(this.idBitsSize);
2195 +
2196 + if (this.version == Version2c || this.version == Version3) {
2197 + if (typeof typeOrOid != "string")
2198 + typeOrOid = "1.3.6.1.6.3.1.1.5." + (typeOrOid + 1);
2199 +
2200 + pduVarbinds.unshift(
2201 + {
2202 + oid: "1.3.6.1.2.1.1.3.0",
2203 + type: ObjectType.TimeTicks,
2204 + value: options.upTime || Math.floor(process.uptime() * 100)
2205 + },
2206 + {
2207 + oid: "1.3.6.1.6.3.1.1.4.1.0",
2208 + type: ObjectType.OID,
2209 + value: typeOrOid
2210 + }
2211 + );
2212 +
2213 + pdu = TrapV2Pdu.createFromVariables(id, pduVarbinds, options);
2214 + } else {
2215 + pdu = TrapPdu.createFromVariables(typeOrOid, pduVarbinds, options);
2216 + }
2217 +
2218 + if (this.version == Version3) {
2219 + var msgSecurityParameters = {
2220 + msgAuthoritativeEngineID: this.user.engineID,
2221 + msgAuthoritativeEngineBoots: 0,
2222 + msgAuthoritativeEngineTime: 0
2223 + };
2224 + message = Message.createRequestV3(this.user, msgSecurityParameters, pdu);
2225 + } else {
2226 + message = Message.createCommunity(this.version, this.community, pdu);
2227 + }
2228 +
2229 + req = {
2230 + id: id,
2231 + message: message,
2232 + responseCb: responseCb,
2233 + port: this.trapPort
2234 + };
2235 +
2236 + this.send(req, true);
2237 + } catch (error) {
2238 + if (req.responseCb)
2239 + req.responseCb(error);
2240 + }
2241 +
2242 + return this;
2243 +};
2244
1225 - if (arguments.length < 3) {
1226 - responseCb = arguments[1];
1227 - maxRepetitions = 20;
1228 - } else {
1229 - maxRepetitions = arguments[1];
1230 - responseCb = arguments[2];
1231 - }
2245 +Session.prototype.unregisterRequest = function (id) {
2246 + var req = this.reqs[id];
2247 + if (req) {
2248 + delete this.reqs[id];
2249 + clearTimeout(req.timer);
2250 + delete req.timer;
2251 + this.reqCount--;
2252 + if (this.reqCount <= 0)
2253 + this.dgram.unref();
2254 + return req;
2255 + } else {
2256 + return null;
2257 + }
2258 +};
2259
1233 - var req = {
1234 - responseCb: responseCb,
1235 - maxRepetitions: maxRepetitions,
1236 - baseOid: oid,
1237 - rowOid: oid + ".1.",
1238 - table: {}
1239 - };
2260 +function walkCb(req, error, varbinds) {
2261 + var done = 0;
2262 + var oid;
2263 +
2264 + if (error) {
2265 + if (error instanceof RequestFailedError) {
2266 + if (error.status != ErrorStatus.NoSuchName) {
2267 + req.doneCb(error);
2268 + return;
2269 + } else {
2270 + // signal the version 1 walk code below that it should stop
2271 + done = 1;
2272 + }
2273 + } else {
2274 + req.doneCb(error);
2275 + return;
2276 + }
2277 + }
2278 +
2279 + if (this.version == Version2c || this.version == Version3) {
2280 + for (var i = varbinds[0].length; i > 0; i--) {
2281 + if (varbinds[0][i - 1].type == ObjectType.EndOfMibView) {
2282 + varbinds[0].pop();
2283 + done = 1;
2284 + }
2285 + }
2286 + if (req.feedCb(varbinds[0]))
2287 + done = 1;
2288 + if (!done)
2289 + oid = varbinds[0][varbinds[0].length - 1].oid;
2290 + } else {
2291 + if (!done) {
2292 + if (req.feedCb(varbinds)) {
2293 + done = 1;
2294 + } else {
2295 + oid = varbinds[0].oid;
2296 + }
2297 + }
2298 + }
2299 +
2300 + if (done)
2301 + req.doneCb(null);
2302 + else
2303 + this.walk(oid, req.maxRepetitions, req.feedCb, req.doneCb,
2304 + req.baseOid);
2305 +}
2306
1241 - this.subtree (oid, maxRepetitions, tableFeedCb.bind (me, req),
1242 - tableResponseCb.bind (me, req));
2307 +Session.prototype.walk = function () {
2308 + var me = this;
2309 + var oid = arguments[0];
2310 + var maxRepetitions, feedCb, doneCb, baseOid;
2311 +
2312 + if (arguments.length < 4) {
2313 + maxRepetitions = 20;
2314 + feedCb = arguments[1];
2315 + doneCb = arguments[2];
2316 + } else {
2317 + maxRepetitions = arguments[1];
2318 + feedCb = arguments[2];
2319 + doneCb = arguments[3];
2320 + }
2321 +
2322 + var req = {
2323 + maxRepetitions: maxRepetitions,
2324 + feedCb: feedCb,
2325 + doneCb: doneCb
2326 + };
2327 +
2328 + if (this.version == Version2c || this.version == Version3)
2329 + this.getBulk([oid], 0, maxRepetitions,
2330 + walkCb.bind(me, req));
2331 + else
2332 + this.getNext([oid], walkCb.bind(me, req));
2333 +
2334 + return this;
2335 +};
2336
1244 - return this;
2337 +Session.prototype.sendV3Req = function (pdu, feedCb, responseCb, options, port) {
2338 + var message = Message.createRequestV3(this.user, this.msgSecurityParameters, pdu);
2339 + var reqOptions = options || {};
2340 + var req = new Req(this, message, feedCb, responseCb, reqOptions);
2341 + req.port = port;
2342 + this.send(req);
2343 };
2344
1247 -Session.prototype.trap = function () {
1248 - var req = {};
1249 -
1250 - try {
1251 - var typeOrOid = arguments[0];
1252 - var varbinds, options = {}, responseCb;
1253 -
1254 - /**
1255 - ** Support the following signatures:
1256 - **
1257 - ** typeOrOid, varbinds, options, callback
1258 - ** typeOrOid, varbinds, agentAddr, callback
1259 - ** typeOrOid, varbinds, callback
1260 - ** typeOrOid, agentAddr, callback
1261 - ** typeOrOid, options, callback
1262 - ** typeOrOid, callback
1263 - **/
1264 - if (arguments.length >= 4) {
1265 - varbinds = arguments[1];
1266 - if (typeof arguments[2] == "string") {
1267 - options.agentAddr = arguments[2];
1268 - } else if (arguments[2].constructor != Array) {
1269 - options = arguments[2];
1270 - }
1271 - responseCb = arguments[3];
1272 - } else if (arguments.length >= 3) {
1273 - if (typeof arguments[1] == "string") {
1274 - varbinds = [];
1275 - options.agentAddr = arguments[1];
1276 - } else if (arguments[1].constructor != Array) {
1277 - varbinds = [];
1278 - options = arguments[1];
1279 - } else {
1280 - varbinds = arguments[1];
1281 - agentAddr = null;
1282 - }
1283 - responseCb = arguments[2];
1284 - } else {
1285 - varbinds = [];
1286 - responseCb = arguments[1];
1287 - }
1288 -
1289 - var pdu, pduVarbinds = [];
1290 -
1291 - for (var i = 0; i < varbinds.length; i++) {
1292 - var varbind = {
1293 - oid: varbinds[i].oid,
1294 - type: varbinds[i].type,
1295 - value: varbinds[i].value
1296 - };
1297 - pduVarbinds.push (varbind);
1298 - }
1299 -
1300 - var id = _generateId (this.idBitsSize);
1301 -
1302 - if (this.version == Version2c) {
1303 - if (typeof typeOrOid != "string")
1304 - typeOrOid = "1.3.6.1.6.3.1.1.5." + (typeOrOid + 1);
1305 -
1306 - pduVarbinds.unshift (
1307 - {
1308 - oid: "1.3.6.1.2.1.1.3.0",
1309 - type: ObjectType.TimeTicks,
1310 - value: options.upTime || Math.floor (process.uptime () * 100)
1311 - },
1312 - {
1313 - oid: "1.3.6.1.6.3.1.1.4.1.0",
1314 - type: ObjectType.OID,
1315 - value: typeOrOid
1316 - }
1317 - );
1318 -
1319 - pdu = new TrapV2Pdu (id, pduVarbinds, options);
1320 - } else {
1321 - pdu = new TrapPdu (typeOrOid, pduVarbinds, options);
1322 - }
1323 -
1324 - var message = new RequestMessage (this.version, this.community, pdu);
1325 -
1326 - req = {
1327 - id: id,
1328 - message: message,
1329 - responseCb: responseCb,
1330 - port: this.trapPort
1331 - };
1332 -
1333 - this.send (req, true);
1334 - } catch (error) {
1335 - if (req.responseCb)
1336 - req.responseCb (error);
1337 - }
1338 -
1339 - return this;
2345 +var Engine = function (engineID, engineBoots, engineTime) {
2346 + if (engineID) {
2347 + this.engineID = Buffer.from(engineID, 'hex');
2348 + } else {
2349 + this.generateEngineID();
2350 + }
2351 + this.engineBoots = 0;
2352 + this.engineTime = 10;
2353 };
2354
1342 -Session.prototype.unregisterRequest = function (id) {
1343 - var req = this.reqs[id];
1344 - if (req) {
1345 - delete this.reqs[id];
1346 - clearTimeout (req.timer);
1347 - delete req.timer;
1348 - this.reqCount--;
1349 - if (this.reqCount <= 0)
1350 - this.dgram.unref();
1351 - return req;
1352 - } else {
1353 - return null;
1354 - }
1355 -};
1356 -
1357 -function walkCb (req, error, varbinds) {
1358 - var done = 0;
1359 - var oid;
1360 -
1361 - if (error) {
1362 - if (error instanceof RequestFailedError) {
1363 - if (error.status != ErrorStatus.NoSuchName) {
1364 - req.doneCb (error);
1365 - return;
1366 - } else {
1367 - // signal the version 1 walk code below that it should stop
1368 - done = 1;
1369 - }
1370 - } else {
1371 - req.doneCb (error);
1372 - return;
1373 - }
1374 - }
1375 -
1376 - if (this.version == Version2c) {
1377 - for (var i = varbinds[0].length; i > 0; i--) {
1378 - if (varbinds[0][i - 1].type == ObjectType.EndOfMibView) {
1379 - varbinds[0].pop ();
1380 - done = 1;
1381 - }
1382 - }
1383 - if (req.feedCb (varbinds[0]))
1384 - done = 1;
1385 - if (! done)
1386 - oid = varbinds[0][varbinds[0].length - 1].oid;
1387 - } else {
1388 - if (! done) {
1389 - if (req.feedCb (varbinds)) {
1390 - done = 1;
1391 - } else {
1392 - oid = varbinds[0].oid;
1393 - }
1394 - }
1395 - }
1396 -
1397 - if (done)
1398 - req.doneCb (null);
1399 - else
1400 - this.walk (oid, req.maxRepetitions, req.feedCb, req.doneCb,
1401 - req.baseOid);
2355 +Engine.prototype.generateEngineID = function () {
2356 + // generate a 17-byte engine ID in the following format:
2357 + // 0x80 + 0x00B983 (enterprise OID) | 0x80 (enterprise-specific format) | 12 bytes of random
2358 + this.engineID = Buffer.alloc(17);
2359 + this.engineID.fill('8000B98380', 'hex', 0, 5);
2360 + this.engineID.fill(crypto.randomBytes(12), 5, 17, 'hex');
2361 +}
2362 +
2363 +var Listener = function (options, receiver) {
2364 + this.receiver = receiver;
2365 + this.callback = receiver.onMsg;
2366 + this.family = options.transport || 'udp4';
2367 + this.port = options.port || 161;
2368 + this.disableAuthorization = options.disableAuthorization || false;
2369 +};
2370 +
2371 +Listener.prototype.startListening = function (receiver) {
2372 + var me = this;
2373 + this.dgram = dgram.createSocket(this.family);
2374 + this.dgram.bind(this.port);
2375 + this.dgram.on("message", me.callback.bind(me.receiver));
2376 +};
2377 +
2378 +Listener.prototype.send = function (message, rinfo) {
2379 + var me = this;
2380 +
2381 + var buffer = message.toBuffer();
2382 +
2383 + this.dgram.send(buffer, 0, buffer.length, rinfo.port, rinfo.address,
2384 + function (error, bytes) {
2385 + if (error) {
2386 + // me.callback (error);
2387 + console.error("Error sending: " + error.message);
2388 + } else {
2389 + // debug ("Listener sent response message");
2390 + }
2391 + });
2392 +};
2393 +
2394 +Listener.formatCallbackData = function (pdu, rinfo) {
2395 + if (pdu.contextEngineID) {
2396 + pdu.contextEngineID = pdu.contextEngineID.toString('hex');
2397 + }
2398 + delete pdu.nonRepeaters;
2399 + delete pdu.maxRepetitions;
2400 + return {
2401 + pdu: pdu,
2402 + rinfo: rinfo
2403 + };
2404 +};
2405 +
2406 +Listener.processIncoming = function (buffer, authorizer, callback) {
2407 + var message = Message.createFromBuffer(buffer);
2408 + var community;
2409 +
2410 + // Authorization
2411 + if (message.version == Version3) {
2412 + message.user = authorizer.users.filter(localUser => localUser.name ==
2413 + message.msgSecurityParameters.msgUserName)[0];
2414 + message.disableAuthentication = authorizer.disableAuthorization;
2415 + if (!message.user) {
2416 + if (message.msgSecurityParameters.msgUserName != "" && !authorizer.disableAuthorization) {
2417 + callback(new RequestFailedError("Local user not found for message with user " +
2418 + message.msgSecurityParameters.msgUserName));
2419 + return;
2420 + } else if (message.hasAuthentication()) {
2421 + callback(new RequestFailedError("Local user not found and message requires authentication with user " +
2422 + message.msgSecurityParameters.msgUserName));
2423 + return;
2424 + } else {
2425 + message.user = {
2426 + name: "",
2427 + level: SecurityLevel.noAuthNoPriv
2428 + };
2429 + }
2430 + }
2431 + if (!message.processIncomingSecurity(message.user, callback)) {
2432 + return;
2433 + }
2434 + } else {
2435 + community = authorizer.communities.filter(localCommunity => localCommunity == message.community)[0];
2436 + if (!community && !authorizer.disableAuthorization) {
2437 + callback(new RequestFailedError("Local community not found for message with community " + message.community));
2438 + return;
2439 + }
2440 + }
2441 +
2442 + return message;
2443 +};
2444 +
2445 +var Authorizer = function () {
2446 + this.communities = [];
2447 + this.users = [];
2448 +}
2449 +
2450 +Authorizer.prototype.addCommunity = function (community) {
2451 + if (this.getCommunity(community)) {
2452 + return;
2453 + } else {
2454 + this.communities.push(community);
2455 + }
2456 +};
2457 +
2458 +Authorizer.prototype.getCommunity = function (community) {
2459 + return this.communities.filter(localCommunity => localCommunity == community)[0] || null;
2460 +};
2461 +
2462 +Authorizer.prototype.getCommunities = function () {
2463 + return this.communities;
2464 +};
2465 +
2466 +Authorizer.prototype.deleteCommunity = function (community) {
2467 + var index = this.communities.indexOf(community);
2468 + if (index > -1) {
2469 + this.communities.splice(index, 1);
2470 + }
2471 +};
2472 +
2473 +Authorizer.prototype.addUser = function (user) {
2474 + if (this.getUser(user.name)) {
2475 + this.deleteUser(user.name);
2476 + }
2477 + this.users.push(user);
2478 +};
2479 +
2480 +Authorizer.prototype.getUser = function (userName) {
2481 + return this.users.filter(localUser => localUser.name == userName)[0] || null;
2482 +};
2483 +
2484 +Authorizer.prototype.getUsers = function () {
2485 + return this.users;
2486 +};
2487 +
2488 +Authorizer.prototype.deleteUser = function (userName) {
2489 + var index = this.users.findIndex(localUser => localUser.name == userName);
2490 + if (index > -1) {
2491 + this.users.splice(index, 1);
2492 + }
2493 +};
2494 +
2495 +
2496 +/*****************************************************************************
2497 + ** Receiver class definition
2498 + **/
2499 +
2500 +var Receiver = function (options, callback) {
2501 + DEBUG = options.debug;
2502 + this.listener = new Listener(options, this);
2503 + this.authorizer = new Authorizer();
2504 + this.engine = new Engine(options.engineID);
2505 +
2506 + this.engineBoots = 0;
2507 + this.engineTime = 10;
2508 + this.disableAuthorization = false;
2509 +
2510 + this.callback = callback;
2511 + this.family = options.transport || 'udp4';
2512 + this.port = options.port || 162;
2513 + options.port = this.port;
2514 + this.disableAuthorization = options.disableAuthorization || false;
2515 + this.context = (options && options.context) ? options.context : "";
2516 + this.listener = new Listener(options, this);
2517 +};
2518 +
2519 +Receiver.prototype.addCommunity = function (community) {
2520 + this.authorizer.addCommunity(community);
2521 +};
2522 +
2523 +Receiver.prototype.getCommunity = function (community) {
2524 + return this.authorizer.getCommunity(community);
2525 +};
2526 +
2527 +Receiver.prototype.getCommunities = function () {
2528 + return this.authorizer.getCommunities();
2529 +};
2530 +
2531 +Receiver.prototype.deleteCommunity = function (community) {
2532 + this.authorizer.deleteCommunities(community);
2533 +};
2534 +
2535 +Receiver.prototype.addUser = function (user) {
2536 + this.authorizer.addUser(user);
2537 +};
2538 +
2539 +Receiver.prototype.getUser = function (userName) {
2540 + return this.authorizer.getUser(userName);
2541 +};
2542 +
2543 +Receiver.prototype.getUsers = function () {
2544 + return this.authorizer.getUsers();
2545 +};
2546 +
2547 +Receiver.prototype.deleteUser = function (userName) {
2548 + this.authorizer.deleteUser(userName);
2549 +};
2550 +
2551 +Receiver.prototype.onMsg = function (buffer, rinfo) {
2552 + var message = Listener.processIncoming(buffer, this.authorizer, this.callback);
2553 + var reportMessage;
2554 +
2555 + if (!message) {
2556 + return;
2557 + }
2558 +
2559 + // The only GetRequest PDUs supported are those used for SNMPv3 discovery
2560 + if (message.pdu.type == PduType.GetRequest) {
2561 + if (message.version != Version3) {
2562 + this.callback(new RequestInvalidError("Only SNMPv3 discovery GetRequests are supported"));
2563 + return;
2564 + } else if (message.hasAuthentication()) {
2565 + this.callback(new RequestInvalidError("Only discovery (noAuthNoPriv) GetRequests are supported but this message has authentication"));
2566 + return;
2567 + } else if (!message.isReportable()) {
2568 + this.callback(new RequestInvalidError("Only discovery GetRequests are supported and this message does not have the reportable flag set"));
2569 + return;
2570 + }
2571 + var reportMessage = message.createReportResponseMessage(this.engine, this.context);
2572 + this.listener.send(reportMessage, rinfo);
2573 + return;
2574 + }
2575 + ;
2576 +
2577 + // Inform/trap processing
2578 + debug(JSON.stringify(message.pdu, null, 2));
2579 + if (message.pdu.type == PduType.Trap || message.pdu.type == PduType.TrapV2) {
2580 + this.callback(null, this.formatCallbackData(message.pdu, rinfo));
2581 + } else if (message.pdu.type == PduType.InformRequest) {
2582 + message.pdu.type = PduType.GetResponse;
2583 + message.buffer = null;
2584 + message.setReportable(false);
2585 + this.listener.send(message, rinfo);
2586 + message.pdu.type = PduType.InformRequest;
2587 + this.callback(null, this.formatCallbackData(message.pdu, rinfo));
2588 + } else {
2589 + this.callback(new RequestInvalidError("Unexpected PDU type " + message.pdu.type + " (" + PduType[message.pdu.type] + ")"));
2590 + }
2591 }
2592
1404 -Session.prototype.walk = function () {
1405 - var me = this;
1406 - var oid = arguments[0];
1407 - var maxRepetitions, feedCb, doneCb, baseOid;
2593 +Receiver.prototype.formatCallbackData = function (pdu, rinfo) {
2594 + if (pdu.contextEngineID) {
2595 + pdu.contextEngineID = pdu.contextEngineID.toString('hex');
2596 + }
2597 + delete pdu.nonRepeaters;
2598 + delete pdu.maxRepetitions;
2599 + return {
2600 + pdu: pdu,
2601 + rinfo: rinfo
2602 + };
2603 +};
2604 +
2605 +Receiver.prototype.close = function () {
2606 + this.listener.close();
2607 +};
2608 +
2609 +Receiver.create = function (options, callback) {
2610 + var receiver = new Receiver(options, callback);
2611 + receiver.listener.startListening();
2612 + return receiver;
2613 +};
2614 +
2615 +var MibNode = function (address, parent) {
2616 + this.address = address;
2617 + this.oid = this.address.join('.');
2618 + ;
2619 + this.parent = parent;
2620 + this.children = {};
2621 +};
2622 +
2623 +MibNode.prototype.child = function (index) {
2624 + return this.children[index];
2625 +};
2626 +
2627 +MibNode.prototype.listChildren = function (lowest) {
2628 + var sorted = [];
2629 +
2630 + lowest = lowest || 0;
2631 +
2632 + this.children.forEach(function (c, i) {
2633 + if (i >= lowest)
2634 + sorted.push(i);
2635 + });
2636 +
2637 + sorted.sort(function (a, b) {
2638 + return (a - b);
2639 + });
2640 +
2641 + return sorted;
2642 +};
2643 +
2644 +MibNode.prototype.isDescendant = function (address) {
2645 + return MibNode.oidIsDescended(this.address, address);
2646 +};
2647 +
2648 +MibNode.prototype.isAncestor = function (address) {
2649 + return MibNode.oidIsDescended(address, this.address);
2650 +};
2651 +
2652 +MibNode.prototype.getAncestorProvider = function () {
2653 + if (this.provider) {
2654 + return this;
2655 + } else if (!this.parent) {
2656 + return null;
2657 + } else {
2658 + return this.parent.getAncestorProvider();
2659 + }
2660 +};
2661 +
2662 +MibNode.prototype.getInstanceNodeForTableRow = function () {
2663 + var childCount = Object.keys(this.children).length;
2664 + if (childCount == 0) {
2665 + if (this.value) {
2666 + return this;
2667 + } else {
2668 + return null;
2669 + }
2670 + } else if (childCount == 1) {
2671 + return this.children[0].getInstanceNodeForTableRow();
2672 + } else if (childCount > 1) {
2673 + return null;
2674 + }
2675 +};
2676 +
2677 +MibNode.prototype.getInstanceNodeForTableRowIndex = function (index) {
2678 + var childCount = Object.keys(this.children).length;
2679 + if (childCount == 0) {
2680 + if (this.value) {
2681 + return this;
2682 + } else {
2683 + // not found
2684 + return null;
2685 + }
2686 + } else {
2687 + if (index.length == 0) {
2688 + return this.getInstanceNodeForTableRow();
2689 + } else {
2690 + var nextChildIndexPart = index[0];
2691 + if (!nextChildIndexPart) {
2692 + return null;
2693 + }
2694 + remainingIndex = index.slice(1);
2695 + return this.children[nextChildIndexPart].getInstanceNodeForTableRowIndex(remainingIndex);
2696 + }
2697 + }
2698 +};
2699 +
2700 +MibNode.prototype.getNextInstanceNode = function () {
2701 +
2702 + node = this;
2703 + if (this.value) {
2704 + // Need upwards traversal first
2705 + node = this;
2706 + while (node) {
2707 + siblingIndex = node.address.slice(-1)[0];
2708 + node = node.parent;
2709 + if (!node) {
2710 + // end of MIB
2711 + return null;
2712 + } else {
2713 + childrenAddresses = Object.keys(node.children).sort((a, b) => a - b);
2714 + siblingPosition = childrenAddresses.indexOf(siblingIndex.toString());
2715 + if (siblingPosition + 1 < childrenAddresses.length) {
2716 + node = node.children[childrenAddresses[siblingPosition + 1]];
2717 + break;
2718 + }
2719 + }
2720 + }
2721 + }
2722 + // Descent
2723 + while (node) {
2724 + if (node.value) {
2725 + return node;
2726 + }
2727 + childrenAddresses = Object.keys(node.children).sort((a, b) => a - b);
2728 + node = node.children[childrenAddresses[0]];
2729 + if (!node) {
2730 + // unexpected
2731 + return null;
2732 + }
2733 + }
2734 +};
2735 +
2736 +MibNode.prototype.delete = function () {
2737 + if (Object.keys(this.children) > 0) {
2738 + throw new Error("Cannot delete non-leaf MIB node");
2739 + }
2740 + addressLastPart = this.address.slice(-1)[0];
2741 + delete this.parent.children[addressLastPart];
2742 + this.parent = null;
2743 +};
2744 +
2745 +MibNode.prototype.pruneUpwards = function () {
2746 + if (!this.parent) {
2747 + return
2748 + }
2749 + if (Object.keys(this.children).length == 0) {
2750 + var lastAddressPart = this.address.splice(-1)[0].toString();
2751 + delete this.parent.children[lastAddressPart];
2752 + this.parent.pruneUpwards();
2753 + this.parent = null;
2754 + }
2755 +}
2756 +
2757 +MibNode.prototype.dump = function (options) {
2758 + var valueString;
2759 + if ((!options.leavesOnly || options.showProviders) && this.provider) {
2760 + console.log(this.oid + " [" + MibProviderType[this.provider.type] + ": " + this.provider.name + "]");
2761 + } else if ((!options.leavesOnly) || Object.keys(this.children).length == 0) {
2762 + if (this.value) {
2763 + valueString = " = ";
2764 + valueString += options.showTypes ? ObjectType[this.valueType] + ": " : "";
2765 + valueString += options.showValues ? this.value : "";
2766 + } else {
2767 + valueString = "";
2768 + }
2769 + console.log(this.oid + valueString);
2770 + }
2771 + for (node of Object.keys(this.children).sort((a, b) => a - b)) {
2772 + this.children[node].dump(options);
2773 + }
2774 +};
2775 +
2776 +MibNode.oidIsDescended = function (oid, ancestor) {
2777 + var ancestorAddress = Mib.convertOidToAddress(ancestor);
2778 + var address = Mib.convertOidToAddress(oid);
2779 + var isAncestor = true;
2780 +
2781 + if (address.length <= ancestorAddress.length) {
2782 + return false;
2783 + }
2784
1409 - if (arguments.length < 4) {
1410 - maxRepetitions = 20;
1411 - feedCb = arguments[1];
1412 - doneCb = arguments[2];
1413 - } else {
1414 - maxRepetitions = arguments[1];
1415 - feedCb = arguments[2];
1416 - doneCb = arguments[3];
1417 - }
2785 + ancestorAddress.forEach(function (o, i) {
2786 + if (address[i] !== ancestorAddress[i]) {
2787 + isAncestor = false;
2788 + }
2789 + });
2790
1419 - var req = {
1420 - maxRepetitions: maxRepetitions,
1421 - feedCb: feedCb,
1422 - doneCb: doneCb
1423 - };
2791 + return isAncestor;
2792 +};
2793 +
2794 +var Mib = function () {
2795 + this.root = new MibNode([], null);
2796 + this.providers = {};
2797 + this.providerNodes = {};
2798 +};
2799 +
2800 +Mib.prototype.addNodesForOid = function (oidString) {
2801 + var address = Mib.convertOidToAddress(oidString);
2802 + return this.addNodesForAddress(address);
2803 +};
2804 +
2805 +Mib.prototype.addNodesForAddress = function (address) {
2806 + var address;
2807 + var node;
2808 + var i;
2809 +
2810 + node = this.root;
2811 +
2812 + for (i = 0; i < address.length; i++) {
2813 + if (!node.children.hasOwnProperty(address[i])) {
2814 + node.children[address[i]] = new MibNode(address.slice(0, i + 1), node);
2815 + }
2816 + node = node.children[address[i]];
2817 + }
2818 +
2819 + return node;
2820 +};
2821 +
2822 +Mib.prototype.lookup = function (oid) {
2823 + var address;
2824 + var i;
2825 + var node;
2826 +
2827 + address = Mib.convertOidToAddress(oid);
2828 + node = this.root;
2829 + for (i = 0; i < address.length; i++) {
2830 + if (!node.children.hasOwnProperty(address[i])) {
2831 + return null
2832 + }
2833 + node = node.children[address[i]];
2834 + }
2835 +
2836 + return node;
2837 +};
2838 +
2839 +Mib.prototype.getProviderNodeForInstance = function (instanceNode) {
2840 + if (instanceNode.provider) {
2841 + throw new ReferenceError("Instance node has provider which should never happen");
2842 + }
2843 + return instanceNode.getAncestorProvider();
2844 +};
2845 +
2846 +Mib.prototype.addProviderToNode = function (provider) {
2847 + var node = this.addNodesForOid(provider.oid);
2848 +
2849 + node.provider = provider;
2850 + if (provider.type == MibProviderType.Table) {
2851 + if (!provider.index) {
2852 + provider.index = [1];
2853 + }
2854 + }
2855 + this.providerNodes[provider.name] = node;
2856 + return node;
2857 +};
2858 +
2859 +Mib.prototype.registerProvider = function (provider) {
2860 + this.providers[provider.name] = provider;
2861 +};
2862 +
2863 +Mib.prototype.unregisterProvider = function (name) {
2864 + var providerNode = this.providerNodes[name];
2865 + if (providerNode) {
2866 + providerNodeParent = providerNode.parent;
2867 + providerNode.delete();
2868 + providerNodeParent.pruneUpwards();
2869 + delete this.providerNodes[name];
2870 + }
2871 + delete this.providers[name];
2872 +};
2873 +
2874 +Mib.prototype.getProvider = function (name) {
2875 + return this.providers[name];
2876 +};
2877 +
2878 +Mib.prototype.getProviders = function () {
2879 + return this.providers;
2880 +};
2881 +
2882 +Mib.prototype.getScalarValue = function (scalarName) {
2883 + var providerNode = this.providerNodes[scalarName];
2884 + if (!providerNode || !providerNode.provider || providerNode.provider.type != MibProviderType.Scalar) {
2885 + throw new ReferenceError("Failed to get node for registered MIB provider " + scalarName);
2886 + }
2887 + var instanceAddress = providerNode.address.concat([0]);
2888 + if (!this.lookup(instanceAddress)) {
2889 + throw new Error("Failed created instance node for registered MIB provider " + scalarName);
2890 + }
2891 + var instanceNode = this.lookup(instanceAddress);
2892 + return instanceNode.value;
2893 +};
2894 +
2895 +Mib.prototype.setScalarValue = function (scalarName, newValue) {
2896 + var providerNode;
2897 + var instanceNode;
2898 +
2899 + if (!this.providers[scalarName]) {
2900 + throw new ReferenceError("Provider " + scalarName + " not registered with this MIB");
2901 + }
2902 +
2903 + providerNode = this.providerNodes[scalarName];
2904 + if (!providerNode) {
2905 + providerNode = this.addProviderToNode(this.providers[scalarName]);
2906 + }
2907 + if (!providerNode || !providerNode.provider || providerNode.provider.type != MibProviderType.Scalar) {
2908 + throw new ReferenceError("Could not find MIB node for registered provider " + scalarName);
2909 + }
2910 + var instanceAddress = providerNode.address.concat([0]);
2911 + instanceNode = this.lookup(instanceAddress);
2912 + if (!instanceNode) {
2913 + this.addNodesForAddress(instanceAddress);
2914 + instanceNode = this.lookup(instanceAddress);
2915 + instanceNode.valueType = providerNode.provider.scalarType;
2916 + }
2917 + instanceNode.value = newValue;
2918 +};
2919 +
2920 +Mib.prototype.getProviderNodeForTable = function (table) {
2921 + var providerNode;
2922 + var provider;
2923 +
2924 + providerNode = this.providerNodes[table];
2925 + if (!providerNode) {
2926 + throw new ReferenceError("No MIB provider registered for " + table);
2927 + }
2928 + provider = providerNode.provider;
2929 + if (!providerNode) {
2930 + throw new ReferenceError("No MIB provider definition for registered provider " + table);
2931 + }
2932 + if (provider.type != MibProviderType.Table) {
2933 + throw new TypeError("Registered MIB provider " + table +
2934 + " is not of the correct type (is type " + MibProviderType[provider.type] + ")");
2935 + }
2936 + return providerNode;
2937 +};
2938 +
2939 +Mib.prototype.addTableRow = function (table, row) {
2940 + var providerNode;
2941 + var provider;
2942 + var instance = [];
2943 + var instanceAddress;
2944 + var instanceNode;
2945 +
2946 + if (this.providers[table] && !this.providerNodes[table]) {
2947 + this.addProviderToNode(this.providers[table]);
2948 + }
2949 + providerNode = this.getProviderNodeForTable(table);
2950 + provider = providerNode.provider;
2951 + for (var indexPart of provider.index) {
2952 + columnPosition = provider.columns.findIndex(column => column.number == indexPart);
2953 + instance.push(row[columnPosition]);
2954 + }
2955 + for (var i = 0; i < providerNode.provider.columns.length; i++) {
2956 + var column = providerNode.provider.columns[i];
2957 + instanceAddress = providerNode.address.concat(column.number).concat(instance);
2958 + this.addNodesForAddress(instanceAddress);
2959 + instanceNode = this.lookup(instanceAddress);
2960 + instanceNode.valueType = column.type;
2961 + instanceNode.value = row[i];
2962 + }
2963 +};
2964 +
2965 +Mib.prototype.getTableColumnDefinitions = function (table) {
2966 + var providerNode;
2967 + var provider;
2968 +
2969 + providerNode = this.getProviderNodeForTable(table);
2970 + provider = providerNode.provider;
2971 + return provider.columns;
2972 +};
2973 +
2974 +Mib.prototype.getTableColumnCells = function (table, columnNumber) {
2975 + providerNode = this.getProviderNodeForTable(table);
2976 + columnNode = providerNode.children[columnNumber];
2977 + column = []
2978 + for (var row of Object.keys(columnNode.children)) {
2979 + instanceNode = columnNode.children[row].getInstanceNodeForTableRow();
2980 + column.push(instanceNode.value);
2981 + }
2982 + return column;
2983 +};
2984 +
2985 +Mib.prototype.getTableRowCells = function (table, rowIndex) {
2986 + var providerNode;
2987 + var columnNode;
2988 + var instanceNode;
2989 + var row = [];
2990 +
2991 + providerNode = this.getProviderNodeForTable(table);
2992 + for (var columnNumber of Object.keys(providerNode.children)) {
2993 + columnNode = providerNode.children[columnNumber];
2994 + instanceNode = columnNode.getInstanceNodeForTableRowIndex(rowIndex);
2995 + row.push(instanceNode.value);
2996 + }
2997 + return row;
2998 +};
2999 +
3000 +Mib.prototype.getTableCells = function (table, byRows) {
3001 + var providerNode;
3002 + var columnNode;
3003 + var data = [];
3004 +
3005 + providerNode = this.getProviderNodeForTable(table);
3006 + for (var columnNumber of Object.keys(providerNode.children)) {
3007 + columnNode = providerNode.children[columnNumber];
3008 + column = [];
3009 + data.push(column);
3010 + for (var row of Object.keys(columnNode.children)) {
3011 + instanceNode = columnNode.children[row].getInstanceNodeForTableRow();
3012 + column.push(instanceNode.value);
3013 + }
3014 + }
3015 +
3016 + if (byRows) {
3017 + return Object.keys(data[0]).map(function (c) {
3018 + return data.map(function (r) {
3019 + return r[c];
3020 + });
3021 + });
3022 + } else {
3023 + return data;
3024 + }
3025 +
3026 +};
3027 +
3028 +Mib.prototype.getTableSingleCell = function (table, columnNumber, rowIndex) {
3029 + var providerNode;
3030 + var columnNode;
3031 + var instanceNode;
3032 +
3033 + providerNode = this.getProviderNodeForTable(table);
3034 + columnNode = providerNode.children[columnNumber];
3035 + instanceNode = columnNode.getInstanceNodeForTableRowIndex(rowIndex);
3036 + return instanceNode.value;
3037 +};
3038 +
3039 +Mib.prototype.setTableSingleCell = function (table, columnNumber, rowIndex, value) {
3040 + var providerNode;
3041 + var columnNode;
3042 + var instanceNode;
3043 +
3044 + providerNode = this.getProviderNodeForTable(table);
3045 + columnNode = providerNode.children[columnNumber];
3046 + instanceNode = columnNode.getInstanceNodeForTableRowIndex(rowIndex);
3047 + instanceNode.value = value;
3048 +};
3049 +
3050 +Mib.prototype.deleteTableRow = function (table, rowIndex) {
3051 + var providerNode;
3052 + var columnNode;
3053 + var instanceNode;
3054 + var row = [];
3055 +
3056 + providerNode = this.getProviderNodeForTable(table);
3057 + for (var columnNumber of Object.keys(providerNode.children)) {
3058 + columnNode = providerNode.children[columnNumber];
3059 + instanceNode = columnNode.getInstanceNodeForTableRowIndex(rowIndex);
3060 + if (instanceNode) {
3061 + instanceParentNode = instanceNode.parent;
3062 + instanceNode.delete();
3063 + instanceParentNode.pruneUpwards();
3064 + } else {
3065 + throw new ReferenceError("Cannot find row for index " + rowIndex + " at registered provider " + table);
3066 + }
3067 + }
3068 + return row;
3069 +};
3070 +
3071 +Mib.prototype.dump = function (options) {
3072 + if (!options) {
3073 + options = {};
3074 + }
3075 + var completedOptions = {
3076 + leavesOnly: options.leavesOnly || true,
3077 + showProviders: options.leavesOnly || true,
3078 + showValues: options.leavesOnly || true,
3079 + showTypes: options.leavesOnly || true
3080 + };
3081 + this.root.dump(completedOptions);
3082 +};
3083 +
3084 +Mib.convertOidToAddress = function (oid) {
3085 + var address;
3086 + var oidArray;
3087 + var i;
3088 +
3089 + if (typeof (oid) === 'object' && util.isArray(oid)) {
3090 + address = oid;
3091 + } else if (typeof (oid) === 'string') {
3092 + address = oid.split('.');
3093 + } else {
3094 + throw new TypeError('oid (string or array) is required');
3095 + }
3096 +
3097 + if (address.length < 3)
3098 + throw new RangeError('object identifier is too short');
3099 +
3100 + oidArray = [];
3101 + for (i = 0; i < address.length; i++) {
3102 + var n;
3103 +
3104 + if (address[i] === '')
3105 + continue;
3106 +
3107 + if (address[i] === true || address[i] === false) {
3108 + throw new TypeError('object identifier component ' +
3109 + address[i] + ' is malformed');
3110 + }
3111 +
3112 + n = Number(address[i]);
3113 +
3114 + if (isNaN(n)) {
3115 + throw new TypeError('object identifier component ' +
3116 + address[i] + ' is malformed');
3117 + }
3118 + if (n % 1 !== 0) {
3119 + throw new TypeError('object identifier component ' +
3120 + address[i] + ' is not an integer');
3121 + }
3122 + if (i === 0 && n > 2) {
3123 + throw new RangeError('object identifier does not ' +
3124 + 'begin with 0, 1, or 2');
3125 + }
3126 + if (i === 1 && n > 39) {
3127 + throw new RangeError('object identifier second ' +
3128 + 'component ' + n + ' exceeds encoding limit of 39');
3129 + }
3130 + if (n < 0) {
3131 + throw new RangeError('object identifier component ' +
3132 + address[i] + ' is negative');
3133 + }
3134 + if (n > MAX_INT32) {
3135 + throw new RangeError('object identifier component ' +
3136 + address[i] + ' is too large');
3137 + }
3138 + oidArray.push(n);
3139 + }
3140 +
3141 + return oidArray;
3142 +
3143 +};
3144 +
3145 +var MibRequest = function (requestDefinition) {
3146 + this.operation = requestDefinition.operation;
3147 + this.address = Mib.convertOidToAddress(requestDefinition.oid);
3148 + this.oid = this.address.join('.');
3149 + this.providerNode = requestDefinition.providerNode;
3150 + this.instanceNode = requestDefinition.instanceNode;
3151 +};
3152 +
3153 +MibRequest.prototype.isScalar = function () {
3154 + return this.providerNode && this.providerNode.provider &&
3155 + this.providerNode.provider.type == MibProviderType.Scalar;
3156 +};
3157
1425 - if (this.version == Version2c)
1426 - this.getBulk ([oid], 0, maxRepetitions,
1427 - walkCb.bind (me, req));
1428 - else
1429 - this.getNext ([oid], walkCb.bind (me, req));
3158 +MibRequest.prototype.isTabular = function () {
3159 + return this.providerNode && this.providerNode.provider &&
3160 + this.providerNode.provider.type == MibProviderType.Table;
3161 +};
3162 +
3163 +var Agent = function (options, callback) {
3164 + DEBUG = options.debug;
3165 + this.listener = new Listener(options, this);
3166 + this.engine = new Engine(options.engineID);
3167 + this.authorizer = new Authorizer();
3168 + this.mib = new Mib();
3169 + this.callback = callback || function () {
3170 + };
3171 + this.context = "";
3172 +};
3173 +
3174 +Agent.prototype.getMib = function () {
3175 + return this.mib;
3176 +};
3177 +
3178 +Agent.prototype.getAuthorizer = function () {
3179 + return this.authorizer;
3180 +};
3181 +
3182 +Agent.prototype.registerProvider = function (provider) {
3183 + this.mib.registerProvider(provider);
3184 +};
3185
1431 - return this;
3186 +Agent.prototype.unregisterProvider = function (provider) {
3187 + this.mib.unregisterProvider(provider);
3188 +};
3189 +
3190 +Agent.prototype.getProvider = function (provider) {
3191 + return this.mib.getProvider(provider);
3192 +};
3193 +
3194 +Agent.prototype.getProviders = function () {
3195 + return this.mib.getProviders();
3196 +};
3197 +
3198 +Agent.prototype.onMsg = function (buffer, rinfo) {
3199 + var message = Listener.processIncoming(buffer, this.authorizer, this.callback);
3200 + var reportMessage;
3201 + var responseMessage;
3202 +
3203 + if (!message) {
3204 + return;
3205 + }
3206 +
3207 + // SNMPv3 discovery
3208 + if (message.version == Version3 && message.pdu.type == PduType.GetRequest &&
3209 + !message.hasAuthoritativeEngineID() && message.isReportable()) {
3210 + reportMessage = message.createReportResponseMessage(this.engine, this.context);
3211 + this.listener.send(reportMessage, rinfo);
3212 + return;
3213 + }
3214 +
3215 + // Request processing
3216 + debug(JSON.stringify(message.pdu, null, 2));
3217 + if (message.pdu.type == PduType.GetRequest) {
3218 + responseMessage = this.request(message, rinfo);
3219 + } else if (message.pdu.type == PduType.SetRequest) {
3220 + responseMessage = this.request(message, rinfo);
3221 + } else if (message.pdu.type == PduType.GetNextRequest) {
3222 + responseMessage = this.getNextRequest(message, rinfo);
3223 + } else if (message.pdu.type == PduType.GetBulkRequest) {
3224 + responseMessage = this.getBulkRequest(message, rinfo);
3225 + } else {
3226 + this.callback(new RequestInvalidError("Unexpected PDU type " +
3227 + message.pdu.type + " (" + PduType[message.pdu.type] + ")"));
3228 + }
3229 +
3230 +};
3231 +
3232 +Agent.prototype.request = function (requestMessage, rinfo) {
3233 + var me = this;
3234 + var varbindsCompleted = 0;
3235 + var requestPdu = requestMessage.pdu;
3236 + var varbindsLength = requestPdu.varbinds.length;
3237 + var responsePdu = requestPdu.getResponsePduForRequest();
3238 +
3239 + for (var i = 0; i < requestPdu.varbinds.length; i++) {
3240 + var requestVarbind = requestPdu.varbinds[i];
3241 + var instanceNode = this.mib.lookup(requestVarbind.oid);
3242 + var providerNode;
3243 + var mibRequest;
3244 + var handler;
3245 + var responseVarbindType;
3246 +
3247 + if (!instanceNode) {
3248 + mibRequest = new MibRequest({
3249 + operation: requestPdu.type,
3250 + oid: requestVarbind.oid
3251 + });
3252 + handler = function getNsoHandler(mibRequestForNso) {
3253 + mibRequestForNso.done({
3254 + errorStatus: ErrorStatus.NoSuchName,
3255 + errorIndex: i
3256 + });
3257 + };
3258 + } else {
3259 + providerNode = this.mib.getProviderNodeForInstance(instanceNode);
3260 + mibRequest = new MibRequest({
3261 + operation: requestPdu.type,
3262 + providerNode: providerNode,
3263 + instanceNode: instanceNode,
3264 + oid: requestVarbind.oid
3265 + });
3266 + handler = providerNode.provider.handler;
3267 + }
3268 +
3269 + mibRequest.done = function (error) {
3270 + if (error) {
3271 + responsePdu.errorStatus = error.errorStatus;
3272 + responsePdu.errorIndex = error.errorIndex;
3273 + responseVarbind = {
3274 + oid: mibRequest.oid,
3275 + type: ObjectType.Null,
3276 + value: null
3277 + };
3278 + } else {
3279 + if (requestPdu.type == PduType.SetRequest) {
3280 + mibRequest.instanceNode.value = requestVarbind.value;
3281 + }
3282 + if (requestPdu.type == PduType.GetNextRequest && requestVarbind.type == ObjectType.EndOfMibView) {
3283 + responseVarbindType = ObjectType.EndOfMibView;
3284 + } else {
3285 + responseVarbindType = mibRequest.instanceNode.valueType;
3286 + }
3287 + responseVarbind = {
3288 + oid: mibRequest.oid,
3289 + type: responseVarbindType,
3290 + value: mibRequest.instanceNode.value
3291 + };
3292 + }
3293 + me.setSingleVarbind(responsePdu, i, responseVarbind);
3294 + if (++varbindsCompleted == varbindsLength) {
3295 + me.sendResponse.call(me, rinfo, requestMessage, responsePdu);
3296 + }
3297 + };
3298 + if (handler) {
3299 + handler(mibRequest);
3300 + } else {
3301 + mibRequest.done();
3302 + }
3303 + }
3304 + ;
3305 +};
3306 +
3307 +Agent.prototype.addGetNextVarbind = function (targetVarbinds, startOid) {
3308 + var startNode = this.mib.lookup(startOid);
3309 + var getNextNode;
3310 +
3311 + if (!startNode) {
3312 + // Off-tree start specified
3313 + targetVarbinds.push({
3314 + oid: requestVarbind.oid,
3315 + type: ObjectType.Null,
3316 + value: null
3317 + });
3318 + } else {
3319 + getNextNode = startNode.getNextInstanceNode();
3320 + if (!getNextNode) {
3321 + // End of MIB
3322 + targetVarbinds.push({
3323 + oid: requestVarbind.oid,
3324 + type: ObjectType.EndOfMibView,
3325 + value: null
3326 + });
3327 + } else {
3328 + // Normal response
3329 + targetVarbinds.push({
3330 + oid: getNextNode.oid,
3331 + type: getNextNode.valueType,
3332 + value: getNextNode.value
3333 + });
3334 + }
3335 + }
3336 + return getNextNode;
3337 +};
3338 +
3339 +Agent.prototype.getNextRequest = function (requestMessage, rinfo) {
3340 + var requestPdu = requestMessage.pdu;
3341 + var varbindsLength = requestPdu.varbinds.length;
3342 + var getNextVarbinds = [];
3343 +
3344 + for (var i = 0; i < varbindsLength; i++) {
3345 + this.addGetNextVarbind(getNextVarbinds, requestPdu.varbinds[i].oid);
3346 + }
3347 +
3348 + requestMessage.pdu.varbinds = getNextVarbinds;
3349 + this.request(requestMessage, rinfo);
3350 +};
3351 +
3352 +Agent.prototype.getBulkRequest = function (requestMessage, rinfo) {
3353 + var requestPdu = requestMessage.pdu;
3354 + var requestVarbinds = requestPdu.varbinds;
3355 + var getBulkVarbinds = [];
3356 + var startOid = [];
3357 + var getNextNode;
3358 +
3359 + for (var n = 0; n < requestPdu.nonRepeaters; n++) {
3360 + this.addGetNextVarbind(getBulkVarbinds, requestVarbinds[n].oid);
3361 + }
3362 +
3363 + for (var v = requestPdu.nonRepeaters; v < requestVarbinds.length; v++) {
3364 + startOid.push(requestVarbinds[v].oid);
3365 + }
3366 +
3367 + for (var r = 0; r < requestPdu.maxRepetitions; r++) {
3368 + for (var v = requestPdu.nonRepeaters; v < requestVarbinds.length; v++) {
3369 + getNextNode = this.addGetNextVarbind(getBulkVarbinds, startOid[v - requestPdu.nonRepeaters]);
3370 + if (getNextNode) {
3371 + startOid[v - requestPdu.nonRepeaters] = getNextNode.oid;
3372 + }
3373 + }
3374 + }
3375 +
3376 + requestMessage.pdu.varbinds = getBulkVarbinds;
3377 + this.request(requestMessage, rinfo);
3378 +};
3379 +
3380 +Agent.prototype.setSingleVarbind = function (responsePdu, index, responseVarbind) {
3381 + responsePdu.varbinds[index] = responseVarbind;
3382 +};
3383 +
3384 +Agent.prototype.sendResponse = function (rinfo, requestMessage, responsePdu) {
3385 + var responseMessage = requestMessage.createResponseForRequest(responsePdu);
3386 + this.listener.send(responseMessage, rinfo);
3387 + this.callback(null, Listener.formatCallbackData(responseMessage.pdu, rinfo));
3388 +};
3389 +
3390 +Agent.create = function (options, callback) {
3391 + var agent = new Agent(options, callback);
3392 + agent.listener.startListening();
3393 + return agent;
3394 };
3395
3396 /*****************************************************************************
@@ -1438,18 +3400,41 @@ Session.prototype.walk = function () {
3400 exports.Session = Session;
3401
3402 exports.createSession = function (target, community, options) {
1441 - return new Session (target, community, options);
3403 + if (options.version && !(options.version == Version1 || options.version == Version2c)) {
3404 + throw new ResponseInvalidError("SNMP community session requested but version '" + options.version + "' specified in options not valid");
3405 + } else {
3406 + return new Session(target, community, options);
3407 + }
3408 };
3409
3410 +exports.createV3Session = function (target, user, options) {
3411 + if (options.version && options.version != Version3) {
3412 + throw new ResponseInvalidError("SNMPv3 session requested but version '" + options.version + "' specified in options");
3413 + } else {
3414 + options.version = Version3;
3415 + }
3416 + return new Session(target, user, options);
3417 +};
3418 +
3419 +exports.createReceiver = Receiver.create;
3420 +exports.createAgent = Agent.create;
3421 +
3422 exports.isVarbindError = isVarbindError;
3423 exports.varbindError = varbindError;
3424
3425 exports.Version1 = Version1;
3426 exports.Version2c = Version2c;
3427 +exports.Version3 = Version3;
3428 +exports.Version = Version;
3429
3430 exports.ErrorStatus = ErrorStatus;
3431 exports.TrapType = TrapType;
3432 exports.ObjectType = ObjectType;
3433 +exports.PduType = PduType;
3434 +exports.MibProviderType = MibProviderType;
3435 +exports.SecurityLevel = SecurityLevel;
3436 +exports.AuthProtocols = AuthProtocols;
3437 +exports.PrivProtocols = PrivProtocols;
3438
3439 exports.ResponseInvalidError = ResponseInvalidError;
3440 exports.RequestInvalidError = RequestInvalidError;
@@ -1460,6 +3445,8 @@ exports.RequestTimedOutError = RequestTimedOutError;
3445 ** We've added this for testing.
3446 **/
3447 exports.ObjectParser = {
1463 - readInt: readInt,
1464 - readUint: readUint
3448 + readInt: readInt,
3449 + readUint: readUint
3450 };
3451 +exports.Authentication = Authentication;
3452 +exports.Encryption = Encryption;
collectors/node.d.plugin/snmp/README.md
+204 -141
@@ -1,15 +1,20 @@
1 # SNMP Data Collector
2
3 -Using this collector, Netdata can collect data from any SNMP device.
3 +Using this collector, Netdata can collect data from any SNMP device. This collector uses [net-snmp](https://github.com/markabrahams/node-net-snmp) module.
4
5 -This collector supports:
5 +It supports:
6
7 +- all SNMP versions: SNMPv1, SNMPv2c and SNMPv3
8 - any number of SNMP devices
9 - each SNMP device can be used to collect data for any number of charts
10 - each chart may have any number of dimensions
11 - each SNMP device may have a different update frequency
12 - each SNMP device will accept one or more batches to report values (you can set `max_request_size` per SNMP server, to control the size of batches).
13
14 +## Requirements
15 +
16 +- `nodejs` minimum required version 4
17 +
18 ## Configuration
19
20 You will need to create the file `/etc/netdata/node.d/snmp.conf` with data like the following.
@@ -32,7 +37,9 @@ In this example:
37 "community": "public",
38 "update_every": 10,
39 "max_request_size": 50,
35 - "options": { "timeout": 10000 },
40 + "options": {
41 + "timeout": 10000
42 + },
43 "charts": {
44 "snmp_switch.bandwidth_port1": {
45 "title": "Switch Bandwidth for port 1",
@@ -109,7 +116,9 @@ If you need to define many charts using incremental OIDs, you can use something
116 "hostname": "10.11.12.8",
117 "community": "public",
118 "update_every": 10,
112 - "options": { "timeout": 20000 },
119 + "options": {
120 + "timeout": 20000
121 + },
122 "charts": {
123 "snmp_switch.bandwidth_port": {
124 "title": "Switch Bandwidth for port ",
@@ -117,7 +126,10 @@ If you need to define many charts using incremental OIDs, you can use something
126 "type": "area",
127 "priority": 1,
128 "family": "ports",
120 - "multiply_range": [ 1, 24 ],
129 + "multiply_range": [
130 + 1,
131 + 24
132 + ],
133 "dimensions": {
134 "in": {
135 "oid": "1.3.6.1.2.1.2.2.1.10.",
@@ -152,11 +164,55 @@ Each of the 24 new charts will have its id (1-24) appended at:
164
165 The `options` given for each server, are:
166
155 -- `timeout`, the time to wait for the SNMP device to respond. The default is 5000 ms.
156 -- `version`, the SNMP version to use. `0` is Version 1, `1` is Version 2c. The default is Version 1 (`0`).
157 -- `transport`, the default is `udp4`.
158 -- `port`, the port of the SNMP device to connect to. The default is `161`.
159 -- `retries`, the number of attempts to make to fetch the data. The default is `1`.
167 +- `port` - UDP port to send requests too. Defaults to `161`.
168 +- `retries` - number of times to re-send a request. Defaults to `1`.
169 +- `sourceAddress` - IP address from which SNMP requests should originate, there is no default for this option, the operating system will select an appropriate source address when the SNMP request is sent.
170 +- `sourcePort` - UDP port from which SNMP requests should originate, defaults to an ephemeral port selected by the operation system.
171 +- `timeout` - number of milliseconds to wait for a response before re-trying or failing. Defaults to `5000`.
172 +- `transport` - specify the transport to use, can be either `udp4` or `udp6`. Defaults to `udp4`.
173 +- `version` - either `0` (v1) or `1` (v2) or `3` (v3). Defaults to `0`.
174 +- `idBitsSize` - either `16` or `32`. Defaults to `32`. Used to reduce the size of the generated id for compatibility with some older devices.
175 +
176 +## SNMPv3
177 +
178 +To use SNMPv3:
179 +
180 +- set `version` to 3
181 +- use `user` instead of `community`
182 +
183 +User syntax:
184 +
185 +```json
186 +{
187 + "user": {
188 + "name": "userName",
189 + "level": 3,
190 + "authProtocol": "3",
191 + "authKey": "authKey",
192 + "privProtocol": "2",
193 + "privKey": "privKey"
194 + }
195 +}
196 +```
197 +
198 +Security levels:
199 +
200 +- 1 is `noAuthNoPriv`
201 +- 2 is `authNoPriv`
202 +- 3 is `authPriv`
203 +
204 +Authentication protocols:
205 +
206 +- "1" is `none`
207 +- "2" is `md5`
208 +- "3" is `sha`
209 +
210 +Privacy protocols:
211 +
212 +- "1" is `none`
213 +- "2" is `des`
214 +
215 +For additional details please see [net-snmp module readme](https://github.com/markabrahams/node-net-snmp#snmpcreatev3session-target-user-options).
216
217 ## Retrieving names from snmp
218
@@ -218,145 +274,152 @@ This switch has a very slow SNMP processors. To respond, it needs about 8 second
274 "enable_autodetect": false,
275 "update_every": 5,
276 "servers": [
221 - {
222 - "hostname": "10.11.12.8",
223 - "community": "public",
224 - "update_every": 15,
225 - "options": { "timeout": 20000, "version": 1 },
226 - "charts": {
227 - "snmp_switch.power": {
228 - "title": "Switch Power Supply",
229 - "units": "watts",
230 - "type": "line",
231 - "priority": 10,
232 - "family": "power",
233 - "dimensions": {
234 - "supply": {
235 - "oid": ".1.3.6.1.2.1.105.1.3.1.1.2.1",
236 - "algorithm": "absolute",
237 - "multiplier": 1,
238 - "divisor": 1,
239 - "offset": 0
240 - },
241 - "used": {
242 - "oid": ".1.3.6.1.2.1.105.1.3.1.1.4.1",
243 - "algorithm": "absolute",
244 - "multiplier": 1,
245 - "divisor": 1,
246 - "offset": 0
247 - }
248 - }
249 - }
250 - , "snmp_switch.input": {
251 - "title": "Switch Packets Input",
252 - "units": "packets/s",
253 - "type": "area",
254 - "priority": 20,
255 - "family": "IP",
256 - "dimensions": {
257 - "receives": {
258 - "oid": ".1.3.6.1.2.1.4.3.0",
259 - "algorithm": "incremental",
260 - "multiplier": 1,
261 - "divisor": 1,
262 - "offset": 0
263 - }
264 - , "discards": {
265 - "oid": ".1.3.6.1.2.1.4.8.0",
266 - "algorithm": "incremental",
267 - "multiplier": 1,
268 - "divisor": 1,
269 - "offset": 0
270 - }
271 - }
272 - }
273 - , "snmp_switch.input_errors": {
274 - "title": "Switch Received Packets with Errors",
275 - "units": "packets/s",
276 - "type": "line",
277 - "priority": 30,
278 - "family": "IP",
279 - "dimensions": {
280 - "bad_header": {
281 - "oid": ".1.3.6.1.2.1.4.4.0",
282 - "algorithm": "incremental",
283 - "multiplier": 1,
284 - "divisor": 1,
285 - "offset": 0
286 - }
287 - , "bad_address": {
288 - "oid": ".1.3.6.1.2.1.4.5.0",
289 - "algorithm": "incremental",
290 - "multiplier": 1,
291 - "divisor": 1,
292 - "offset": 0
293 - }
294 - , "unknown_protocol": {
295 - "oid": ".1.3.6.1.2.1.4.7.0",
296 - "algorithm": "incremental",
297 - "multiplier": 1,
298 - "divisor": 1,
299 - "offset": 0
300 - }
301 - }
302 - }
303 - , "snmp_switch.output": {
304 - "title": "Switch Output Packets",
305 - "units": "packets/s",
306 - "type": "line",
307 - "priority": 40,
308 - "family": "IP",
309 - "dimensions": {
310 - "requests": {
311 - "oid": ".1.3.6.1.2.1.4.10.0",
312 - "algorithm": "incremental",
313 - "multiplier": 1,
314 - "divisor": 1,
315 - "offset": 0
277 + {
278 + "hostname": "10.11.12.8",
279 + "community": "public",
280 + "update_every": 15,
281 + "options": {
282 + "timeout": 20000,
283 + "version": 1
284 + },
285 + "charts": {
286 + "snmp_switch.power": {
287 + "title": "Switch Power Supply",
288 + "units": "watts",
289 + "type": "line",
290 + "priority": 10,
291 + "family": "power",
292 + "dimensions": {
293 + "supply": {
294 + "oid": ".1.3.6.1.2.1.105.1.3.1.1.2.1",
295 + "algorithm": "absolute",
296 + "multiplier": 1,
297 + "divisor": 1,
298 + "offset": 0
299 + },
300 + "used": {
301 + "oid": ".1.3.6.1.2.1.105.1.3.1.1.4.1",
302 + "algorithm": "absolute",
303 + "multiplier": 1,
304 + "divisor": 1,
305 + "offset": 0
306 + }
307 }
317 - , "discards": {
318 - "oid": ".1.3.6.1.2.1.4.11.0",
319 - "algorithm": "incremental",
320 - "multiplier": -1,
321 - "divisor": 1,
322 - "offset": 0
308 + },
309 + "snmp_switch.input": {
310 + "title": "Switch Packets Input",
311 + "units": "packets/s",
312 + "type": "area",
313 + "priority": 20,
314 + "family": "IP",
315 + "dimensions": {
316 + "receives": {
317 + "oid": ".1.3.6.1.2.1.4.3.0",
318 + "algorithm": "incremental",
319 + "multiplier": 1,
320 + "divisor": 1,
321 + "offset": 0
322 + },
323 + "discards": {
324 + "oid": ".1.3.6.1.2.1.4.8.0",
325 + "algorithm": "incremental",
326 + "multiplier": 1,
327 + "divisor": 1,
328 + "offset": 0
329 + }
330 }
324 - , "no_route": {
325 - "oid": ".1.3.6.1.2.1.4.12.0",
326 - "algorithm": "incremental",
327 - "multiplier": -1,
328 - "divisor": 1,
329 - "offset": 0
331 + },
332 + "snmp_switch.input_errors": {
333 + "title": "Switch Received Packets with Errors",
334 + "units": "packets/s",
335 + "type": "line",
336 + "priority": 30,
337 + "family": "IP",
338 + "dimensions": {
339 + "bad_header": {
340 + "oid": ".1.3.6.1.2.1.4.4.0",
341 + "algorithm": "incremental",
342 + "multiplier": 1,
343 + "divisor": 1,
344 + "offset": 0
345 + },
346 + "bad_address": {
347 + "oid": ".1.3.6.1.2.1.4.5.0",
348 + "algorithm": "incremental",
349 + "multiplier": 1,
350 + "divisor": 1,
351 + "offset": 0
352 + },
353 + "unknown_protocol": {
354 + "oid": ".1.3.6.1.2.1.4.7.0",
355 + "algorithm": "incremental",
356 + "multiplier": 1,
357 + "divisor": 1,
358 + "offset": 0
359 + }
360 }
331 - }
332 - }
333 - , "snmp_switch.bandwidth_port": {
334 - "title": "Switch Bandwidth for port ",
335 - "titleoid": ".1.3.6.1.2.1.31.1.1.1.18.",
336 - "units": "kilobits/s",
337 - "type": "area",
338 - "priority": 100,
339 - "family": "ports",
340 - "multiply_range": [ 1, 24 ],
341 - "dimensions": {
342 - "in": {
343 - "oid": ".1.3.6.1.2.1.2.2.1.10.",
344 - "algorithm": "incremental",
345 - "multiplier": 8,
346 - "divisor": 1024,
347 - "offset": 0
361 + },
362 + "snmp_switch.output": {
363 + "title": "Switch Output Packets",
364 + "units": "packets/s",
365 + "type": "line",
366 + "priority": 40,
367 + "family": "IP",
368 + "dimensions": {
369 + "requests": {
370 + "oid": ".1.3.6.1.2.1.4.10.0",
371 + "algorithm": "incremental",
372 + "multiplier": 1,
373 + "divisor": 1,
374 + "offset": 0
375 + },
376 + "discards": {
377 + "oid": ".1.3.6.1.2.1.4.11.0",
378 + "algorithm": "incremental",
379 + "multiplier": -1,
380 + "divisor": 1,
381 + "offset": 0
382 + },
383 + "no_route": {
384 + "oid": ".1.3.6.1.2.1.4.12.0",
385 + "algorithm": "incremental",
386 + "multiplier": -1,
387 + "divisor": 1,
388 + "offset": 0
389 + }
390 }
349 - , "out": {
350 - "oid": ".1.3.6.1.2.1.2.2.1.16.",
351 - "algorithm": "incremental",
352 - "multiplier": -8,
353 - "divisor": 1024,
354 - "offset": 0
391 + },
392 + "snmp_switch.bandwidth_port": {
393 + "title": "Switch Bandwidth for port ",
394 + "titleoid": ".1.3.6.1.2.1.31.1.1.1.18.",
395 + "units": "kilobits/s",
396 + "type": "area",
397 + "priority": 100,
398 + "family": "ports",
399 + "multiply_range": [
400 + 1,
401 + 24
402 + ],
403 + "dimensions": {
404 + "in": {
405 + "oid": ".1.3.6.1.2.1.2.2.1.10.",
406 + "algorithm": "incremental",
407 + "multiplier": 8,
408 + "divisor": 1024,
409 + "offset": 0
410 + },
411 + "out": {
412 + "oid": ".1.3.6.1.2.1.2.2.1.16.",
413 + "algorithm": "incremental",
414 + "multiplier": -8,
415 + "divisor": 1024,
416 + "offset": 0
417 + }
418 }
419 }
420 }
421 }
359 - }],
422 + ]
423 }
424 ```
425
collectors/node.d.plugin/snmp/snmp.node.js
+16 -4
@@ -341,11 +341,23 @@ netdata.processors.snmp = {
341 // no SNMP session has been created for this service
342 // the SNMP session is just the initialization of NET-SNMP
343
344 - if(__DEBUG === true)
345 - netdata.debug(service.module.name + ': ' + service.name + ': opening ' + this.name + ' session on ' + service.request.hostname + ' community ' + service.request.community + ' options ' + netdata.stringify(service.request.options));
344 + var snmp_version = (service.request.options && service.request.options.version)
345 + ? service.request.options.version
346 + : net_snmp.Version1;
347 +
348 + if(snmp_version === net_snmp.Version3) {
349 + if(__DEBUG === true)
350 + netdata.debug(service.module.name + ': ' + service.name + ': opening ' + this.name + ' session on ' + service.request.hostname + ' user ' + service.request.user + ' options ' + netdata.stringify(service.request.options));
351
347 - // create the SNMP session
348 - service.snmp_session = net_snmp.createSession (service.request.hostname, service.request.community, service.request.options);
352 + // create the SNMP session
353 + service.snmp_session = net_snmp.createV3Session (service.request.hostname, service.request.user, service.request.options);
354 + } else {
355 + if(__DEBUG === true)
356 + netdata.debug(service.module.name + ': ' + service.name + ': opening ' + this.name + ' session on ' + service.request.hostname + ' community ' + service.request.community + ' options ' + netdata.stringify(service.request.options));
357 +
358 + // create the SNMP session
359 + service.snmp_session = net_snmp.createSession (service.request.hostname, service.request.community, service.request.options);
360 + }
361
362 if(__DEBUG === true)
363 netdata.debug(service.module.name + ': ' + service.name + ': got ' + this.name + ' session: ' + netdata.stringify(service.snmp_session));