Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * |
3 | | * (C) 2013-24 - ntop.org |
4 | | * |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software Foundation, |
18 | | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | | * |
20 | | */ |
21 | | |
22 | | #include "ntop_includes.h" |
23 | | |
24 | | /* Code needed by both implementations for batch mode */ |
25 | | extern "C" { |
26 | | #include "../third-party/snmp/snmp.c" |
27 | | #include "../third-party/snmp/asn1.c" |
28 | | #include "../third-party/snmp/net.c" |
29 | | }; |
30 | | |
31 | | #ifdef HAVE_LIBSNMP |
32 | | |
33 | | /* ******************************* */ |
34 | | |
35 | | SNMPSession::SNMPSession() { session_ptr = NULL; } |
36 | | |
37 | | /* ******************************* */ |
38 | | |
39 | | SNMPSession::~SNMPSession() { |
40 | | if (session_ptr) snmp_sess_close(session_ptr); |
41 | | } |
42 | | |
43 | | /* ******************************* */ |
44 | | |
45 | | SNMP::SNMP() { |
46 | | if(trace_new_delete) ntop->getTrace()->traceEvent(TRACE_NORMAL, "[new] %s", __FILE__); |
47 | | batch_mode = false; |
48 | | #ifdef HAVE_LIBSNMP |
49 | | init_snmp("ntopng"); |
50 | | #endif |
51 | | } |
52 | | |
53 | | /* ******************************* */ |
54 | | |
55 | | SNMP::~SNMP() { |
56 | | for (unsigned int i = 0; i < sessions.size(); i++) delete sessions.at(i); |
57 | | } |
58 | | |
59 | | /* ******************************* */ |
60 | | |
61 | | /* |
62 | | http://www.net-snmp.org/docs/README.thread.html |
63 | | https://github.com/bluecmd/python3-netsnmp/blob/master/netsnmp/client_intf.c |
64 | | */ |
65 | | |
66 | | void SNMP::handle_async_response(struct snmp_pdu *pdu, const char *agent_ip) { |
67 | | netsnmp_variable_list *vp = pdu->variables; |
68 | | bool table_added = false; |
69 | | |
70 | | while (vp != NULL) { |
71 | | /* OID */ |
72 | | char rsp_oid[256], buf[256]; |
73 | | int offset = 0; |
74 | | |
75 | | switch (vp->type) { |
76 | | case SNMP_NOSUCHOBJECT: |
77 | | case SNMP_NOSUCHINSTANCE: |
78 | | case SNMP_ENDOFMIBVIEW: |
79 | | vp = vp->next_variable; |
80 | | continue; /* Error found */ |
81 | | break; |
82 | | } |
83 | | |
84 | | if (batch_mode) |
85 | | snprintf(rsp_oid, sizeof(rsp_oid), "%s", agent_ip); |
86 | | else { |
87 | | for (u_int i = 0; i < vp->name_length; i++) { |
88 | | int rc = snprintf(&rsp_oid[offset], sizeof(rsp_oid) - offset, "%s%d", |
89 | | (offset > 0) ? "." : "", (int)vp->name_loc[i]); |
90 | | |
91 | | if (rc > 0) |
92 | | offset += rc; |
93 | | else |
94 | | break; |
95 | | } |
96 | | } |
97 | | |
98 | | if (!table_added) lua_newtable(vm), table_added = true; |
99 | | |
100 | | switch (vp->type) { |
101 | | case ASN_INTEGER: |
102 | | /* case ASN_GAUGE: */ /* Alias of ASN_INTEGER */ |
103 | | #ifdef NATIVE_TYPE |
104 | | lua_push_int32_table_entry(vm, rsp_oid, (long)*vp->val.integer); |
105 | | #else |
106 | | snprintf(buf, sizeof(buf), "%ld", (long)*vp->val.integer); |
107 | | lua_push_str_table_entry(vm, rsp_oid, buf); |
108 | | #endif |
109 | | break; |
110 | | |
111 | | case ASN_UNSIGNED: |
112 | | case ASN_TIMETICKS: |
113 | | case ASN_COUNTER: |
114 | | // ntop->getTrace()->traceEvent(TRACE_WARNING, "%s = %d", rsp_oid, |
115 | | // vp->val.integer); |
116 | | #ifdef NATIVE_TYPE |
117 | | lua_push_uint32_table_entry(vm, rsp_oid, (u_int32_t)*vp->val.integer); |
118 | | #else |
119 | | snprintf(buf, sizeof(buf), "%u", (u_int32_t)*vp->val.integer); |
120 | | lua_push_str_table_entry(vm, rsp_oid, buf); |
121 | | #endif |
122 | | break; |
123 | | |
124 | | case ASN_COUNTER64: { |
125 | | u_int64_t v = |
126 | | ((u_int64_t)vp->val.counter64->high << 32) + vp->val.counter64->low; |
127 | | |
128 | | #ifdef NATIVE_TYPE |
129 | | lua_push_uint32_table_entry(vm, rsp_oid, v); |
130 | | #else |
131 | | snprintf(buf, sizeof(buf), "%llu", (long long unsigned int)v); |
132 | | lua_push_str_table_entry(vm, rsp_oid, buf); |
133 | | #endif |
134 | | } break; |
135 | | |
136 | | case ASN_OCTET_STR: { |
137 | | // ntop->getTrace()->traceEvent(TRACE_WARNING, "%s = %s", rsp_oid, |
138 | | // vp->val.string); |
139 | | char buf[512]; |
140 | | bool is_printable = true; |
141 | | u_int i, len = min(sizeof(buf) - 1, vp->val_len); |
142 | | |
143 | | for (i = 0; i < len; i++) { |
144 | | if ((!isprint(vp->val.string[i])) && (!isspace(vp->val.string[i]))) { |
145 | | is_printable = false; |
146 | | } |
147 | | } |
148 | | |
149 | | if (is_printable) { |
150 | | strncpy(buf, (const char *)vp->val.string, len); |
151 | | buf[len] = '\0'; |
152 | | } else if (len == 4) { |
153 | | snprintf(buf, sizeof(buf), "%u.%u.%u.%u", vp->val.string[0], |
154 | | vp->val.string[1], vp->val.string[2], vp->val.string[3]); |
155 | | } else { |
156 | | u_int idx = 0; |
157 | | |
158 | | for (i = 0; i < len; i++) { |
159 | | int left = sizeof(buf) - idx - 1; |
160 | | int rc; |
161 | | |
162 | | if (left <= 2) break; |
163 | | rc = snprintf(&buf[idx], left, "%s%02X", (i == 0) ? "" : " ", |
164 | | vp->val.string[i] & 0xFF); |
165 | | |
166 | | if (rc <= 0) |
167 | | break; |
168 | | else |
169 | | idx += rc; |
170 | | } /* for */ |
171 | | |
172 | | buf[idx] = '\0'; |
173 | | } |
174 | | |
175 | | lua_push_str_table_entry(vm, rsp_oid, buf); |
176 | | } break; |
177 | | |
178 | | case ASN_OBJECT_ID: { |
179 | | char response[128]; |
180 | | int rsp_offset = 0; |
181 | | |
182 | | for (u_int i = 0; i < vp->val_len / 8; i++) { |
183 | | int rc = snprintf(&response[rsp_offset], |
184 | | sizeof(response) - rsp_offset, "%s%d", |
185 | | (rsp_offset > 0) ? "." : "", (int)vp->val.objid[i]); |
186 | | |
187 | | if (rc > 0) |
188 | | rsp_offset += rc; |
189 | | else |
190 | | break; |
191 | | } |
192 | | |
193 | | lua_push_str_table_entry(vm, rsp_oid, response); |
194 | | } break; |
195 | | |
196 | | case ASN_APPLICATION: |
197 | | case ASN_NULL: |
198 | | lua_push_nil_table_entry(vm, rsp_oid); |
199 | | break; |
200 | | |
201 | | default: |
202 | | ntop->getTrace()->traceEvent(TRACE_WARNING, |
203 | | "Missing %d type handler [agent: %s]", |
204 | | vp->type, agent_ip); |
205 | | lua_push_nil_table_entry(vm, rsp_oid); |
206 | | break; |
207 | | } |
208 | | |
209 | | vp = vp->next_variable; |
210 | | } /* while */ |
211 | | |
212 | | if (!table_added) lua_pushnil(vm); |
213 | | } |
214 | | |
215 | | /* ******************************* */ |
216 | | |
217 | | int asynch_response(int operation, struct snmp_session *sp, int reqid, |
218 | | struct snmp_pdu *pdu, void *magic) { |
219 | | SNMP *s = (SNMP *)magic; |
220 | | int rc = 0; |
221 | | |
222 | | switch (operation) { |
223 | | case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE: |
224 | | if (pdu->command == SNMP_MSG_RESPONSE) { |
225 | | sockaddr_in *sa = (sockaddr_in *)pdu->transport_data; |
226 | | char buf[32], *peer = sp->peername; |
227 | | |
228 | | if (peer == NULL) { |
229 | | if (sa->sin_family == 2) /* IPv4 */ |
230 | | peer = Utils::intoaV4(ntohl(sa->sin_addr.s_addr), buf, sizeof(buf)); |
231 | | else |
232 | | ntop->getTrace()->traceEvent(TRACE_WARNING, "Missing IPv6 support"); |
233 | | } |
234 | | |
235 | | s->handle_async_response(pdu, peer), rc = 1; |
236 | | } else |
237 | | ntop->getTrace()->traceEvent(TRACE_WARNING, "Unhandled pdu command %d", |
238 | | pdu->command); |
239 | | break; |
240 | | case NETSNMP_CALLBACK_OP_TIMED_OUT: |
241 | | /* Reached when snmp_sess_timeout is called due to a timeout */ |
242 | | default: |
243 | | break; |
244 | | } |
245 | | |
246 | | return (rc); |
247 | | } |
248 | | |
249 | | /* ******************************* */ |
250 | | |
251 | | /* See |
252 | | * https://raw.githubusercontent.com/winlibs/net-snmp/master/snmplib/snmp_client.c |
253 | | */ |
254 | | |
255 | | void SNMP::send_snmpv1v2c_request(char *agent_host, char *community, |
256 | | snmp_pdu_primitive pduType, u_int version, |
257 | | char *_oid[SNMP_MAX_NUM_OIDS], |
258 | | bool _batch_mode) { |
259 | | int rc, pdu_type = SNMP_MSG_GET; |
260 | | struct snmp_pdu *pdu; |
261 | | SNMPSession *snmpSession; |
262 | | bool initSession = false; |
263 | | |
264 | | batch_mode = _batch_mode; |
265 | | |
266 | | if (batch_mode) { |
267 | | create_snmp_session: |
268 | | try { |
269 | | snmpSession = new SNMPSession; |
270 | | sessions.push_back(snmpSession); |
271 | | initSession = true; |
272 | | } catch (std::bad_alloc &ba) { |
273 | | ntop->getTrace()->traceEvent(TRACE_WARNING, |
274 | | "Unable to allocate SNMP session"); |
275 | | return; |
276 | | } |
277 | | } else { |
278 | | if (sessions.size() == 0) { |
279 | | goto create_snmp_session; |
280 | | } else { |
281 | | snmpSession = sessions.at(0); |
282 | | } |
283 | | } |
284 | | |
285 | | /* Initialize the session */ |
286 | | if (initSession) { |
287 | | snmp_sess_init(&snmpSession->session); |
288 | | snmpSession->session.peername = agent_host; |
289 | | |
290 | | /* set the SNMP version number */ |
291 | | snmpSession->session.version = |
292 | | (version == 0) ? SNMP_VERSION_1 : SNMP_VERSION_2c; |
293 | | |
294 | | /* set the SNMP community name used for authentication */ |
295 | | snmpSession->session.community = (u_char *)community; |
296 | | snmpSession->session.community_len = strlen(community); |
297 | | snmpSession->session.callback = asynch_response; |
298 | | snmpSession->session.callback_magic = this; |
299 | | |
300 | | /* Open the session */ |
301 | | snmpSession->session_ptr = snmp_sess_open(&snmpSession->session); |
302 | | } |
303 | | |
304 | | /* Create the PDU */ |
305 | | switch (pduType) { |
306 | | case snmp_get_pdu: |
307 | | pdu_type = SNMP_MSG_GET; |
308 | | break; |
309 | | case snmp_get_next_pdu: |
310 | | pdu_type = SNMP_MSG_GETNEXT; |
311 | | break; |
312 | | case snmp_get_bulk_pdu: |
313 | | pdu_type = |
314 | | (version == 0 /* SNMPv1 */) ? SNMP_MSG_GETNEXT : SNMP_MSG_GETBULK; |
315 | | break; |
316 | | case snmp_set_pdu: |
317 | | pdu_type = SNMP_MSG_SET; |
318 | | break; |
319 | | } |
320 | | |
321 | | if ((pdu = snmp_pdu_create(pdu_type)) == NULL) { |
322 | | ntop->getTrace()->traceEvent(TRACE_WARNING, "SNMP PDU create error"); |
323 | | return; |
324 | | } |
325 | | |
326 | | if (pdu_type == SNMP_MSG_GETBULK) { |
327 | | pdu->non_repeaters = 0; /* GET */ |
328 | | pdu->max_repetitions = 10; /* GET-NEXT */ |
329 | | } |
330 | | |
331 | | for (u_int i = 0; i < SNMP_MAX_NUM_OIDS; i++) { |
332 | | if (_oid[i] != NULL) { |
333 | | size_t name_length = MAX_OID_LEN; |
334 | | oid name[MAX_OID_LEN]; |
335 | | |
336 | | if (snmp_parse_oid(_oid[i], name, &name_length)) |
337 | | snmp_add_null_var(pdu, name, name_length); |
338 | | } else |
339 | | break; |
340 | | } |
341 | | |
342 | | /* Send the request */ |
343 | | if ((rc = snmp_sess_send(snmpSession->session_ptr, pdu)) == 0) { |
344 | | snmp_free_pdu(pdu); |
345 | | snmp_perror("snmp_sess_send"); |
346 | | ntop->getTrace()->traceEvent(TRACE_WARNING, "SNMP send error [rc: %d]", rc); |
347 | | } |
348 | | |
349 | | // snmp_free_pdu(pdu); /* TODO: this is apparently freed when we close the |
350 | | // session */ |
351 | | } |
352 | | |
353 | | /* ******************************************* */ |
354 | | |
355 | | void SNMP::send_snmpv3_request(char *agent_host, char *level, char *username, |
356 | | char *auth_protocol, char *auth_passphrase, |
357 | | char *privacy_protocol, char *privacy_passphrase, |
358 | | snmp_pdu_primitive pduType, |
359 | | char *oid[SNMP_MAX_NUM_OIDS], |
360 | | char value_types[SNMP_MAX_NUM_OIDS], |
361 | | char *values[SNMP_MAX_NUM_OIDS], |
362 | | bool _batch_mode) { |
363 | | send_snmp_request(agent_host, 2 /* SNMPv3 */, NULL, level, username, |
364 | | auth_protocol, auth_passphrase, privacy_protocol, |
365 | | privacy_passphrase, pduType, oid, value_types, values, |
366 | | _batch_mode); |
367 | | } |
368 | | |
369 | | /* ******************************************* */ |
370 | | |
371 | | void SNMP::send_snmp_request(char *agent_host, u_int version, char *community, |
372 | | char *level, char *username, char *auth_protocol, |
373 | | char *auth_passphrase, char *privacy_protocol, |
374 | | char *privacy_passphrase, |
375 | | snmp_pdu_primitive pduType, |
376 | | char *_oid[SNMP_MAX_NUM_OIDS], |
377 | | char value_types[SNMP_MAX_NUM_OIDS], |
378 | | char *values[SNMP_MAX_NUM_OIDS], |
379 | | bool _batch_mode) { |
380 | | int rc, pdu_type; |
381 | | struct snmp_pdu *pdu; |
382 | | SNMPSession *snmpSession; |
383 | | bool initSession = false; |
384 | | |
385 | | batch_mode = _batch_mode; |
386 | | |
387 | | if (batch_mode) { |
388 | | create_snmp_session: |
389 | | try { |
390 | | snmpSession = new SNMPSession; |
391 | | sessions.push_back(snmpSession); |
392 | | initSession = true; |
393 | | } catch (std::bad_alloc &ba) { |
394 | | ntop->getTrace()->traceEvent(TRACE_WARNING, |
395 | | "Unable to allocate SNMP session"); |
396 | | return; |
397 | | } |
398 | | } else { |
399 | | if (sessions.size() == 0) { |
400 | | goto create_snmp_session; |
401 | | } else { |
402 | | snmpSession = sessions.at(0); |
403 | | } |
404 | | } |
405 | | |
406 | | /* Initialize the session */ |
407 | | if (initSession) { |
408 | | snmp_sess_init(&snmpSession->session); |
409 | | snmpSession->session.peername = agent_host; |
410 | | |
411 | | if (version <= 1) { |
412 | | /* SNMP v1/v2c */ |
413 | | snmpSession->session.version = |
414 | | (version == 0) ? SNMP_VERSION_1 : SNMP_VERSION_2c; |
415 | | |
416 | | /* set the SNMP community name used for authentication */ |
417 | | snmpSession->session.community = (u_char *)community; |
418 | | snmpSession->session.community_len = strlen(community); |
419 | | } else { |
420 | | /* SNMP v3 */ |
421 | | snmpSession->session.version = SNMP_VERSION_3; |
422 | | |
423 | | if (!strcasecmp(level, "noAuthNoPriv")) { |
424 | | snmpSession->session.securityLevel = SNMP_SEC_LEVEL_NOAUTH; |
425 | | username = NULL; |
426 | | auth_protocol = NULL; |
427 | | privacy_protocol = NULL; |
428 | | } else { |
429 | | /* set the SNMPv3 user name */ |
430 | | if (username) { |
431 | | snmpSession->session.securityName = strdup(username); |
432 | | snmpSession->session.securityNameLen = |
433 | | strlen(snmpSession->session.securityName); |
434 | | } else { |
435 | | ntop->getTrace()->traceEvent(TRACE_WARNING, |
436 | | "SNMP PDU no username specified"); |
437 | | return; |
438 | | } |
439 | | |
440 | | if ((!strcasecmp(level, "authNoPriv")) || |
441 | | (!strcasecmp(level, "authPriv"))) { |
442 | | if (!strcasecmp(auth_protocol, "md5")) { |
443 | | snmpSession->session.securityAuthProto = usmHMACMD5AuthProtocol; |
444 | | snmpSession->session.securityAuthProtoLen = |
445 | | sizeof(usmHMACMD5AuthProtocol) / sizeof(oid); |
446 | | snmpSession->session.securityAuthKeyLen = USM_AUTH_KU_LEN; |
447 | | } else if (!strcasecmp(auth_protocol, "sha")) { |
448 | | snmpSession->session.securityAuthProto = usmHMACSHA1AuthProtocol; |
449 | | snmpSession->session.securityAuthProtoLen = |
450 | | sizeof(usmHMACSHA1AuthProtocol) / sizeof(oid); |
451 | | snmpSession->session.securityAuthKeyLen = |
452 | | USM_AUTH_KU_LEN; /* CHECK */ |
453 | | } else { |
454 | | ntop->getTrace()->traceEvent( |
455 | | TRACE_WARNING, "SNMP PDU invalid authentication protocol [%s]", |
456 | | auth_protocol); |
457 | | return; |
458 | | } |
459 | | |
460 | | if (generate_Ku(snmpSession->session.securityAuthProto, |
461 | | snmpSession->session.securityAuthProtoLen, |
462 | | (u_char *)auth_passphrase, strlen(auth_passphrase), |
463 | | snmpSession->session.securityAuthKey, |
464 | | &snmpSession->session.securityAuthKeyLen) != |
465 | | SNMPERR_SUCCESS) { |
466 | | ntop->getTrace()->traceEvent( |
467 | | TRACE_WARNING, "SNMP PDU authentication pass phrase error"); |
468 | | return; |
469 | | } |
470 | | |
471 | | if (!strcasecmp(level, "authPriv")) { |
472 | | snmpSession->session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV; |
473 | | |
474 | | #ifndef NETSNMP_DISABLE_DES |
475 | | if (!strcasecmp(privacy_protocol, "DES")) { |
476 | | snmpSession->session.securityPrivProto = snmp_duplicate_objid( |
477 | | usmDESPrivProtocol, USM_PRIV_PROTO_DES_LEN); |
478 | | snmpSession->session.securityPrivProtoLen = |
479 | | USM_PRIV_PROTO_DES_LEN; |
480 | | } else |
481 | | #endif |
482 | | if (!strncasecmp(privacy_protocol, "AES", 3)) { |
483 | | snmpSession->session.securityPrivProto = snmp_duplicate_objid( |
484 | | usmAESPrivProtocol, USM_PRIV_PROTO_AES_LEN); |
485 | | snmpSession->session.securityPrivProtoLen = |
486 | | USM_PRIV_PROTO_AES_LEN; |
487 | | } |
488 | | |
489 | | snmpSession->session.securityPrivKeyLen = USM_PRIV_KU_LEN; |
490 | | if (generate_Ku(snmpSession->session.securityAuthProto, |
491 | | snmpSession->session.securityAuthProtoLen, |
492 | | (u_char *)privacy_passphrase, |
493 | | strlen(privacy_passphrase), |
494 | | snmpSession->session.securityPrivKey, |
495 | | &snmpSession->session.securityPrivKeyLen) != |
496 | | SNMPERR_SUCCESS) { |
497 | | ntop->getTrace()->traceEvent(TRACE_WARNING, |
498 | | "SNMP PDU security privacy error"); |
499 | | return; |
500 | | } |
501 | | } else |
502 | | snmpSession->session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV; |
503 | | } |
504 | | } |
505 | | } |
506 | | |
507 | | snmpSession->session.callback = asynch_response; |
508 | | snmpSession->session.callback_magic = this; |
509 | | |
510 | | /* Open the session */ |
511 | | snmpSession->session_ptr = snmp_sess_open(&snmpSession->session); |
512 | | } |
513 | | |
514 | | /* Create the PDU */ |
515 | | switch (pduType) { |
516 | | case snmp_get_pdu: |
517 | | pdu_type = SNMP_MSG_GET; |
518 | | break; |
519 | | case snmp_get_next_pdu: |
520 | | pdu_type = SNMP_MSG_GETNEXT; |
521 | | break; |
522 | | case snmp_get_bulk_pdu: |
523 | | pdu_type = |
524 | | (version == 0 /* SNMPv1 */) ? SNMP_MSG_GETNEXT : SNMP_MSG_GETBULK; |
525 | | break; |
526 | | case snmp_set_pdu: |
527 | | pdu_type = SNMP_MSG_SET; |
528 | | if (values == NULL) { |
529 | | ntop->getTrace()->traceEvent(TRACE_WARNING, "SNMP PDU create error"); |
530 | | return; |
531 | | } |
532 | | break; |
533 | | default: |
534 | | ntop->getTrace()->traceEvent(TRACE_WARNING, "Unknown SNMP PDU type %u", |
535 | | pduType); |
536 | | pdu_type = SNMP_MSG_GET; |
537 | | break; |
538 | | } |
539 | | |
540 | | if ((pdu = snmp_pdu_create(pdu_type)) == NULL) { |
541 | | ntop->getTrace()->traceEvent(TRACE_WARNING, "SNMP PDU create error"); |
542 | | return; |
543 | | } |
544 | | |
545 | | if (pdu_type == SNMP_MSG_GETBULK) { |
546 | | pdu->non_repeaters = 0; /* GET */ |
547 | | pdu->max_repetitions = 10; /* GET-NEXT */ |
548 | | } |
549 | | |
550 | | for (u_int i = 0; i < SNMP_MAX_NUM_OIDS; i++) { |
551 | | if (_oid[i] != NULL) { |
552 | | size_t name_length = MAX_OID_LEN; |
553 | | oid name[MAX_OID_LEN]; |
554 | | |
555 | | if (snmp_parse_oid(_oid[i], name, &name_length)) { |
556 | | if ((values != NULL) && (values[i] != NULL)) |
557 | | snmp_add_var(pdu, name, name_length, value_types[i], values[i]); |
558 | | else |
559 | | snmp_add_null_var(pdu, name, name_length); |
560 | | } |
561 | | } else |
562 | | break; |
563 | | } |
564 | | |
565 | | /* Send the request */ |
566 | | if ((rc = snmp_sess_send(snmpSession->session_ptr, pdu)) == 0) { |
567 | | snmp_free_pdu(pdu); |
568 | | snmp_perror("snmp_sess_send"); |
569 | | ntop->getTrace()->traceEvent(TRACE_WARNING, "SNMP send error [rc: %d]", rc); |
570 | | } |
571 | | |
572 | | // snmp_free_pdu(pdu); /* TODO: this is apparently freed when we close the |
573 | | // session */ |
574 | | } |
575 | | |
576 | | /* ******************************************* */ |
577 | | |
578 | | void SNMP::send_snmp_set_request(char *agent_host, char *community, |
579 | | snmp_pdu_primitive pduType, u_int version, |
580 | | char *_oid[SNMP_MAX_NUM_OIDS], |
581 | | char value_types[SNMP_MAX_NUM_OIDS], |
582 | | char *values[SNMP_MAX_NUM_OIDS]) { |
583 | | int rc; |
584 | | struct snmp_pdu *pdu; |
585 | | SNMPSession *snmpSession; |
586 | | bool initSession = false; |
587 | | |
588 | | batch_mode = false; |
589 | | |
590 | | if (batch_mode) { |
591 | | create_snmp_session: |
592 | | try { |
593 | | snmpSession = new SNMPSession; |
594 | | sessions.push_back(snmpSession); |
595 | | initSession = true; |
596 | | } catch (std::bad_alloc &ba) { |
597 | | ntop->getTrace()->traceEvent(TRACE_WARNING, |
598 | | "Unable to allocate SNMP session"); |
599 | | return; |
600 | | } |
601 | | } else { |
602 | | if (sessions.size() == 0) { |
603 | | goto create_snmp_session; |
604 | | } else { |
605 | | snmpSession = sessions.at(0); |
606 | | } |
607 | | } |
608 | | |
609 | | /* Initialize the session */ |
610 | | if (initSession) { |
611 | | snmp_sess_init(&snmpSession->session); |
612 | | snmpSession->session.peername = agent_host; |
613 | | |
614 | | /* set the SNMP version number */ |
615 | | snmpSession->session.version = |
616 | | (version == 0) ? SNMP_VERSION_1 : SNMP_VERSION_2c; |
617 | | |
618 | | /* set the SNMP community name used for authentication */ |
619 | | snmpSession->session.community = (u_char *)community; |
620 | | snmpSession->session.community_len = strlen(community); |
621 | | snmpSession->session.callback = asynch_response; |
622 | | snmpSession->session.callback_magic = this; |
623 | | |
624 | | /* Open the session */ |
625 | | snmpSession->session_ptr = snmp_sess_open(&snmpSession->session); |
626 | | } |
627 | | |
628 | | /* Create the PDU */ |
629 | | if ((pdu = snmp_pdu_create(SNMP_MSG_SET)) == NULL) { |
630 | | ntop->getTrace()->traceEvent(TRACE_WARNING, "SNMP PDU create error"); |
631 | | return; |
632 | | } |
633 | | |
634 | | for (u_int i = 0; i < SNMP_MAX_NUM_OIDS; i++) { |
635 | | if (_oid[i] != NULL) { |
636 | | size_t name_length = MAX_OID_LEN; |
637 | | oid name[MAX_OID_LEN]; |
638 | | |
639 | | if (snmp_parse_oid(_oid[i], name, &name_length)) |
640 | | snmp_add_var(pdu, name, name_length, value_types[i], values[i]); |
641 | | } else |
642 | | break; |
643 | | } |
644 | | |
645 | | /* Send the request */ |
646 | | if ((rc = snmp_sess_send(snmpSession->session_ptr, pdu)) == 0) { |
647 | | snmp_free_pdu(pdu); |
648 | | snmp_perror("snmp_sess_send"); |
649 | | ntop->getTrace()->traceEvent(TRACE_WARNING, "SNMP send error [rc: %d]", rc); |
650 | | } |
651 | | } |
652 | | |
653 | | /* ******************************************* */ |
654 | | |
655 | | void SNMP::snmp_fetch_responses(lua_State *_vm, u_int timeout) { |
656 | | bool add_nil = true; |
657 | | |
658 | | // ntop->getTrace()->traceEvent(TRACE_WARNING, "%s(%u)", __FUNCTION__, |
659 | | // batch_mode ? 1 : 0); |
660 | | |
661 | | for (unsigned int i = 0; i < sessions.size(); i++) { |
662 | | int numfds; |
663 | | fd_set fdset; |
664 | | struct timeval tvp; |
665 | | int count, block = 0; |
666 | | SNMPSession *snmpSession = sessions.at(i); |
667 | | |
668 | | numfds = 0; |
669 | | FD_ZERO(&fdset); |
670 | | tvp.tv_sec = timeout, tvp.tv_usec = 0; |
671 | | |
672 | | snmp_sess_select_info(snmpSession->session_ptr, &numfds, &fdset, &tvp, |
673 | | &block); |
674 | | |
675 | | /* |
676 | | Experiments run have shown that: |
677 | | |
678 | | 1. `tvp` is altered by `snmp_sess_select_info` into something >= 0 |
679 | | 2. `block` |
680 | | - When there's data, i.e, `count` > 0, then `block` == 0 always |
681 | | - Then there's NO data, i.e., `count` == 0 then block == 0 but |
682 | | timeout is set to zero as well. |
683 | | |
684 | | So select can safely be called when block == 0 to have it non-blocking for |
685 | | `timeout` == 0. Examples: |
686 | | https://www.itcodet.com/cpp/cpp-snmp_sess_read-function-examples.html |
687 | | */ |
688 | | |
689 | | if(timeout > 0 /* The caller is willing to wait up to a timeout */ |
690 | | || block == 0 /* The caller doesn't want to wait so the select is only performed when it doesn't block */) { |
691 | | count = select(numfds, &fdset, NULL, NULL, &tvp); |
692 | | |
693 | | if (count > 0) { |
694 | | vm = _vm; |
695 | | snmp_sess_read(snmpSession->session_ptr, |
696 | | &fdset); /* Will trigger asynch_response() */ |
697 | | |
698 | | /* Add a nil in case no response was pushed in the stack */ |
699 | | if (lua_gettop(vm) > 0) add_nil = false; |
700 | | } else if (timeout > 0) { |
701 | | /* |
702 | | If select(2) times out (that is, it returns zero), snmp_sess_timeout() |
703 | | should be called to see if a timeout has occurred on the SNMP session. |
704 | | */ |
705 | | snmp_sess_timeout(snmpSession->session_ptr); |
706 | | } |
707 | | } |
708 | | } |
709 | | |
710 | | if (add_nil) lua_pushnil(_vm); |
711 | | } |
712 | | |
713 | | /* ******************************************* */ |
714 | | |
715 | | int SNMP::snmp_read_response(lua_State *_vm, u_int timeout) { |
716 | | snmp_fetch_responses(_vm, timeout); |
717 | | return (CONST_LUA_OK); |
718 | | } |
719 | | |
720 | | /* ******************************* */ |
721 | | /* ******************************* */ |
722 | | |
723 | | #else |
724 | | |
725 | | /* ******************************* */ |
726 | | /* ******************************* */ |
727 | | |
728 | | /* Self-contained SNMP implementation */ |
729 | | |
730 | | /* ******************************************* */ |
731 | | |
732 | 0 | int SNMP::snmp_read_response(lua_State *vm, u_int timeout) { |
733 | 0 | int i = 0; |
734 | |
|
735 | 0 | if (ntop->getGlobals()->isShutdown() || |
736 | 0 | input_timeout(udp_sock, timeout) == 0) { |
737 | | /* Timeout or shutdown in progress */ |
738 | 0 | lua_pushnil(vm); |
739 | 0 | } else { |
740 | 0 | char buf[BUFLEN]; |
741 | 0 | SNMPMessage *message; |
742 | 0 | char *sender_host, *oid_str, *value_str; |
743 | 0 | int sender_port, added = 0, len; |
744 | | |
745 | | /* This receive doesn't block */ |
746 | 0 | len = |
747 | 0 | receive_udp_datagram(buf, BUFLEN, udp_sock, &sender_host, &sender_port); |
748 | 0 | message = snmp_parse_message(buf, len); |
749 | |
|
750 | 0 | i = 0; |
751 | 0 | while (snmp_get_varbind_as_string(message, i, &oid_str, NULL, &value_str)) { |
752 | 0 | if (!added) lua_newtable(vm), added = 1; |
753 | 0 | lua_push_str_table_entry(vm, oid_str, value_str); |
754 | 0 | if (value_str) free(value_str), value_str = NULL; |
755 | 0 | i++; |
756 | 0 | } |
757 | |
|
758 | 0 | snmp_destroy_message(message); |
759 | 0 | free(message); /* malloc'd by snmp_parse_message */ |
760 | |
|
761 | 0 | if (!added) lua_pushnil(vm); |
762 | 0 | } |
763 | |
|
764 | 0 | return (CONST_LUA_OK); |
765 | 0 | } |
766 | | |
767 | | /* ******************************************* */ |
768 | | |
769 | | void SNMP::send_snmpv1v2c_request(char *agent_host, char *community, |
770 | | snmp_pdu_primitive pduType, u_int version, |
771 | | char *oid[SNMP_MAX_NUM_OIDS], |
772 | 0 | bool _batch_mode) { |
773 | 0 | u_int agent_port = 161; |
774 | 0 | int i = 0; |
775 | 0 | SNMPMessage *message; |
776 | 0 | int len; |
777 | 0 | u_char buf[1500]; |
778 | 0 | int operation = (pduType == snmp_get_pdu) ? NTOP_SNMP_GET_REQUEST_TYPE |
779 | 0 | : NTOP_SNMP_GETNEXT_REQUEST_TYPE; |
780 | |
|
781 | 0 | batch_mode = _batch_mode; |
782 | |
|
783 | 0 | if ((message = snmp_create_message())) { |
784 | 0 | snmp_set_version(message, version); |
785 | 0 | snmp_set_community(message, community); |
786 | 0 | snmp_set_pdu_type(message, operation); |
787 | 0 | snmp_set_request_id(message, request_id++); |
788 | 0 | snmp_set_error(message, 0); |
789 | 0 | snmp_set_error_index(message, 0); |
790 | |
|
791 | 0 | for (i = 0; i < SNMP_MAX_NUM_OIDS; i++) { |
792 | 0 | if (oid[i] != NULL) |
793 | 0 | snmp_add_varbind_null(message, oid[i]); |
794 | 0 | else |
795 | 0 | break; |
796 | 0 | } |
797 | |
|
798 | 0 | len = snmp_message_length(message); |
799 | 0 | snmp_render_message(message, buf); |
800 | 0 | snmp_destroy_message(message); |
801 | 0 | free(message); /* malloc'd by snmp_create_message */ |
802 | |
|
803 | 0 | send_udp_datagram(buf, len, udp_sock, agent_host, agent_port); |
804 | 0 | } |
805 | 0 | } |
806 | | |
807 | | /* ******************************************* */ |
808 | | |
809 | 0 | void SNMP::snmp_fetch_responses(lua_State *vm, u_int sec_timeout) { |
810 | 0 | int i = 0; |
811 | |
|
812 | 0 | if (ntop->getGlobals()->isShutdown() || |
813 | 0 | input_timeout(udp_sock, sec_timeout) == 0) { |
814 | | /* Timeout or shutdown in progress */ |
815 | 0 | } else { |
816 | 0 | char buf[BUFLEN]; |
817 | 0 | SNMPMessage *message; |
818 | 0 | char *sender_host, *oid_str, *value_str = NULL; |
819 | 0 | int sender_port, len; |
820 | |
|
821 | 0 | len = |
822 | 0 | receive_udp_datagram(buf, BUFLEN, udp_sock, &sender_host, &sender_port); |
823 | |
|
824 | 0 | if ((message = snmp_parse_message(buf, len))) { |
825 | 0 | bool table_added = false; |
826 | |
|
827 | 0 | i = 0; |
828 | |
|
829 | 0 | while ( |
830 | 0 | snmp_get_varbind_as_string(message, i, &oid_str, NULL, &value_str)) { |
831 | 0 | if (value_str /* && (value_str[0] != '\0') */) { |
832 | 0 | if (!table_added) lua_newtable(vm), table_added = true; |
833 | |
|
834 | 0 | if (batch_mode /* Used in batch mode */) { |
835 | | /* |
836 | | The key is the IP address as this is used when contacting multiple |
837 | | hosts so we need to know who has sent back the response |
838 | | */ |
839 | 0 | lua_push_str_table_entry(vm, sender_host /* Sender IP */, |
840 | 0 | value_str); |
841 | 0 | } else |
842 | 0 | lua_push_str_table_entry(vm, oid_str, value_str); |
843 | |
|
844 | 0 | free(value_str), |
845 | 0 | value_str = NULL; /* malloc'd by snmp_get_varbind_as_string */ |
846 | 0 | } |
847 | |
|
848 | 0 | i++; |
849 | 0 | } /* while */ |
850 | |
|
851 | 0 | snmp_destroy_message(message); |
852 | 0 | free(message); /* malloc'd by snmp_parse_message */ |
853 | 0 | if (table_added) return; |
854 | 0 | } |
855 | 0 | } |
856 | | |
857 | 0 | lua_pushnil(vm); |
858 | 0 | } |
859 | | |
860 | | /* ******************************************* */ |
861 | | |
862 | 0 | SNMP::SNMP() { |
863 | 0 | char version[4] = {'\0'}; |
864 | |
|
865 | 0 | ntop->getRedis()->get((char *)CONST_RUNTIME_PREFS_SNMP_PROTO_VERSION, version, |
866 | 0 | sizeof(version)); |
867 | |
|
868 | 0 | if ((udp_sock = Utils::openSocket(AF_INET, SOCK_DGRAM, 0, "SNMP")) < 0) |
869 | 0 | throw("Unable to start network discovery"); |
870 | | |
871 | 0 | Utils::maximizeSocketBuffer(udp_sock, true /* RX */, 2 /* MB */); |
872 | 0 | snmp_version = atoi(version); |
873 | 0 | if (snmp_version > 1 /* v2c */) snmp_version = 1; |
874 | 0 | request_id = rand(); // Avoid overlaps with coroutines |
875 | 0 | } |
876 | | |
877 | | /* ******************************************* */ |
878 | | |
879 | 0 | SNMP::~SNMP() { |
880 | 0 | Utils::closeSocket(udp_sock); |
881 | 0 | } |
882 | | |
883 | | /* ******************************************* */ |
884 | | |
885 | | #endif /* HAVE_LIBSNMP */ |
886 | | |
887 | | /* Common code */ |
888 | | |
889 | | /* ******************************************* */ |
890 | | |
891 | 0 | int SNMP::get(lua_State *vm, bool skip_first_param) { |
892 | 0 | return (snmp_get_fctn(vm, snmp_get_pdu, skip_first_param, false)); |
893 | 0 | } |
894 | | |
895 | | /* ******************************************* */ |
896 | | |
897 | 0 | int SNMP::getnext(lua_State *vm, bool skip_first_param) { |
898 | 0 | return (snmp_get_fctn(vm, snmp_get_next_pdu, skip_first_param, false)); |
899 | 0 | } |
900 | | |
901 | | /* ******************************************* */ |
902 | | |
903 | 0 | int SNMP::getnextbulk(lua_State *vm, bool skip_first_param) { |
904 | 0 | return (snmp_get_fctn(vm, |
905 | | #ifdef HAVE_LIBSNMP |
906 | | snmp_get_bulk_pdu /* GET-BULK (next only) */, |
907 | | #else |
908 | 0 | snmp_get_next_pdu /* GET-NEXT (no bulk) */, |
909 | 0 | #endif |
910 | 0 | skip_first_param, false)); |
911 | 0 | } |
912 | | |
913 | | /* ******************************************* */ |
914 | | |
915 | 0 | int SNMP::set(lua_State *vm, bool skip_first_param) { |
916 | | #ifdef HAVE_LIBSNMP |
917 | | return (snmp_get_fctn(vm, snmp_set_pdu, skip_first_param, false)); |
918 | | #else |
919 | 0 | return (-1); |
920 | 0 | #endif |
921 | 0 | } |
922 | | |
923 | | /* ******************************************* */ |
924 | | |
925 | | #ifdef HAVE_LIBSNMP |
926 | | int SNMP::snmpv3_get_fctn(lua_State *vm, snmp_pdu_primitive pduType, |
927 | | bool skip_first_param, bool _batch_mode) { |
928 | | char *agent_host, *level, *username, *auth_protocol, *auth_passphrase, |
929 | | *privacy_protocol, *privacy_passphrase; |
930 | | u_int timeout = 5, oid_idx = 0, idx = skip_first_param ? 2 : 1; |
931 | | char *oid[SNMP_MAX_NUM_OIDS] = {NULL}, |
932 | | value_types[SNMP_MAX_NUM_OIDS] = {'\0'}, |
933 | | *values[SNMP_MAX_NUM_OIDS] = {NULL}; |
934 | | |
935 | | if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TSTRING) != CONST_LUA_OK) |
936 | | return (CONST_LUA_ERROR); |
937 | | agent_host = (char *)lua_tostring(vm, idx++); |
938 | | |
939 | | if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TSTRING) != CONST_LUA_OK) |
940 | | return (CONST_LUA_ERROR); |
941 | | level = (char *)lua_tostring(vm, idx++); |
942 | | |
943 | | if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TSTRING) != CONST_LUA_OK) |
944 | | return (CONST_LUA_ERROR); |
945 | | username = (char *)lua_tostring(vm, idx++); |
946 | | |
947 | | if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TSTRING) != CONST_LUA_OK) |
948 | | return (CONST_LUA_ERROR); |
949 | | auth_protocol = (char *)lua_tostring(vm, idx++); |
950 | | |
951 | | if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TSTRING) != CONST_LUA_OK) |
952 | | return (CONST_LUA_ERROR); |
953 | | auth_passphrase = (char *)lua_tostring(vm, idx++); |
954 | | |
955 | | if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TSTRING) != CONST_LUA_OK) |
956 | | return (CONST_LUA_ERROR); |
957 | | privacy_protocol = (char *)lua_tostring(vm, idx++); |
958 | | |
959 | | if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TSTRING) != CONST_LUA_OK) |
960 | | return (CONST_LUA_ERROR); |
961 | | privacy_passphrase = (char *)lua_tostring(vm, idx++); |
962 | | |
963 | | if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TNUMBER) != CONST_LUA_OK) |
964 | | return (CONST_LUA_ERROR); |
965 | | timeout = min(timeout, (u_int)lua_tointeger(vm, idx)); |
966 | | idx++; // Do not out idx++ above as min is a #define and on some platforms it |
967 | | // will increase idx twice |
968 | | |
969 | | /* Add OIDs */ |
970 | | while ((oid_idx < SNMP_MAX_NUM_OIDS) && (lua_type(vm, idx) == LUA_TSTRING)) { |
971 | | if (pduType == snmp_set_pdu) { |
972 | | /* SET */ |
973 | | oid[oid_idx] = (char *)lua_tostring(vm, idx); |
974 | | |
975 | | /* Types |
976 | | i: INTEGER, u: unsigned INTEGER, t: TIMETICKS, a: IPADDRESS |
977 | | o: OBJID, s: STRING, x: HEX STRING, d: DECIMAL STRING |
978 | | U: unsigned int64, I: signed int64, F: float, D: double |
979 | | */ |
980 | | if (lua_type(vm, idx + 1) != LUA_TSTRING) return (CONST_LUA_ERROR); |
981 | | value_types[oid_idx] = ((char *)lua_tostring(vm, idx + 1))[0]; |
982 | | |
983 | | if (lua_type(vm, idx + 2) != LUA_TSTRING) return (CONST_LUA_ERROR); |
984 | | values[oid_idx] = (char *)lua_tostring(vm, idx + 2); |
985 | | |
986 | | oid_idx += 3, idx += 3; |
987 | | } else { |
988 | | oid[oid_idx++] = (char *)lua_tostring(vm, idx); |
989 | | idx++; |
990 | | } |
991 | | } |
992 | | |
993 | | if (oid_idx == 0) { |
994 | | /* Missing OIDs */ |
995 | | return (CONST_LUA_ERROR); |
996 | | } |
997 | | |
998 | | send_snmpv3_request(agent_host, level, username, auth_protocol, |
999 | | auth_passphrase, privacy_protocol, privacy_passphrase, |
1000 | | pduType, oid, value_types, values, _batch_mode); |
1001 | | |
1002 | | if (skip_first_param) |
1003 | | return (CONST_LUA_OK); /* This is an async call */ |
1004 | | else |
1005 | | return (snmp_read_response(vm, timeout)); |
1006 | | } |
1007 | | #endif |
1008 | | |
1009 | | /* ******************************************* */ |
1010 | | |
1011 | | int SNMP::snmp_get_fctn(lua_State *vm, snmp_pdu_primitive pduType, |
1012 | 0 | bool skip_first_param, bool _batch_mode) { |
1013 | | #ifdef HAVE_LIBSNMP |
1014 | | if (lua_type(vm, skip_first_param ? 5 : 4) != LUA_TNUMBER) |
1015 | | return (snmpv3_get_fctn(vm, pduType, skip_first_param, _batch_mode)); |
1016 | | else |
1017 | | #endif |
1018 | 0 | { |
1019 | 0 | char *agent_host, *community; |
1020 | 0 | u_int timeout = 5, version = snmp_version, oid_idx = 0, |
1021 | 0 | idx = skip_first_param ? 2 : 1; |
1022 | 0 | char *oid[SNMP_MAX_NUM_OIDS] = {NULL}; |
1023 | | #ifdef HAVE_LIBSNMP |
1024 | | char value_types[SNMP_MAX_NUM_OIDS] = {'\0'}, |
1025 | | *values[SNMP_MAX_NUM_OIDS] = {NULL}; |
1026 | | #endif |
1027 | |
|
1028 | 0 | if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TSTRING) != CONST_LUA_OK) |
1029 | 0 | return (CONST_LUA_ERROR); |
1030 | 0 | agent_host = (char *)lua_tostring(vm, idx++); |
1031 | |
|
1032 | 0 | if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TSTRING) != CONST_LUA_OK) |
1033 | 0 | return (CONST_LUA_ERROR); |
1034 | 0 | community = (char *)lua_tostring(vm, idx++); |
1035 | |
|
1036 | 0 | if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TNUMBER) != CONST_LUA_OK) |
1037 | 0 | return (CONST_LUA_ERROR); |
1038 | 0 | timeout = min(timeout, (u_int)lua_tointeger(vm, idx)); |
1039 | 0 | idx++; // Do not out idx++ above as min is a #define and on some platforms |
1040 | | // it will increase idx twice |
1041 | |
|
1042 | 0 | if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TNUMBER) != CONST_LUA_OK) |
1043 | 0 | return (CONST_LUA_ERROR); |
1044 | 0 | version = (u_int)lua_tointeger(vm, idx++); |
1045 | | |
1046 | | /* Add OIDs */ |
1047 | 0 | while ((oid_idx < SNMP_MAX_NUM_OIDS) && |
1048 | 0 | (lua_type(vm, idx) == LUA_TSTRING)) { |
1049 | 0 | if (pduType == snmp_set_pdu) { |
1050 | | /* SET */ |
1051 | 0 | oid[oid_idx] = (char *)lua_tostring(vm, idx); |
1052 | | |
1053 | | /* Types |
1054 | | i: INTEGER, u: unsigned INTEGER, t: TIMETICKS, a: IPADDRESS |
1055 | | o: OBJID, s: STRING, x: HEX STRING, d: DECIMAL STRING |
1056 | | U: unsigned int64, I: signed int64, F: float, D: double |
1057 | | */ |
1058 | 0 | if (lua_type(vm, idx + 1) != LUA_TSTRING) return (CONST_LUA_ERROR); |
1059 | | #ifdef HAVE_LIBSNMP |
1060 | | value_types[oid_idx] = ((char *)lua_tostring(vm, idx + 1))[0]; |
1061 | | #endif |
1062 | | |
1063 | 0 | if (lua_type(vm, idx + 2) != LUA_TSTRING) return (CONST_LUA_ERROR); |
1064 | | #ifdef HAVE_LIBSNMP |
1065 | | values[oid_idx] = (char *)lua_tostring(vm, idx + 2); |
1066 | | #endif |
1067 | | |
1068 | 0 | oid_idx += 3, idx += 3; |
1069 | 0 | } else { |
1070 | 0 | oid[oid_idx++] = (char *)lua_tostring(vm, idx); |
1071 | 0 | idx++; |
1072 | 0 | } |
1073 | 0 | } |
1074 | | |
1075 | 0 | if (oid_idx == 0) { |
1076 | | /* Missing OIDs */ |
1077 | 0 | return (CONST_LUA_ERROR); |
1078 | 0 | } |
1079 | | |
1080 | 0 | if (pduType == snmp_set_pdu) { |
1081 | | /* SET */ |
1082 | | #ifdef HAVE_LIBSNMP |
1083 | | send_snmp_set_request(agent_host, community, pduType, version, oid, |
1084 | | value_types, values); |
1085 | | #else |
1086 | 0 | return (CONST_LUA_ERROR); /* not supported */ |
1087 | 0 | #endif |
1088 | 0 | } else { |
1089 | 0 | send_snmpv1v2c_request(agent_host, community, pduType, version, oid, |
1090 | 0 | _batch_mode); |
1091 | 0 | } |
1092 | | |
1093 | 0 | if (skip_first_param) |
1094 | 0 | return (CONST_LUA_OK); /* This is an async call */ |
1095 | 0 | else |
1096 | 0 | return (snmp_read_response(vm, timeout)); |
1097 | 0 | } |
1098 | 0 | } |