snmp_pdu.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/*
10 * SNMP PDU Encoding
11 *
12 * Complies with:
13 *
14 * RFC 1902: Structure of Management Information for SNMPv2
15 *
16 */
17
18/**********************************************************************
19 *
20 * Copyright 1997 by Carnegie Mellon University
21 *
22 * All Rights Reserved
23 *
24 * Permission to use, copy, modify, and distribute this software and its
25 * documentation for any purpose and without fee is hereby granted,
26 * provided that the above copyright notice appear in all copies and that
27 * both that copyright notice and this permission notice appear in
28 * supporting documentation, and that the name of CMU not be
29 * used in advertising or publicity pertaining to distribution of the
30 * software without specific, written prior permission.
31 *
32 * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
33 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
34 * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
35 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
36 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
37 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
38 * SOFTWARE.
39 *
40 * Author: Ryan Troll <ryan+@andrew.cmu.edu>
41 *
42 **********************************************************************/
43
44#include "squid.h"
45
46#if HAVE_UNISTD_H
47#include <unistd.h>
48#endif
49#if HAVE_STDLIB_H
50#include <stdlib.h>
51#endif
52#if HAVE_SYS_TYPES_H
53#include <sys/types.h>
54#endif
55#if HAVE_CTYPE_H
56#include <ctype.h>
57#endif
58#if HAVE_GNUMALLOC_H
59#include <gnumalloc.h>
60#elif HAVE_MALLOC_H
61#include <malloc.h>
62#endif
63#if HAVE_MEMORY_H
64#include <memory.h>
65#endif
66#if HAVE_STRING_H
67#include <string.h>
68#endif
69#if HAVE_STRINGS_H
70#include <strings.h>
71#endif
72#if HAVE_BSTRING_H
73#include <bstring.h>
74#endif
75#if HAVE_SYS_SOCKET_H
76#include <sys/socket.h>
77#endif
78#if HAVE_NETINET_IN_H
79#include <netinet/in.h>
80#endif
81#if HAVE_ARPA_INET_H
82#include <arpa/inet.h>
83#endif
84#if HAVE_SYS_TIME_H
85#include <sys/time.h>
86#endif
87#if HAVE_NETDB_H
88#include <netdb.h>
89#endif
90
91#include "asn1.h"
92#include "snmp.h"
93#include "snmp_api_error.h"
94#include "snmp_error.h"
95#include "snmp_msg.h"
96#include "snmp_pdu.h"
97#include "snmp_vars.h"
98
99#include "util.h"
100
101/* #define DEBUG_PDU 1 */
102/* #define DEBUG_PDU_DECODE 1 */
103/* #define DEBUG_PDU_ENCODE 1 */
104
105#define ASN_PARSE_ERROR(x) { return(x); }
106
107/**********************************************************************/
108
109/* Create a PDU.
110 */
111
112struct snmp_pdu *
114 struct snmp_pdu *pdu;
115
116#if DEBUG_PDU
117 snmplib_debug(8, "PDU: Creating\n");
118#endif
119
120 pdu = (struct snmp_pdu *) xmalloc(sizeof(struct snmp_pdu));
121 if (pdu == NULL) {
123 return (NULL);
124 }
125 memset((char *) pdu, '\0', sizeof(struct snmp_pdu));
126
127 pdu->command = command;
130 pdu->address.sin_addr.s_addr = SNMP_DEFAULT_ADDRESS;
131 pdu->enterprise = NULL;
132 pdu->enterprise_length = 0;
133 pdu->variables = NULL;
134
135#if DEBUG_PDU
136 snmplib_debug(8, "PDU: Created %x\n", (unsigned int) pdu);
137#endif
138
139 return (pdu);
140}
141
142/**********************************************************************/
143
144/* Clone an existing PDU.
145 */
146struct snmp_pdu *
148 struct snmp_pdu *Dest;
149
150#if DEBUG_PDU
151 snmplib_debug(8, "PDU %x: Cloning\n", (unsigned int) Src);
152#endif
153
154 Dest = (struct snmp_pdu *) xmalloc(sizeof(struct snmp_pdu));
155 if (Dest == NULL) {
157 return (NULL);
158 }
159 memcpy((char *) Dest, (char *) Src, sizeof(struct snmp_pdu));
160
161#if DEBUG_PDU
162 snmplib_debug(8, "PDU %x: Created %x\n", (unsigned int) Src, (unsigned int) Dest);
163#endif
164 return (Dest);
165}
166
167/**********************************************************************/
168
169/*
170 * If there was an error in the input pdu, creates a clone of the pdu
171 * that includes all the variables except the one marked by the errindex.
172 * The command is set to the input command and the reqid, errstat, and
173 * errindex are set to default values.
174 * If the error status didn't indicate an error, the error index didn't
175 * indicate a variable, the pdu wasn't a get response message, or there
176 * would be no remaining variables, this function will return NULL.
177 * If everything was successful, a pointer to the fixed cloned pdu will
178 * be returned.
179 */
180struct snmp_pdu *
181snmp_pdu_fix(struct snmp_pdu *pdu, int command) {
182 return (snmp_fix_pdu(pdu, command));
183}
184
185struct snmp_pdu *
186snmp_fix_pdu(struct snmp_pdu *pdu, int command) {
187 struct variable_list *var, *newvar;
188 struct snmp_pdu *newpdu;
189 int i;
190 int copied = 0;
191
192#if DEBUG_PDU
193 snmplib_debug(8, "PDU %x: Fixing. Err index is %d\n",
194 (unsigned int) pdu, (unsigned int) pdu->errindex);
195#endif
196
197 if (pdu->command != SNMP_PDU_RESPONSE ||
198 pdu->errstat == SNMP_ERR_NOERROR ||
199 pdu->errindex <= 0) {
201 return (NULL);
202 }
203 /* clone the pdu */
204 newpdu = snmp_pdu_clone(pdu);
205 if (newpdu == NULL)
206 return (NULL);
207
208 newpdu->variables = 0;
209 newpdu->command = command;
210 newpdu->reqid = SNMP_DEFAULT_REQID;
213
214 /* Loop through the variables, removing whatever isn't necessary */
215
216 var = pdu->variables;
217 i = 1;
218
219 /* skip first variable if necessary */
220 if (pdu->errindex == i) {
221 var = var->next_variable;
222 i++;
223 }
224 if (var != NULL) {
225
226 /* VAR is the first uncopied variable */
227
228 /* Clone this variable */
229 newpdu->variables = snmp_var_clone(var);
230 if (newpdu->variables == NULL) {
231 snmp_pdu_free(newpdu);
232 return (NULL);
233 }
234 copied++;
235
236 newvar = newpdu->variables;
237
238 /* VAR has been copied to NEWVAR. */
239 while (var->next_variable) {
240
241 /* Skip the item that was bad */
242 if (++i == pdu->errindex) {
243 var = var->next_variable;
244 continue;
245 }
246 /* Copy this var */
248 if (newvar->next_variable == NULL) {
249 snmp_pdu_free(newpdu);
250 return (NULL);
251 }
252 /* Move to the next one */
253 newvar = newvar->next_variable;
254 var = var->next_variable;
255 copied++;
256 }
257 newvar->next_variable = NULL;
258 }
259 /* If we didn't copy anything, free the new pdu. */
260 if (i < pdu->errindex || copied == 0) {
261 snmp_free_pdu(newpdu);
263 return (NULL);
264 }
265#if DEBUG_PDU
266 snmplib_debug(8, "PDU %x: Fixed PDU is %x\n",
267 (unsigned int) pdu, (unsigned int) newpdu);
268#endif
269 return (newpdu);
270}
271
272/**********************************************************************/
273
274void
276{
277 snmp_free_pdu(pdu);
278}
279
280/*
281 * Frees the pdu and any xmalloc'd data associated with it.
282 */
283void
285{
286 struct variable_list *vp, *ovp;
287
288 vp = pdu->variables;
289 while (vp) {
290 ovp = vp;
291 vp = vp->next_variable;
292 snmp_var_free(ovp);
293 }
294
295 if (pdu->enterprise)
296 xfree((char *) pdu->enterprise);
297 xfree((char *) pdu);
298}
299
300/**********************************************************************/
301
302/* Encode this PDU into DestBuf.
303 *
304 * Returns a pointer to the next byte in the buffer (where the Variable
305 * Bindings belong.)
306 */
307
308/*
309 * RFC 1902: Structure of Management Information for SNMPv2
310 *
311 * PDU ::=
312 * SEQUENCE {
313 * request-id INTEGER32
314 * error-status INTEGER
315 * error-index INTEGER
316 * Variable Bindings
317 * }
318 *
319 * BulkPDU ::=
320 * SEQUENCE {
321 * request-id INTEGER32
322 * non-repeaters INTEGER
323 * max-repetitions INTEGER
324 * Variable Bindings
325 * }
326 */
327
328/*
329 * RFC 1157: A Simple Network Management Protocol (SNMP)
330 *
331 * PDU ::=
332 * SEQUENCE {
333 * request-id INTEGER
334 * error-status INTEGER
335 * error-index INTEGER
336 * Variable Bindings
337 * }
338 *
339 * TrapPDU ::=
340 * SEQUENCE {
341 * enterprise NetworkAddress
342 * generic-trap INTEGER
343 * specific-trap INTEGER
344 * time-stamp TIMETICKS
345 * Variable Bindings
346 * }
347 */
348
349u_char *
350snmp_pdu_encode(u_char * DestBuf, int *DestBufLen,
351 struct snmp_pdu *PDU)
352{
353 u_char *bufp;
354
355#if DEBUG_PDU_ENCODE
356 snmplib_debug(8, "PDU: Encoding %d\n", PDU->command);
357#endif
358
359 /* ASN.1 Header */
360 switch (PDU->command) {
361
362 /**********************************************************************/
363#if TRP_REQ_MSG
364 case TRP_REQ_MSG:
365
366 /* SNMPv1 Trap */
367
368 /* enterprise */
369 bufp = asn_build_objid(DestBuf, DestBufLen,
371 (oid *) PDU->enterprise, PDU->enterprise_length);
372 if (bufp == NULL)
373 return (NULL);
374
375 /* agent-addr */
376 bufp = asn_build_string(bufp, DestBufLen,
377 (u_char) (SMI_IPADDRESS | ASN_PRIMITIVE),
378 (u_char *) & PDU->agent_addr.sin_addr.s_addr,
379 sizeof(PDU->agent_addr.sin_addr.s_addr));
380 if (bufp == NULL)
381 return (NULL);
382
383 /* generic trap */
384 bufp = asn_build_int(bufp, DestBufLen,
386 (int *) &PDU->trap_type, sizeof(PDU->trap_type));
387 if (bufp == NULL)
388 return (NULL);
389
390 /* specific trap */
391 bufp = asn_build_int(bufp, DestBufLen,
393 (int *) &PDU->specific_type,
394 sizeof(PDU->specific_type));
395 if (bufp == NULL)
396 return (NULL);
397
398 /* timestamp */
399 bufp = asn_build_unsigned_int(bufp, DestBufLen,
400 (u_char) (SMI_TIMETICKS | ASN_PRIMITIVE),
401 &PDU->time, sizeof(PDU->time));
402 if (bufp == NULL)
403 return (NULL);
404 break;
405#endif
406
407 /**********************************************************************/
408
409 case SNMP_PDU_GETBULK:
410
411 /* SNMPv2 Bulk Request */
412
413 /* request id */
414 bufp = asn_build_int(DestBuf, DestBufLen,
416 &PDU->reqid, sizeof(PDU->reqid));
417 if (bufp == NULL)
418 return (NULL);
419
420 /* non-repeaters */
421 bufp = asn_build_int(bufp, DestBufLen,
423 &PDU->non_repeaters,
424 sizeof(PDU->non_repeaters));
425 if (bufp == NULL)
426 return (NULL);
427
428 /* max-repetitions */
429 bufp = asn_build_int(bufp, DestBufLen,
431 &PDU->max_repetitions,
432 sizeof(PDU->max_repetitions));
433 if (bufp == NULL)
434 return (NULL);
435 break;
436
437 /**********************************************************************/
438
439 default:
440
441 /* Normal PDU Encoding */
442
443 /* request id */
444#if DEBUG_PDU_ENCODE
445 snmplib_debug(8, "PDU: Request ID %d (0x%x)\n", PDU->reqid, DestBuf);
446#endif
447 bufp = asn_build_int(DestBuf, DestBufLen,
449 &PDU->reqid, sizeof(PDU->reqid));
450 if (bufp == NULL)
451 return (NULL);
452
453 /* error status */
454#if DEBUG_PDU_ENCODE
455 snmplib_debug(8, "PDU: Error Status %d (0x%x)\n", PDU->errstat, bufp);
456#endif
457 bufp = asn_build_int(bufp, DestBufLen,
459 &PDU->errstat, sizeof(PDU->errstat));
460 if (bufp == NULL)
461 return (NULL);
462
463 /* error index */
464#if DEBUG_PDU_ENCODE
465 snmplib_debug(8, "PDU: Error index %d (0x%x)\n", PDU->errindex, bufp);
466#endif
467 bufp = asn_build_int(bufp, DestBufLen,
469 &PDU->errindex, sizeof(PDU->errindex));
470 if (bufp == NULL)
471 return (NULL);
472 break;
473 } /* End of encoding */
474
475 return (bufp);
476}
477
478/**********************************************************************/
479
480/* Decodes PDU from Packet into PDU.
481 *
482 * Returns a pointer to the next byte of the packet, which is where the
483 * Variable Bindings start.
484 */
485u_char *
486snmp_pdu_decode(u_char * Packet, /* data */
487 int *Length, /* &length */
488 struct snmp_pdu * PDU)
489{ /* pdu */
490 u_char *bufp;
491 u_char PDUType;
492 u_char ASNType;
493
494 bufp = asn_parse_header(Packet, Length, &PDUType);
495 if (bufp == NULL)
497
498#if DEBUG_PDU_DECODE
499 snmplib_debug(8, "PDU Type: %d\n", PDUType);
500#endif
501
502 PDU->command = PDUType;
503 switch (PDUType) {
504
505#if TRP_REQ_MSG
506 case TRP_REQ_MSG:
507
508 /* SNMPv1 Trap Message */
509
510 /* enterprise */
512 bufp = asn_parse_objid(bufp, Length,
513 &ASNType, objid, &PDU->enterprise_length);
514 if (bufp == NULL)
516
517 PDU->enterprise = (oid *) xmalloc(PDU->enterprise_length * sizeof(oid));
518 if (PDU->enterprise == NULL) {
520 return (NULL);
521 }
522 memcpy((char *) PDU->enterprise, (char *) objid,
523 PDU->enterprise_length * sizeof(oid));
524
525 /* Agent-addr */
526 four = 4;
527 bufp = asn_parse_string(bufp, Length,
528 &ASNType,
529 (u_char *) & PDU->agent_addr.sin_addr.s_addr,
530 &four);
531 if (bufp == NULL)
533
534 /* Generic trap */
535 bufp = asn_parse_int(bufp, Length,
536 &ASNType,
537 (int *) &PDU->trap_type,
538 sizeof(PDU->trap_type));
539 if (bufp == NULL)
541
542 /* Specific Trap */
543 bufp = asn_parse_int(bufp, Length,
544 &ASNType,
545 (int *) &PDU->specific_type,
546 sizeof(PDU->specific_type));
547 if (bufp == NULL)
549
550 /* Timestamp */
551 bufp = asn_parse_unsigned_int(bufp, Length,
552 &ASNType,
553 &PDU->time, sizeof(PDU->time));
554 if (bufp == NULL)
556 break;
557#endif
558
559 /**********************************************************************/
560
561 case SNMP_PDU_GETBULK:
562
563 /* SNMPv2 Bulk Request */
564
565 /* request id */
566 bufp = asn_parse_int(bufp, Length,
567 &ASNType,
568 &PDU->reqid, sizeof(PDU->reqid));
569 if (bufp == NULL)
571
572 /* non-repeaters */
573 bufp = asn_parse_int(bufp, Length,
574 &ASNType,
575 &PDU->non_repeaters, sizeof(PDU->non_repeaters));
576 if (bufp == NULL)
578
579 /* max-repetitions */
580 bufp = asn_parse_int(bufp, Length,
581 &ASNType,
582 &PDU->max_repetitions, sizeof(PDU->max_repetitions));
583 if (bufp == NULL)
585 break;
586
587 /**********************************************************************/
588
589 default:
590
591 /* Normal PDU Encoding */
592
593 /* request id */
594 bufp = asn_parse_int(bufp, Length,
595 &ASNType,
596 &PDU->reqid, sizeof(PDU->reqid));
597 if (bufp == NULL)
599
600#if DEBUG_PDU_DECODE
601 snmplib_debug(8, "PDU Request ID: %d\n", PDU->reqid);
602#endif
603
604 /* error status */
605 bufp = asn_parse_int(bufp, Length,
606 &ASNType,
607 &PDU->errstat, sizeof(PDU->errstat));
608 if (bufp == NULL)
610
611#if DEBUG_PDU_DECODE
612 snmplib_debug(8, "PDU Error Status: %d\n", PDU->errstat);
613#endif
614
615 /* error index */
616 bufp = asn_parse_int(bufp, Length,
617 &ASNType,
618 &PDU->errindex, sizeof(PDU->errindex));
619 if (bufp == NULL)
621
622#if DEBUG_PDU_DECODE
623 snmplib_debug(8, "PDU Error Index: %d\n", PDU->errindex);
624#endif
625
626 break;
627 }
628
629 return (bufp);
630}
631
632/*
633 * Add a null variable with the requested name to the end of the list of
634 * variables for this pdu.
635 */
636void
638{
639 struct variable_list *vars;
640 struct variable_list *ptr;
641
643 if (vars == NULL) {
644 perror("snmp_add_null_var:xmalloc");
645 return;
646 }
647 if (pdu->variables == NULL) {
648 pdu->variables = vars;
649 } else {
650
651 /* Insert at the end */
652 for (ptr = pdu->variables;
653 ptr->next_variable;
654 ptr = ptr->next_variable)
655 /*EXIT */ ;
656 ptr->next_variable = vars;
657 }
658
659 return;
660}
661
u_int oid
Definition: asn1.h:42
u_char * asn_build_unsigned_int(u_char *, int *, u_char, u_int *, int)
Definition: asn1.c:311
u_char * asn_parse_unsigned_int(u_char *, int *, u_char *, u_int *, int)
Definition: asn1.c:179
#define ASN_OBJECT_ID
Definition: asn1.h:56
#define ASN_PRIMITIVE
Definition: asn1.h:65
u_char * asn_build_objid(u_char *, int *, u_char, oid *, int)
Definition: asn1.c:723
#define ASN_INTEGER
Definition: asn1.h:52
u_char * asn_parse_int(u_char *, int *, u_char *, int *, int)
Definition: asn1.c:114
#define ASN_UNIVERSAL
Definition: asn1.h:60
u_char * asn_parse_objid(u_char *, int *, u_char *, oid *, int *)
Definition: asn1.c:638
u_char * asn_parse_string(u_char *, int *, u_char *, u_char *, int *)
Definition: asn1.c:387
u_char * asn_build_int(u_char *, int *, u_char, int *, int)
Definition: asn1.c:245
u_char * asn_parse_header(u_char *, int *, u_char *)
Definition: asn1.c:470
u_char * asn_build_string(u_char *, int *, u_char, u_char *, int)
Definition: asn1.c:433
#define xfree
#define xmalloc
#define SNMPERR_OS_ERR
void snmp_set_api_error(int)
#define SNMPERR_UNABLE_TO_FIX
SQUIDCEXTERN void snmplib_debug(int, const char *,...) PRINTF_FORMAT_ARG2
Definition: snmplib_debug.c:21
#define SNMP_ERR_NOERROR
Definition: snmp_error.h:42
struct snmp_pdu * snmp_pdu_create(int command)
Definition: snmp_pdu.c:113
u_char * snmp_pdu_encode(u_char *DestBuf, int *DestBufLen, struct snmp_pdu *PDU)
Definition: snmp_pdu.c:350
u_char * snmp_pdu_decode(u_char *Packet, int *Length, struct snmp_pdu *PDU)
Definition: snmp_pdu.c:486
void snmp_pdu_free(struct snmp_pdu *pdu)
Definition: snmp_pdu.c:275
void snmp_add_null_var(struct snmp_pdu *pdu, oid *name, int name_length)
Definition: snmp_pdu.c:637
#define ASN_PARSE_ERROR(x)
Definition: snmp_pdu.c:105
struct snmp_pdu * snmp_pdu_fix(struct snmp_pdu *pdu, int command)
Definition: snmp_pdu.c:181
void snmp_free_pdu(struct snmp_pdu *pdu)
Definition: snmp_pdu.c:284
struct snmp_pdu * snmp_pdu_clone(struct snmp_pdu *Src)
Definition: snmp_pdu.c:147
struct snmp_pdu * snmp_fix_pdu(struct snmp_pdu *pdu, int command)
Definition: snmp_pdu.c:186
#define SNMP_PDU_RESPONSE
Definition: snmp_pdu.h:94
#define SNMP_PDU_GETBULK
Definition: snmp_pdu.h:95
#define SNMP_DEFAULT_ERRSTAT
Definition: snmp_pdu.h:97
#define SNMP_DEFAULT_ERRINDEX
Definition: snmp_pdu.h:98
#define SNMP_DEFAULT_ADDRESS
Definition: snmp_pdu.h:99
#define SNMP_DEFAULT_REQID
Definition: snmp_pdu.h:100
struct variable_list * snmp_var_new(oid *, int)
Definition: snmp_vars.c:109
struct variable_list * snmp_var_clone(struct variable_list *)
Definition: snmp_vars.c:166
#define SMI_TIMETICKS
Definition: snmp_vars.h:79
void snmp_var_free(struct variable_list *)
Definition: snmp_vars.c:227
#define SMI_IPADDRESS
Definition: snmp_vars.h:75
#define MAX_NAME_LEN
Definition: snmp_vars.h:65
struct sockaddr_in address
Definition: snmp_pdu.h:52
int non_repeaters
Definition: snmp_pdu.h:59
oid * enterprise
Definition: snmp_pdu.h:65
int enterprise_length
Definition: snmp_pdu.h:66
int trap_type
Definition: snmp_pdu.h:68
int errindex
Definition: snmp_pdu.h:56
int reqid
Definition: snmp_pdu.h:54
int command
Definition: snmp_pdu.h:51
struct variable_list * variables
Definition: snmp_pdu.h:62
int max_repetitions
Definition: snmp_pdu.h:60
struct sockaddr_in agent_addr
Definition: snmp_pdu.h:67
int errstat
Definition: snmp_pdu.h:55
int specific_type
Definition: snmp_pdu.h:69
u_int time
Definition: snmp_pdu.h:70
struct variable_list * next_variable
Definition: snmp_vars.h:45
int name_length
Definition: snmp_vars.h:47
oid * objid
Definition: snmp_vars.h:52
oid * name
Definition: snmp_vars.h:46
#define NULL
Definition: types.h:145

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors