net-snmp 3.23.0 → 3.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +132 -0
- package/eslint.config.js +3 -0
- package/example/agentx-subagent.js +44 -9
- package/index.js +345 -125
- package/package.json +2 -2
- package/test/README-test-coverage.md +76 -0
- package/test/snmpv3-auth-failures.test.js +331 -0
- package/test/subagent.test.js +469 -0
@@ -0,0 +1,469 @@
|
|
1
|
+
const assert = require('assert');
|
2
|
+
const net = require('net');
|
3
|
+
const snmp = require('..');
|
4
|
+
|
5
|
+
describe('Subagent', function() {
|
6
|
+
let subagent;
|
7
|
+
let mockSocket;
|
8
|
+
let mockServer;
|
9
|
+
|
10
|
+
beforeEach(function() {
|
11
|
+
// Create a mock server to simulate master agent
|
12
|
+
mockServer = net.createServer();
|
13
|
+
mockSocket = {
|
14
|
+
connect: () => {},
|
15
|
+
on: () => {},
|
16
|
+
write: () => {},
|
17
|
+
end: () => {}
|
18
|
+
};
|
19
|
+
|
20
|
+
// Use the factory method instead of constructor
|
21
|
+
subagent = snmp.createSubagent({
|
22
|
+
master: 'localhost',
|
23
|
+
masterPort: 705,
|
24
|
+
timeout: 5,
|
25
|
+
description: 'Test Subagent'
|
26
|
+
});
|
27
|
+
|
28
|
+
// Mock socket connection to avoid actual networking
|
29
|
+
subagent.socket = mockSocket;
|
30
|
+
subagent.sessionID = 123;
|
31
|
+
});
|
32
|
+
|
33
|
+
afterEach(function() {
|
34
|
+
if (mockServer) {
|
35
|
+
mockServer.close();
|
36
|
+
}
|
37
|
+
if (subagent && typeof subagent.close === 'function') {
|
38
|
+
subagent.close();
|
39
|
+
}
|
40
|
+
});
|
41
|
+
|
42
|
+
describe('Constructor', function() {
|
43
|
+
it('creates subagent with default options', function() {
|
44
|
+
const sub = snmp.createSubagent({});
|
45
|
+
// Prevent actual network connection
|
46
|
+
sub.connectSocket = () => {};
|
47
|
+
|
48
|
+
assert.equal(sub.master, 'localhost');
|
49
|
+
assert.equal(sub.masterPort, 705);
|
50
|
+
assert.equal(sub.timeout, 0);
|
51
|
+
assert.equal(sub.descr, "Node net-snmp AgentX sub-agent");
|
52
|
+
assert(sub.mib);
|
53
|
+
|
54
|
+
// Clean up
|
55
|
+
if (typeof sub.close === 'function') {
|
56
|
+
sub.close();
|
57
|
+
}
|
58
|
+
});
|
59
|
+
|
60
|
+
it('creates subagent with custom options', function() {
|
61
|
+
const sub = snmp.createSubagent({
|
62
|
+
master: '192.168.1.1',
|
63
|
+
masterPort: 8080,
|
64
|
+
timeout: 10,
|
65
|
+
description: 'Custom Subagent'
|
66
|
+
});
|
67
|
+
// Prevent actual network connection
|
68
|
+
sub.connectSocket = () => {};
|
69
|
+
|
70
|
+
assert.equal(sub.master, '192.168.1.1');
|
71
|
+
assert.equal(sub.masterPort, 8080);
|
72
|
+
assert.equal(sub.timeout, 10);
|
73
|
+
assert.equal(sub.descr, 'Custom Subagent');
|
74
|
+
|
75
|
+
// Clean up
|
76
|
+
if (typeof sub.close === 'function') {
|
77
|
+
sub.close();
|
78
|
+
}
|
79
|
+
});
|
80
|
+
});
|
81
|
+
|
82
|
+
describe('Provider Management', function() {
|
83
|
+
let scalarProvider, tableProvider;
|
84
|
+
|
85
|
+
beforeEach(function() {
|
86
|
+
scalarProvider = {
|
87
|
+
name: "testScalar",
|
88
|
+
type: snmp.MibProviderType.Scalar,
|
89
|
+
oid: "1.3.6.1.4.1.8072.9999.1",
|
90
|
+
scalarType: snmp.ObjectType.Integer,
|
91
|
+
maxAccess: snmp.MaxAccess['read-write']
|
92
|
+
};
|
93
|
+
|
94
|
+
tableProvider = {
|
95
|
+
name: "testTable",
|
96
|
+
type: snmp.MibProviderType.Table,
|
97
|
+
oid: "1.3.6.1.4.1.8072.9999.2",
|
98
|
+
maxAccess: snmp.MaxAccess['not-accessible'],
|
99
|
+
tableColumns: [
|
100
|
+
{
|
101
|
+
number: 1,
|
102
|
+
name: "testIndex",
|
103
|
+
type: snmp.ObjectType.Integer,
|
104
|
+
maxAccess: snmp.MaxAccess['not-accessible']
|
105
|
+
},
|
106
|
+
{
|
107
|
+
number: 2,
|
108
|
+
name: "testValue",
|
109
|
+
type: snmp.ObjectType.OctetString,
|
110
|
+
maxAccess: snmp.MaxAccess['read-write']
|
111
|
+
},
|
112
|
+
{
|
113
|
+
number: 3,
|
114
|
+
name: "testReadOnly",
|
115
|
+
type: snmp.ObjectType.Integer,
|
116
|
+
maxAccess: snmp.MaxAccess['read-only']
|
117
|
+
}
|
118
|
+
],
|
119
|
+
tableIndex: [{ columnName: "testIndex" }]
|
120
|
+
};
|
121
|
+
});
|
122
|
+
|
123
|
+
it('registers scalar provider', function() {
|
124
|
+
let pduSent = null;
|
125
|
+
subagent.sendPdu = (pdu, callback) => {
|
126
|
+
pduSent = pdu;
|
127
|
+
if (callback) callback(null, { error: 0 });
|
128
|
+
};
|
129
|
+
|
130
|
+
subagent.registerProvider(scalarProvider);
|
131
|
+
|
132
|
+
assert(pduSent);
|
133
|
+
assert.equal(pduSent.pduType, snmp.AgentXPduType.Register);
|
134
|
+
assert.equal(pduSent.oid, scalarProvider.oid);
|
135
|
+
assert(subagent.getProvider('testScalar'));
|
136
|
+
});
|
137
|
+
|
138
|
+
it('registers table provider', function() {
|
139
|
+
let pduSent = null;
|
140
|
+
subagent.sendPdu = (pdu, callback) => {
|
141
|
+
pduSent = pdu;
|
142
|
+
if (callback) callback(null, { error: 0 });
|
143
|
+
};
|
144
|
+
|
145
|
+
subagent.registerProvider(tableProvider);
|
146
|
+
|
147
|
+
assert(pduSent);
|
148
|
+
assert.equal(pduSent.pduType, snmp.AgentXPduType.Register);
|
149
|
+
assert.equal(pduSent.oid, tableProvider.oid);
|
150
|
+
assert(subagent.getProvider('testTable'));
|
151
|
+
});
|
152
|
+
|
153
|
+
it('unregisters provider', function() {
|
154
|
+
subagent.getMib().registerProvider(scalarProvider);
|
155
|
+
|
156
|
+
let pduSent = null;
|
157
|
+
subagent.sendPdu = (pdu, callback) => {
|
158
|
+
pduSent = pdu;
|
159
|
+
if (callback) callback(null, { error: 0 });
|
160
|
+
};
|
161
|
+
|
162
|
+
subagent.unregisterProvider('testScalar');
|
163
|
+
|
164
|
+
assert(pduSent);
|
165
|
+
assert.equal(pduSent.pduType, snmp.AgentXPduType.Unregister);
|
166
|
+
assert.equal(pduSent.oid, scalarProvider.oid);
|
167
|
+
});
|
168
|
+
});
|
169
|
+
|
170
|
+
describe('Administrative PDUs', function() {
|
171
|
+
it('sends ping PDU', function() {
|
172
|
+
let pduSent = null;
|
173
|
+
subagent.sendPdu = (pdu, callback) => {
|
174
|
+
pduSent = pdu;
|
175
|
+
if (callback) callback(null, { error: 0 });
|
176
|
+
};
|
177
|
+
|
178
|
+
subagent.ping();
|
179
|
+
|
180
|
+
assert(pduSent);
|
181
|
+
assert.equal(pduSent.pduType, snmp.AgentXPduType.Ping);
|
182
|
+
assert.equal(pduSent.sessionID, 123);
|
183
|
+
});
|
184
|
+
|
185
|
+
it('sends notify PDU', function() {
|
186
|
+
let pduSent = null;
|
187
|
+
subagent.sendPdu = (pdu, callback) => {
|
188
|
+
pduSent = pdu;
|
189
|
+
if (callback) callback(null, { error: 0 });
|
190
|
+
};
|
191
|
+
|
192
|
+
const varbinds = [
|
193
|
+
{
|
194
|
+
oid: '1.3.6.1.2.1.1.1.0',
|
195
|
+
type: snmp.ObjectType.OctetString,
|
196
|
+
value: 'test notification'
|
197
|
+
}
|
198
|
+
];
|
199
|
+
|
200
|
+
subagent.notify('1.3.6.1.6.3.1.1.5.1', varbinds);
|
201
|
+
|
202
|
+
assert(pduSent);
|
203
|
+
assert.equal(pduSent.pduType, snmp.AgentXPduType.Notify);
|
204
|
+
assert(Array.isArray(pduSent.varbinds));
|
205
|
+
assert.equal(pduSent.varbinds.length, 3); // sysUpTime + snmpTrapOID + user varbinds
|
206
|
+
});
|
207
|
+
|
208
|
+
it('adds agent capabilities', function() {
|
209
|
+
let pduSent = null;
|
210
|
+
subagent.sendPdu = (pdu, callback) => {
|
211
|
+
pduSent = pdu;
|
212
|
+
if (callback) callback(null, { error: 0 });
|
213
|
+
};
|
214
|
+
|
215
|
+
subagent.addAgentCaps('1.3.6.1.2.1.1', 'Test capability');
|
216
|
+
|
217
|
+
assert(pduSent);
|
218
|
+
assert.equal(pduSent.pduType, snmp.AgentXPduType.AddAgentCaps);
|
219
|
+
assert.equal(pduSent.oid, '1.3.6.1.2.1.1');
|
220
|
+
assert.equal(pduSent.descr, 'Test capability');
|
221
|
+
});
|
222
|
+
|
223
|
+
it('removes agent capabilities', function() {
|
224
|
+
let pduSent = null;
|
225
|
+
subagent.sendPdu = (pdu, callback) => {
|
226
|
+
pduSent = pdu;
|
227
|
+
if (callback) callback(null, { error: 0 });
|
228
|
+
};
|
229
|
+
|
230
|
+
subagent.removeAgentCaps('1.3.6.1.2.1.1');
|
231
|
+
|
232
|
+
assert(pduSent);
|
233
|
+
assert.equal(pduSent.pduType, snmp.AgentXPduType.RemoveAgentCaps);
|
234
|
+
assert.equal(pduSent.oid, '1.3.6.1.2.1.1');
|
235
|
+
});
|
236
|
+
});
|
237
|
+
|
238
|
+
describe('Utility Methods', function() {
|
239
|
+
it('returns correct MIB instance', function() {
|
240
|
+
assert(subagent.getMib());
|
241
|
+
assert.equal(typeof subagent.getMib().registerProvider, 'function');
|
242
|
+
});
|
243
|
+
|
244
|
+
it('emits close event', function(done) {
|
245
|
+
subagent.on('close', () => {
|
246
|
+
done();
|
247
|
+
});
|
248
|
+
subagent.onClose();
|
249
|
+
});
|
250
|
+
|
251
|
+
it('emits error event', function(done) {
|
252
|
+
const testError = new Error('Test error');
|
253
|
+
subagent.on('error', (error) => {
|
254
|
+
assert.equal(error, testError);
|
255
|
+
done();
|
256
|
+
});
|
257
|
+
subagent.onError(testError);
|
258
|
+
});
|
259
|
+
});
|
260
|
+
|
261
|
+
describe('Subagent Enhanced Tests for PR #280', function() {
|
262
|
+
// Tests for new functionality from PR #280
|
263
|
+
|
264
|
+
describe('isAllowed Method (Access Control)', function() {
|
265
|
+
let scalarProvider, tableProvider;
|
266
|
+
|
267
|
+
beforeEach(function() {
|
268
|
+
scalarProvider = {
|
269
|
+
name: "testScalar",
|
270
|
+
type: snmp.MibProviderType.Scalar,
|
271
|
+
oid: "1.3.6.1.4.1.8072.9999.1",
|
272
|
+
scalarType: snmp.ObjectType.Integer,
|
273
|
+
maxAccess: snmp.MaxAccess['read-write']
|
274
|
+
};
|
275
|
+
|
276
|
+
tableProvider = {
|
277
|
+
name: "testTable",
|
278
|
+
type: snmp.MibProviderType.Table,
|
279
|
+
oid: "1.3.6.1.4.1.8072.9999.2",
|
280
|
+
maxAccess: snmp.MaxAccess['not-accessible'],
|
281
|
+
tableColumns: [
|
282
|
+
{
|
283
|
+
number: 1,
|
284
|
+
name: "testIndex",
|
285
|
+
type: snmp.ObjectType.Integer,
|
286
|
+
maxAccess: snmp.MaxAccess['not-accessible']
|
287
|
+
},
|
288
|
+
{
|
289
|
+
number: 2,
|
290
|
+
name: "testValue",
|
291
|
+
type: snmp.ObjectType.OctetString,
|
292
|
+
maxAccess: snmp.MaxAccess['read-write']
|
293
|
+
},
|
294
|
+
{
|
295
|
+
number: 3,
|
296
|
+
name: "testReadOnly",
|
297
|
+
type: snmp.ObjectType.Integer,
|
298
|
+
maxAccess: snmp.MaxAccess['read-only']
|
299
|
+
}
|
300
|
+
],
|
301
|
+
tableIndex: [{ columnName: "testIndex" }]
|
302
|
+
};
|
303
|
+
|
304
|
+
subagent.getMib().registerProvider(scalarProvider);
|
305
|
+
subagent.getMib().registerProvider(tableProvider);
|
306
|
+
subagent.getMib().addTableRow('testTable', [1, 'test', 42]);
|
307
|
+
});
|
308
|
+
|
309
|
+
it('allows read access to read-write scalar', function() {
|
310
|
+
if (typeof subagent.isAllowed === 'function') {
|
311
|
+
const result = subagent.isAllowed(snmp.AgentXPduType.Get, scalarProvider, null);
|
312
|
+
assert.equal(result, true);
|
313
|
+
}
|
314
|
+
});
|
315
|
+
|
316
|
+
it('allows write access to read-write scalar', function() {
|
317
|
+
if (typeof subagent.isAllowed === 'function') {
|
318
|
+
const result = subagent.isAllowed(snmp.AgentXPduType.TestSet, scalarProvider, null);
|
319
|
+
assert.equal(result, true);
|
320
|
+
}
|
321
|
+
});
|
322
|
+
|
323
|
+
it('allows read access to read-only table column', function() {
|
324
|
+
if (typeof subagent.isAllowed === 'function') {
|
325
|
+
const instanceNode = subagent.getMib().lookup('1.3.6.1.4.1.8072.9999.2.3.1');
|
326
|
+
if (instanceNode) {
|
327
|
+
const result = subagent.isAllowed(snmp.AgentXPduType.Get, tableProvider, instanceNode);
|
328
|
+
assert.equal(result, true);
|
329
|
+
}
|
330
|
+
}
|
331
|
+
});
|
332
|
+
|
333
|
+
it('denies write access to read-only table column', function() {
|
334
|
+
if (typeof subagent.isAllowed === 'function') {
|
335
|
+
const instanceNode = subagent.getMib().lookup('1.3.6.1.4.1.8072.9999.2.3.1');
|
336
|
+
if (instanceNode) {
|
337
|
+
const result = subagent.isAllowed(snmp.AgentXPduType.TestSet, tableProvider, instanceNode);
|
338
|
+
assert.equal(result, false);
|
339
|
+
}
|
340
|
+
}
|
341
|
+
});
|
342
|
+
});
|
343
|
+
|
344
|
+
describe('Set Operations Transaction Management', function() {
|
345
|
+
let scalarProvider;
|
346
|
+
|
347
|
+
beforeEach(function() {
|
348
|
+
scalarProvider = {
|
349
|
+
name: "testScalar",
|
350
|
+
type: snmp.MibProviderType.Scalar,
|
351
|
+
oid: "1.3.6.1.4.1.8072.9999.1",
|
352
|
+
scalarType: snmp.ObjectType.Integer,
|
353
|
+
maxAccess: snmp.MaxAccess['read-write']
|
354
|
+
};
|
355
|
+
|
356
|
+
subagent.getMib().registerProvider(scalarProvider);
|
357
|
+
subagent.getMib().setScalarValue('testScalar', 100);
|
358
|
+
});
|
359
|
+
|
360
|
+
it('manages set transactions correctly', function() {
|
361
|
+
// Create proper AgentXPdu objects using createFromVariables
|
362
|
+
const testSetPdu = snmp.AgentXPdu.createFromVariables({
|
363
|
+
pduType: snmp.AgentXPduType.TestSet,
|
364
|
+
sessionID: subagent.sessionID,
|
365
|
+
transactionID: 123,
|
366
|
+
varbinds: [{
|
367
|
+
oid: '1.3.6.1.4.1.8072.9999.1.0',
|
368
|
+
type: snmp.ObjectType.Integer,
|
369
|
+
value: 200
|
370
|
+
}]
|
371
|
+
});
|
372
|
+
|
373
|
+
subagent.testSet(testSetPdu);
|
374
|
+
assert(subagent.setTransactions[123]);
|
375
|
+
|
376
|
+
const cleanupSetPdu = snmp.AgentXPdu.createFromVariables({
|
377
|
+
pduType: snmp.AgentXPduType.CleanupSet,
|
378
|
+
sessionID: subagent.sessionID,
|
379
|
+
transactionID: 123
|
380
|
+
});
|
381
|
+
|
382
|
+
subagent.cleanupSet(cleanupSetPdu);
|
383
|
+
assert(!subagent.setTransactions[123]);
|
384
|
+
});
|
385
|
+
|
386
|
+
it('handles unexpected transaction IDs', function() {
|
387
|
+
const commitSetPdu = snmp.AgentXPdu.createFromVariables({
|
388
|
+
pduType: snmp.AgentXPduType.CommitSet,
|
389
|
+
sessionID: subagent.sessionID,
|
390
|
+
transactionID: 999
|
391
|
+
});
|
392
|
+
|
393
|
+
assert.throws(() => {
|
394
|
+
subagent.commitSet(commitSetPdu);
|
395
|
+
}, /Unexpected CommitSet PDU/);
|
396
|
+
});
|
397
|
+
});
|
398
|
+
|
399
|
+
describe('Bulk Set Handler', function() {
|
400
|
+
let scalarProvider1, scalarProvider2;
|
401
|
+
|
402
|
+
beforeEach(function() {
|
403
|
+
scalarProvider1 = {
|
404
|
+
name: "testScalar1",
|
405
|
+
type: snmp.MibProviderType.Scalar,
|
406
|
+
oid: "1.3.6.1.4.1.8072.9999.1",
|
407
|
+
scalarType: snmp.ObjectType.Integer,
|
408
|
+
maxAccess: snmp.MaxAccess['read-write']
|
409
|
+
};
|
410
|
+
|
411
|
+
scalarProvider2 = {
|
412
|
+
name: "testScalar2",
|
413
|
+
type: snmp.MibProviderType.Scalar,
|
414
|
+
oid: "1.3.6.1.4.1.8072.9999.2",
|
415
|
+
scalarType: snmp.ObjectType.Integer,
|
416
|
+
maxAccess: snmp.MaxAccess['read-write']
|
417
|
+
};
|
418
|
+
|
419
|
+
subagent.getMib().registerProvider(scalarProvider1);
|
420
|
+
subagent.getMib().registerProvider(scalarProvider2);
|
421
|
+
subagent.getMib().setScalarValue('testScalar1', 100);
|
422
|
+
subagent.getMib().setScalarValue('testScalar2', 200);
|
423
|
+
});
|
424
|
+
|
425
|
+
it('sets bulk set handler correctly', function() {
|
426
|
+
const handler = (mibRequests, mib, testSet) => {
|
427
|
+
return snmp.ErrorStatus.NoError;
|
428
|
+
};
|
429
|
+
|
430
|
+
if (typeof subagent.setBulkSetHandler === 'function') {
|
431
|
+
subagent.setBulkSetHandler(handler);
|
432
|
+
assert.equal(subagent.bulkSetHandler, handler);
|
433
|
+
}
|
434
|
+
});
|
435
|
+
});
|
436
|
+
|
437
|
+
describe('Value Validation', function() {
|
438
|
+
let scalarProvider;
|
439
|
+
|
440
|
+
beforeEach(function() {
|
441
|
+
scalarProvider = {
|
442
|
+
name: "testScalar",
|
443
|
+
type: snmp.MibProviderType.Scalar,
|
444
|
+
oid: "1.3.6.1.4.1.8072.9999.1",
|
445
|
+
scalarType: snmp.ObjectType.Integer,
|
446
|
+
maxAccess: snmp.MaxAccess['read-write'],
|
447
|
+
constraints: {
|
448
|
+
ranges: [{ min: 1, max: 100 }]
|
449
|
+
}
|
450
|
+
};
|
451
|
+
|
452
|
+
subagent.getMib().registerProvider(scalarProvider);
|
453
|
+
subagent.getMib().setScalarValue('testScalar', 50);
|
454
|
+
});
|
455
|
+
|
456
|
+
it('validates integer constraints', function() {
|
457
|
+
// This tests the underlying validation that would be used in set operations
|
458
|
+
const instanceNode = subagent.getMib().lookup('1.3.6.1.4.1.8072.9999.1.0');
|
459
|
+
if (instanceNode && typeof instanceNode.validateValue === 'function') {
|
460
|
+
const validResult = instanceNode.validateValue(snmp.ObjectType.Integer, 75);
|
461
|
+
assert.equal(validResult, true);
|
462
|
+
|
463
|
+
const invalidResult = instanceNode.validateValue(snmp.ObjectType.Integer, 150);
|
464
|
+
assert.equal(invalidResult, false);
|
465
|
+
}
|
466
|
+
});
|
467
|
+
});
|
468
|
+
});
|
469
|
+
});
|