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