net-snmp 3.21.2 → 3.23.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.cn.md +1 -0
- package/README.md +38 -2
- package/index.js +9 -10
- package/package.json +14 -14
- package/test/crypto.test.js +384 -0
- package/test/dgram-module.test.js +71 -0
- package/test/transport-option.test.js +53 -0
package/README.cn.md
CHANGED
@@ -100,6 +100,7 @@ var session = snmp.createSession ("127.0.0.1", "public", options);
|
|
100
100
|
* `version` - `snmp.Version1`或`snmp.Version2c`,默认为`snmp.Version1`。
|
101
101
|
* "backwardsGetNexts"----允许进行GetNext操作的布尔值,以检索词法上在前的OIDs。
|
102
102
|
* `idBitsSize` - `16`或`32`,默认为`32`。用来减少生成的id的大小,以便与一些旧设备兼容。
|
103
|
+
* `dgramModule` – 一个与 Node.js [`dgram`](https://nodejs.org/api/dgram.html) 模块接口兼容的模块。您可以通过提供自定义或包装的 `dgram` 实现来扩展或覆盖默认的 UDP 套接字行为。
|
103
104
|
|
104
105
|
当一个会话结束后,应该关闭它。
|
105
106
|
|
package/README.md
CHANGED
@@ -344,7 +344,7 @@ Actions
|
|
344
344
|
- `4 - ECouldNotDecrypt`
|
345
345
|
- `5 - EAuthFailure`
|
346
346
|
- `6 - EReqResOidNoMatch`
|
347
|
-
- `7 - (no longer used)
|
347
|
+
- `7 - (no longer used)`
|
348
348
|
- `8 - EOutOfOrder`
|
349
349
|
- `9 - EVersionNoMatch`
|
350
350
|
- `10 - ECommunityNoMatch`
|
@@ -588,7 +588,8 @@ var options = {
|
|
588
588
|
version: snmp.Version1,
|
589
589
|
backwardsGetNexts: true,
|
590
590
|
reportOidMismatchErrors: false,
|
591
|
-
idBitsSize: 32
|
591
|
+
idBitsSize: 32,
|
592
|
+
dgramModule: dgram
|
592
593
|
};
|
593
594
|
|
594
595
|
var session = snmp.createSession ("127.0.0.1", "public", options);
|
@@ -620,6 +621,10 @@ is an object, and can contain the following items:
|
|
620
621
|
requests and responses, defaults to `false`
|
621
622
|
* `idBitsSize` - Either `16` or `32`, defaults to `32`. Used to reduce the size
|
622
623
|
of the generated id for compatibility with some older devices.
|
624
|
+
* `dgramModule` – A module that is interface-compatible with the Node.js [`dgram`](https://nodejs.org/api/dgram.html) module.
|
625
|
+
This can be used to extend or override the default UDP socket behavior by supplying
|
626
|
+
a custom or wrapped implementation of `dgram`.
|
627
|
+
|
623
628
|
|
624
629
|
When a session has been finished with it should be closed:
|
625
630
|
|
@@ -2493,6 +2498,27 @@ pre-loaded "base" modules is:
|
|
2493
2498
|
* SNMPv2-TC
|
2494
2499
|
* SNMPv2-MIB
|
2495
2500
|
|
2501
|
+
By default, the `createModuleStore()` function creates a new `ModuleStore` instance with all the base modules pre-loaded.
|
2502
|
+
However, you can now customize which base modules are loaded by passing an options object:
|
2503
|
+
|
2504
|
+
```js
|
2505
|
+
// Example of selecting only SNMPv2 MIBs
|
2506
|
+
const store = snmp.createModuleStore({
|
2507
|
+
baseModules: [
|
2508
|
+
'SNMPv2-SMI',
|
2509
|
+
'SNMPv2-CONF',
|
2510
|
+
'SNMPv2-TC',
|
2511
|
+
'SNMPv2-MIB',
|
2512
|
+
],
|
2513
|
+
});
|
2514
|
+
```
|
2515
|
+
|
2516
|
+
The `options` object can contain:
|
2517
|
+
|
2518
|
+
* `baseModules` - An array of module names to use as the base modules. This allows you to explicitly control which MIBs are loaded, which can be useful to avoid unexpected type overrides that might occur with the full set of base modules.
|
2519
|
+
|
2520
|
+
This feature is helpful when dealing with constraints for SNMPv2-TC defined textual conventions like DisplayString that might get preempted by subsequent definitions as plain OCTET STRING in RFC MIBs.
|
2521
|
+
|
2496
2522
|
## store.loadFromFile (fileName)
|
2497
2523
|
|
2498
2524
|
Loads all MIB modules in the given file into the module store. By convention, there is
|
@@ -3529,6 +3555,16 @@ Example programs are included under the module's `example` directory.
|
|
3529
3555
|
|
3530
3556
|
* Add custom base module list
|
3531
3557
|
|
3558
|
+
# Version 3.22.0 - 27/04/2025
|
3559
|
+
|
3560
|
+
* Fix incorrect SNMPv3 engineID handling
|
3561
|
+
|
3562
|
+
* Add custom base module list
|
3563
|
+
|
3564
|
+
# Version 3.23.0 - 20/06/2025
|
3565
|
+
|
3566
|
+
* Add support for custom dgram module
|
3567
|
+
|
3532
3568
|
# License
|
3533
3569
|
|
3534
3570
|
Copyright (c) 2020 Mark Abrahams <mark@abrahams.co.nz>
|
package/index.js
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
// Copyright 2013 Stephen Vickers <stephen.vickers.sv@gmail.com>
|
3
2
|
|
4
3
|
const ber = require ("asn1-ber").Ber;
|
@@ -2038,12 +2037,13 @@ var Session = function (target, authenticator, options) {
|
|
2038
2037
|
DEBUG |= options.debug;
|
2039
2038
|
|
2040
2039
|
this.engine = new Engine ({
|
2041
|
-
|
2040
|
+
engineID: options.engineID
|
2042
2041
|
});
|
2043
2042
|
this.reqs = {};
|
2044
2043
|
this.reqCount = 0;
|
2045
2044
|
|
2046
|
-
|
2045
|
+
const dgramMod = options.dgramModule || dgram;
|
2046
|
+
this.dgram = dgramMod.createSocket (this.transport);
|
2047
2047
|
this.dgram.unref();
|
2048
2048
|
|
2049
2049
|
var me = this;
|
@@ -3009,7 +3009,7 @@ Session.createV3 = function (target, user, options) {
|
|
3009
3009
|
};
|
3010
3010
|
|
3011
3011
|
var Engine = function (engineOptions) {
|
3012
|
-
|
3012
|
+
let { engineID } = engineOptions;
|
3013
3013
|
if ( engineID ) {
|
3014
3014
|
if ( ! (engineID instanceof Buffer) ) {
|
3015
3015
|
engineID = engineID.replace('0x', '');
|
@@ -3035,10 +3035,8 @@ Engine.prototype.generateEngineID = function() {
|
|
3035
3035
|
var Listener = function (options, receiver) {
|
3036
3036
|
this.receiver = receiver;
|
3037
3037
|
this.callback = receiver.onMsg;
|
3038
|
-
// this.transport = options.transport || 'udp4';
|
3039
|
-
// this.port = options.port || 161;
|
3040
|
-
// this.address = options.address;
|
3041
3038
|
this.disableAuthorization = options.disableAuthorization || false;
|
3039
|
+
this.dgramModule = options.dgramModule || dgram;
|
3042
3040
|
if ( options.sockets ) {
|
3043
3041
|
this.socketOptions = options.sockets;
|
3044
3042
|
} else {
|
@@ -3061,7 +3059,8 @@ Listener.prototype.startListening = function () {
|
|
3061
3059
|
var me = this;
|
3062
3060
|
this.sockets = {};
|
3063
3061
|
for ( const socketOptions of this.socketOptions ) {
|
3064
|
-
const
|
3062
|
+
const dgramMod = this.dgramModule;
|
3063
|
+
const socket = dgramMod.createSocket (socketOptions.transport);
|
3065
3064
|
socket.on ("error", me.receiver.callback);
|
3066
3065
|
socket.bind (socketOptions.port, socketOptions.address);
|
3067
3066
|
socket.on ("message", me.callback.bind (me.receiver, socket));
|
@@ -3355,7 +3354,7 @@ var Receiver = function (options, callback) {
|
|
3355
3354
|
DEBUG |= options.debug;
|
3356
3355
|
this.authorizer = new Authorizer (options);
|
3357
3356
|
this.engine = new Engine ({
|
3358
|
-
|
3357
|
+
engineID: options.engineID
|
3359
3358
|
});
|
3360
3359
|
|
3361
3360
|
this.engineBoots = 0;
|
@@ -4874,7 +4873,7 @@ var Agent = function (options, callback, mib) {
|
|
4874
4873
|
DEBUG |= options.debug;
|
4875
4874
|
this.listener = new Listener (options, this);
|
4876
4875
|
this.engine = new Engine ({
|
4877
|
-
|
4876
|
+
engineID: options.engineID
|
4878
4877
|
});
|
4879
4878
|
this.authorizer = new Authorizer (options);
|
4880
4879
|
this.callback = callback || function () {};
|
package/package.json
CHANGED
@@ -1,19 +1,16 @@
|
|
1
1
|
{
|
2
2
|
"name": "net-snmp",
|
3
|
-
"version": "3.
|
3
|
+
"version": "3.23.0",
|
4
4
|
"description": "JavaScript implementation of the Simple Network Management Protocol (SNMP)",
|
5
|
+
"author": "Mark Abrahams <mark@abrahams.co.nz>",
|
6
|
+
"license": "MIT",
|
5
7
|
"main": "index.js",
|
6
8
|
"directories": {
|
7
9
|
"example": "example"
|
8
10
|
},
|
9
|
-
"
|
10
|
-
"
|
11
|
-
"
|
12
|
-
},
|
13
|
-
"devDependencies": {
|
14
|
-
"eslint": "^9.9.1",
|
15
|
-
"getopts": "^2.3.0",
|
16
|
-
"mocha": "^11.0.1"
|
11
|
+
"scripts": {
|
12
|
+
"lint": "eslint . ./**/*.js",
|
13
|
+
"test": "node --openssl-legacy-provider ./node_modules/mocha/bin/mocha.js"
|
17
14
|
},
|
18
15
|
"contributors": [
|
19
16
|
{
|
@@ -45,10 +42,13 @@
|
|
45
42
|
"monitor",
|
46
43
|
"monitoring"
|
47
44
|
],
|
48
|
-
"
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
45
|
+
"dependencies": {
|
46
|
+
"asn1-ber": "^1.2.1",
|
47
|
+
"smart-buffer": "^4.1.0"
|
48
|
+
},
|
49
|
+
"devDependencies": {
|
50
|
+
"eslint": "^9.9.1",
|
51
|
+
"getopts": "^2.3.0",
|
52
|
+
"mocha": "^11.0.1"
|
53
53
|
}
|
54
54
|
}
|
@@ -0,0 +1,384 @@
|
|
1
|
+
const assert = require('assert');
|
2
|
+
// crypto is used indirectly by Authentication and Encryption modules
|
3
|
+
const snmp = require('../');
|
4
|
+
const { SecurityLevel, AuthProtocols, PrivProtocols, Authentication, Encryption } = snmp;
|
5
|
+
|
6
|
+
describe('SNMPv3 Authentication and Encryption', function () {
|
7
|
+
// Sample data for tests
|
8
|
+
const authPassword = 'test_auth_password';
|
9
|
+
const privPassword = 'test_priv_password';
|
10
|
+
const engineID = Buffer.from('8000B98380ABCDEF', 'hex');
|
11
|
+
|
12
|
+
// Test data that will be encrypted/authenticated
|
13
|
+
const testData = Buffer.from('Test data for SNMP authentication and privacy tests', 'utf8');
|
14
|
+
|
15
|
+
describe('Authentication', function () {
|
16
|
+
it('should support noAuthNoPriv security level', function () {
|
17
|
+
// noAuthNoPriv doesn't use authentication, verify this is handled appropriately
|
18
|
+
const user = {
|
19
|
+
name: 'noAuthUser',
|
20
|
+
level: SecurityLevel.noAuthNoPriv,
|
21
|
+
};
|
22
|
+
|
23
|
+
// No authentication should be required for this user
|
24
|
+
assert.strictEqual(user.level, SecurityLevel.noAuthNoPriv);
|
25
|
+
assert.strictEqual(user.authProtocol, undefined);
|
26
|
+
assert.strictEqual(user.authKey, undefined);
|
27
|
+
});
|
28
|
+
|
29
|
+
it('should support MD5 authentication protocol', function () {
|
30
|
+
// Generate authentication key using MD5
|
31
|
+
const authKey = Authentication.passwordToKey(AuthProtocols.md5, authPassword, engineID);
|
32
|
+
|
33
|
+
// Verify key length matches expected MD5 output length
|
34
|
+
assert.strictEqual(authKey.length, Authentication.algorithms[AuthProtocols.md5].KEY_LENGTH);
|
35
|
+
|
36
|
+
// Create a test digest
|
37
|
+
const digest = Authentication.calculateDigest(testData, AuthProtocols.md5, authPassword, engineID);
|
38
|
+
|
39
|
+
// Verify digest length
|
40
|
+
assert.strictEqual(digest.length, Authentication.algorithms[AuthProtocols.md5].AUTHENTICATION_CODE_LENGTH);
|
41
|
+
|
42
|
+
// Verify authentication works
|
43
|
+
const testBuffer = Buffer.concat([testData]);
|
44
|
+
const digestInMessage = Buffer.alloc(
|
45
|
+
Authentication.algorithms[AuthProtocols.md5].AUTHENTICATION_CODE_LENGTH
|
46
|
+
);
|
47
|
+
Authentication.writeParameters(testBuffer, AuthProtocols.md5, authPassword, engineID, digestInMessage);
|
48
|
+
|
49
|
+
assert.strictEqual(
|
50
|
+
Authentication.isAuthentic(testBuffer, AuthProtocols.md5, authPassword, engineID, digestInMessage),
|
51
|
+
true
|
52
|
+
);
|
53
|
+
});
|
54
|
+
|
55
|
+
it('should support SHA authentication protocol', function () {
|
56
|
+
// Generate authentication key using SHA
|
57
|
+
const authKey = Authentication.passwordToKey(AuthProtocols.sha, authPassword, engineID);
|
58
|
+
|
59
|
+
// Verify key length matches expected SHA output length
|
60
|
+
assert.strictEqual(authKey.length, Authentication.algorithms[AuthProtocols.sha].KEY_LENGTH);
|
61
|
+
|
62
|
+
// Create a test digest
|
63
|
+
const digest = Authentication.calculateDigest(testData, AuthProtocols.sha, authPassword, engineID);
|
64
|
+
|
65
|
+
// Verify digest length
|
66
|
+
assert.strictEqual(digest.length, Authentication.algorithms[AuthProtocols.sha].AUTHENTICATION_CODE_LENGTH);
|
67
|
+
|
68
|
+
// Verify authentication works
|
69
|
+
const testBuffer = Buffer.concat([testData]);
|
70
|
+
const digestInMessage = Buffer.alloc(
|
71
|
+
Authentication.algorithms[AuthProtocols.sha].AUTHENTICATION_CODE_LENGTH
|
72
|
+
);
|
73
|
+
Authentication.writeParameters(testBuffer, AuthProtocols.sha, authPassword, engineID, digestInMessage);
|
74
|
+
|
75
|
+
assert.strictEqual(
|
76
|
+
Authentication.isAuthentic(testBuffer, AuthProtocols.sha, authPassword, engineID, digestInMessage),
|
77
|
+
true
|
78
|
+
);
|
79
|
+
});
|
80
|
+
|
81
|
+
it('should support SHA-256 authentication protocol', function () {
|
82
|
+
// Generate authentication key using SHA-256
|
83
|
+
const authKey = Authentication.passwordToKey(AuthProtocols.sha256, authPassword, engineID);
|
84
|
+
|
85
|
+
// Verify key length matches expected SHA-256 output length
|
86
|
+
assert.strictEqual(authKey.length, Authentication.algorithms[AuthProtocols.sha256].KEY_LENGTH);
|
87
|
+
|
88
|
+
// Create a test digest
|
89
|
+
const digest = Authentication.calculateDigest(testData, AuthProtocols.sha256, authPassword, engineID);
|
90
|
+
|
91
|
+
// Verify digest length
|
92
|
+
assert.strictEqual(
|
93
|
+
digest.length,
|
94
|
+
Authentication.algorithms[AuthProtocols.sha256].AUTHENTICATION_CODE_LENGTH
|
95
|
+
);
|
96
|
+
|
97
|
+
// Verify authentication works
|
98
|
+
const testBuffer = Buffer.concat([testData]);
|
99
|
+
const digestInMessage = Buffer.alloc(
|
100
|
+
Authentication.algorithms[AuthProtocols.sha256].AUTHENTICATION_CODE_LENGTH
|
101
|
+
);
|
102
|
+
Authentication.writeParameters(testBuffer, AuthProtocols.sha256, authPassword, engineID, digestInMessage);
|
103
|
+
|
104
|
+
assert.strictEqual(
|
105
|
+
Authentication.isAuthentic(testBuffer, AuthProtocols.sha256, authPassword, engineID, digestInMessage),
|
106
|
+
true
|
107
|
+
);
|
108
|
+
});
|
109
|
+
|
110
|
+
it('should support SHA-512 authentication protocol', function () {
|
111
|
+
// Generate authentication key using SHA-512
|
112
|
+
const authKey = Authentication.passwordToKey(AuthProtocols.sha512, authPassword, engineID);
|
113
|
+
|
114
|
+
// Verify key length matches expected SHA-512 output length
|
115
|
+
assert.strictEqual(authKey.length, Authentication.algorithms[AuthProtocols.sha512].KEY_LENGTH);
|
116
|
+
|
117
|
+
// Create a test digest
|
118
|
+
const digest = Authentication.calculateDigest(testData, AuthProtocols.sha512, authPassword, engineID);
|
119
|
+
|
120
|
+
// Verify digest length
|
121
|
+
assert.strictEqual(
|
122
|
+
digest.length,
|
123
|
+
Authentication.algorithms[AuthProtocols.sha512].AUTHENTICATION_CODE_LENGTH
|
124
|
+
);
|
125
|
+
|
126
|
+
// Verify authentication works
|
127
|
+
const testBuffer = Buffer.concat([testData]);
|
128
|
+
const digestInMessage = Buffer.alloc(
|
129
|
+
Authentication.algorithms[AuthProtocols.sha512].AUTHENTICATION_CODE_LENGTH
|
130
|
+
);
|
131
|
+
Authentication.writeParameters(testBuffer, AuthProtocols.sha512, authPassword, engineID, digestInMessage);
|
132
|
+
|
133
|
+
assert.strictEqual(
|
134
|
+
Authentication.isAuthentic(testBuffer, AuthProtocols.sha512, authPassword, engineID, digestInMessage),
|
135
|
+
true
|
136
|
+
);
|
137
|
+
});
|
138
|
+
});
|
139
|
+
|
140
|
+
describe('Encryption', function () {
|
141
|
+
// Create a mock engine for encryption tests
|
142
|
+
const engine = {
|
143
|
+
engineID: engineID,
|
144
|
+
engineBoots: 1,
|
145
|
+
engineTime: 123,
|
146
|
+
};
|
147
|
+
|
148
|
+
it('should support DES encryption protocol', function () {
|
149
|
+
// Test DES encryption/decryption with SHA authentication
|
150
|
+
const authProtocol = AuthProtocols.sha;
|
151
|
+
const privProtocol = PrivProtocols.des;
|
152
|
+
|
153
|
+
// Encrypt the test data
|
154
|
+
const { encryptedPdu, msgPrivacyParameters } = Encryption.encryptPdu(
|
155
|
+
privProtocol,
|
156
|
+
testData,
|
157
|
+
privPassword,
|
158
|
+
authProtocol,
|
159
|
+
engine
|
160
|
+
);
|
161
|
+
|
162
|
+
// Verify encryption was done (output should be different from input)
|
163
|
+
assert.notDeepStrictEqual(encryptedPdu, testData);
|
164
|
+
|
165
|
+
// Decrypt the data
|
166
|
+
const decryptedPdu = Encryption.decryptPdu(
|
167
|
+
privProtocol,
|
168
|
+
encryptedPdu,
|
169
|
+
msgPrivacyParameters,
|
170
|
+
privPassword,
|
171
|
+
authProtocol,
|
172
|
+
engine
|
173
|
+
);
|
174
|
+
|
175
|
+
// Verify decryption works
|
176
|
+
assert.deepStrictEqual(decryptedPdu.slice(0, testData.length), testData);
|
177
|
+
});
|
178
|
+
|
179
|
+
it('should support AES encryption protocol', function () {
|
180
|
+
// Test AES encryption/decryption with SHA authentication
|
181
|
+
const authProtocol = AuthProtocols.sha;
|
182
|
+
const privProtocol = PrivProtocols.aes;
|
183
|
+
|
184
|
+
// Encrypt the test data
|
185
|
+
const { encryptedPdu, msgPrivacyParameters } = Encryption.encryptPdu(
|
186
|
+
privProtocol,
|
187
|
+
testData,
|
188
|
+
privPassword,
|
189
|
+
authProtocol,
|
190
|
+
engine
|
191
|
+
);
|
192
|
+
|
193
|
+
// Verify encryption was done (output should be different from input)
|
194
|
+
assert.notDeepStrictEqual(encryptedPdu, testData);
|
195
|
+
|
196
|
+
// Decrypt the data
|
197
|
+
const decryptedPdu = Encryption.decryptPdu(
|
198
|
+
privProtocol,
|
199
|
+
encryptedPdu,
|
200
|
+
msgPrivacyParameters,
|
201
|
+
privPassword,
|
202
|
+
authProtocol,
|
203
|
+
engine
|
204
|
+
);
|
205
|
+
|
206
|
+
// Verify decryption works
|
207
|
+
assert.deepStrictEqual(decryptedPdu.slice(0, testData.length), testData);
|
208
|
+
});
|
209
|
+
|
210
|
+
it('should support AES-256b (Blumenthal) encryption protocol', function () {
|
211
|
+
// Test AES-256 Blumenthal encryption/decryption with SHA authentication
|
212
|
+
const authProtocol = AuthProtocols.sha;
|
213
|
+
const privProtocol = PrivProtocols.aes256b;
|
214
|
+
|
215
|
+
// Encrypt the test data
|
216
|
+
const { encryptedPdu, msgPrivacyParameters } = Encryption.encryptPdu(
|
217
|
+
privProtocol,
|
218
|
+
testData,
|
219
|
+
privPassword,
|
220
|
+
authProtocol,
|
221
|
+
engine
|
222
|
+
);
|
223
|
+
|
224
|
+
// Verify encryption was done (output should be different from input)
|
225
|
+
assert.notDeepStrictEqual(encryptedPdu, testData);
|
226
|
+
|
227
|
+
// Decrypt the data
|
228
|
+
const decryptedPdu = Encryption.decryptPdu(
|
229
|
+
privProtocol,
|
230
|
+
encryptedPdu,
|
231
|
+
msgPrivacyParameters,
|
232
|
+
privPassword,
|
233
|
+
authProtocol,
|
234
|
+
engine
|
235
|
+
);
|
236
|
+
|
237
|
+
// Verify decryption works
|
238
|
+
assert.deepStrictEqual(decryptedPdu.slice(0, testData.length), testData);
|
239
|
+
});
|
240
|
+
|
241
|
+
it('should support AES-256r (Reeder) encryption protocol', function () {
|
242
|
+
// Test AES-256 Reeder encryption/decryption with SHA authentication
|
243
|
+
const authProtocol = AuthProtocols.sha;
|
244
|
+
const privProtocol = PrivProtocols.aes256r;
|
245
|
+
|
246
|
+
// Encrypt the test data
|
247
|
+
const { encryptedPdu, msgPrivacyParameters } = Encryption.encryptPdu(
|
248
|
+
privProtocol,
|
249
|
+
testData,
|
250
|
+
privPassword,
|
251
|
+
authProtocol,
|
252
|
+
engine
|
253
|
+
);
|
254
|
+
|
255
|
+
// Verify encryption was done (output should be different from input)
|
256
|
+
assert.notDeepStrictEqual(encryptedPdu, testData);
|
257
|
+
|
258
|
+
// Decrypt the data
|
259
|
+
const decryptedPdu = Encryption.decryptPdu(
|
260
|
+
privProtocol,
|
261
|
+
encryptedPdu,
|
262
|
+
msgPrivacyParameters,
|
263
|
+
privPassword,
|
264
|
+
authProtocol,
|
265
|
+
engine
|
266
|
+
);
|
267
|
+
|
268
|
+
// Verify decryption works
|
269
|
+
assert.deepStrictEqual(decryptedPdu.slice(0, testData.length), testData);
|
270
|
+
});
|
271
|
+
});
|
272
|
+
|
273
|
+
describe('SecurityLevel combinations', function () {
|
274
|
+
it('should support authNoPriv security level', function () {
|
275
|
+
// Create a user with authentication but no privacy
|
276
|
+
const user = {
|
277
|
+
name: 'authNoPrivUser',
|
278
|
+
level: SecurityLevel.authNoPriv,
|
279
|
+
authProtocol: AuthProtocols.sha,
|
280
|
+
authKey: 'authPassword',
|
281
|
+
};
|
282
|
+
|
283
|
+
assert.strictEqual(user.level, SecurityLevel.authNoPriv);
|
284
|
+
assert.strictEqual(user.authProtocol, AuthProtocols.sha);
|
285
|
+
assert.strictEqual(user.authKey, 'authPassword');
|
286
|
+
assert.strictEqual(user.privProtocol, undefined);
|
287
|
+
assert.strictEqual(user.privKey, undefined);
|
288
|
+
});
|
289
|
+
|
290
|
+
it('should support authPriv security level', function () {
|
291
|
+
// Create a user with authentication and privacy
|
292
|
+
const user = {
|
293
|
+
name: 'authPrivUser',
|
294
|
+
level: SecurityLevel.authPriv,
|
295
|
+
authProtocol: AuthProtocols.sha256,
|
296
|
+
authKey: 'authPassword',
|
297
|
+
privProtocol: PrivProtocols.aes,
|
298
|
+
privKey: 'privPassword',
|
299
|
+
};
|
300
|
+
|
301
|
+
assert.strictEqual(user.level, SecurityLevel.authPriv);
|
302
|
+
assert.strictEqual(user.authProtocol, AuthProtocols.sha256);
|
303
|
+
assert.strictEqual(user.authKey, 'authPassword');
|
304
|
+
assert.strictEqual(user.privProtocol, PrivProtocols.aes);
|
305
|
+
assert.strictEqual(user.privKey, 'privPassword');
|
306
|
+
});
|
307
|
+
|
308
|
+
it('should validate all required parameters are provided for each security level', function () {
|
309
|
+
// noAuthNoPriv only requires username and level
|
310
|
+
const user1 = {
|
311
|
+
name: 'user1',
|
312
|
+
level: SecurityLevel.noAuthNoPriv,
|
313
|
+
};
|
314
|
+
|
315
|
+
// authNoPriv requires authentication parameters
|
316
|
+
const user2 = {
|
317
|
+
name: 'user2',
|
318
|
+
level: SecurityLevel.authNoPriv,
|
319
|
+
authProtocol: AuthProtocols.sha,
|
320
|
+
authKey: 'authPassword',
|
321
|
+
};
|
322
|
+
|
323
|
+
// authPriv requires both authentication and privacy parameters
|
324
|
+
const user3 = {
|
325
|
+
name: 'user3',
|
326
|
+
level: SecurityLevel.authPriv,
|
327
|
+
authProtocol: AuthProtocols.sha,
|
328
|
+
authKey: 'authPassword',
|
329
|
+
privProtocol: PrivProtocols.aes,
|
330
|
+
privKey: 'privPassword',
|
331
|
+
};
|
332
|
+
|
333
|
+
// This function would typically be part of parameter validation
|
334
|
+
function validateUser(user) {
|
335
|
+
if (user.level === SecurityLevel.authNoPriv || user.level === SecurityLevel.authPriv) {
|
336
|
+
assert.ok(user.authProtocol, 'authProtocol required for this security level');
|
337
|
+
assert.ok(user.authKey, 'authKey required for this security level');
|
338
|
+
}
|
339
|
+
|
340
|
+
if (user.level === SecurityLevel.authPriv) {
|
341
|
+
assert.ok(user.privProtocol, 'privProtocol required for this security level');
|
342
|
+
assert.ok(user.privKey, 'privKey required for this security level');
|
343
|
+
}
|
344
|
+
|
345
|
+
return true;
|
346
|
+
}
|
347
|
+
|
348
|
+
assert.strictEqual(validateUser(user1), true);
|
349
|
+
assert.strictEqual(validateUser(user2), true);
|
350
|
+
assert.strictEqual(validateUser(user3), true);
|
351
|
+
});
|
352
|
+
});
|
353
|
+
|
354
|
+
describe('Custom engineID handling', function () {
|
355
|
+
it('should correctly use engineID parameter', function () {
|
356
|
+
// This test verifies the fix for issue #283
|
357
|
+
// Create a session with default settings (no engineID)
|
358
|
+
const defaultSession = new snmp.Session({
|
359
|
+
host: 'example.org',
|
360
|
+
version: snmp.Version3
|
361
|
+
});
|
362
|
+
|
363
|
+
// Default session should have an engineID of expected format (17 bytes)
|
364
|
+
assert.strictEqual(defaultSession.engine.engineID.length, 17);
|
365
|
+
|
366
|
+
// Convert to hex string for easier inspection
|
367
|
+
const defaultEngineIDHex = defaultSession.engine.engineID.toString('hex');
|
368
|
+
// First 5 bytes should match the standard format 8000B98380
|
369
|
+
assert.strictEqual(defaultEngineIDHex.substring(0, 10), '8000b98380');
|
370
|
+
|
371
|
+
// Create a second session - should generate a different random engineID
|
372
|
+
const anotherDefaultSession = new snmp.Session({
|
373
|
+
host: 'example.org',
|
374
|
+
version: snmp.Version3
|
375
|
+
});
|
376
|
+
|
377
|
+
// The two sessions should have different engineIDs (random part differs)
|
378
|
+
assert.notStrictEqual(
|
379
|
+
defaultSession.engine.engineID.toString('hex'),
|
380
|
+
anotherDefaultSession.engine.engineID.toString('hex')
|
381
|
+
);
|
382
|
+
});
|
383
|
+
});
|
384
|
+
});
|
@@ -0,0 +1,71 @@
|
|
1
|
+
const assert = require('assert');
|
2
|
+
const snmp = require('../');
|
3
|
+
|
4
|
+
describe('Custom dgram module support', function () {
|
5
|
+
it('should use custom dgram module in Session', function (done) {
|
6
|
+
let createSocketCalled = false;
|
7
|
+
const mockDgram = {
|
8
|
+
createSocket: function (transport) {
|
9
|
+
createSocketCalled = true;
|
10
|
+
assert.equal(transport, 'udp4');
|
11
|
+
|
12
|
+
// Return a mock socket
|
13
|
+
return {
|
14
|
+
unref: function () {},
|
15
|
+
on: function () {},
|
16
|
+
bind: function () {},
|
17
|
+
close: function () {}
|
18
|
+
};
|
19
|
+
}
|
20
|
+
};
|
21
|
+
|
22
|
+
const session = snmp.createSession('127.0.0.1', 'public', {
|
23
|
+
dgramModule: mockDgram
|
24
|
+
});
|
25
|
+
|
26
|
+
assert(createSocketCalled, 'Custom dgram module createSocket should have been called');
|
27
|
+
session.close();
|
28
|
+
done();
|
29
|
+
});
|
30
|
+
|
31
|
+
it('should use custom dgram module in Receiver', function (done) {
|
32
|
+
let createSocketCalled = false;
|
33
|
+
const mockDgram = {
|
34
|
+
createSocket: function (transport) {
|
35
|
+
createSocketCalled = true;
|
36
|
+
assert.equal(transport, 'udp4');
|
37
|
+
|
38
|
+
// Return a mock socket
|
39
|
+
return {
|
40
|
+
on: function () {},
|
41
|
+
bind: function () {},
|
42
|
+
close: function () {},
|
43
|
+
address: function () {
|
44
|
+
return { address: '127.0.0.1', family: 'IPv4', port: 162 };
|
45
|
+
}
|
46
|
+
};
|
47
|
+
}
|
48
|
+
};
|
49
|
+
|
50
|
+
const receiver = snmp.createReceiver({
|
51
|
+
dgramModule: mockDgram,
|
52
|
+
port: 1162
|
53
|
+
}, function () {});
|
54
|
+
|
55
|
+
assert(createSocketCalled, 'Custom dgram module createSocket should have been called');
|
56
|
+
receiver.close();
|
57
|
+
done();
|
58
|
+
});
|
59
|
+
|
60
|
+
it('should fallback to default dgram when no custom module provided', function (done) {
|
61
|
+
// This should not throw an error
|
62
|
+
const session = snmp.createSession('127.0.0.1', 'public', {
|
63
|
+
// No dgramModule specified
|
64
|
+
});
|
65
|
+
|
66
|
+
// Session should be created successfully
|
67
|
+
assert(session);
|
68
|
+
session.close();
|
69
|
+
done();
|
70
|
+
});
|
71
|
+
});
|
@@ -0,0 +1,53 @@
|
|
1
|
+
const assert = require('assert');
|
2
|
+
const snmp = require('../index.js');
|
3
|
+
|
4
|
+
describe('Transport Option Handling in createV3Session', function() {
|
5
|
+
const user = {
|
6
|
+
name: "testuser",
|
7
|
+
level: snmp.SecurityLevel.noAuthNoPriv
|
8
|
+
};
|
9
|
+
|
10
|
+
afterEach(function() {
|
11
|
+
// Clean up any open sessions
|
12
|
+
// Note: sessions are closed in individual tests
|
13
|
+
});
|
14
|
+
|
15
|
+
it('should use default transport when not specified', function() {
|
16
|
+
const session = snmp.createV3Session("127.0.0.1", user);
|
17
|
+
assert.strictEqual(session.transport, "udp4");
|
18
|
+
session.close();
|
19
|
+
});
|
20
|
+
|
21
|
+
it('should use default transport when options is empty object', function() {
|
22
|
+
const session = snmp.createV3Session("127.0.0.1", user, {});
|
23
|
+
assert.strictEqual(session.transport, "udp4");
|
24
|
+
session.close();
|
25
|
+
});
|
26
|
+
|
27
|
+
it('should preserve explicit udp4 transport', function() {
|
28
|
+
const session = snmp.createV3Session("127.0.0.1", user, { transport: "udp4" });
|
29
|
+
assert.strictEqual(session.transport, "udp4");
|
30
|
+
session.close();
|
31
|
+
});
|
32
|
+
|
33
|
+
it('should preserve udp6 transport', function() {
|
34
|
+
const session = snmp.createV3Session("127.0.0.1", user, { transport: "udp6" });
|
35
|
+
assert.strictEqual(session.transport, "udp6");
|
36
|
+
session.close();
|
37
|
+
});
|
38
|
+
|
39
|
+
it('should handle null transport by using default', function() {
|
40
|
+
const session = snmp.createV3Session("127.0.0.1", user, { transport: null });
|
41
|
+
assert.strictEqual(session.transport, "udp4");
|
42
|
+
session.close();
|
43
|
+
});
|
44
|
+
|
45
|
+
it('should preserve invalid transport values (let Node.js validate)', function() {
|
46
|
+
assert.throws(function() {
|
47
|
+
snmp.createV3Session("127.0.0.1", user, { transport: "invalid" });
|
48
|
+
}, function(err) {
|
49
|
+
return err.code === 'ERR_SOCKET_BAD_TYPE';
|
50
|
+
});
|
51
|
+
});
|
52
|
+
|
53
|
+
});
|