]> The Tcpdump Group git mirrors - tcpdump/blob - print-snmp.c
Switch to config.h instead of passing defines in DEFS.
[tcpdump] / print-snmp.c
1 /*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by John Robert LoVerso.
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
12 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
14 *
15 * This implementation has been influenced by the CMU SNMP release,
16 * by Steve Waldbusser. However, this shares no code with that system.
17 * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
18 * Earlier forms of this implementation were derived and/or inspired by an
19 * awk script originally written by C. Philip Wood of LANL (but later
20 * heavily modified by John Robert LoVerso). The copyright notice for
21 * that work is preserved below, even though it may not rightly apply
22 * to this file.
23 *
24 * This started out as a very simple program, but the incremental decoding
25 * (into the BE structure) complicated things.
26 *
27 # Los Alamos National Laboratory
28 #
29 # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
30 # This software was produced under a U.S. Government contract
31 # (W-7405-ENG-36) by Los Alamos National Laboratory, which is
32 # operated by the University of California for the U.S. Department
33 # of Energy. The U.S. Government is licensed to use, reproduce,
34 # and distribute this software. Permission is granted to the
35 # public to copy and use this software without charge, provided
36 # that this Notice and any statement of authorship are reproduced
37 # on all copies. Neither the Government nor the University makes
38 # any warranty, express or implied, or assumes any liability or
39 # responsibility for the use of this software.
40 # @(#)snmp.awk.x 1.1 (LANL) 1/15/90
41 */
42
43 #ifndef lint
44 static const char rcsid[] =
45 "@(#) $Header: /tcpdump/master/tcpdump/print-snmp.c,v 1.37 1999-11-21 09:37:01 fenner Exp $ (LBL)";
46 #endif
47
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51
52 #include <sys/param.h>
53 #include <sys/time.h>
54
55 #include <ctype.h>
56 #ifdef HAVE_MEMORY_H
57 #include <memory.h>
58 #endif
59 #include <stdio.h>
60 #include <string.h>
61
62 #include "interface.h"
63 #include "addrtoname.h"
64
65 /*
66 * Universal ASN.1 types
67 * (we only care about the tag values for those allowed in the Internet SMI)
68 */
69 char *Universal[] = {
70 "U-0",
71 "Boolean",
72 "Integer",
73 #define INTEGER 2
74 "Bitstring",
75 "String",
76 #define STRING 4
77 "Null",
78 #define ASN_NULL 5
79 "ObjID",
80 #define OBJECTID 6
81 "ObjectDes",
82 "U-8","U-9","U-10","U-11", /* 8-11 */
83 "U-12","U-13","U-14","U-15", /* 12-15 */
84 "Sequence",
85 #define SEQUENCE 16
86 "Set"
87 };
88
89 /*
90 * Application-wide ASN.1 types from the Internet SMI and their tags
91 */
92 char *Application[] = {
93 "IpAddress",
94 #define IPADDR 0
95 "Counter",
96 #define COUNTER 1
97 "Gauge",
98 #define GAUGE 2
99 "TimeTicks",
100 #define TIMETICKS 3
101 "Opaque",
102 #define OPAQUE 4
103 "C-5",
104 "Counter64"
105 #define COUNTER64 6
106 };
107
108 /*
109 * Context-specific ASN.1 types for the SNMP PDUs and their tags
110 */
111 char *Context[] = {
112 "GetRequest",
113 #define GETREQ 0
114 "GetNextRequest",
115 #define GETNEXTREQ 1
116 "GetResponse",
117 #define GETRESP 2
118 "SetRequest",
119 #define SETREQ 3
120 "Trap",
121 #define TRAP 4
122 "GetBulk",
123 #define GETBULKREQ 5
124 "Inform",
125 #define INFORMREQ 6
126 "V2Trap",
127 #define V2TRAP 7
128 "Report"
129 #define REPORT 8
130 };
131
132 /*
133 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
134 */
135 char *Exceptions[] = {
136 "noSuchObject",
137 #define NOSUCHOBJECT 0
138 "noSuchInstance",
139 #define NOSUCHINSTANCE 1
140 "endOfMibView",
141 #define ENDOFMIBVIEW 2
142 };
143
144 /*
145 * Private ASN.1 types
146 * The Internet SMI does not specify any
147 */
148 char *Private[] = {
149 "P-0"
150 };
151
152 /*
153 * error-status values for any SNMP PDU
154 */
155 char *ErrorStatus[] = {
156 "noError",
157 "tooBig",
158 "noSuchName",
159 "badValue",
160 "readOnly",
161 "genErr",
162 "noAccess",
163 "wrongType",
164 "wrongLength",
165 "wrongEncoding",
166 "wrongValue",
167 "noCreation",
168 "inconsistentValue",
169 "resourceUnavailable",
170 "commitFailed",
171 "undoFailed",
172 "authorizationError",
173 "notWritable",
174 "inconsistentName"
175 };
176 #define DECODE_ErrorStatus(e) \
177 ( e >= 0 && e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
178 ? ErrorStatus[e] : (sprintf(errbuf, "err=%u", e), errbuf))
179
180 /*
181 * generic-trap values in the SNMP Trap-PDU
182 */
183 char *GenericTrap[] = {
184 "coldStart",
185 "warmStart",
186 "linkDown",
187 "linkUp",
188 "authenticationFailure",
189 "egpNeighborLoss",
190 "enterpriseSpecific"
191 #define GT_ENTERPRISE 7
192 };
193 #define DECODE_GenericTrap(t) \
194 ( t >= 0 && t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
195 ? GenericTrap[t] : (sprintf(buf, "gt=%d", t), buf))
196
197 /*
198 * ASN.1 type class table
199 * Ties together the preceding Universal, Application, Context, and Private
200 * type definitions.
201 */
202 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
203 struct {
204 char *name;
205 char **Id;
206 int numIDs;
207 } Class[] = {
208 defineCLASS(Universal),
209 #define UNIVERSAL 0
210 defineCLASS(Application),
211 #define APPLICATION 1
212 defineCLASS(Context),
213 #define CONTEXT 2
214 defineCLASS(Private),
215 #define PRIVATE 3
216 defineCLASS(Exceptions),
217 #define EXCEPTIONS 4
218 };
219
220 /*
221 * defined forms for ASN.1 types
222 */
223 char *Form[] = {
224 "Primitive",
225 #define PRIMITIVE 0
226 "Constructed",
227 #define CONSTRUCTED 1
228 };
229
230 /*
231 * A structure for the OID tree for the compiled-in MIB.
232 * This is stored as a general-order tree.
233 */
234 struct obj {
235 char *desc; /* name of object */
236 u_char oid; /* sub-id following parent */
237 u_char type; /* object type (unused) */
238 struct obj *child, *next; /* child and next sibling pointers */
239 } *objp = NULL;
240
241 /*
242 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
243 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
244 * a value for `mibroot'.
245 *
246 * In particular, this is gross, as this is including initialized structures,
247 * and by right shouldn't be an "include" file.
248 */
249 #include "mib.h"
250
251 /*
252 * This defines a list of OIDs which will be abbreviated on output.
253 * Currently, this includes the prefixes for the Internet MIB, the
254 * private enterprises tree, and the experimental tree.
255 */
256 struct obj_abrev {
257 char *prefix; /* prefix for this abrev */
258 struct obj *node; /* pointer into object table */
259 char *oid; /* ASN.1 encoded OID */
260 } obj_abrev_list[] = {
261 #ifndef NO_ABREV_MIB
262 /* .iso.org.dod.internet.mgmt.mib */
263 { "", &_mib_obj, "\53\6\1\2\1" },
264 #endif
265 #ifndef NO_ABREV_ENTER
266 /* .iso.org.dod.internet.private.enterprises */
267 { "E:", &_enterprises_obj, "\53\6\1\4\1" },
268 #endif
269 #ifndef NO_ABREV_EXPERI
270 /* .iso.org.dod.internet.experimental */
271 { "X:", &_experimental_obj, "\53\6\1\3" },
272 #endif
273 #ifndef NO_ABBREV_SNMPMODS
274 /* .iso.org.dod.internet.snmpV2.snmpModules */
275 { "S:", &_snmpModules_obj, "\53\6\1\6\3" },
276 #endif
277 { 0,0,0 }
278 };
279
280 /*
281 * This is used in the OID print routine to walk down the object tree
282 * rooted at `mibroot'.
283 */
284 #define OBJ_PRINT(o, suppressdot) \
285 { \
286 if (objp) { \
287 do { \
288 if ((o) == objp->oid) \
289 break; \
290 } while ((objp = objp->next) != NULL); \
291 } \
292 if (objp) { \
293 printf(suppressdot?"%s":".%s", objp->desc); \
294 objp = objp->child; \
295 } else \
296 printf(suppressdot?"%u":".%u", (o)); \
297 }
298
299 /*
300 * This is the definition for the Any-Data-Type storage used purely for
301 * temporary internal representation while decoding an ASN.1 data stream.
302 */
303 struct be {
304 u_int32_t asnlen;
305 union {
306 caddr_t raw;
307 int32_t integer;
308 u_int32_t uns;
309 const u_char *str;
310 struct {
311 u_int32_t high;
312 u_int32_t low;
313 } uns64;
314 } data;
315 u_short id;
316 u_char form, class; /* tag info */
317 u_char type;
318 #define BE_ANY 255
319 #define BE_NONE 0
320 #define BE_NULL 1
321 #define BE_OCTET 2
322 #define BE_OID 3
323 #define BE_INT 4
324 #define BE_UNS 5
325 #define BE_STR 6
326 #define BE_SEQ 7
327 #define BE_INETADDR 8
328 #define BE_PDU 9
329 #define BE_UNS64 10
330 #define BE_NOSUCHOBJECT 128
331 #define BE_NOSUCHINST 129
332 #define BE_ENDOFMIBVIEW 130
333 };
334
335 /*
336 * SNMP versions recognized by this module
337 */
338 char *SnmpVersion[] = {
339 "SNMPv1",
340 #define SNMP_VERSION_1 0
341 "SNMPv2c",
342 #define SNMP_VERSION_2 1
343 "SNMPv2u",
344 #define SNMP_VERSION_2U 2
345 "SNMPv3"
346 #define SNMP_VERSION_3 3
347 };
348
349 /*
350 * Defaults for SNMP PDU components
351 */
352 #define DEF_COMMUNITY "public"
353
354 /*
355 * constants for ASN.1 decoding
356 */
357 #define OIDMUX 40
358 #define ASNLEN_INETADDR 4
359 #define ASN_SHIFT7 7
360 #define ASN_SHIFT8 8
361 #define ASN_BIT8 0x80
362 #define ASN_LONGLEN 0x80
363
364 #define ASN_ID_BITS 0x1f
365 #define ASN_FORM_BITS 0x20
366 #define ASN_FORM_SHIFT 5
367 #define ASN_CLASS_BITS 0xc0
368 #define ASN_CLASS_SHIFT 6
369
370 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
371
372 /*
373 * truncated==1 means the packet was complete, but we don't have all of
374 * it to decode.
375 */
376 static int truncated;
377 #define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else
378
379 /*
380 * This decodes the next ASN.1 object in the stream pointed to by "p"
381 * (and of real-length "len") and stores the intermediate data in the
382 * provided BE object.
383 *
384 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
385 * O/w, this returns the number of bytes parsed from "p".
386 */
387 static int
388 asn1_parse(register const u_char *p, u_int len, struct be *elem)
389 {
390 u_char form, class, id;
391 int i, hdr;
392
393 elem->asnlen = 0;
394 elem->type = BE_ANY;
395 if (len < 1) {
396 ifNotTruncated fputs("[nothing to parse]", stdout);
397 return -1;
398 }
399
400 /*
401 * it would be nice to use a bit field, but you can't depend on them.
402 * +---+---+---+---+---+---+---+---+
403 * + class |frm| id |
404 * +---+---+---+---+---+---+---+---+
405 * 7 6 5 4 3 2 1 0
406 */
407 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
408 #ifdef notdef
409 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
410 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
411 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
412 #else
413 form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
414 class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
415 #endif
416 elem->form = form;
417 elem->class = class;
418 elem->id = id;
419 if (vflag)
420 printf("|%.2x", *p);
421 p++; len--; hdr = 1;
422 /* extended tag field */
423 if (id == ASN_ID_EXT) {
424 for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) {
425 if (vflag)
426 printf("|%.2x", *p);
427 id = (id << 7) | (*p & ~ASN_BIT8);
428 }
429 if (len == 0 && *p & ASN_BIT8) {
430 ifNotTruncated fputs("[Xtagfield?]", stdout);
431 return -1;
432 }
433 elem->id = id = (id << 7) | *p;
434 --len;
435 ++hdr;
436 ++p;
437 }
438 if (len < 1) {
439 ifNotTruncated fputs("[no asnlen]", stdout);
440 return -1;
441 }
442 elem->asnlen = *p;
443 if (vflag)
444 printf("|%.2x", *p);
445 p++; len--; hdr++;
446 if (elem->asnlen & ASN_BIT8) {
447 int noct = elem->asnlen % ASN_BIT8;
448 elem->asnlen = 0;
449 if (len < noct) {
450 ifNotTruncated printf("[asnlen? %d<%d]", len, noct);
451 return -1;
452 }
453 for (; noct-- > 0; len--, hdr++) {
454 if (vflag)
455 printf("|%.2x", *p);
456 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
457 }
458 }
459 if (len < elem->asnlen) {
460 if (!truncated) {
461 printf("[len%d<asnlen%u]", len, elem->asnlen);
462 return -1;
463 }
464 /* maybe should check at least 4? */
465 elem->asnlen = len;
466 }
467 if (form >= sizeof(Form)/sizeof(Form[0])) {
468 ifNotTruncated printf("[form?%d]", form);
469 return -1;
470 }
471 if (class >= sizeof(Class)/sizeof(Class[0])) {
472 ifNotTruncated printf("[class?%c/%d]", *Form[form], class);
473 return -1;
474 }
475 if ((int)id >= Class[class].numIDs) {
476 ifNotTruncated printf("[id?%c/%s/%d]", *Form[form],
477 Class[class].name, id);
478 return -1;
479 }
480
481 switch (form) {
482 case PRIMITIVE:
483 switch (class) {
484 case UNIVERSAL:
485 switch (id) {
486 case STRING:
487 elem->type = BE_STR;
488 elem->data.str = p;
489 break;
490
491 case INTEGER: {
492 register int32_t data;
493 elem->type = BE_INT;
494 data = 0;
495
496 if (*p & ASN_BIT8) /* negative */
497 data = -1;
498 for (i = elem->asnlen; i-- > 0; p++)
499 data = (data << ASN_SHIFT8) | *p;
500 elem->data.integer = data;
501 break;
502 }
503
504 case OBJECTID:
505 elem->type = BE_OID;
506 elem->data.raw = (caddr_t)p;
507 break;
508
509 case ASN_NULL:
510 elem->type = BE_NULL;
511 elem->data.raw = NULL;
512 break;
513
514 default:
515 elem->type = BE_OCTET;
516 elem->data.raw = (caddr_t)p;
517 printf("[P/U/%s]",
518 Class[class].Id[id]);
519 break;
520 }
521 break;
522
523 case APPLICATION:
524 switch (id) {
525 case IPADDR:
526 elem->type = BE_INETADDR;
527 elem->data.raw = (caddr_t)p;
528 break;
529
530 case COUNTER:
531 case GAUGE:
532 case TIMETICKS: {
533 register u_int32_t data;
534 elem->type = BE_UNS;
535 data = 0;
536 for (i = elem->asnlen; i-- > 0; p++)
537 data = (data << 8) + *p;
538 elem->data.uns = data;
539 break;
540 }
541
542 case COUNTER64: {
543 register u_int32_t high, low;
544 elem->type = BE_UNS64;
545 high = 0, low = 0;
546 for (i = elem->asnlen; i-- > 0; p++) {
547 high = (high << 8) |
548 ((low & 0xFF000000) >> 24);
549 low = (low << 8) | *p;
550 }
551 elem->data.uns64.high = high;
552 elem->data.uns64.low = low;
553 break;
554 }
555
556 default:
557 elem->type = BE_OCTET;
558 elem->data.raw = (caddr_t)p;
559 printf("[P/A/%s]",
560 Class[class].Id[id]);
561 break;
562 }
563 break;
564
565 case CONTEXT:
566 switch (id) {
567 case NOSUCHOBJECT:
568 elem->type = BE_NOSUCHOBJECT;
569 elem->data.raw = NULL;
570 break;
571
572 case NOSUCHINSTANCE:
573 elem->type = BE_NOSUCHINST;
574 elem->data.raw = NULL;
575 break;
576
577 case ENDOFMIBVIEW:
578 elem->type = BE_ENDOFMIBVIEW;
579 elem->data.raw = NULL;
580 break;
581 }
582 break;
583
584 default:
585 elem->type = BE_OCTET;
586 elem->data.raw = (caddr_t)p;
587 printf("[P/%s/%s]",
588 Class[class].name, Class[class].Id[id]);
589 break;
590 }
591 break;
592
593 case CONSTRUCTED:
594 switch (class) {
595 case UNIVERSAL:
596 switch (id) {
597 case SEQUENCE:
598 elem->type = BE_SEQ;
599 elem->data.raw = (caddr_t)p;
600 break;
601
602 default:
603 elem->type = BE_OCTET;
604 elem->data.raw = (caddr_t)p;
605 printf("C/U/%s", Class[class].Id[id]);
606 break;
607 }
608 break;
609
610 case CONTEXT:
611 elem->type = BE_PDU;
612 elem->data.raw = (caddr_t)p;
613 break;
614
615 default:
616 elem->type = BE_OCTET;
617 elem->data.raw = (caddr_t)p;
618 printf("C/%s/%s",
619 Class[class].name, Class[class].Id[id]);
620 break;
621 }
622 break;
623 }
624 p += elem->asnlen;
625 len -= elem->asnlen;
626 return elem->asnlen + hdr;
627 }
628
629 /*
630 * Display the ASN.1 object represented by the BE object.
631 * This used to be an integral part of asn1_parse() before the intermediate
632 * BE form was added.
633 */
634 static void
635 asn1_print(struct be *elem)
636 {
637 u_char *p = (u_char *)elem->data.raw;
638 u_int32_t asnlen = elem->asnlen;
639 int i;
640
641 switch (elem->type) {
642
643 case BE_OCTET:
644 for (i = asnlen; i-- > 0; p++);
645 printf("_%.2x", *p);
646 break;
647
648 case BE_NULL:
649 break;
650
651 case BE_OID: {
652 int o = 0, first = -1, i = asnlen;
653
654 if (!nflag && asnlen > 2) {
655 struct obj_abrev *a = &obj_abrev_list[0];
656 for (; a->node; a++) {
657 if (!memcmp(a->oid, (char *)p,
658 strlen(a->oid))) {
659 objp = a->node->child;
660 i -= strlen(a->oid);
661 p += strlen(a->oid);
662 fputs(a->prefix, stdout);
663 first = 1;
664 break;
665 }
666 }
667 }
668 for (; i-- > 0; p++) {
669 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
670 if (*p & ASN_LONGLEN)
671 continue;
672
673 /*
674 * first subitem encodes two items with 1st*OIDMUX+2nd
675 */
676 if (first < 0) {
677 if (!nflag)
678 objp = mibroot;
679 first = 0;
680 OBJ_PRINT(o/OIDMUX, first);
681 o %= OIDMUX;
682 }
683 OBJ_PRINT(o, first);
684 if (--first < 0)
685 first = 0;
686 o = 0;
687 }
688 break;
689 }
690
691 case BE_INT:
692 printf("%d", elem->data.integer);
693 break;
694
695 case BE_UNS:
696 printf("%d", elem->data.uns);
697 break;
698
699 case BE_UNS64: { /* idea borrowed from by Marshall Rose */
700 double d;
701 int j, carry;
702 char *cpf, *cpl, last[6], first[30];
703 if (elem->data.uns64.high == 0) {
704 printf("%u", elem->data.uns64.low);
705 break;
706 }
707 d = elem->data.uns64.high * 4294967296.0; /* 2^32 */
708 if (elem->data.uns64.high <= 0x1fffff) {
709 d += elem->data.uns64.low;
710 printf("%.f", d);
711 break;
712 }
713 d += (elem->data.uns64.low & 0xfffff000);
714 sprintf(first, "%.f", d);
715 sprintf(last, "%5.5d", elem->data.uns64.low & 0xfff);
716 for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4;
717 cpl >= last;
718 cpf--, cpl--) {
719 j = carry + (*cpf - '0') + (*cpl - '0');
720 if (j > 9) {
721 j -= 10;
722 carry = 1;
723 } else {
724 carry = 0;
725 }
726 *cpf = j + '0';
727 }
728 fputs(first, stdout);
729 break;
730 }
731
732 case BE_STR: {
733 register int printable = 1, first = 1;
734 const u_char *p = elem->data.str;
735 for (i = asnlen; printable && i-- > 0; p++)
736 printable = isprint(*p) || isspace(*p);
737 p = elem->data.str;
738 if (printable) {
739 putchar('"');
740 (void)fn_print(p, p + asnlen);
741 putchar('"');
742 } else
743 for (i = asnlen; i-- > 0; p++) {
744 printf(first ? "%.2x" : "_%.2x", *p);
745 first = 0;
746 }
747 break;
748 }
749
750 case BE_SEQ:
751 printf("Seq(%u)", elem->asnlen);
752 break;
753
754 case BE_INETADDR: {
755 char sep;
756 if (asnlen != ASNLEN_INETADDR)
757 printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
758 sep='[';
759 for (i = asnlen; i-- > 0; p++) {
760 printf("%c%u", sep, *p);
761 sep='.';
762 }
763 putchar(']');
764 break;
765 }
766
767 case BE_NOSUCHOBJECT:
768 case BE_NOSUCHINST:
769 case BE_ENDOFMIBVIEW:
770 printf("[%s]", Class[EXCEPTIONS].Id[elem->id]);
771 break;
772
773 case BE_PDU:
774 printf("%s(%u)",
775 Class[CONTEXT].Id[elem->id], elem->asnlen);
776 break;
777
778 case BE_ANY:
779 fputs("[BE_ANY!?]", stdout);
780 break;
781
782 default:
783 fputs("[be!?]", stdout);
784 break;
785 }
786 }
787
788 #ifdef notdef
789 /*
790 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
791 * This will work for any ASN.1 stream, not just an SNMP PDU.
792 *
793 * By adding newlines and spaces at the correct places, this would print in
794 * Rose-Normal-Form.
795 *
796 * This is not currently used.
797 */
798 static void
799 asn1_decode(u_char *p, u_int length)
800 {
801 struct be elem;
802 int i = 0;
803
804 while (i >= 0 && length > 0) {
805 i = asn1_parse(p, length, &elem);
806 if (i >= 0) {
807 fputs(" ", stdout);
808 asn1_print(&elem);
809 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
810 fputs(" {", stdout);
811 asn1_decode(elem.data.raw, elem.asnlen);
812 fputs(" }", stdout);
813 }
814 length -= i;
815 p += i;
816 }
817 }
818 }
819 #endif
820
821 /*
822 * General SNMP header
823 * SEQUENCE {
824 * version INTEGER {version-1(0)},
825 * community OCTET STRING,
826 * data ANY -- PDUs
827 * }
828 * PDUs for all but Trap: (see rfc1157 from page 15 on)
829 * SEQUENCE {
830 * request-id INTEGER,
831 * error-status INTEGER,
832 * error-index INTEGER,
833 * varbindlist SEQUENCE OF
834 * SEQUENCE {
835 * name ObjectName,
836 * value ObjectValue
837 * }
838 * }
839 * PDU for Trap:
840 * SEQUENCE {
841 * enterprise OBJECT IDENTIFIER,
842 * agent-addr NetworkAddress,
843 * generic-trap INTEGER,
844 * specific-trap INTEGER,
845 * time-stamp TimeTicks,
846 * varbindlist SEQUENCE OF
847 * SEQUENCE {
848 * name ObjectName,
849 * value ObjectValue
850 * }
851 * }
852 */
853
854 /*
855 * Decode SNMP varBind
856 */
857 static void
858 varbind_print(u_char pduid, const u_char *np, u_int length, int error)
859 {
860 struct be elem;
861 int count = 0, ind;
862
863 /* Sequence of varBind */
864 if ((count = asn1_parse(np, length, &elem)) < 0)
865 return;
866 if (elem.type != BE_SEQ) {
867 fputs("[!SEQ of varbind]", stdout);
868 asn1_print(&elem);
869 return;
870 }
871 if (count < length)
872 printf("[%d extra after SEQ of varbind]", length - count);
873 /* descend */
874 length = elem.asnlen;
875 np = (u_char *)elem.data.raw;
876
877 for (ind = 1; length > 0; ind++) {
878 const u_char *vbend;
879 u_int vblength;
880
881 if (!error || ind == error)
882 fputs(" ", stdout);
883
884 /* Sequence */
885 if ((count = asn1_parse(np, length, &elem)) < 0)
886 return;
887 if (elem.type != BE_SEQ) {
888 fputs("[!varbind]", stdout);
889 asn1_print(&elem);
890 return;
891 }
892 vbend = np + count;
893 vblength = length - count;
894 /* descend */
895 length = elem.asnlen;
896 np = (u_char *)elem.data.raw;
897
898 /* objName (OID) */
899 if ((count = asn1_parse(np, length, &elem)) < 0)
900 return;
901 if (elem.type != BE_OID) {
902 fputs("[objName!=OID]", stdout);
903 asn1_print(&elem);
904 return;
905 }
906 if (!error || ind == error)
907 asn1_print(&elem);
908 length -= count;
909 np += count;
910
911 if (pduid != GETREQ && pduid != GETNEXTREQ
912 && pduid != GETBULKREQ && !error)
913 fputs("=", stdout);
914
915 /* objVal (ANY) */
916 if ((count = asn1_parse(np, length, &elem)) < 0)
917 return;
918 if (pduid == GETREQ || pduid == GETNEXTREQ
919 || pduid == GETBULKREQ) {
920 if (elem.type != BE_NULL) {
921 fputs("[objVal!=NULL]", stdout);
922 asn1_print(&elem);
923 }
924 } else
925 if (error && ind == error && elem.type != BE_NULL)
926 fputs("[err objVal!=NULL]", stdout);
927 if (!error || ind == error)
928 asn1_print(&elem);
929
930 length = vblength;
931 np = vbend;
932 }
933 }
934
935 /*
936 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
937 * GetBulk, Inform, V2Trap, and Report
938 */
939 static void
940 snmppdu_print(u_char pduid, const u_char *np, u_int length)
941 {
942 struct be elem;
943 int count = 0, error;
944
945 /* reqId (Integer) */
946 if ((count = asn1_parse(np, length, &elem)) < 0)
947 return;
948 if (elem.type != BE_INT) {
949 fputs("[reqId!=INT]", stdout);
950 asn1_print(&elem);
951 return;
952 }
953 /* ignore the reqId */
954 length -= count;
955 np += count;
956
957 /* errorStatus (Integer) */
958 if ((count = asn1_parse(np, length, &elem)) < 0)
959 return;
960 if (elem.type != BE_INT) {
961 fputs("[errorStatus!=INT]", stdout);
962 asn1_print(&elem);
963 return;
964 }
965 error = 0;
966 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
967 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
968 && elem.data.integer != 0) {
969 char errbuf[10];
970 printf("[errorStatus(%s)!=0]",
971 DECODE_ErrorStatus(elem.data.integer));
972 } else if (pduid == GETBULKREQ) {
973 printf(" N=%d", elem.data.integer);
974 } else if (elem.data.integer != 0) {
975 char errbuf[10];
976 printf(" %s", DECODE_ErrorStatus(elem.data.integer));
977 error = elem.data.integer;
978 }
979 length -= count;
980 np += count;
981
982 /* errorIndex (Integer) */
983 if ((count = asn1_parse(np, length, &elem)) < 0)
984 return;
985 if (elem.type != BE_INT) {
986 fputs("[errorIndex!=INT]", stdout);
987 asn1_print(&elem);
988 return;
989 }
990 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
991 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
992 && elem.data.integer != 0)
993 printf("[errorIndex(%d)!=0]", elem.data.integer);
994 else if (pduid == GETBULKREQ)
995 printf(" M=%d", elem.data.integer);
996 else if (elem.data.integer != 0) {
997 if (!error)
998 printf("[errorIndex(%d) w/o errorStatus]",
999 elem.data.integer);
1000 else {
1001 printf("@%d", elem.data.integer);
1002 error = elem.data.integer;
1003 }
1004 } else if (error) {
1005 fputs("[errorIndex==0]", stdout);
1006 error = 0;
1007 }
1008 length -= count;
1009 np += count;
1010
1011 varbind_print(pduid, np, length, error);
1012 return;
1013 }
1014
1015 /*
1016 * Decode SNMP Trap PDU
1017 */
1018 static void
1019 trappdu_print(const u_char *np, u_int length)
1020 {
1021 struct be elem;
1022 int count = 0, generic;
1023
1024 putchar(' ');
1025
1026 /* enterprise (oid) */
1027 if ((count = asn1_parse(np, length, &elem)) < 0)
1028 return;
1029 if (elem.type != BE_OID) {
1030 fputs("[enterprise!=OID]", stdout);
1031 asn1_print(&elem);
1032 return;
1033 }
1034 asn1_print(&elem);
1035 length -= count;
1036 np += count;
1037
1038 putchar(' ');
1039
1040 /* agent-addr (inetaddr) */
1041 if ((count = asn1_parse(np, length, &elem)) < 0)
1042 return;
1043 if (elem.type != BE_INETADDR) {
1044 fputs("[agent-addr!=INETADDR]", stdout);
1045 asn1_print(&elem);
1046 return;
1047 }
1048 asn1_print(&elem);
1049 length -= count;
1050 np += count;
1051
1052 /* generic-trap (Integer) */
1053 if ((count = asn1_parse(np, length, &elem)) < 0)
1054 return;
1055 if (elem.type != BE_INT) {
1056 fputs("[generic-trap!=INT]", stdout);
1057 asn1_print(&elem);
1058 return;
1059 }
1060 generic = elem.data.integer;
1061 {
1062 char buf[10];
1063 printf(" %s", DECODE_GenericTrap(generic));
1064 }
1065 length -= count;
1066 np += count;
1067
1068 /* specific-trap (Integer) */
1069 if ((count = asn1_parse(np, length, &elem)) < 0)
1070 return;
1071 if (elem.type != BE_INT) {
1072 fputs("[specific-trap!=INT]", stdout);
1073 asn1_print(&elem);
1074 return;
1075 }
1076 if (generic != GT_ENTERPRISE) {
1077 if (elem.data.integer != 0)
1078 printf("[specific-trap(%d)!=0]", elem.data.integer);
1079 } else
1080 printf(" s=%d", elem.data.integer);
1081 length -= count;
1082 np += count;
1083
1084 putchar(' ');
1085
1086 /* time-stamp (TimeTicks) */
1087 if ((count = asn1_parse(np, length, &elem)) < 0)
1088 return;
1089 if (elem.type != BE_UNS) { /* XXX */
1090 fputs("[time-stamp!=TIMETICKS]", stdout);
1091 asn1_print(&elem);
1092 return;
1093 }
1094 asn1_print(&elem);
1095 length -= count;
1096 np += count;
1097
1098 varbind_print (TRAP, np, length, 0);
1099 return;
1100 }
1101
1102 /*
1103 * Decode arbitrary SNMP PDUs.
1104 */
1105 static void
1106 pdu_print(const u_char *np, u_int length, int version)
1107 {
1108 struct be pdu;
1109 int count = 0;
1110
1111 /* PDU (Context) */
1112 if ((count = asn1_parse(np, length, &pdu)) < 0)
1113 return;
1114 if (pdu.type != BE_PDU) {
1115 fputs("[no PDU]", stdout);
1116 return;
1117 }
1118 if (count < length)
1119 printf("[%d extra after PDU]", length - count);
1120 asn1_print(&pdu);
1121 /* descend into PDU */
1122 length = pdu.asnlen;
1123 np = (u_char *)pdu.data.raw;
1124
1125 if (version == SNMP_VERSION_1 &&
1126 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1127 pdu.id == V2TRAP || pdu.id == REPORT)) {
1128 printf("[v2 PDU in v1 message]");
1129 return;
1130 }
1131
1132 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1133 printf("[v1 PDU in v2 message]");
1134 return;
1135 }
1136
1137 switch (pdu.id) {
1138 case TRAP:
1139 trappdu_print(np, length);
1140 break;
1141 case GETREQ:
1142 case GETNEXTREQ:
1143 case GETRESP:
1144 case SETREQ:
1145 case GETBULKREQ:
1146 case INFORMREQ:
1147 case V2TRAP:
1148 case REPORT:
1149 snmppdu_print(pdu.id, np, length);
1150 break;
1151 }
1152 }
1153
1154 /*
1155 * Decode a scoped SNMP PDU.
1156 */
1157 static void
1158 scopedpdu_print(const u_char *np, u_int length, int version)
1159 {
1160 struct be elem;
1161 int i, count = 0;
1162
1163 /* Sequence */
1164 if ((count = asn1_parse(np, length, &elem)) < 0)
1165 return;
1166 if (elem.type != BE_SEQ) {
1167 fputs("[!scoped PDU]", stdout);
1168 asn1_print(&elem);
1169 return;
1170 }
1171 length = elem.asnlen;
1172 np = (u_char *)elem.data.raw;
1173
1174 /* contextEngineID (OCTET STRING) */
1175 if ((count = asn1_parse(np, length, &elem)) < 0)
1176 return;
1177 if (elem.type != BE_STR) {
1178 fputs("[contextEngineID!=STR]", stdout);
1179 asn1_print(&elem);
1180 return;
1181 }
1182 length -= count;
1183 np += count;
1184
1185 fputs("E= ", stdout);
1186 for (i = 0; i < (int)elem.asnlen; i++) {
1187 printf("0x%02X", elem.data.str[i]);
1188 }
1189 fputs(" ", stdout);
1190
1191 /* contextName (OCTET STRING) */
1192 if ((count = asn1_parse(np, length, &elem)) < 0)
1193 return;
1194 if (elem.type != BE_STR) {
1195 fputs("[contextName!=STR]", stdout);
1196 asn1_print(&elem);
1197 return;
1198 }
1199 length -= count;
1200 np += count;
1201
1202 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1203
1204 pdu_print(np, length, version);
1205 }
1206
1207 /*
1208 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1209 */
1210 static void
1211 community_print(const u_char *np, u_int length, int version)
1212 {
1213 struct be elem;
1214 int count = 0;
1215
1216 /* Community (String) */
1217 if ((count = asn1_parse(np, length, &elem)) < 0)
1218 return;
1219 if (elem.type != BE_STR) {
1220 fputs("[comm!=STR]", stdout);
1221 asn1_print(&elem);
1222 return;
1223 }
1224 /* default community */
1225 if (strncmp((char *)elem.data.str, DEF_COMMUNITY,
1226 sizeof(DEF_COMMUNITY) - 1))
1227 /* ! "public" */
1228 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1229 length -= count;
1230 np += count;
1231
1232 pdu_print(np, length, version);
1233 }
1234
1235 /*
1236 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1237 */
1238 static void
1239 usm_print(const u_char *np, u_int length)
1240 {
1241 struct be elem;
1242 int count = 0;
1243
1244 /* Sequence */
1245 if ((count = asn1_parse(np, length, &elem)) < 0)
1246 return;
1247 if (elem.type != BE_SEQ) {
1248 fputs("[!usm]", stdout);
1249 asn1_print(&elem);
1250 return;
1251 }
1252 length = elem.asnlen;
1253 np = (u_char *)elem.data.raw;
1254
1255 /* msgAuthoritativeEngineID (OCTET STRING) */
1256 if ((count = asn1_parse(np, length, &elem)) < 0)
1257 return;
1258 if (elem.type != BE_STR) {
1259 fputs("[msgAuthoritativeEngineID!=STR]", stdout);
1260 asn1_print(&elem);
1261 return;
1262 }
1263 length -= count;
1264 np += count;
1265
1266 /* msgAuthoritativeEngineBoots (INTEGER) */
1267 if ((count = asn1_parse(np, length, &elem)) < 0)
1268 return;
1269 if (elem.type != BE_INT) {
1270 fputs("[msgAuthoritativeEngineBoots!=INT]", stdout);
1271 asn1_print(&elem);
1272 return;
1273 }
1274 if (vflag)
1275 printf("B=%d ", elem.data.integer);
1276 length -= count;
1277 np += count;
1278
1279 /* msgAuthoritativeEngineTime (INTEGER) */
1280 if ((count = asn1_parse(np, length, &elem)) < 0)
1281 return;
1282 if (elem.type != BE_INT) {
1283 fputs("[msgAuthoritativeEngineTime!=INT]", stdout);
1284 asn1_print(&elem);
1285 return;
1286 }
1287 if (vflag)
1288 printf("T=%d ", elem.data.integer);
1289 length -= count;
1290 np += count;
1291
1292 /* msgUserName (OCTET STRING) */
1293 if ((count = asn1_parse(np, length, &elem)) < 0)
1294 return;
1295 if (elem.type != BE_STR) {
1296 fputs("[msgUserName!=STR]", stdout);
1297 asn1_print(&elem);
1298 return;
1299 }
1300 length -= count;
1301 np += count;
1302
1303 printf("U=%.*s ", (int)elem.asnlen, elem.data.str);
1304
1305 /* msgAuthenticationParameters (OCTET STRING) */
1306 if ((count = asn1_parse(np, length, &elem)) < 0)
1307 return;
1308 if (elem.type != BE_STR) {
1309 fputs("[msgAuthenticationParameters!=STR]", stdout);
1310 asn1_print(&elem);
1311 return;
1312 }
1313 length -= count;
1314 np += count;
1315
1316 /* msgPrivacyParameters (OCTET STRING) */
1317 if ((count = asn1_parse(np, length, &elem)) < 0)
1318 return;
1319 if (elem.type != BE_STR) {
1320 fputs("[msgPrivacyParameters!=STR]", stdout);
1321 asn1_print(&elem);
1322 return;
1323 }
1324 length -= count;
1325 np += count;
1326
1327 if (count < length)
1328 printf("[%d extra after usm SEQ]", length - count);
1329 }
1330
1331 /*
1332 * Decode SNMPv3 Message Header (SNMPv3)
1333 */
1334 static void
1335 v3msg_print(const u_char *np, u_int length)
1336 {
1337 struct be elem;
1338 int count = 0;
1339 u_char flags;
1340 int model;
1341 const u_char *xnp = np;
1342 int xlength = length;
1343
1344 /* Sequence */
1345 if ((count = asn1_parse(np, length, &elem)) < 0)
1346 return;
1347 if (elem.type != BE_SEQ) {
1348 fputs("[!message]", stdout);
1349 asn1_print(&elem);
1350 return;
1351 }
1352 length = elem.asnlen;
1353 np = (u_char *)elem.data.raw;
1354
1355 /* msgID (INTEGER) */
1356 if ((count = asn1_parse(np, length, &elem)) < 0)
1357 return;
1358 if (elem.type != BE_INT) {
1359 fputs("[msgID!=INT]", stdout);
1360 asn1_print(&elem);
1361 return;
1362 }
1363 length -= count;
1364 np += count;
1365
1366 /* msgMaxSize (INTEGER) */
1367 if ((count = asn1_parse(np, length, &elem)) < 0)
1368 return;
1369 if (elem.type != BE_INT) {
1370 fputs("[msgMaxSize!=INT]", stdout);
1371 asn1_print(&elem);
1372 return;
1373 }
1374 length -= count;
1375 np += count;
1376
1377 /* msgFlags (OCTET STRING) */
1378 if ((count = asn1_parse(np, length, &elem)) < 0)
1379 return;
1380 if (elem.type != BE_STR) {
1381 fputs("[msgFlags!=STR]", stdout);
1382 asn1_print(&elem);
1383 return;
1384 }
1385 if (elem.asnlen != 1) {
1386 printf("[msgFlags size %d]", elem.asnlen);
1387 return;
1388 }
1389 flags = elem.data.str[0];
1390 if (flags != 0x00 && flags != 0x01 && flags != 0x03
1391 && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1392 printf("[msgFlags=0x%02X]", flags);
1393 return;
1394 }
1395 length -= count;
1396 np += count;
1397
1398 fputs("F=", stdout);
1399 if (flags & 0x01) fputs("a", stdout);
1400 if (flags & 0x02) fputs("p", stdout);
1401 if (flags & 0x04) fputs("r", stdout);
1402 fputs(" ", stdout);
1403
1404 /* msgSecurityModel (INTEGER) */
1405 if ((count = asn1_parse(np, length, &elem)) < 0)
1406 return;
1407 if (elem.type != BE_INT) {
1408 fputs("[msgSecurityModel!=INT]", stdout);
1409 asn1_print(&elem);
1410 return;
1411 }
1412 model = elem.data.integer;
1413 length -= count;
1414 np += count;
1415
1416 if (count < length)
1417 printf("[%d extra after message SEQ]", length - count);
1418
1419 if (model == 3) {
1420 if (vflag) {
1421 fputs("USM ", stdout);
1422 }
1423 } else {
1424 printf("[security model %d]", model);
1425 return;
1426 }
1427
1428 np = xnp + (np - xnp);
1429 length = xlength - (np - xnp);
1430
1431 /* msgSecurityParameters (OCTET STRING) */
1432 if ((count = asn1_parse(np, length, &elem)) < 0)
1433 return;
1434 if (elem.type != BE_STR) {
1435 fputs("[msgSecurityParameters!=STR]", stdout);
1436 asn1_print(&elem);
1437 return;
1438 }
1439 length -= count;
1440 np += count;
1441
1442 if (model == 3) {
1443 usm_print(elem.data.str, elem.asnlen);
1444 }
1445
1446 if (vflag) {
1447 fputs("ScopedPDU ", stdout);
1448 }
1449
1450 scopedpdu_print(np, length, 3);
1451 }
1452
1453 /*
1454 * Decode SNMP header and pass on to PDU printing routines
1455 */
1456 void
1457 snmp_print(const u_char *np, u_int length)
1458 {
1459 struct be elem;
1460 int count = 0;
1461 int version = 0;
1462
1463 truncated = 0;
1464
1465 /* truncated packet? */
1466 if (np + length > snapend) {
1467 truncated = 1;
1468 length = snapend - np;
1469 }
1470
1471 putchar(' ');
1472
1473 /* initial Sequence */
1474 if ((count = asn1_parse(np, length, &elem)) < 0)
1475 return;
1476 if (elem.type != BE_SEQ) {
1477 fputs("[!init SEQ]", stdout);
1478 asn1_print(&elem);
1479 return;
1480 }
1481 if (count < length)
1482 printf("[%d extra after iSEQ]", length - count);
1483 /* descend */
1484 length = elem.asnlen;
1485 np = (u_char *)elem.data.raw;
1486
1487 /* Version (INTEGER) */
1488 if ((count = asn1_parse(np, length, &elem)) < 0)
1489 return;
1490 if (elem.type != BE_INT) {
1491 fputs("[version!=INT]", stdout);
1492 asn1_print(&elem);
1493 return;
1494 }
1495
1496 switch (elem.data.integer) {
1497 case SNMP_VERSION_1:
1498 case SNMP_VERSION_2:
1499 case SNMP_VERSION_3:
1500 if (vflag)
1501 printf("%s ", SnmpVersion[elem.data.integer]);
1502 break;
1503 default:
1504 printf("[version = %d]", elem.data.integer);
1505 return;
1506 }
1507 version = elem.data.integer;
1508 length -= count;
1509 np += count;
1510
1511 switch (version) {
1512 case SNMP_VERSION_1:
1513 case SNMP_VERSION_2:
1514 community_print(np, length, version);
1515 break;
1516 case SNMP_VERSION_3:
1517 v3msg_print(np, length);
1518 break;
1519 default:
1520 printf("[version = %d]", elem.data.integer);
1521 break;
1522 }
1523 }