]> The Tcpdump Group git mirrors - tcpdump/blob - print-snmp.c
gre: add support for MikroTik Ethernet-over-IP hack.
[tcpdump] / print-snmp.c
1 /*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * John Robert LoVerso. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 *
28 * This implementation has been influenced by the CMU SNMP release,
29 * by Steve Waldbusser. However, this shares no code with that system.
30 * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
31 * Earlier forms of this implementation were derived and/or inspired by an
32 * awk script originally written by C. Philip Wood of LANL (but later
33 * heavily modified by John Robert LoVerso). The copyright notice for
34 * that work is preserved below, even though it may not rightly apply
35 * to this file.
36 *
37 * Support for SNMPv2c/SNMPv3 and the ability to link the module against
38 * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
39 *
40 * This started out as a very simple program, but the incremental decoding
41 * (into the BE structure) complicated things.
42 *
43 # Los Alamos National Laboratory
44 #
45 # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
46 # This software was produced under a U.S. Government contract
47 # (W-7405-ENG-36) by Los Alamos National Laboratory, which is
48 # operated by the University of California for the U.S. Department
49 # of Energy. The U.S. Government is licensed to use, reproduce,
50 # and distribute this software. Permission is granted to the
51 # public to copy and use this software without charge, provided
52 # that this Notice and any statement of authorship are reproduced
53 # on all copies. Neither the Government nor the University makes
54 # any warranty, express or implied, or assumes any liability or
55 # responsibility for the use of this software.
56 # @(#)snmp.awk.x 1.1 (LANL) 1/15/90
57 */
58
59 /* \summary: Simple Network Management Protocol (SNMP) printer */
60
61 #ifdef HAVE_CONFIG_H
62 #include <config.h>
63 #endif
64
65 #include "netdissect-stdinc.h"
66
67 #include <stdio.h>
68 #include <string.h>
69 #include <limits.h>
70
71 #ifdef USE_LIBSMI
72 #include <smi.h>
73 #endif
74
75 #include "netdissect-ctype.h"
76
77 #define ND_LONGJMP_FROM_TCHECK
78 #include "netdissect.h"
79 #include "extract.h"
80
81 #undef OPAQUE /* defined in <wingdi.h> */
82
83
84 /*
85 * Universal ASN.1 types
86 * (we only care about the tag values for those allowed in the Internet SMI)
87 */
88 static const char *Universal[] = {
89 "U-0",
90 "Boolean",
91 "Integer",
92 #define INTEGER 2
93 "Bitstring",
94 "String",
95 #define STRING 4
96 "Null",
97 #define ASN_NULL 5
98 "ObjID",
99 #define OBJECTID 6
100 "ObjectDes",
101 "U-8","U-9","U-10","U-11", /* 8-11 */
102 "U-12","U-13","U-14","U-15", /* 12-15 */
103 "Sequence",
104 #define SEQUENCE 16
105 "Set"
106 };
107
108 /*
109 * Application-wide ASN.1 types from the Internet SMI and their tags
110 */
111 static const char *Application[] = {
112 "IpAddress",
113 #define IPADDR 0
114 "Counter",
115 #define COUNTER 1
116 "Gauge",
117 #define GAUGE 2
118 "TimeTicks",
119 #define TIMETICKS 3
120 "Opaque",
121 #define OPAQUE 4
122 "C-5",
123 "Counter64"
124 #define COUNTER64 6
125 };
126
127 /*
128 * Context-specific ASN.1 types for the SNMP PDUs and their tags
129 */
130 static const char *Context[] = {
131 "GetRequest",
132 #define GETREQ 0
133 "GetNextRequest",
134 #define GETNEXTREQ 1
135 "GetResponse",
136 #define GETRESP 2
137 "SetRequest",
138 #define SETREQ 3
139 "Trap",
140 #define TRAP 4
141 "GetBulk",
142 #define GETBULKREQ 5
143 "Inform",
144 #define INFORMREQ 6
145 "V2Trap",
146 #define V2TRAP 7
147 "Report"
148 #define REPORT 8
149 };
150
151 #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
152 #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
153 #define WRITE_CLASS(x) (x == SETREQ)
154 #define RESPONSE_CLASS(x) (x == GETRESP)
155 #define INTERNAL_CLASS(x) (x == REPORT)
156
157 /*
158 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
159 */
160 static const char *Exceptions[] = {
161 "noSuchObject",
162 #define NOSUCHOBJECT 0
163 "noSuchInstance",
164 #define NOSUCHINSTANCE 1
165 "endOfMibView",
166 #define ENDOFMIBVIEW 2
167 };
168
169 /*
170 * Private ASN.1 types
171 * The Internet SMI does not specify any
172 */
173 static const char *Private[] = {
174 "P-0"
175 };
176
177 /*
178 * error-status values for any SNMP PDU
179 */
180 static const char *ErrorStatus[] = {
181 "noError",
182 "tooBig",
183 "noSuchName",
184 "badValue",
185 "readOnly",
186 "genErr",
187 "noAccess",
188 "wrongType",
189 "wrongLength",
190 "wrongEncoding",
191 "wrongValue",
192 "noCreation",
193 "inconsistentValue",
194 "resourceUnavailable",
195 "commitFailed",
196 "undoFailed",
197 "authorizationError",
198 "notWritable",
199 "inconsistentName"
200 };
201 #define DECODE_ErrorStatus(e) \
202 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
203 ? ErrorStatus[e] \
204 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
205
206 /*
207 * generic-trap values in the SNMP Trap-PDU
208 */
209 static const char *GenericTrap[] = {
210 "coldStart",
211 "warmStart",
212 "linkDown",
213 "linkUp",
214 "authenticationFailure",
215 "egpNeighborLoss",
216 "enterpriseSpecific"
217 #define GT_ENTERPRISE 6
218 };
219 #define DECODE_GenericTrap(t) \
220 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
221 ? GenericTrap[t] \
222 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
223
224 /*
225 * ASN.1 type class table
226 * Ties together the preceding Universal, Application, Context, and Private
227 * type definitions.
228 */
229 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
230 static const struct {
231 const char *name;
232 const char **Id;
233 int numIDs;
234 } Class[] = {
235 defineCLASS(Universal),
236 #define UNIVERSAL 0
237 defineCLASS(Application),
238 #define APPLICATION 1
239 defineCLASS(Context),
240 #define CONTEXT 2
241 defineCLASS(Private),
242 #define PRIVATE 3
243 defineCLASS(Exceptions),
244 #define EXCEPTIONS 4
245 };
246
247 /*
248 * defined forms for ASN.1 types
249 */
250 static const char *Form[] = {
251 "Primitive",
252 #define PRIMITIVE 0
253 "Constructed",
254 #define CONSTRUCTED 1
255 };
256
257 /*
258 * A structure for the OID tree for the compiled-in MIB.
259 * This is stored as a general-order tree.
260 */
261 static struct obj {
262 const char *desc; /* name of object */
263 u_char oid; /* sub-id following parent */
264 u_char type; /* object type (unused) */
265 struct obj *child, *next; /* child and next sibling pointers */
266 } *objp = NULL;
267
268 /*
269 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
270 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
271 * a value for `mibroot'.
272 *
273 * In particular, this is gross, as this is including initialized structures,
274 * and by right shouldn't be an "include" file.
275 */
276 #include "mib.h"
277
278 /*
279 * This defines a list of OIDs which will be abbreviated on output.
280 * Currently, this includes the prefixes for the Internet MIB, the
281 * private enterprises tree, and the experimental tree.
282 */
283 #define OID_FIRST_OCTET(x, y) (((x)*40) + (y)) /* X.690 8.19.4 */
284
285 #ifndef NO_ABREV_MIB
286 static const uint8_t mib_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 2, 1 };
287 #endif
288 #ifndef NO_ABREV_ENTER
289 static const uint8_t enterprises_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 4, 1 };
290 #endif
291 #ifndef NO_ABREV_EXPERI
292 static const uint8_t experimental_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 3 };
293 #endif
294 #ifndef NO_ABBREV_SNMPMODS
295 static const uint8_t snmpModules_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 6, 3 };
296 #endif
297
298 #define OBJ_ABBREV_ENTRY(prefix, obj) \
299 { prefix, &_ ## obj ## _obj, obj ## _oid, sizeof (obj ## _oid) }
300 static const struct obj_abrev {
301 const char *prefix; /* prefix for this abrev */
302 struct obj *node; /* pointer into object table */
303 const uint8_t *oid; /* ASN.1 encoded OID */
304 size_t oid_len; /* length of OID */
305 } obj_abrev_list[] = {
306 #ifndef NO_ABREV_MIB
307 /* .iso.org.dod.internet.mgmt.mib */
308 OBJ_ABBREV_ENTRY("", mib),
309 #endif
310 #ifndef NO_ABREV_ENTER
311 /* .iso.org.dod.internet.private.enterprises */
312 OBJ_ABBREV_ENTRY("E:", enterprises),
313 #endif
314 #ifndef NO_ABREV_EXPERI
315 /* .iso.org.dod.internet.experimental */
316 OBJ_ABBREV_ENTRY("X:", experimental),
317 #endif
318 #ifndef NO_ABBREV_SNMPMODS
319 /* .iso.org.dod.internet.snmpV2.snmpModules */
320 OBJ_ABBREV_ENTRY("S:", snmpModules),
321 #endif
322 { 0,0,0,0 }
323 };
324
325 /*
326 * This is used in the OID print routine to walk down the object tree
327 * rooted at `mibroot'.
328 */
329 #define OBJ_PRINT(o, suppressdot) \
330 { \
331 if (objp) { \
332 do { \
333 if ((o) == objp->oid) \
334 break; \
335 } while ((objp = objp->next) != NULL); \
336 } \
337 if (objp) { \
338 ND_PRINT(suppressdot?"%s":".%s", objp->desc); \
339 objp = objp->child; \
340 } else \
341 ND_PRINT(suppressdot?"%u":".%u", (o)); \
342 }
343
344 /*
345 * This is the definition for the Any-Data-Type storage used purely for
346 * temporary internal representation while decoding an ASN.1 data stream.
347 */
348 struct be {
349 uint32_t asnlen;
350 union {
351 const uint8_t *raw;
352 int32_t integer;
353 uint32_t uns;
354 const u_char *str;
355 uint64_t uns64;
356 } data;
357 u_short id;
358 u_char form, class; /* tag info */
359 u_char type;
360 #define BE_ANY 255
361 #define BE_NONE 0
362 #define BE_NULL 1
363 #define BE_OCTET 2
364 #define BE_OID 3
365 #define BE_INT 4
366 #define BE_UNS 5
367 #define BE_STR 6
368 #define BE_SEQ 7
369 #define BE_INETADDR 8
370 #define BE_PDU 9
371 #define BE_UNS64 10
372 #define BE_NOSUCHOBJECT 128
373 #define BE_NOSUCHINST 129
374 #define BE_ENDOFMIBVIEW 130
375 };
376
377 /*
378 * SNMP versions recognized by this module
379 */
380 static const char *SnmpVersion[] = {
381 "SNMPv1",
382 #define SNMP_VERSION_1 0
383 "SNMPv2c",
384 #define SNMP_VERSION_2 1
385 "SNMPv2u",
386 #define SNMP_VERSION_2U 2
387 "SNMPv3"
388 #define SNMP_VERSION_3 3
389 };
390
391 /*
392 * Defaults for SNMP PDU components
393 */
394 #define DEF_COMMUNITY "public"
395
396 /*
397 * constants for ASN.1 decoding
398 */
399 #define OIDMUX 40
400 #define ASNLEN_INETADDR 4
401 #define ASN_SHIFT7 7
402 #define ASN_SHIFT8 8
403 #define ASN_BIT8 0x80
404 #define ASN_LONGLEN 0x80
405
406 #define ASN_ID_BITS 0x1f
407 #define ASN_FORM_BITS 0x20
408 #define ASN_FORM_SHIFT 5
409 #define ASN_CLASS_BITS 0xc0
410 #define ASN_CLASS_SHIFT 6
411
412 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
413
414 /*
415 * This decodes the next ASN.1 object in the stream pointed to by "p"
416 * (and of real-length "len") and stores the intermediate data in the
417 * provided BE object.
418 *
419 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
420 * O/w, this returns the number of bytes parsed from "p".
421 */
422 static int
423 asn1_parse(netdissect_options *ndo,
424 const u_char *p, u_int len, struct be *elem)
425 {
426 u_char form, class, id;
427 u_int i, hdr;
428
429 elem->asnlen = 0;
430 elem->type = BE_ANY;
431 if (len < 1) {
432 ND_PRINT("[nothing to parse]");
433 goto invalid;
434 }
435
436 /*
437 * it would be nice to use a bit field, but you can't depend on them.
438 * +---+---+---+---+---+---+---+---+
439 * + class |frm| id |
440 * +---+---+---+---+---+---+---+---+
441 * 7 6 5 4 3 2 1 0
442 */
443 id = GET_U_1(p) & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
444 #ifdef notdef
445 form = (GET_U_1(p) & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
446 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
447 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
448 #else
449 form = (u_char)(GET_U_1(p) & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
450 class = (u_char)(GET_U_1(p) & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
451 #endif
452 elem->form = form;
453 elem->class = class;
454 elem->id = id;
455 p++; len--; hdr = 1;
456 /* extended tag field */
457 if (id == ASN_ID_EXT) {
458 /*
459 * The ID follows, as a sequence of octets with the
460 * 8th bit set and the remaining 7 bits being
461 * the next 7 bits of the value, terminated with
462 * an octet with the 8th bit not set.
463 *
464 * First, assemble all the octets with the 8th
465 * bit set. XXX - this doesn't handle a value
466 * that won't fit in 32 bits.
467 */
468 id = 0;
469 while (GET_U_1(p) & ASN_BIT8) {
470 if (len < 1) {
471 ND_PRINT("[Xtagfield?]");
472 goto invalid;
473 }
474 id = (id << 7) | (GET_U_1(p) & ~ASN_BIT8);
475 len--;
476 hdr++;
477 p++;
478 }
479 if (len < 1) {
480 ND_PRINT("[Xtagfield?]");
481 goto invalid;
482 }
483 elem->id = id = (id << 7) | GET_U_1(p);
484 --len;
485 ++hdr;
486 ++p;
487 }
488 if (len < 1) {
489 ND_PRINT("[no asnlen]");
490 goto invalid;
491 }
492 elem->asnlen = GET_U_1(p);
493 p++; len--; hdr++;
494 if (elem->asnlen & ASN_BIT8) {
495 uint32_t noct = elem->asnlen % ASN_BIT8;
496 elem->asnlen = 0;
497 if (len < noct) {
498 ND_PRINT("[asnlen? %d<%d]", len, noct);
499 goto invalid;
500 }
501 for (; noct != 0; len--, hdr++, noct--) {
502 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | GET_U_1(p);
503 p++;
504 }
505 }
506 if (len < elem->asnlen) {
507 ND_PRINT("[len%d<asnlen%u]", len, elem->asnlen);
508 goto invalid;
509 }
510 if (form >= sizeof(Form)/sizeof(Form[0])) {
511 ND_PRINT("[form?%d]", form);
512 goto invalid;
513 }
514 if (class >= sizeof(Class)/sizeof(Class[0])) {
515 ND_PRINT("[class?%c/%d]", *Form[form], class);
516 goto invalid;
517 }
518 if ((int)id >= Class[class].numIDs) {
519 ND_PRINT("[id?%c/%s/%d]", *Form[form], Class[class].name, id);
520 goto invalid;
521 }
522 ND_TCHECK_LEN(p, elem->asnlen);
523
524 switch (form) {
525 case PRIMITIVE:
526 switch (class) {
527 case UNIVERSAL:
528 switch (id) {
529 case STRING:
530 elem->type = BE_STR;
531 elem->data.str = p;
532 break;
533
534 case INTEGER: {
535 uint32_t data;
536 elem->type = BE_INT;
537 data = 0;
538
539 if (elem->asnlen == 0) {
540 ND_PRINT("[asnlen=0]");
541 goto invalid;
542 }
543 if (GET_U_1(p) & ASN_BIT8) /* negative */
544 data = UINT_MAX;
545 for (i = elem->asnlen; i != 0; p++, i--)
546 data = (data << ASN_SHIFT8) | GET_U_1(p);
547 elem->data.integer = data;
548 break;
549 }
550
551 case OBJECTID:
552 elem->type = BE_OID;
553 elem->data.raw = (const uint8_t *)p;
554 break;
555
556 case ASN_NULL:
557 elem->type = BE_NULL;
558 elem->data.raw = NULL;
559 break;
560
561 default:
562 elem->type = BE_OCTET;
563 elem->data.raw = (const uint8_t *)p;
564 ND_PRINT("[P/U/%s]", Class[class].Id[id]);
565 break;
566 }
567 break;
568
569 case APPLICATION:
570 switch (id) {
571 case IPADDR:
572 elem->type = BE_INETADDR;
573 elem->data.raw = (const uint8_t *)p;
574 break;
575
576 case COUNTER:
577 case GAUGE:
578 case TIMETICKS: {
579 uint32_t data;
580 elem->type = BE_UNS;
581 data = 0;
582 for (i = elem->asnlen; i != 0; p++, i--)
583 data = (data << 8) + GET_U_1(p);
584 elem->data.uns = data;
585 break;
586 }
587
588 case COUNTER64: {
589 uint64_t data64;
590 elem->type = BE_UNS64;
591 data64 = 0;
592 for (i = elem->asnlen; i != 0; p++, i--)
593 data64 = (data64 << 8) + GET_U_1(p);
594 elem->data.uns64 = data64;
595 break;
596 }
597
598 default:
599 elem->type = BE_OCTET;
600 elem->data.raw = (const uint8_t *)p;
601 ND_PRINT("[P/A/%s]",
602 Class[class].Id[id]);
603 break;
604 }
605 break;
606
607 case CONTEXT:
608 switch (id) {
609 case NOSUCHOBJECT:
610 elem->type = BE_NOSUCHOBJECT;
611 elem->data.raw = NULL;
612 break;
613
614 case NOSUCHINSTANCE:
615 elem->type = BE_NOSUCHINST;
616 elem->data.raw = NULL;
617 break;
618
619 case ENDOFMIBVIEW:
620 elem->type = BE_ENDOFMIBVIEW;
621 elem->data.raw = NULL;
622 break;
623 }
624 break;
625
626 default:
627 ND_PRINT("[P/%s/%s]", Class[class].name, Class[class].Id[id]);
628 elem->type = BE_OCTET;
629 elem->data.raw = (const uint8_t *)p;
630 break;
631 }
632 break;
633
634 case CONSTRUCTED:
635 switch (class) {
636 case UNIVERSAL:
637 switch (id) {
638 case SEQUENCE:
639 elem->type = BE_SEQ;
640 elem->data.raw = (const uint8_t *)p;
641 break;
642
643 default:
644 elem->type = BE_OCTET;
645 elem->data.raw = (const uint8_t *)p;
646 ND_PRINT("C/U/%s", Class[class].Id[id]);
647 break;
648 }
649 break;
650
651 case CONTEXT:
652 elem->type = BE_PDU;
653 elem->data.raw = (const uint8_t *)p;
654 break;
655
656 default:
657 elem->type = BE_OCTET;
658 elem->data.raw = (const uint8_t *)p;
659 ND_PRINT("C/%s/%s", Class[class].name, Class[class].Id[id]);
660 break;
661 }
662 break;
663 }
664 p += elem->asnlen;
665 len -= elem->asnlen;
666 return elem->asnlen + hdr;
667
668 invalid:
669 return -1;
670 }
671
672 static void
673 asn1_print_octets(netdissect_options *ndo, struct be *elem)
674 {
675 const u_char *p = (const u_char *)elem->data.raw;
676 uint32_t asnlen = elem->asnlen;
677 uint32_t i;
678
679 for (i = asnlen; i != 0; p++, i--)
680 ND_PRINT("_%.2x", GET_U_1(p));
681 }
682
683 static void
684 asn1_print_string(netdissect_options *ndo, struct be *elem)
685 {
686 int printable = 1, first = 1;
687 const u_char *p;
688 uint32_t asnlen = elem->asnlen;
689 uint32_t i;
690
691 p = elem->data.str;
692 for (i = asnlen; printable && i != 0; p++, i--)
693 printable = ND_ASCII_ISPRINT(GET_U_1(p));
694 p = elem->data.str;
695 if (printable) {
696 ND_PRINT("\"");
697 nd_printjn(ndo, p, asnlen);
698 ND_PRINT("\"");
699 } else {
700 for (i = asnlen; i != 0; p++, i--) {
701 ND_PRINT(first ? "%.2x" : "_%.2x", GET_U_1(p));
702 first = 0;
703 }
704 }
705 }
706
707 /*
708 * Display the ASN.1 object represented by the BE object.
709 * This used to be an integral part of asn1_parse() before the intermediate
710 * BE form was added.
711 */
712 static int
713 asn1_print(netdissect_options *ndo,
714 struct be *elem)
715 {
716 const u_char *p;
717 uint32_t asnlen = elem->asnlen;
718 uint32_t i;
719
720 switch (elem->type) {
721
722 case BE_OCTET:
723 asn1_print_octets(ndo, elem);
724 break;
725
726 case BE_NULL:
727 break;
728
729 case BE_OID: {
730 int first = -1;
731 uint32_t o = 0;
732
733 p = (const u_char *)elem->data.raw;
734 i = asnlen;
735 if (!ndo->ndo_nflag && asnlen > 2) {
736 const struct obj_abrev *a = &obj_abrev_list[0];
737 for (; a->node; a++) {
738 if (i < a->oid_len)
739 continue;
740 ND_TCHECK_LEN(p, a->oid_len);
741 if (memcmp(a->oid, p, a->oid_len) == 0) {
742 objp = a->node->child;
743 i -= a->oid_len;
744 p += a->oid_len;
745 ND_PRINT("%s", a->prefix);
746 first = 1;
747 break;
748 }
749 }
750 }
751
752 for (; i != 0; p++, i--) {
753 o = (o << ASN_SHIFT7) + (GET_U_1(p) & ~ASN_BIT8);
754 if (GET_U_1(p) & ASN_LONGLEN)
755 continue;
756
757 /*
758 * first subitem encodes two items with
759 * 1st*OIDMUX+2nd
760 * (see X.690:1997 clause 8.19 for the details)
761 */
762 if (first < 0) {
763 int s;
764 if (!ndo->ndo_nflag)
765 objp = mibroot;
766 first = 0;
767 s = o / OIDMUX;
768 if (s > 2) s = 2;
769 OBJ_PRINT(s, first);
770 o -= s * OIDMUX;
771 }
772 OBJ_PRINT(o, first);
773 if (--first < 0)
774 first = 0;
775 o = 0;
776 }
777 break;
778 }
779
780 case BE_INT:
781 ND_PRINT("%d", elem->data.integer);
782 break;
783
784 case BE_UNS:
785 ND_PRINT("%u", elem->data.uns);
786 break;
787
788 case BE_UNS64:
789 ND_PRINT("%" PRIu64, elem->data.uns64);
790 break;
791
792 case BE_STR:
793 asn1_print_string(ndo, elem);
794 break;
795
796 case BE_SEQ:
797 ND_PRINT("Seq(%u)", elem->asnlen);
798 break;
799
800 case BE_INETADDR:
801 if (asnlen != ASNLEN_INETADDR)
802 ND_PRINT("[inetaddr len!=%d]", ASNLEN_INETADDR);
803 p = (const u_char *)elem->data.raw;
804 for (i = asnlen; i != 0; p++, i--) {
805 ND_PRINT((i == asnlen) ? "%u" : ".%u", GET_U_1(p));
806 }
807 break;
808
809 case BE_NOSUCHOBJECT:
810 case BE_NOSUCHINST:
811 case BE_ENDOFMIBVIEW:
812 ND_PRINT("[%s]", Class[EXCEPTIONS].Id[elem->id]);
813 break;
814
815 case BE_PDU:
816 ND_PRINT("%s(%u)", Class[CONTEXT].Id[elem->id], elem->asnlen);
817 break;
818
819 case BE_ANY:
820 ND_PRINT("[BE_ANY!?]");
821 break;
822
823 default:
824 ND_PRINT("[be!?]");
825 break;
826 }
827 /* This function now always returns 0. Don't make it void yet, as other
828 * code checks for negative result and this function might need to signal
829 * invalid data later.
830 */
831 return 0;
832 }
833
834 #ifdef notdef
835 /*
836 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
837 * This will work for any ASN.1 stream, not just an SNMP PDU.
838 *
839 * By adding newlines and spaces at the correct places, this would print in
840 * Rose-Normal-Form.
841 *
842 * This is not currently used.
843 */
844 static void
845 asn1_decode(u_char *p, u_int length)
846 {
847 struct be elem;
848 int i = 0;
849
850 while (i >= 0 && length > 0) {
851 i = asn1_parse(ndo, p, length, &elem);
852 if (i >= 0) {
853 ND_PRINT(" ");
854 if (asn1_print(ndo, &elem) < 0)
855 return;
856 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
857 ND_PRINT(" {");
858 asn1_decode(elem.data.raw, elem.asnlen);
859 ND_PRINT(" }");
860 }
861 length -= i;
862 p += i;
863 }
864 }
865 }
866 #endif
867
868 #ifdef USE_LIBSMI
869
870 struct smi2be {
871 SmiBasetype basetype;
872 int be;
873 };
874
875 static const struct smi2be smi2betab[] = {
876 { SMI_BASETYPE_INTEGER32, BE_INT },
877 { SMI_BASETYPE_OCTETSTRING, BE_STR },
878 { SMI_BASETYPE_OCTETSTRING, BE_INETADDR },
879 { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID },
880 { SMI_BASETYPE_UNSIGNED32, BE_UNS },
881 { SMI_BASETYPE_INTEGER64, BE_NONE },
882 { SMI_BASETYPE_UNSIGNED64, BE_UNS64 },
883 { SMI_BASETYPE_FLOAT32, BE_NONE },
884 { SMI_BASETYPE_FLOAT64, BE_NONE },
885 { SMI_BASETYPE_FLOAT128, BE_NONE },
886 { SMI_BASETYPE_ENUM, BE_INT },
887 { SMI_BASETYPE_BITS, BE_STR },
888 { SMI_BASETYPE_UNKNOWN, BE_NONE }
889 };
890
891 static int
892 smi_decode_oid(netdissect_options *ndo,
893 struct be *elem, unsigned int *oid,
894 unsigned int oidsize, unsigned int *oidlen)
895 {
896 const u_char *p = (const u_char *)elem->data.raw;
897 uint32_t asnlen = elem->asnlen;
898 uint32_t i = asnlen;
899 int o = 0, first = -1;
900 unsigned int firstval;
901
902 for (*oidlen = 0; i != 0; p++, i--) {
903 o = (o << ASN_SHIFT7) + (GET_U_1(p) & ~ASN_BIT8);
904 if (GET_U_1(p) & ASN_LONGLEN)
905 continue;
906
907 /*
908 * first subitem encodes two items with 1st*OIDMUX+2nd
909 * (see X.690:1997 clause 8.19 for the details)
910 */
911 if (first < 0) {
912 first = 0;
913 firstval = o / OIDMUX;
914 if (firstval > 2) firstval = 2;
915 o -= firstval * OIDMUX;
916 if (*oidlen < oidsize) {
917 oid[(*oidlen)++] = firstval;
918 }
919 }
920 if (*oidlen < oidsize) {
921 oid[(*oidlen)++] = o;
922 }
923 o = 0;
924 }
925 return 0;
926 }
927
928 static int smi_check_type(SmiBasetype basetype, int be)
929 {
930 int i;
931
932 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
933 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
934 return 1;
935 }
936 }
937
938 return 0;
939 }
940
941 static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
942 struct be *elem)
943 {
944 int ok = 1;
945
946 switch (smiType->basetype) {
947 case SMI_BASETYPE_OBJECTIDENTIFIER:
948 case SMI_BASETYPE_OCTETSTRING:
949 if (smiRange->minValue.value.unsigned32
950 == smiRange->maxValue.value.unsigned32) {
951 ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
952 } else {
953 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
954 && elem->asnlen <= smiRange->maxValue.value.unsigned32);
955 }
956 break;
957
958 case SMI_BASETYPE_INTEGER32:
959 ok = (elem->data.integer >= smiRange->minValue.value.integer32
960 && elem->data.integer <= smiRange->maxValue.value.integer32);
961 break;
962
963 case SMI_BASETYPE_UNSIGNED32:
964 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
965 && elem->data.uns <= smiRange->maxValue.value.unsigned32);
966 break;
967
968 case SMI_BASETYPE_UNSIGNED64:
969 /* XXX */
970 break;
971
972 /* case SMI_BASETYPE_INTEGER64: SMIng */
973 /* case SMI_BASETYPE_FLOAT32: SMIng */
974 /* case SMI_BASETYPE_FLOAT64: SMIng */
975 /* case SMI_BASETYPE_FLOAT128: SMIng */
976
977 case SMI_BASETYPE_ENUM:
978 case SMI_BASETYPE_BITS:
979 case SMI_BASETYPE_UNKNOWN:
980 ok = 1;
981 break;
982
983 default:
984 ok = 0;
985 break;
986 }
987
988 return ok;
989 }
990
991 static int smi_check_range(SmiType *smiType, struct be *elem)
992 {
993 SmiRange *smiRange;
994 int ok = 1;
995
996 for (smiRange = smiGetFirstRange(smiType);
997 smiRange;
998 smiRange = smiGetNextRange(smiRange)) {
999
1000 ok = smi_check_a_range(smiType, smiRange, elem);
1001
1002 if (ok) {
1003 break;
1004 }
1005 }
1006
1007 if (ok) {
1008 SmiType *parentType;
1009 parentType = smiGetParentType(smiType);
1010 if (parentType) {
1011 ok = smi_check_range(parentType, elem);
1012 }
1013 }
1014
1015 return ok;
1016 }
1017
1018 static SmiNode *
1019 smi_print_variable(netdissect_options *ndo,
1020 struct be *elem, int *status)
1021 {
1022 unsigned int oid[128], oidlen;
1023 SmiNode *smiNode = NULL;
1024 unsigned int i;
1025
1026 if (!nd_smi_module_loaded) {
1027 *status = asn1_print(ndo, elem);
1028 return NULL;
1029 }
1030 *status = smi_decode_oid(ndo, elem, oid, sizeof(oid) / sizeof(unsigned int),
1031 &oidlen);
1032 if (*status < 0)
1033 return NULL;
1034 smiNode = smiGetNodeByOID(oidlen, oid);
1035 if (! smiNode) {
1036 *status = asn1_print(ndo, elem);
1037 return NULL;
1038 }
1039 if (ndo->ndo_vflag) {
1040 ND_PRINT("%s::", smiGetNodeModule(smiNode)->name);
1041 }
1042 ND_PRINT("%s", smiNode->name);
1043 if (smiNode->oidlen < oidlen) {
1044 for (i = smiNode->oidlen; i < oidlen; i++) {
1045 ND_PRINT(".%u", oid[i]);
1046 }
1047 }
1048 *status = 0;
1049 return smiNode;
1050 }
1051
1052 static int
1053 smi_print_value(netdissect_options *ndo,
1054 SmiNode *smiNode, u_short pduid, struct be *elem)
1055 {
1056 unsigned int i, oid[128], oidlen;
1057 SmiType *smiType;
1058 SmiNamedNumber *nn;
1059 int done = 0;
1060
1061 if (! smiNode || ! (smiNode->nodekind
1062 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
1063 return asn1_print(ndo, elem);
1064 }
1065
1066 if (elem->type == BE_NOSUCHOBJECT
1067 || elem->type == BE_NOSUCHINST
1068 || elem->type == BE_ENDOFMIBVIEW) {
1069 return asn1_print(ndo, elem);
1070 }
1071
1072 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
1073 ND_PRINT("[notNotifyable]");
1074 }
1075
1076 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
1077 ND_PRINT("[notReadable]");
1078 }
1079
1080 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
1081 ND_PRINT("[notWritable]");
1082 }
1083
1084 if (RESPONSE_CLASS(pduid)
1085 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1086 ND_PRINT("[noAccess]");
1087 }
1088
1089 smiType = smiGetNodeType(smiNode);
1090 if (! smiType) {
1091 return asn1_print(ndo, elem);
1092 }
1093
1094 if (! smi_check_type(smiType->basetype, elem->type)) {
1095 ND_PRINT("[wrongType]");
1096 }
1097
1098 if (! smi_check_range(smiType, elem)) {
1099 ND_PRINT("[outOfRange]");
1100 }
1101
1102 /* resolve bits to named bits */
1103
1104 /* check whether instance identifier is valid */
1105
1106 /* apply display hints (integer, octetstring) */
1107
1108 /* convert instance identifier to index type values */
1109
1110 switch (elem->type) {
1111 case BE_OID:
1112 if (smiType->basetype == SMI_BASETYPE_BITS) {
1113 /* print bit labels */
1114 } else {
1115 if (nd_smi_module_loaded &&
1116 smi_decode_oid(ndo, elem, oid,
1117 sizeof(oid)/sizeof(unsigned int),
1118 &oidlen) == 0) {
1119 smiNode = smiGetNodeByOID(oidlen, oid);
1120 if (smiNode) {
1121 if (ndo->ndo_vflag) {
1122 ND_PRINT("%s::", smiGetNodeModule(smiNode)->name);
1123 }
1124 ND_PRINT("%s", smiNode->name);
1125 if (smiNode->oidlen < oidlen) {
1126 for (i = smiNode->oidlen;
1127 i < oidlen; i++) {
1128 ND_PRINT(".%u", oid[i]);
1129 }
1130 }
1131 done++;
1132 }
1133 }
1134 }
1135 break;
1136
1137 case BE_INT:
1138 if (smiType->basetype == SMI_BASETYPE_ENUM) {
1139 for (nn = smiGetFirstNamedNumber(smiType);
1140 nn;
1141 nn = smiGetNextNamedNumber(nn)) {
1142 if (nn->value.value.integer32
1143 == elem->data.integer) {
1144 ND_PRINT("%s", nn->name);
1145 ND_PRINT("(%d)", elem->data.integer);
1146 done++;
1147 break;
1148 }
1149 }
1150 }
1151 break;
1152 }
1153
1154 if (! done) {
1155 return asn1_print(ndo, elem);
1156 }
1157 return 0;
1158 }
1159 #endif
1160
1161 /*
1162 * General SNMP header
1163 * SEQUENCE {
1164 * version INTEGER {version-1(0)},
1165 * community OCTET STRING,
1166 * data ANY -- PDUs
1167 * }
1168 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1169 * SEQUENCE {
1170 * request-id INTEGER,
1171 * error-status INTEGER,
1172 * error-index INTEGER,
1173 * varbindlist SEQUENCE OF
1174 * SEQUENCE {
1175 * name ObjectName,
1176 * value ObjectValue
1177 * }
1178 * }
1179 * PDU for Trap:
1180 * SEQUENCE {
1181 * enterprise OBJECT IDENTIFIER,
1182 * agent-addr NetworkAddress,
1183 * generic-trap INTEGER,
1184 * specific-trap INTEGER,
1185 * time-stamp TimeTicks,
1186 * varbindlist SEQUENCE OF
1187 * SEQUENCE {
1188 * name ObjectName,
1189 * value ObjectValue
1190 * }
1191 * }
1192 */
1193
1194 /*
1195 * Decode SNMP varBind
1196 */
1197 static void
1198 varbind_print(netdissect_options *ndo,
1199 u_short pduid, const u_char *np, u_int length)
1200 {
1201 struct be elem;
1202 int count = 0;
1203 #ifdef USE_LIBSMI
1204 SmiNode *smiNode = NULL;
1205 #endif
1206 int status;
1207
1208 /* Sequence of varBind */
1209 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1210 return;
1211 if (elem.type != BE_SEQ) {
1212 ND_PRINT("[!SEQ of varbind]");
1213 asn1_print(ndo, &elem);
1214 return;
1215 }
1216 if ((u_int)count < length)
1217 ND_PRINT("[%d extra after SEQ of varbind]", length - count);
1218 /* descend */
1219 length = elem.asnlen;
1220 np = (const u_char *)elem.data.raw;
1221
1222 while (length) {
1223 const u_char *vbend;
1224 u_int vblength;
1225
1226 ND_PRINT(" ");
1227
1228 /* Sequence */
1229 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1230 return;
1231 if (elem.type != BE_SEQ) {
1232 ND_PRINT("[!varbind]");
1233 asn1_print(ndo, &elem);
1234 return;
1235 }
1236 vbend = np + count;
1237 vblength = length - count;
1238 /* descend */
1239 length = elem.asnlen;
1240 np = (const u_char *)elem.data.raw;
1241
1242 /* objName (OID) */
1243 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1244 return;
1245 if (elem.type != BE_OID) {
1246 ND_PRINT("[objName!=OID]");
1247 asn1_print(ndo, &elem);
1248 return;
1249 }
1250 #ifdef USE_LIBSMI
1251 smiNode = smi_print_variable(ndo, &elem, &status);
1252 #else
1253 status = asn1_print(ndo, &elem);
1254 #endif
1255 if (status < 0)
1256 return;
1257 length -= count;
1258 np += count;
1259
1260 if (pduid != GETREQ && pduid != GETNEXTREQ
1261 && pduid != GETBULKREQ)
1262 ND_PRINT("=");
1263
1264 /* objVal (ANY) */
1265 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1266 return;
1267 if (pduid == GETREQ || pduid == GETNEXTREQ
1268 || pduid == GETBULKREQ) {
1269 if (elem.type != BE_NULL) {
1270 ND_PRINT("[objVal!=NULL]");
1271 if (asn1_print(ndo, &elem) < 0)
1272 return;
1273 }
1274 } else {
1275 if (elem.type != BE_NULL) {
1276 #ifdef USE_LIBSMI
1277 status = smi_print_value(ndo, smiNode, pduid, &elem);
1278 #else
1279 status = asn1_print(ndo, &elem);
1280 #endif
1281 }
1282 if (status < 0)
1283 return;
1284 }
1285 length = vblength;
1286 np = vbend;
1287 }
1288 }
1289
1290 /*
1291 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1292 * GetBulk, Inform, V2Trap, and Report
1293 */
1294 static void
1295 snmppdu_print(netdissect_options *ndo,
1296 u_short pduid, const u_char *np, u_int length)
1297 {
1298 struct be elem;
1299 int count = 0, error_status;
1300
1301 /* reqId (Integer) */
1302 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1303 return;
1304 if (elem.type != BE_INT) {
1305 ND_PRINT("[reqId!=INT]");
1306 asn1_print(ndo, &elem);
1307 return;
1308 }
1309 if (ndo->ndo_vflag)
1310 ND_PRINT("R=%d ", elem.data.integer);
1311 length -= count;
1312 np += count;
1313
1314 /* errorStatus (Integer) */
1315 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1316 return;
1317 if (elem.type != BE_INT) {
1318 ND_PRINT("[errorStatus!=INT]");
1319 asn1_print(ndo, &elem);
1320 return;
1321 }
1322 error_status = 0;
1323 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1324 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1325 && elem.data.integer != 0) {
1326 char errbuf[20];
1327 ND_PRINT("[errorStatus(%s)!=0]",
1328 DECODE_ErrorStatus(elem.data.integer));
1329 } else if (pduid == GETBULKREQ) {
1330 ND_PRINT(" N=%d", elem.data.integer);
1331 } else if (elem.data.integer != 0) {
1332 char errbuf[20];
1333 ND_PRINT(" %s", DECODE_ErrorStatus(elem.data.integer));
1334 error_status = elem.data.integer;
1335 }
1336 length -= count;
1337 np += count;
1338
1339 /* errorIndex (Integer) */
1340 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1341 return;
1342 if (elem.type != BE_INT) {
1343 ND_PRINT("[errorIndex!=INT]");
1344 asn1_print(ndo, &elem);
1345 return;
1346 }
1347 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1348 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1349 && elem.data.integer != 0)
1350 ND_PRINT("[errorIndex(%d)!=0]", elem.data.integer);
1351 else if (pduid == GETBULKREQ)
1352 ND_PRINT(" M=%d", elem.data.integer);
1353 else if (elem.data.integer != 0) {
1354 if (!error_status)
1355 ND_PRINT("[errorIndex(%d) w/o errorStatus]", elem.data.integer);
1356 else
1357 ND_PRINT("@%d", elem.data.integer);
1358 } else if (error_status) {
1359 ND_PRINT("[errorIndex==0]");
1360 }
1361 length -= count;
1362 np += count;
1363
1364 varbind_print(ndo, pduid, np, length);
1365 }
1366
1367 /*
1368 * Decode SNMP Trap PDU
1369 */
1370 static void
1371 trappdu_print(netdissect_options *ndo,
1372 const u_char *np, u_int length)
1373 {
1374 struct be elem;
1375 int count = 0, generic;
1376
1377 ND_PRINT(" ");
1378
1379 /* enterprise (oid) */
1380 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1381 return;
1382 if (elem.type != BE_OID) {
1383 ND_PRINT("[enterprise!=OID]");
1384 asn1_print(ndo, &elem);
1385 return;
1386 }
1387 if (asn1_print(ndo, &elem) < 0)
1388 return;
1389 length -= count;
1390 np += count;
1391
1392 ND_PRINT(" ");
1393
1394 /* agent-addr (inetaddr) */
1395 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1396 return;
1397 if (elem.type != BE_INETADDR) {
1398 ND_PRINT("[agent-addr!=INETADDR]");
1399 asn1_print(ndo, &elem);
1400 return;
1401 }
1402 if (asn1_print(ndo, &elem) < 0)
1403 return;
1404 length -= count;
1405 np += count;
1406
1407 /* generic-trap (Integer) */
1408 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1409 return;
1410 if (elem.type != BE_INT) {
1411 ND_PRINT("[generic-trap!=INT]");
1412 asn1_print(ndo, &elem);
1413 return;
1414 }
1415 generic = elem.data.integer;
1416 {
1417 char buf[20];
1418 ND_PRINT(" %s", DECODE_GenericTrap(generic));
1419 }
1420 length -= count;
1421 np += count;
1422
1423 /* specific-trap (Integer) */
1424 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1425 return;
1426 if (elem.type != BE_INT) {
1427 ND_PRINT("[specific-trap!=INT]");
1428 asn1_print(ndo, &elem);
1429 return;
1430 }
1431 if (generic != GT_ENTERPRISE) {
1432 if (elem.data.integer != 0)
1433 ND_PRINT("[specific-trap(%d)!=0]", elem.data.integer);
1434 } else
1435 ND_PRINT(" s=%d", elem.data.integer);
1436 length -= count;
1437 np += count;
1438
1439 ND_PRINT(" ");
1440
1441 /* time-stamp (TimeTicks) */
1442 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1443 return;
1444 if (elem.type != BE_UNS) { /* XXX */
1445 ND_PRINT("[time-stamp!=TIMETICKS]");
1446 asn1_print(ndo, &elem);
1447 return;
1448 }
1449 if (asn1_print(ndo, &elem) < 0)
1450 return;
1451 length -= count;
1452 np += count;
1453
1454 varbind_print(ndo, TRAP, np, length);
1455 }
1456
1457 /*
1458 * Decode arbitrary SNMP PDUs.
1459 */
1460 static void
1461 pdu_print(netdissect_options *ndo,
1462 const u_char *np, u_int length, int version)
1463 {
1464 struct be pdu;
1465 int count = 0;
1466
1467 /* PDU (Context) */
1468 if ((count = asn1_parse(ndo, np, length, &pdu)) < 0)
1469 return;
1470 if (pdu.type != BE_PDU) {
1471 ND_PRINT("[no PDU]");
1472 return;
1473 }
1474 if ((u_int)count < length)
1475 ND_PRINT("[%d extra after PDU]", length - count);
1476 if (ndo->ndo_vflag) {
1477 ND_PRINT("{ ");
1478 }
1479 if (asn1_print(ndo, &pdu) < 0)
1480 return;
1481 ND_PRINT(" ");
1482 /* descend into PDU */
1483 length = pdu.asnlen;
1484 np = (const u_char *)pdu.data.raw;
1485
1486 if (version == SNMP_VERSION_1 &&
1487 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1488 pdu.id == V2TRAP || pdu.id == REPORT)) {
1489 ND_PRINT("[v2 PDU in v1 message]");
1490 return;
1491 }
1492
1493 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1494 ND_PRINT("[v1 PDU in v2 message]");
1495 return;
1496 }
1497
1498 switch (pdu.id) {
1499 case TRAP:
1500 trappdu_print(ndo, np, length);
1501 break;
1502 case GETREQ:
1503 case GETNEXTREQ:
1504 case GETRESP:
1505 case SETREQ:
1506 case GETBULKREQ:
1507 case INFORMREQ:
1508 case V2TRAP:
1509 case REPORT:
1510 snmppdu_print(ndo, pdu.id, np, length);
1511 break;
1512 }
1513
1514 if (ndo->ndo_vflag) {
1515 ND_PRINT(" } ");
1516 }
1517 }
1518
1519 /*
1520 * Decode a scoped SNMP PDU.
1521 */
1522 static void
1523 scopedpdu_print(netdissect_options *ndo,
1524 const u_char *np, u_int length, int version)
1525 {
1526 struct be elem;
1527 int count = 0;
1528
1529 /* Sequence */
1530 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1531 return;
1532 if (elem.type != BE_SEQ) {
1533 ND_PRINT("[!scoped PDU]");
1534 asn1_print(ndo, &elem);
1535 return;
1536 }
1537 length = elem.asnlen;
1538 np = (const u_char *)elem.data.raw;
1539
1540 /* contextEngineID (OCTET STRING) */
1541 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1542 return;
1543 if (elem.type != BE_STR) {
1544 ND_PRINT("[contextEngineID!=STR]");
1545 asn1_print(ndo, &elem);
1546 return;
1547 }
1548 length -= count;
1549 np += count;
1550
1551 ND_PRINT("E=");
1552 asn1_print_octets(ndo, &elem);
1553 ND_PRINT(" ");
1554
1555 /* contextName (OCTET STRING) */
1556 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1557 return;
1558 if (elem.type != BE_STR) {
1559 ND_PRINT("[contextName!=STR]");
1560 asn1_print(ndo, &elem);
1561 return;
1562 }
1563 length -= count;
1564 np += count;
1565
1566 ND_PRINT("C=");
1567 asn1_print_string(ndo, &elem);
1568 ND_PRINT(" ");
1569
1570 pdu_print(ndo, np, length, version);
1571 }
1572
1573 /*
1574 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1575 */
1576 static void
1577 community_print(netdissect_options *ndo,
1578 const u_char *np, u_int length, int version)
1579 {
1580 struct be elem;
1581 int count = 0;
1582
1583 /* Community (String) */
1584 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1585 return;
1586 if (elem.type != BE_STR) {
1587 ND_PRINT("[comm!=STR]");
1588 asn1_print(ndo, &elem);
1589 return;
1590 }
1591 /* default community */
1592 if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
1593 strncmp((const char *)elem.data.str, DEF_COMMUNITY,
1594 sizeof(DEF_COMMUNITY) - 1) == 0)) {
1595 /* ! "public" */
1596 ND_PRINT("C=");
1597 asn1_print_string(ndo, &elem);
1598 ND_PRINT(" ");
1599 }
1600 length -= count;
1601 np += count;
1602
1603 pdu_print(ndo, np, length, version);
1604 }
1605
1606 /*
1607 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1608 */
1609 static void
1610 usm_print(netdissect_options *ndo,
1611 const u_char *np, u_int length)
1612 {
1613 struct be elem;
1614 int count = 0;
1615
1616 /* Sequence */
1617 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1618 return;
1619 if (elem.type != BE_SEQ) {
1620 ND_PRINT("[!usm]");
1621 asn1_print(ndo, &elem);
1622 return;
1623 }
1624 length = elem.asnlen;
1625 np = (const u_char *)elem.data.raw;
1626
1627 /* msgAuthoritativeEngineID (OCTET STRING) */
1628 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1629 return;
1630 if (elem.type != BE_STR) {
1631 ND_PRINT("[msgAuthoritativeEngineID!=STR]");
1632 asn1_print(ndo, &elem);
1633 return;
1634 }
1635 length -= count;
1636 np += count;
1637
1638 /* msgAuthoritativeEngineBoots (INTEGER) */
1639 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1640 return;
1641 if (elem.type != BE_INT) {
1642 ND_PRINT("[msgAuthoritativeEngineBoots!=INT]");
1643 asn1_print(ndo, &elem);
1644 return;
1645 }
1646 if (ndo->ndo_vflag)
1647 ND_PRINT("B=%d ", elem.data.integer);
1648 length -= count;
1649 np += count;
1650
1651 /* msgAuthoritativeEngineTime (INTEGER) */
1652 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1653 return;
1654 if (elem.type != BE_INT) {
1655 ND_PRINT("[msgAuthoritativeEngineTime!=INT]");
1656 asn1_print(ndo, &elem);
1657 return;
1658 }
1659 if (ndo->ndo_vflag)
1660 ND_PRINT("T=%d ", elem.data.integer);
1661 length -= count;
1662 np += count;
1663
1664 /* msgUserName (OCTET STRING) */
1665 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1666 return;
1667 if (elem.type != BE_STR) {
1668 ND_PRINT("[msgUserName!=STR]");
1669 asn1_print(ndo, &elem);
1670 return;
1671 }
1672 length -= count;
1673 np += count;
1674
1675 ND_PRINT("U=");
1676 asn1_print_string(ndo, &elem);
1677 ND_PRINT(" ");
1678
1679 /* msgAuthenticationParameters (OCTET STRING) */
1680 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1681 return;
1682 if (elem.type != BE_STR) {
1683 ND_PRINT("[msgAuthenticationParameters!=STR]");
1684 asn1_print(ndo, &elem);
1685 return;
1686 }
1687 length -= count;
1688 np += count;
1689
1690 /* msgPrivacyParameters (OCTET STRING) */
1691 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1692 return;
1693 if (elem.type != BE_STR) {
1694 ND_PRINT("[msgPrivacyParameters!=STR]");
1695 asn1_print(ndo, &elem);
1696 return;
1697 }
1698 length -= count;
1699 np += count;
1700
1701 if ((u_int)count < length)
1702 ND_PRINT("[%d extra after usm SEQ]", length - count);
1703 }
1704
1705 /*
1706 * Decode SNMPv3 Message Header (SNMPv3)
1707 */
1708 static void
1709 v3msg_print(netdissect_options *ndo,
1710 const u_char *np, u_int length)
1711 {
1712 struct be elem;
1713 int count = 0;
1714 u_char flags;
1715 int model;
1716 const u_char *xnp = np;
1717 int xlength = length;
1718
1719 /* Sequence */
1720 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1721 return;
1722 if (elem.type != BE_SEQ) {
1723 ND_PRINT("[!message]");
1724 asn1_print(ndo, &elem);
1725 return;
1726 }
1727 length = elem.asnlen;
1728 np = (const u_char *)elem.data.raw;
1729
1730 if (ndo->ndo_vflag) {
1731 ND_PRINT("{ ");
1732 }
1733
1734 /* msgID (INTEGER) */
1735 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1736 return;
1737 if (elem.type != BE_INT) {
1738 ND_PRINT("[msgID!=INT]");
1739 asn1_print(ndo, &elem);
1740 return;
1741 }
1742 length -= count;
1743 np += count;
1744
1745 /* msgMaxSize (INTEGER) */
1746 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1747 return;
1748 if (elem.type != BE_INT) {
1749 ND_PRINT("[msgMaxSize!=INT]");
1750 asn1_print(ndo, &elem);
1751 return;
1752 }
1753 length -= count;
1754 np += count;
1755
1756 /* msgFlags (OCTET STRING) */
1757 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1758 return;
1759 if (elem.type != BE_STR) {
1760 ND_PRINT("[msgFlags!=STR]");
1761 asn1_print(ndo, &elem);
1762 return;
1763 }
1764 if (elem.asnlen != 1) {
1765 ND_PRINT("[msgFlags size %d]", elem.asnlen);
1766 return;
1767 }
1768 flags = GET_U_1(elem.data.str);
1769 if (flags != 0x00 && flags != 0x01 && flags != 0x03
1770 && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1771 ND_PRINT("[msgFlags=0x%02X]", flags);
1772 return;
1773 }
1774 length -= count;
1775 np += count;
1776
1777 ND_PRINT("F=%s%s%s ",
1778 flags & 0x01 ? "a" : "",
1779 flags & 0x02 ? "p" : "",
1780 flags & 0x04 ? "r" : "");
1781
1782 /* msgSecurityModel (INTEGER) */
1783 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1784 return;
1785 if (elem.type != BE_INT) {
1786 ND_PRINT("[msgSecurityModel!=INT]");
1787 asn1_print(ndo, &elem);
1788 return;
1789 }
1790 model = elem.data.integer;
1791 length -= count;
1792 np += count;
1793
1794 if ((u_int)count < length)
1795 ND_PRINT("[%d extra after message SEQ]", length - count);
1796
1797 if (ndo->ndo_vflag) {
1798 ND_PRINT("} ");
1799 }
1800
1801 if (model == 3) {
1802 if (ndo->ndo_vflag) {
1803 ND_PRINT("{ USM ");
1804 }
1805 } else {
1806 ND_PRINT("[security model %d]", model);
1807 return;
1808 }
1809
1810 np = xnp + (np - xnp);
1811 length = xlength - (np - xnp);
1812
1813 /* msgSecurityParameters (OCTET STRING) */
1814 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1815 return;
1816 if (elem.type != BE_STR) {
1817 ND_PRINT("[msgSecurityParameters!=STR]");
1818 asn1_print(ndo, &elem);
1819 return;
1820 }
1821 length -= count;
1822 np += count;
1823
1824 if (model == 3) {
1825 usm_print(ndo, elem.data.str, elem.asnlen);
1826 if (ndo->ndo_vflag) {
1827 ND_PRINT("} ");
1828 }
1829 }
1830
1831 if (ndo->ndo_vflag) {
1832 ND_PRINT("{ ScopedPDU ");
1833 }
1834
1835 scopedpdu_print(ndo, np, length, 3);
1836
1837 if (ndo->ndo_vflag) {
1838 ND_PRINT("} ");
1839 }
1840 }
1841
1842 /*
1843 * Decode SNMP header and pass on to PDU printing routines
1844 */
1845 void
1846 snmp_print(netdissect_options *ndo,
1847 const u_char *np, u_int length)
1848 {
1849 struct be elem;
1850 int count = 0;
1851 int version = 0;
1852
1853 ndo->ndo_protocol = "snmp";
1854 ND_PRINT(" ");
1855
1856 /* initial Sequence */
1857 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1858 return;
1859 if (elem.type != BE_SEQ) {
1860 ND_PRINT("[!init SEQ]");
1861 asn1_print(ndo, &elem);
1862 return;
1863 }
1864 if ((u_int)count < length)
1865 ND_PRINT("[%d extra after iSEQ]", length - count);
1866 /* descend */
1867 length = elem.asnlen;
1868 np = (const u_char *)elem.data.raw;
1869
1870 /* Version (INTEGER) */
1871 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1872 return;
1873 if (elem.type != BE_INT) {
1874 ND_PRINT("[version!=INT]");
1875 asn1_print(ndo, &elem);
1876 return;
1877 }
1878
1879 switch (elem.data.integer) {
1880 case SNMP_VERSION_1:
1881 case SNMP_VERSION_2:
1882 case SNMP_VERSION_3:
1883 if (ndo->ndo_vflag)
1884 ND_PRINT("{ %s ", SnmpVersion[elem.data.integer]);
1885 break;
1886 default:
1887 ND_PRINT("SNMP [version = %d]", elem.data.integer);
1888 return;
1889 }
1890 version = elem.data.integer;
1891 length -= count;
1892 np += count;
1893
1894 switch (version) {
1895 case SNMP_VERSION_1:
1896 case SNMP_VERSION_2:
1897 community_print(ndo, np, length, version);
1898 break;
1899 case SNMP_VERSION_3:
1900 v3msg_print(ndo, np, length);
1901 break;
1902 default:
1903 ND_PRINT("[version = %d]", elem.data.integer);
1904 break;
1905 }
1906
1907 if (ndo->ndo_vflag) {
1908 ND_PRINT("} ");
1909 }
1910 }