1 /**
2 * @file
3 * SNMP message processing (RFC1157).
4 */
5
6 /*
7 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
8 * Copyright (c) 2016 Elias Oenal.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31 * OF SUCH DAMAGE.
32 *
33 * Author: Christiaan Simons <[email protected]>
34 * Martin Hentschel <[email protected]>
35 * Elias Oenal <[email protected]>
36 */
37
38 #include "lwip/apps/snmp_opts.h"
39
40 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
41
42 #include "snmp_msg.h"
43 #include "snmp_asn1.h"
44 #include "snmp_core_priv.h"
45 #include "lwip/ip_addr.h"
46 #include "lwip/stats.h"
47
48 #if LWIP_SNMP_V3
49 #include "lwip/apps/snmpv3.h"
50 #include "snmpv3_priv.h"
51 #ifdef LWIP_SNMPV3_INCLUDE_ENGINE
52 #include LWIP_SNMPV3_INCLUDE_ENGINE
53 #endif
54 #endif
55
56 #include <string.h>
57
58 /* public (non-static) constants */
59 /** SNMP community string */
60 const char *snmp_community = SNMP_COMMUNITY;
61 /** SNMP community string for write access */
62 const char *snmp_community_write = SNMP_COMMUNITY_WRITE;
63 /** SNMP community string for sending traps */
64 const char *snmp_community_trap = SNMP_COMMUNITY_TRAP;
65
66 snmp_write_callback_fct snmp_write_callback = NULL;
67 void* snmp_write_callback_arg = NULL;
68
69 /**
70 * @ingroup snmp_core
71 * Returns current SNMP community string.
72 * @return current SNMP community string
73 */
74 const char *
snmp_get_community(void)75 snmp_get_community(void)
76 {
77 return snmp_community;
78 }
79
80 /**
81 * @ingroup snmp_core
82 * Sets SNMP community string.
83 * The string itself (its storage) must be valid throughout the whole life of
84 * program (or until it is changed to sth else).
85 *
86 * @param community is a pointer to new community string
87 */
88 void
snmp_set_community(const char * const community)89 snmp_set_community(const char * const community)
90 {
91 LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
92 snmp_community = community;
93 }
94
95 /**
96 * @ingroup snmp_core
97 * Returns current SNMP write-access community string.
98 * @return current SNMP write-access community string
99 */
100 const char *
snmp_get_community_write(void)101 snmp_get_community_write(void)
102 {
103 return snmp_community_write;
104 }
105
106 /**
107 * @ingroup snmp_traps
108 * Returns current SNMP community string used for sending traps.
109 * @return current SNMP community string used for sending traps
110 */
111 const char *
snmp_get_community_trap(void)112 snmp_get_community_trap(void)
113 {
114 return snmp_community_trap;
115 }
116
117 /**
118 * @ingroup snmp_core
119 * Sets SNMP community string for write-access.
120 * The string itself (its storage) must be valid throughout the whole life of
121 * program (or until it is changed to sth else).
122 *
123 * @param community is a pointer to new write-access community string
124 */
125 void
snmp_set_community_write(const char * const community)126 snmp_set_community_write(const char * const community)
127 {
128 LWIP_ASSERT("community string must not be NULL", community != NULL);
129 LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
130 snmp_community_write = community;
131 }
132
133 /**
134 * @ingroup snmp_traps
135 * Sets SNMP community string used for sending traps.
136 * The string itself (its storage) must be valid throughout the whole life of
137 * program (or until it is changed to sth else).
138 *
139 * @param community is a pointer to new trap community string
140 */
141 void
snmp_set_community_trap(const char * const community)142 snmp_set_community_trap(const char * const community)
143 {
144 LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
145 snmp_community_trap = community;
146 }
147
148 /**
149 * @ingroup snmp_core
150 * Callback fired on every successful write access
151 */
152 void
snmp_set_write_callback(snmp_write_callback_fct write_callback,void * callback_arg)153 snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg)
154 {
155 snmp_write_callback = write_callback;
156 snmp_write_callback_arg = callback_arg;
157 }
158
159 /* ----------------------------------------------------------------------- */
160 /* forward declarations */
161 /* ----------------------------------------------------------------------- */
162
163 static err_t snmp_process_get_request(struct snmp_request *request);
164 static err_t snmp_process_getnext_request(struct snmp_request *request);
165 static err_t snmp_process_getbulk_request(struct snmp_request *request);
166 static err_t snmp_process_set_request(struct snmp_request *request);
167
168 static err_t snmp_parse_inbound_frame(struct snmp_request *request);
169 static err_t snmp_prepare_outbound_frame(struct snmp_request *request);
170 static err_t snmp_complete_outbound_frame(struct snmp_request *request);
171 static void snmp_execute_write_callbacks(struct snmp_request *request);
172
173
174 /* ----------------------------------------------------------------------- */
175 /* implementation */
176 /* ----------------------------------------------------------------------- */
177
178 void
snmp_receive(void * handle,struct pbuf * p,const ip_addr_t * source_ip,u16_t port)179 snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port)
180 {
181 err_t err;
182 struct snmp_request request;
183
184 memset(&request, 0, sizeof(request));
185 request.handle = handle;
186 request.source_ip = source_ip;
187 request.source_port = port;
188 request.inbound_pbuf = p;
189
190 snmp_stats.inpkts++;
191
192 err = snmp_parse_inbound_frame(&request);
193 if (err == ERR_OK) {
194 err = snmp_prepare_outbound_frame(&request);
195 if (err == ERR_OK) {
196
197 if (request.error_status == SNMP_ERR_NOERROR) {
198 /* only process frame if we do not already have an error to return (e.g. all readonly) */
199 if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_REQ) {
200 err = snmp_process_get_request(&request);
201 } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ) {
202 err = snmp_process_getnext_request(&request);
203 } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
204 err = snmp_process_getbulk_request(&request);
205 } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
206 err = snmp_process_set_request(&request);
207 }
208 }
209
210 if (err == ERR_OK) {
211 err = snmp_complete_outbound_frame(&request);
212
213 if (err == ERR_OK) {
214 err = snmp_sendto(request.handle, request.outbound_pbuf, request.source_ip, request.source_port);
215
216 if ((request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)
217 && (request.error_status == SNMP_ERR_NOERROR)
218 && (snmp_write_callback != NULL)) {
219 /* raise write notification for all written objects */
220 snmp_execute_write_callbacks(&request);
221 }
222 }
223 }
224 }
225
226 if (request.outbound_pbuf != NULL) {
227 pbuf_free(request.outbound_pbuf);
228 }
229 }
230 }
231
232 static u8_t
snmp_msg_getnext_validate_node_inst(struct snmp_node_instance * node_instance,void * validate_arg)233 snmp_msg_getnext_validate_node_inst(struct snmp_node_instance* node_instance, void* validate_arg)
234 {
235 if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != SNMP_NODE_INSTANCE_ACCESS_READ) || (node_instance->get_value == NULL)) {
236 return SNMP_ERR_NOSUCHINSTANCE;
237 }
238
239 if ((node_instance->asn1_type == SNMP_ASN1_TYPE_COUNTER64) && (((struct snmp_request*)validate_arg)->version == SNMP_VERSION_1)) {
240 /* according to RFC 2089 skip Counter64 objects in GetNext requests from v1 clients */
241 return SNMP_ERR_NOSUCHINSTANCE;
242 }
243
244 return SNMP_ERR_NOERROR;
245 }
246
247 static void
snmp_process_varbind(struct snmp_request * request,struct snmp_varbind * vb,u8_t get_next)248 snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t get_next)
249 {
250 err_t err;
251 struct snmp_node_instance node_instance;
252 memset(&node_instance, 0, sizeof(node_instance));
253
254 if (get_next) {
255 struct snmp_obj_id result_oid;
256 request->error_status = snmp_get_next_node_instance_from_oid(vb->oid.id, vb->oid.len, snmp_msg_getnext_validate_node_inst, request, &result_oid, &node_instance);
257
258 if (request->error_status == SNMP_ERR_NOERROR) {
259 snmp_oid_assign(&vb->oid, result_oid.id, result_oid.len);
260 }
261 } else {
262 request->error_status = snmp_get_node_instance_from_oid(vb->oid.id, vb->oid.len, &node_instance);
263
264 if (request->error_status == SNMP_ERR_NOERROR) {
265 /* use 'getnext_validate' method for validation to avoid code duplication (some checks have to be executed here) */
266 request->error_status = snmp_msg_getnext_validate_node_inst(&node_instance, request);
267
268 if (request->error_status != SNMP_ERR_NOERROR) {
269 if (node_instance.release_instance != NULL) {
270 node_instance.release_instance(&node_instance);
271 }
272 }
273 }
274 }
275
276 if (request->error_status != SNMP_ERR_NOERROR) {
277 if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
278 if ((request->version == SNMP_VERSION_2c) || request->version == SNMP_VERSION_3) {
279 /* in SNMP v2c a varbind related exception is stored in varbind and not in frame header */
280 vb->type = (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | (request->error_status & SNMP_VARBIND_EXCEPTION_MASK));
281 vb->value_len = 0;
282
283 err = snmp_append_outbound_varbind(&(request->outbound_pbuf_stream), vb);
284 if (err == ERR_OK) {
285 /* we stored the exception in varbind -> go on */
286 request->error_status = SNMP_ERR_NOERROR;
287 } else if (err == ERR_BUF) {
288 request->error_status = SNMP_ERR_TOOBIG;
289 } else {
290 request->error_status = SNMP_ERR_GENERROR;
291 }
292 }
293 } else {
294 /* according to RFC 1157/1905, all other errors only return genError */
295 request->error_status = SNMP_ERR_GENERROR;
296 }
297 } else {
298 s16_t len = node_instance.get_value(&node_instance, vb->value);
299 vb->type = node_instance.asn1_type;
300
301 if(len >= 0) {
302 vb->value_len = (u16_t)len; /* cast is OK because we checked >= 0 above */
303
304 LWIP_ASSERT("SNMP_MAX_VALUE_SIZE is configured too low", (vb->value_len & ~SNMP_GET_VALUE_RAW_DATA) <= SNMP_MAX_VALUE_SIZE);
305 err = snmp_append_outbound_varbind(&request->outbound_pbuf_stream, vb);
306
307 if (err == ERR_BUF) {
308 request->error_status = SNMP_ERR_TOOBIG;
309 } else if (err != ERR_OK) {
310 request->error_status = SNMP_ERR_GENERROR;
311 }
312 } else {
313 request->error_status = SNMP_ERR_GENERROR;
314 }
315
316 if (node_instance.release_instance != NULL) {
317 node_instance.release_instance(&node_instance);
318 }
319 }
320 }
321
322
323 /**
324 * Service an internal or external event for SNMP GET.
325 *
326 * @param request points to the associated message process state
327 */
328 static err_t
snmp_process_get_request(struct snmp_request * request)329 snmp_process_get_request(struct snmp_request *request)
330 {
331 snmp_vb_enumerator_err_t err;
332 struct snmp_varbind vb;
333 vb.value = request->value_buffer;
334
335 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get request\n"));
336
337 while (request->error_status == SNMP_ERR_NOERROR) {
338 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
339 if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
340 if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) {
341 snmp_process_varbind(request, &vb, 0);
342 } else {
343 request->error_status = SNMP_ERR_GENERROR;
344 }
345 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
346 /* no more varbinds in request */
347 break;
348 } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
349 /* malformed ASN.1, don't answer */
350 return ERR_ARG;
351 } else {
352 request->error_status = SNMP_ERR_GENERROR;
353 }
354 }
355
356 return ERR_OK;
357 }
358
359 /**
360 * Service an internal or external event for SNMP GET.
361 *
362 * @param request points to the associated message process state
363 */
364 static err_t
snmp_process_getnext_request(struct snmp_request * request)365 snmp_process_getnext_request(struct snmp_request *request)
366 {
367 snmp_vb_enumerator_err_t err;
368 struct snmp_varbind vb;
369 vb.value = request->value_buffer;
370
371 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-next request\n"));
372
373 while (request->error_status == SNMP_ERR_NOERROR) {
374 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
375 if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
376 if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) {
377 snmp_process_varbind(request, &vb, 1);
378 } else {
379 request->error_status = SNMP_ERR_GENERROR;
380 }
381 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
382 /* no more varbinds in request */
383 break;
384 } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
385 /* malformed ASN.1, don't answer */
386 return ERR_ARG;
387 } else {
388 request->error_status = SNMP_ERR_GENERROR;
389 }
390 }
391
392 return ERR_OK;
393 }
394
395 /**
396 * Service an internal or external event for SNMP GETBULKT.
397 *
398 * @param request points to the associated message process state
399 */
400 static err_t
snmp_process_getbulk_request(struct snmp_request * request)401 snmp_process_getbulk_request(struct snmp_request *request)
402 {
403 snmp_vb_enumerator_err_t err;
404 s32_t non_repeaters = request->non_repeaters;
405 s32_t repetitions;
406 u16_t repetition_offset = 0;
407 struct snmp_varbind_enumerator repetition_varbind_enumerator;
408 struct snmp_varbind vb;
409 vb.value = request->value_buffer;
410
411 if (SNMP_LWIP_GETBULK_MAX_REPETITIONS > 0) {
412 repetitions = LWIP_MIN(request->max_repetitions, SNMP_LWIP_GETBULK_MAX_REPETITIONS);
413 } else {
414 repetitions = request->max_repetitions;
415 }
416
417 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-bulk request\n"));
418
419 /* process non repeaters and first repetition */
420 while (request->error_status == SNMP_ERR_NOERROR) {
421 if (non_repeaters == 0) {
422 repetition_offset = request->outbound_pbuf_stream.offset;
423
424 if (repetitions == 0) {
425 /* do not resolve repeaters when repetitions is set to 0 */
426 break;
427 }
428 repetitions--;
429 }
430
431 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
432 if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
433 /* no more varbinds in request */
434 break;
435 } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
436 /* malformed ASN.1, don't answer */
437 return ERR_ARG;
438 } else if ((err != SNMP_VB_ENUMERATOR_ERR_OK) || (vb.type != SNMP_ASN1_TYPE_NULL) || (vb.value_len != 0)) {
439 request->error_status = SNMP_ERR_GENERROR;
440 } else {
441 snmp_process_varbind(request, &vb, 1);
442 non_repeaters--;
443 }
444 }
445
446 /* process repetitions > 1 */
447 while ((request->error_status == SNMP_ERR_NOERROR) && (repetitions > 0) && (request->outbound_pbuf_stream.offset != repetition_offset)) {
448
449 u8_t all_endofmibview = 1;
450
451 snmp_vb_enumerator_init(&repetition_varbind_enumerator, request->outbound_pbuf, repetition_offset, request->outbound_pbuf_stream.offset - repetition_offset);
452 repetition_offset = request->outbound_pbuf_stream.offset; /* for next loop */
453
454 while (request->error_status == SNMP_ERR_NOERROR) {
455 vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned) */
456 err = snmp_vb_enumerator_get_next(&repetition_varbind_enumerator, &vb);
457 if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
458 vb.value = request->value_buffer;
459 snmp_process_varbind(request, &vb, 1);
460
461 if (request->error_status != SNMP_ERR_NOERROR) {
462 /* already set correct error-index (here it cannot be taken from inbound varbind enumerator) */
463 request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count;
464 } else if (vb.type != (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW)) {
465 all_endofmibview = 0;
466 }
467 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
468 /* no more varbinds in request */
469 break;
470 } else {
471 LWIP_DEBUGF(SNMP_DEBUG, ("Very strange, we cannot parse the varbind output that we created just before!"));
472 request->error_status = SNMP_ERR_GENERROR;
473 request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count;
474 }
475 }
476
477 if ((request->error_status == SNMP_ERR_NOERROR) && all_endofmibview) {
478 /* stop when all varbinds in a loop return EndOfMibView */
479 break;
480 }
481
482 repetitions--;
483 }
484
485 if (request->error_status == SNMP_ERR_TOOBIG) {
486 /* for GetBulk it is ok, if not all requested variables fit into the response -> just return the varbinds added so far */
487 request->error_status = SNMP_ERR_NOERROR;
488 }
489
490 return ERR_OK;
491 }
492
493 /**
494 * Service an internal or external event for SNMP SET.
495 *
496 * @param request points to the associated message process state
497 */
498 static err_t
snmp_process_set_request(struct snmp_request * request)499 snmp_process_set_request(struct snmp_request *request)
500 {
501 snmp_vb_enumerator_err_t err;
502 struct snmp_varbind vb;
503 vb.value = request->value_buffer;
504
505 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP set request\n"));
506
507 /* perform set test on all objects */
508 while (request->error_status == SNMP_ERR_NOERROR) {
509 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
510 if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
511 struct snmp_node_instance node_instance;
512 memset(&node_instance, 0, sizeof(node_instance));
513
514 request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
515 if (request->error_status == SNMP_ERR_NOERROR) {
516 if (node_instance.asn1_type != vb.type) {
517 request->error_status = SNMP_ERR_WRONGTYPE;
518 } else if (((node_instance.access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != SNMP_NODE_INSTANCE_ACCESS_WRITE) || (node_instance.set_value == NULL)) {
519 request->error_status = SNMP_ERR_NOTWRITABLE;
520 } else {
521 if (node_instance.set_test != NULL) {
522 request->error_status = node_instance.set_test(&node_instance, vb.value_len, vb.value);
523 }
524 }
525
526 if (node_instance.release_instance != NULL) {
527 node_instance.release_instance(&node_instance);
528 }
529 }
530 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
531 /* no more varbinds in request */
532 break;
533 } else if (err == SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH) {
534 request->error_status = SNMP_ERR_WRONGLENGTH;
535 } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
536 /* malformed ASN.1, don't answer */
537 return ERR_ARG;
538 } else {
539 request->error_status = SNMP_ERR_GENERROR;
540 }
541 }
542
543 /* perform real set operation on all objects */
544 if (request->error_status == SNMP_ERR_NOERROR) {
545 snmp_vb_enumerator_init(&request->inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
546 while (request->error_status == SNMP_ERR_NOERROR) {
547 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
548 if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
549 struct snmp_node_instance node_instance;
550 memset(&node_instance, 0, sizeof(node_instance));
551 request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
552 if (request->error_status == SNMP_ERR_NOERROR) {
553 if (node_instance.set_value(&node_instance, vb.value_len, vb.value) != SNMP_ERR_NOERROR) {
554 if (request->inbound_varbind_enumerator.varbind_count == 1) {
555 request->error_status = SNMP_ERR_COMMITFAILED;
556 } else {
557 /* we cannot undo the set operations done so far */
558 request->error_status = SNMP_ERR_UNDOFAILED;
559 }
560 }
561
562 if (node_instance.release_instance != NULL) {
563 node_instance.release_instance(&node_instance);
564 }
565 }
566 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
567 /* no more varbinds in request */
568 break;
569 } else {
570 /* first time enumerating varbinds work but second time not, although nothing should have changed in between ??? */
571 request->error_status = SNMP_ERR_GENERROR;
572 }
573 }
574 }
575
576 return ERR_OK;
577 }
578
579 #define PARSE_EXEC(code, retValue) \
580 if ((code) != ERR_OK) { \
581 LWIP_DEBUGF(SNMP_DEBUG, ("Malformed ASN.1 detected.\n")); \
582 snmp_stats.inasnparseerrs++; \
583 return retValue; \
584 }
585
586 #define PARSE_ASSERT(cond, retValue) \
587 if (!(cond)) { \
588 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP parse assertion failed!: " # cond)); \
589 snmp_stats.inasnparseerrs++; \
590 return retValue; \
591 }
592
593 #define BUILD_EXEC(code, retValue) \
594 if ((code) != ERR_OK) { \
595 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound frame!: " # code)); \
596 return retValue; \
597 }
598
599 #define IF_PARSE_EXEC(code) PARSE_EXEC(code, ERR_ARG)
600 #define IF_PARSE_ASSERT(code) PARSE_ASSERT(code, ERR_ARG)
601
602 /**
603 * Checks and decodes incoming SNMP message header, logs header errors.
604 *
605 * @param request points to the current message request state return
606 * @return
607 * - ERR_OK SNMP header is sane and accepted
608 * - ERR_VAL SNMP header is either malformed or rejected
609 */
610 static err_t
snmp_parse_inbound_frame(struct snmp_request * request)611 snmp_parse_inbound_frame(struct snmp_request *request)
612 {
613 struct snmp_pbuf_stream pbuf_stream;
614 struct snmp_asn1_tlv tlv;
615 s32_t parent_tlv_value_len;
616 s32_t s32_value;
617 err_t err;
618
619 IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
620
621 /* decode main container consisting of version, community and PDU */
622 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
623 IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length));
624 parent_tlv_value_len = tlv.value_len;
625
626 /* decode version */
627 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
628 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
629 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
630 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
631
632 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
633 if ((s32_value != SNMP_VERSION_1) &&
634 (s32_value != SNMP_VERSION_2c)
635 #if LWIP_SNMP_V3
636 && (s32_value != SNMP_VERSION_3)
637 #endif
638 )
639 {
640 /* unsupported SNMP version */
641 snmp_stats.inbadversions++;
642 return ERR_ARG;
643 }
644 request->version = (u8_t)s32_value;
645
646 #if LWIP_SNMP_V3
647 if (request->version == SNMP_VERSION_3) {
648 u16_t u16_value;
649 u16_t inbound_msgAuthenticationParameters_offset;
650
651 /* SNMPv3 doesn't use communities */
652 /* @todo: Differentiate read/write access */
653 strcpy((char*)request->community, snmp_community);
654 request->community_strlen = (u16_t)strlen(snmp_community);
655
656 /* RFC3414 globalData */
657 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
658 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
659 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
660 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
661
662 /* decode msgID */
663 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
664 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
665 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
666 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
667
668 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
669 request->msg_id = s32_value;
670
671 /* decode msgMaxSize */
672 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
673 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
674 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
675 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
676
677 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
678 request->msg_max_size = s32_value;
679
680 /* decode msgFlags */
681 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
682 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
683 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
684 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
685
686 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
687 request->msg_flags = (u8_t)s32_value;
688
689 /* decode msgSecurityModel */
690 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
691 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
692 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
693 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
694
695 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
696 request->msg_security_model = s32_value;
697
698 /* RFC3414 msgSecurityParameters
699 * The User-based Security Model defines the contents of the OCTET
700 * STRING as a SEQUENCE.
701 *
702 * We skip the protective dummy OCTET STRING header
703 * to access the SEQUENCE header.
704 */
705 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
706 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
707 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
708 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
709
710 /* msgSecurityParameters SEQUENCE header */
711 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
712 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
713 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
714 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
715
716 /* decode msgAuthoritativeEngineID */
717 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
718 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
719 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
720 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
721
722 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authoritative_engine_id,
723 &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
724 request->msg_authoritative_engine_id_len = (u8_t)u16_value;
725
726 /* msgAuthoritativeEngineBoots */
727 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
728 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
729 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
730 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
731 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_boots));
732
733 /* msgAuthoritativeEngineTime */
734 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
735 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
736 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
737 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
738 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_time));
739 /* @todo: Implement time window checking */
740
741 /* msgUserName */
742 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
743 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
744 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
745 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
746
747 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_user_name,
748 &u16_value, SNMP_V3_MAX_USER_LENGTH));
749 request->msg_user_name_len = (u8_t)u16_value;
750 /* @todo: Implement unknown user error response */
751 IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, NULL, NULL));
752
753 /* msgAuthenticationParameters */
754 memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
755 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
756 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
757 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
758 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
759 /* Remember position */
760 inbound_msgAuthenticationParameters_offset = pbuf_stream.offset;
761 LWIP_UNUSED_ARG(inbound_msgAuthenticationParameters_offset);
762 /* Read auth parameters */
763 IF_PARSE_ASSERT(tlv.value_len <= SNMP_V3_MAX_AUTH_PARAM_LENGTH);
764 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authentication_parameters,
765 &u16_value, tlv.value_len));
766
767 #if LWIP_SNMP_V3_CRYPTO
768 if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
769 const u8_t zero_arr[SNMP_V3_MAX_AUTH_PARAM_LENGTH] = { 0 };
770 u8_t key[20];
771 u8_t algo;
772 u8_t hmac[LWIP_MAX(SNMP_V3_SHA_LEN, SNMP_V3_MD5_LEN)];
773 struct snmp_pbuf_stream auth_stream;
774
775 /* Rewind stream */
776 IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
777 IF_PARSE_EXEC(snmp_pbuf_stream_seek_abs(&pbuf_stream, inbound_msgAuthenticationParameters_offset));
778 /* Set auth parameters to zero for verification */
779 IF_PARSE_EXEC(snmp_asn1_enc_raw(&pbuf_stream, zero_arr, tlv.value_len));
780
781 /* Verify authentication */
782 IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
783
784 IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, &algo, key, NULL, NULL));
785 IF_PARSE_EXEC(snmpv3_auth(&auth_stream, request->inbound_pbuf->tot_len, key, algo, hmac));
786 /* @todo: Implement error response */
787 IF_PARSE_EXEC(memcmp(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH));
788 }
789 #else
790 /* Ungraceful exit if we encounter cryptography and don't support it.
791 * @todo: Implement error response
792 */
793 IF_PARSE_ASSERT(!(request->msg_flags & (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG)));
794 #endif
795
796 /* msgPrivacyParameters */
797 memset(request->msg_privacy_parameters, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH);
798 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
799 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
800 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
801 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
802
803 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_privacy_parameters,
804 &u16_value, SNMP_V3_MAX_PRIV_PARAM_LENGTH));
805
806 #if LWIP_SNMP_V3_CRYPTO
807 /* Decrypt message */
808 if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
809 u8_t key[20];
810 u8_t algo;
811
812 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
813 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
814 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
815 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
816
817 IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, &algo, key));
818 IF_PARSE_EXEC(snmpv3_crypt(&pbuf_stream, tlv.value_len, key,
819 request->msg_privacy_parameters, request->msg_authoritative_engine_boots,
820 request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_DECRYPT));
821 }
822 #endif
823
824 /* Scoped PDU
825 * Encryption context
826 */
827 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
828 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
829 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
830 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
831
832 /* contextEngineID */
833 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
834 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
835 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
836 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
837
838 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_engine_id,
839 &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
840 request->context_engine_id_len = (u8_t)u16_value;
841
842 /* contextName */
843 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
844 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
845 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
846 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
847
848 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_name,
849 &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
850 request->context_name_len = (u8_t)u16_value;
851 } else
852 #endif
853 {
854 /* decode community */
855 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
856 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
857 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
858 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
859
860 err = snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->community, &request->community_strlen, SNMP_MAX_COMMUNITY_STR_LEN);
861 if (err == ERR_MEM) {
862 /* community string does not fit in our buffer -> its too long -> its invalid */
863 request->community_strlen = 0;
864 snmp_pbuf_stream_seek(&pbuf_stream, tlv.value_len);
865 } else {
866 IF_PARSE_ASSERT(err == ERR_OK);
867 }
868 /* add zero terminator */
869 request->community[request->community_strlen] = 0;
870 }
871
872 /* decode PDU type (next container level) */
873 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
874 IF_PARSE_ASSERT(tlv.value_len <= pbuf_stream.length);
875 request->inbound_padding_len = pbuf_stream.length - tlv.value_len;
876 parent_tlv_value_len = tlv.value_len;
877
878 /* validate PDU type */
879 switch(tlv.type) {
880 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_REQ):
881 /* GetRequest PDU */
882 snmp_stats.ingetrequests++;
883 break;
884 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ):
885 /* GetNextRequest PDU */
886 snmp_stats.ingetnexts++;
887 break;
888 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ):
889 /* GetBulkRequest PDU */
890 if (request->version < SNMP_VERSION_2c) {
891 /* RFC2089: invalid, drop packet */
892 return ERR_ARG;
893 }
894 break;
895 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_SET_REQ):
896 /* SetRequest PDU */
897 snmp_stats.insetrequests++;
898 break;
899 default:
900 /* unsupported input PDU for this agent (no parse error) */
901 LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d", tlv.type)); \
902 return ERR_ARG;
903 break;
904 }
905 request->request_type = tlv.type & SNMP_ASN1_DATATYPE_MASK;
906
907 /* validate community (do this after decoding PDU type because we don't want to increase 'inbadcommunitynames' for wrong frame types */
908 if (request->community_strlen == 0) {
909 /* community string was too long or really empty*/
910 snmp_stats.inbadcommunitynames++;
911 snmp_authfail_trap();
912 return ERR_ARG;
913 } else if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
914 if (snmp_community_write[0] == 0) {
915 /* our write community is empty, that means all our objects are readonly */
916 request->error_status = SNMP_ERR_NOTWRITABLE;
917 request->error_index = 1;
918 } else if (strncmp(snmp_community_write, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
919 /* community name does not match */
920 snmp_stats.inbadcommunitynames++;
921 snmp_authfail_trap();
922 return ERR_ARG;
923 }
924 } else {
925 if (strncmp(snmp_community, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
926 /* community name does not match */
927 snmp_stats.inbadcommunitynames++;
928 snmp_authfail_trap();
929 return ERR_ARG;
930 }
931 }
932
933 /* decode request ID */
934 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
935 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
936 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
937 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
938
939 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->request_id));
940
941 /* decode error status / non-repeaters */
942 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
943 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
944 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
945 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
946
947 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
948 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->non_repeaters));
949 if (request->non_repeaters < 0) {
950 /* RFC 1905, 4.2.3 */
951 request->non_repeaters = 0;
952 }
953 } else {
954 /* only check valid value, don't touch 'request->error_status', maybe a response error status was already set to above; */
955 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
956 IF_PARSE_ASSERT(s32_value == SNMP_ERR_NOERROR);
957 }
958
959 /* decode error index / max-repetitions */
960 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
961 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
962 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
963 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
964
965 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
966 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->max_repetitions));
967 if (request->max_repetitions < 0) {
968 /* RFC 1905, 4.2.3 */
969 request->max_repetitions = 0;
970 }
971 } else {
972 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->error_index));
973 IF_PARSE_ASSERT(s32_value == 0);
974 }
975
976 /* decode varbind-list type (next container level) */
977 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
978 IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= pbuf_stream.length));
979
980 request->inbound_varbind_offset = pbuf_stream.offset;
981 request->inbound_varbind_len = pbuf_stream.length - request->inbound_padding_len;
982 snmp_vb_enumerator_init(&(request->inbound_varbind_enumerator), request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
983
984 return ERR_OK;
985 }
986
987 #define OF_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG)
988
989 static err_t
snmp_prepare_outbound_frame(struct snmp_request * request)990 snmp_prepare_outbound_frame(struct snmp_request *request)
991 {
992 struct snmp_asn1_tlv tlv;
993 struct snmp_pbuf_stream* pbuf_stream = &(request->outbound_pbuf_stream);
994
995 /* try allocating pbuf(s) for maximum response size */
996 request->outbound_pbuf = pbuf_alloc(PBUF_TRANSPORT, 1472, PBUF_RAM);
997 if (request->outbound_pbuf == NULL) {
998 return ERR_MEM;
999 }
1000
1001 snmp_pbuf_stream_init(pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len);
1002
1003 /* 'Message' sequence */
1004 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
1005 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1006
1007 /* version */
1008 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
1009 snmp_asn1_enc_s32t_cnt(request->version, &tlv.value_len);
1010 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1011 OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->version) );
1012
1013 #if LWIP_SNMP_V3
1014 if (request->version < SNMP_VERSION_3) {
1015 #endif
1016 /* community */
1017 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->community_strlen);
1018 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1019 OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) );
1020 #if LWIP_SNMP_V3
1021 } else {
1022 const char* id;
1023
1024 /* globalData */
1025 request->outbound_msg_global_data_offset = pbuf_stream->offset;
1026 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0);
1027 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1028
1029 /* msgID */
1030 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1031 snmp_asn1_enc_s32t_cnt(request->msg_id, &tlv.value_len);
1032 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1033 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_id));
1034
1035 /* msgMaxSize */
1036 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1037 snmp_asn1_enc_s32t_cnt(request->msg_max_size, &tlv.value_len);
1038 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1039 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_max_size));
1040
1041 /* msgFlags */
1042 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 1);
1043 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1044 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, &request->msg_flags, 1));
1045
1046 /* msgSecurityModel */
1047 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1048 snmp_asn1_enc_s32t_cnt(request->msg_security_model, &tlv.value_len);
1049 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1050 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_security_model));
1051
1052 /* end of msgGlobalData */
1053 request->outbound_msg_global_data_end = pbuf_stream->offset;
1054
1055 /* msgSecurityParameters */
1056 request->outbound_msg_security_parameters_str_offset = pbuf_stream->offset;
1057 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, 0);
1058 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1059
1060 request->outbound_msg_security_parameters_seq_offset = pbuf_stream->offset;
1061 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0);
1062 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1063
1064 /* msgAuthoritativeEngineID */
1065 snmpv3_get_engine_id(&id, &request->msg_authoritative_engine_id_len);
1066 MEMCPY(request->msg_authoritative_engine_id, id, request->msg_authoritative_engine_id_len);
1067 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_authoritative_engine_id_len);
1068 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1069 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authoritative_engine_id, request->msg_authoritative_engine_id_len));
1070
1071 request->msg_authoritative_engine_time = snmpv3_get_engine_time();
1072 request->msg_authoritative_engine_boots = snmpv3_get_engine_boots();
1073
1074 /* msgAuthoritativeEngineBoots */
1075 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
1076 snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_boots, &tlv.value_len);
1077 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1078 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_boots));
1079
1080 /* msgAuthoritativeEngineTime */
1081 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
1082 snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_time, &tlv.value_len);
1083 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1084 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_time));
1085
1086 /* msgUserName */
1087 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_user_name_len);
1088 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1089 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_user_name, request->msg_user_name_len));
1090
1091 #if LWIP_SNMP_V3_CRYPTO
1092 /* msgAuthenticationParameters */
1093 if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
1094 memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
1095 request->outbound_msg_authentication_parameters_offset = pbuf_stream->offset;
1096 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
1097 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1098 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH));
1099 } else
1100 #endif
1101 {
1102 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0);
1103 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1104 }
1105
1106 #if LWIP_SNMP_V3_CRYPTO
1107 /* msgPrivacyParameters */
1108 if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
1109 snmpv3_build_priv_param(request->msg_privacy_parameters);
1110
1111 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH);
1112 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1113 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_privacy_parameters, SNMP_V3_MAX_PRIV_PARAM_LENGTH));
1114 } else
1115 #endif
1116 {
1117 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0);
1118 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1119 }
1120
1121 /* End of msgSecurityParameters, so we can calculate the length of this sequence later */
1122 request->outbound_msg_security_parameters_end = pbuf_stream->offset;
1123
1124 #if LWIP_SNMP_V3_CRYPTO
1125 /* For encryption we have to encapsulate the payload in an octet string */
1126 if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
1127 request->outbound_scoped_pdu_string_offset = pbuf_stream->offset;
1128 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, 0);
1129 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1130 }
1131 #endif
1132 /* Scoped PDU
1133 * Encryption context
1134 */
1135 request->outbound_scoped_pdu_seq_offset = pbuf_stream->offset;
1136 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
1137 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1138
1139 /* contextEngineID */
1140 snmpv3_get_engine_id(&id, &request->context_engine_id_len);
1141 MEMCPY(request->context_engine_id, id, request->context_engine_id_len);
1142 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_engine_id_len);
1143 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1144 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_engine_id, request->context_engine_id_len));
1145
1146 /* contextName */
1147 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_name_len);
1148 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1149 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_name, request->context_name_len));
1150 }
1151 #endif
1152
1153 /* 'PDU' sequence */
1154 request->outbound_pdu_offset = pbuf_stream->offset;
1155 SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, 0);
1156 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1157
1158 /* request ID */
1159 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
1160 snmp_asn1_enc_s32t_cnt(request->request_id, &tlv.value_len);
1161 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1162 OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->request_id) );
1163
1164 /* error status */
1165 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1166 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1167 request->outbound_error_status_offset = pbuf_stream->offset;
1168 OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) );
1169
1170 /* error index */
1171 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1172 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1173 request->outbound_error_index_offset = pbuf_stream->offset;
1174 OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) );
1175
1176 /* 'VarBindList' sequence */
1177 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
1178 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1179
1180 request->outbound_varbind_offset = pbuf_stream->offset;
1181
1182 return ERR_OK;
1183 }
1184
1185 /** Calculate the length of a varbind list */
1186 err_t
snmp_varbind_length(struct snmp_varbind * varbind,struct snmp_varbind_len * len)1187 snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len)
1188 {
1189 /* calculate required lengths */
1190 snmp_asn1_enc_oid_cnt(varbind->oid.id, varbind->oid.len, &len->oid_value_len);
1191 snmp_asn1_enc_length_cnt(len->oid_value_len, &len->oid_len_len);
1192
1193 if (varbind->value_len == 0) {
1194 len->value_value_len = 0;
1195 } else if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) {
1196 len->value_value_len = varbind->value_len & (~SNMP_GET_VALUE_RAW_DATA);
1197 } else {
1198 switch (varbind->type) {
1199 case SNMP_ASN1_TYPE_INTEGER:
1200 if (varbind->value_len != sizeof (s32_t)) {
1201 return ERR_VAL;
1202 }
1203 snmp_asn1_enc_s32t_cnt(*((s32_t*) varbind->value), &len->value_value_len);
1204 break;
1205 case SNMP_ASN1_TYPE_COUNTER:
1206 case SNMP_ASN1_TYPE_GAUGE:
1207 case SNMP_ASN1_TYPE_TIMETICKS:
1208 if (varbind->value_len != sizeof (u32_t)) {
1209 return ERR_VAL;
1210 }
1211 snmp_asn1_enc_u32t_cnt(*((u32_t*) varbind->value), &len->value_value_len);
1212 break;
1213 case SNMP_ASN1_TYPE_OCTET_STRING:
1214 case SNMP_ASN1_TYPE_IPADDR:
1215 case SNMP_ASN1_TYPE_OPAQUE:
1216 len->value_value_len = varbind->value_len;
1217 break;
1218 case SNMP_ASN1_TYPE_NULL:
1219 if (varbind->value_len != 0) {
1220 return ERR_VAL;
1221 }
1222 len->value_value_len = 0;
1223 break;
1224 case SNMP_ASN1_TYPE_OBJECT_ID:
1225 if ((varbind->value_len & 0x03) != 0) {
1226 return ERR_VAL;
1227 }
1228 snmp_asn1_enc_oid_cnt((u32_t*) varbind->value, varbind->value_len >> 2, &len->value_value_len);
1229 break;
1230 case SNMP_ASN1_TYPE_COUNTER64:
1231 if (varbind->value_len != (2 * sizeof (u32_t))) {
1232 return ERR_VAL;
1233 }
1234 snmp_asn1_enc_u64t_cnt((u32_t*) varbind->value, &len->value_value_len);
1235 break;
1236 default:
1237 /* unsupported type */
1238 return ERR_VAL;
1239 }
1240 }
1241 snmp_asn1_enc_length_cnt(len->value_value_len, &len->value_len_len);
1242
1243 len->vb_value_len = 1 + len->oid_len_len + len->oid_value_len + 1 + len->value_len_len + len->value_value_len;
1244 snmp_asn1_enc_length_cnt(len->vb_value_len, &len->vb_len_len);
1245
1246 return ERR_OK;
1247 }
1248
1249 #define OVB_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG)
1250
1251 err_t
snmp_append_outbound_varbind(struct snmp_pbuf_stream * pbuf_stream,struct snmp_varbind * varbind)1252 snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind* varbind)
1253 {
1254 struct snmp_asn1_tlv tlv;
1255 struct snmp_varbind_len len;
1256 err_t err;
1257
1258 err = snmp_varbind_length(varbind, &len);
1259
1260 if (err != ERR_OK) {
1261 return err;
1262 }
1263
1264 /* check length already before adding first data because in case of GetBulk,
1265 * data added so far is returned and therefore no partial data shall be added
1266 */
1267 if ((1 + len.vb_len_len + len.vb_value_len) > pbuf_stream->length) {
1268 return ERR_BUF;
1269 }
1270
1271 /* 'VarBind' sequence */
1272 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, len.vb_len_len, len.vb_value_len);
1273 OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1274
1275 /* VarBind OID */
1276 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, len.oid_len_len, len.oid_value_len);
1277 OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1278 OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, varbind->oid.id, varbind->oid.len));
1279
1280 /* VarBind value */
1281 SNMP_ASN1_SET_TLV_PARAMS(tlv, varbind->type, len.value_len_len, len.value_value_len);
1282 OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1283
1284 if (len.value_value_len > 0) {
1285 if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) {
1286 OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len));
1287 } else {
1288 switch (varbind->type) {
1289 case SNMP_ASN1_TYPE_INTEGER:
1290 OVB_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, len.value_value_len, *((s32_t*) varbind->value)));
1291 break;
1292 case SNMP_ASN1_TYPE_COUNTER:
1293 case SNMP_ASN1_TYPE_GAUGE:
1294 case SNMP_ASN1_TYPE_TIMETICKS:
1295 OVB_BUILD_EXEC(snmp_asn1_enc_u32t(pbuf_stream, len.value_value_len, *((u32_t*) varbind->value)));
1296 break;
1297 case SNMP_ASN1_TYPE_OCTET_STRING:
1298 case SNMP_ASN1_TYPE_IPADDR:
1299 case SNMP_ASN1_TYPE_OPAQUE:
1300 OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len));
1301 len.value_value_len = varbind->value_len;
1302 break;
1303 case SNMP_ASN1_TYPE_OBJECT_ID:
1304 OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, (u32_t*) varbind->value, varbind->value_len / sizeof (u32_t)));
1305 break;
1306 case SNMP_ASN1_TYPE_COUNTER64:
1307 OVB_BUILD_EXEC(snmp_asn1_enc_u64t(pbuf_stream, len.value_value_len, (u32_t*) varbind->value));
1308 break;
1309 default:
1310 LWIP_ASSERT("Unknown variable type", 0);
1311 break;
1312 }
1313 }
1314 }
1315
1316 return ERR_OK;
1317 }
1318
1319 static err_t
snmp_complete_outbound_frame(struct snmp_request * request)1320 snmp_complete_outbound_frame(struct snmp_request *request)
1321 {
1322 struct snmp_asn1_tlv tlv;
1323 u16_t frame_size;
1324 u8_t outbound_padding = 0;
1325
1326 if (request->version == SNMP_VERSION_1) {
1327 if (request->error_status != SNMP_ERR_NOERROR) {
1328 /* map v2c error codes to v1 compliant error code (according to RFC 2089) */
1329 switch (request->error_status) {
1330 /* mapping of implementation specific "virtual" error codes
1331 * (during processing of frame we already stored them in error_status field,
1332 * so no need to check all varbinds here for those exceptions as suggested by RFC) */
1333 case SNMP_ERR_NOSUCHINSTANCE:
1334 case SNMP_ERR_NOSUCHOBJECT:
1335 case SNMP_ERR_ENDOFMIBVIEW:
1336 request->error_status = SNMP_ERR_NOSUCHNAME;
1337 break;
1338 /* mapping according to RFC */
1339 case SNMP_ERR_WRONGVALUE:
1340 case SNMP_ERR_WRONGENCODING:
1341 case SNMP_ERR_WRONGTYPE:
1342 case SNMP_ERR_WRONGLENGTH:
1343 case SNMP_ERR_INCONSISTENTVALUE:
1344 request->error_status = SNMP_ERR_BADVALUE;
1345 break;
1346 case SNMP_ERR_NOACCESS:
1347 case SNMP_ERR_NOTWRITABLE:
1348 case SNMP_ERR_NOCREATION:
1349 case SNMP_ERR_INCONSISTENTNAME:
1350 case SNMP_ERR_AUTHORIZATIONERROR:
1351 request->error_status = SNMP_ERR_NOSUCHNAME;
1352 break;
1353 case SNMP_ERR_RESOURCEUNAVAILABLE:
1354 case SNMP_ERR_COMMITFAILED:
1355 case SNMP_ERR_UNDOFAILED:
1356 default:
1357 request->error_status = SNMP_ERR_GENERROR;
1358 break;
1359 }
1360 }
1361 } else {
1362 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
1363 /* map error codes to according to RFC 1905 (4.2.5. The SetRequest-PDU) return 'NotWritable' for unknown OIDs) */
1364 switch (request->error_status) {
1365 case SNMP_ERR_NOSUCHINSTANCE:
1366 case SNMP_ERR_NOSUCHOBJECT:
1367 case SNMP_ERR_ENDOFMIBVIEW:
1368 request->error_status = SNMP_ERR_NOTWRITABLE;
1369 break;
1370 default:
1371 break;
1372 }
1373 }
1374
1375 if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
1376 /* should never occur because v2 frames store exceptions directly inside varbinds and not as frame error_status */
1377 LWIP_DEBUGF(SNMP_DEBUG, ("snmp_complete_outbound_frame() > Found v2 request with varbind exception code stored as error status!\n"));
1378 return ERR_ARG;
1379 }
1380 }
1381
1382 if ((request->error_status != SNMP_ERR_NOERROR) || (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)) {
1383 /* all inbound vars are returned in response without any modification for error responses and successful set requests*/
1384 struct snmp_pbuf_stream inbound_stream;
1385 OF_BUILD_EXEC( snmp_pbuf_stream_init(&inbound_stream, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len) );
1386 OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, request->outbound_varbind_offset, request->outbound_pbuf->tot_len - request->outbound_varbind_offset) );
1387 snmp_pbuf_stream_writeto(&inbound_stream, &(request->outbound_pbuf_stream), 0);
1388 }
1389
1390 frame_size = request->outbound_pbuf_stream.offset;
1391
1392 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO
1393 /* Calculate padding for encryption */
1394 if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
1395 u8_t i;
1396 outbound_padding = (8 - (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x07)) & 0x07;
1397 for (i = 0; i < outbound_padding; i++) {
1398 snmp_pbuf_stream_write(&request->outbound_pbuf_stream, 0);
1399 }
1400 }
1401 #endif
1402
1403 /* complete missing length in 'Message' sequence ; 'Message' tlv is located at the beginning (offset 0) */
1404 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size + outbound_padding - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
1405 OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, 0, request->outbound_pbuf->tot_len) );
1406 OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
1407
1408 #if LWIP_SNMP_V3
1409 if (request->version == SNMP_VERSION_3) {
1410 /* complete missing length in 'globalData' sequence */
1411 /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
1412 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_global_data_end
1413 - request->outbound_msg_global_data_offset - 1 - 1);
1414 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_global_data_offset));
1415 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1416
1417 /* complete missing length in 'msgSecurityParameters' sequence */
1418 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, request->outbound_msg_security_parameters_end
1419 - request->outbound_msg_security_parameters_str_offset - 1 - 1);
1420 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_str_offset));
1421 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1422
1423 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_security_parameters_end
1424 - request->outbound_msg_security_parameters_seq_offset - 1 - 1);
1425 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_seq_offset));
1426 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1427
1428 /* complete missing length in scoped PDU sequence */
1429 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_scoped_pdu_seq_offset - 1 - 3);
1430 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_seq_offset));
1431 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1432 }
1433 #endif
1434
1435 /* complete missing length in 'PDU' sequence */
1436 SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3,
1437 frame_size - request->outbound_pdu_offset - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
1438 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_pdu_offset) );
1439 OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
1440
1441 /* process and encode final error status */
1442 if (request->error_status != 0) {
1443 u16_t len;
1444 snmp_asn1_enc_s32t_cnt(request->error_status, &len);
1445 if (len != 1) {
1446 /* error, we only reserved one byte for it */
1447 return ERR_ARG;
1448 }
1449 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_status_offset) );
1450 OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_status) );
1451
1452 /* for compatibility to v1, log statistics; in v2 (RFC 1907) these statistics are obsoleted */
1453 switch (request->error_status) {
1454 case SNMP_ERR_TOOBIG:
1455 snmp_stats.outtoobigs++;
1456 break;
1457 case SNMP_ERR_NOSUCHNAME:
1458 snmp_stats.outnosuchnames++;
1459 break;
1460 case SNMP_ERR_BADVALUE:
1461 snmp_stats.outbadvalues++;
1462 break;
1463 case SNMP_ERR_GENERROR:
1464 default:
1465 snmp_stats.outgenerrs++;
1466 break;
1467 }
1468
1469 if (request->error_status == SNMP_ERR_TOOBIG) {
1470 request->error_index = 0; /* defined by RFC 1157 */
1471 } else if (request->error_index == 0) {
1472 /* set index to varbind where error occured (if not already set before, e.g. during GetBulk processing) */
1473 request->error_index = request->inbound_varbind_enumerator.varbind_count;
1474 }
1475 } else {
1476 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
1477 snmp_stats.intotalsetvars += request->inbound_varbind_enumerator.varbind_count;
1478 } else {
1479 snmp_stats.intotalreqvars += request->inbound_varbind_enumerator.varbind_count;
1480 }
1481 }
1482
1483 /* encode final error index*/
1484 if (request->error_index != 0) {
1485 u16_t len;
1486 snmp_asn1_enc_s32t_cnt(request->error_index, &len);
1487 if (len != 1) {
1488 /* error, we only reserved one byte for it */
1489 return ERR_VAL;
1490 }
1491 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_index_offset) );
1492 OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_index) );
1493 }
1494
1495 /* complete missing length in 'VarBindList' sequence ; 'VarBindList' tlv is located directly before varbind offset */
1496 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_varbind_offset);
1497 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_varbind_offset - 1 - 3) ); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
1498 OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
1499
1500 /* Authenticate response */
1501 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO
1502 /* Encrypt response */
1503 if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
1504 u8_t key[20];
1505 u8_t algo;
1506
1507 /* complete missing length in PDU sequence */
1508 OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
1509 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_string_offset));
1510 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, frame_size + outbound_padding
1511 - request->outbound_scoped_pdu_string_offset - 1 - 3);
1512 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1513
1514 OF_BUILD_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, &algo, key));
1515
1516 OF_BUILD_EXEC(snmpv3_crypt(&request->outbound_pbuf_stream, tlv.value_len, key,
1517 request->msg_privacy_parameters, request->msg_authoritative_engine_boots,
1518 request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_ENCRYPT));
1519 }
1520
1521 if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_AUTH_FLAG)) {
1522 u8_t key[20];
1523 u8_t algo;
1524 u8_t hmac[20];
1525
1526 OF_BUILD_EXEC(snmpv3_get_user((char*)request->msg_user_name, &algo, key, NULL, NULL));
1527 OF_BUILD_EXEC(snmp_pbuf_stream_init(&(request->outbound_pbuf_stream),
1528 request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
1529 OF_BUILD_EXEC(snmpv3_auth(&request->outbound_pbuf_stream, frame_size + outbound_padding, key, algo, hmac));
1530
1531 MEMCPY(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
1532 OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream,
1533 request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
1534 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&request->outbound_pbuf_stream,
1535 request->outbound_msg_authentication_parameters_offset));
1536
1537 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
1538 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&request->outbound_pbuf_stream, &tlv));
1539 OF_BUILD_EXEC(snmp_asn1_enc_raw(&request->outbound_pbuf_stream,
1540 request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH));
1541 }
1542 #endif
1543
1544 pbuf_realloc(request->outbound_pbuf, frame_size + outbound_padding);
1545
1546 snmp_stats.outgetresponses++;
1547 snmp_stats.outpkts++;
1548
1549 return ERR_OK;
1550 }
1551
1552 static void
snmp_execute_write_callbacks(struct snmp_request * request)1553 snmp_execute_write_callbacks(struct snmp_request *request)
1554 {
1555 struct snmp_varbind_enumerator inbound_varbind_enumerator;
1556 struct snmp_varbind vb;
1557
1558 snmp_vb_enumerator_init(&inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
1559 vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned, which we don't need here) */
1560
1561 while (snmp_vb_enumerator_get_next(&inbound_varbind_enumerator, &vb) == SNMP_VB_ENUMERATOR_ERR_OK) {
1562 snmp_write_callback(vb.oid.id, vb.oid.len, snmp_write_callback_arg);
1563 }
1564 }
1565
1566
1567 /* ----------------------------------------------------------------------- */
1568 /* VarBind enumerator methods */
1569 /* ----------------------------------------------------------------------- */
1570
1571 void
snmp_vb_enumerator_init(struct snmp_varbind_enumerator * enumerator,struct pbuf * p,u16_t offset,u16_t length)1572 snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length)
1573 {
1574 snmp_pbuf_stream_init(&(enumerator->pbuf_stream), p, offset, length);
1575 enumerator->varbind_count = 0;
1576 }
1577
1578 #define VB_PARSE_EXEC(code) PARSE_EXEC(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR)
1579 #define VB_PARSE_ASSERT(code) PARSE_ASSERT(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR)
1580
1581 snmp_vb_enumerator_err_t
snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator * enumerator,struct snmp_varbind * varbind)1582 snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind)
1583 {
1584 struct snmp_asn1_tlv tlv;
1585 u16_t varbind_len;
1586 err_t err;
1587
1588 if (enumerator->pbuf_stream.length == 0)
1589 {
1590 return SNMP_VB_ENUMERATOR_ERR_EOVB;
1591 }
1592 enumerator->varbind_count++;
1593
1594 /* decode varbind itself (parent container of a varbind) */
1595 VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
1596 VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= enumerator->pbuf_stream.length));
1597 varbind_len = tlv.value_len;
1598
1599 /* decode varbind name (object id) */
1600 VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
1601 VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_OBJECT_ID) && (SNMP_ASN1_TLV_LENGTH(tlv) < varbind_len) && (tlv.value_len < enumerator->pbuf_stream.length));
1602
1603 VB_PARSE_EXEC(snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, varbind->oid.id, &(varbind->oid.len), SNMP_MAX_OBJ_ID_LEN));
1604 varbind_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1605
1606 /* decode varbind value (object id) */
1607 VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
1608 VB_PARSE_ASSERT((SNMP_ASN1_TLV_LENGTH(tlv) == varbind_len) && (tlv.value_len <= enumerator->pbuf_stream.length));
1609 varbind->type = tlv.type;
1610
1611 /* shall the value be decoded ? */
1612 if (varbind->value != NULL) {
1613 switch (varbind->type) {
1614 case SNMP_ASN1_TYPE_INTEGER:
1615 VB_PARSE_EXEC(snmp_asn1_dec_s32t(&(enumerator->pbuf_stream), tlv.value_len, (s32_t*)varbind->value));
1616 varbind->value_len = sizeof(s32_t*);
1617 break;
1618 case SNMP_ASN1_TYPE_COUNTER:
1619 case SNMP_ASN1_TYPE_GAUGE:
1620 case SNMP_ASN1_TYPE_TIMETICKS:
1621 VB_PARSE_EXEC(snmp_asn1_dec_u32t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value));
1622 varbind->value_len = sizeof(u32_t*);
1623 break;
1624 case SNMP_ASN1_TYPE_OCTET_STRING:
1625 case SNMP_ASN1_TYPE_OPAQUE:
1626 err = snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE);
1627 if (err == ERR_MEM) {
1628 return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
1629 }
1630 VB_PARSE_ASSERT(err == ERR_OK);
1631 break;
1632 case SNMP_ASN1_TYPE_NULL:
1633 varbind->value_len = 0;
1634 break;
1635 case SNMP_ASN1_TYPE_OBJECT_ID:
1636 /* misuse tlv.length_len as OID_length transporter */
1637 err = snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value, &tlv.length_len, SNMP_MAX_OBJ_ID_LEN);
1638 if (err == ERR_MEM) {
1639 return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
1640 }
1641 VB_PARSE_ASSERT(err == ERR_OK);
1642 varbind->value_len = tlv.length_len * sizeof(u32_t);
1643 break;
1644 case SNMP_ASN1_TYPE_IPADDR:
1645 if (tlv.value_len == 4) {
1646 /* must be exactly 4 octets! */
1647 VB_PARSE_EXEC(snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE));
1648 } else {
1649 VB_PARSE_ASSERT(0);
1650 }
1651 break;
1652 case SNMP_ASN1_TYPE_COUNTER64:
1653 VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value));
1654 varbind->value_len = 2 * sizeof(u32_t*);
1655 break;
1656 default:
1657 VB_PARSE_ASSERT(0);
1658 break;
1659 }
1660 } else {
1661 snmp_pbuf_stream_seek(&(enumerator->pbuf_stream), tlv.value_len);
1662 varbind->value_len = tlv.value_len;
1663 }
1664
1665 return SNMP_VB_ENUMERATOR_ERR_OK;
1666 }
1667
1668 #endif /* LWIP_SNMP */
1669