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 #define NETDISSECT_REWORKED
60 #ifdef HAVE_CONFIG_H
61 #include "config.h"
62 #endif
63
64 #include <tcpdump-stdinc.h>
65
66 #include <stdio.h>
67 #include <string.h>
68
69 #ifdef USE_LIBSMI
70 #include <smi.h>
71 #endif
72
73 #include "interface.h"
74
75 #undef OPAQUE /* defined in <wingdi.h> */
76
77 static const char tstr[] = "[|snmp]";
78
79 /*
80 * Universal ASN.1 types
81 * (we only care about the tag values for those allowed in the Internet SMI)
82 */
83 static const char *Universal[] = {
84 "U-0",
85 "Boolean",
86 "Integer",
87 #define INTEGER 2
88 "Bitstring",
89 "String",
90 #define STRING 4
91 "Null",
92 #define ASN_NULL 5
93 "ObjID",
94 #define OBJECTID 6
95 "ObjectDes",
96 "U-8","U-9","U-10","U-11", /* 8-11 */
97 "U-12","U-13","U-14","U-15", /* 12-15 */
98 "Sequence",
99 #define SEQUENCE 16
100 "Set"
101 };
102
103 /*
104 * Application-wide ASN.1 types from the Internet SMI and their tags
105 */
106 static const char *Application[] = {
107 "IpAddress",
108 #define IPADDR 0
109 "Counter",
110 #define COUNTER 1
111 "Gauge",
112 #define GAUGE 2
113 "TimeTicks",
114 #define TIMETICKS 3
115 "Opaque",
116 #define OPAQUE 4
117 "C-5",
118 "Counter64"
119 #define COUNTER64 6
120 };
121
122 /*
123 * Context-specific ASN.1 types for the SNMP PDUs and their tags
124 */
125 static const char *Context[] = {
126 "GetRequest",
127 #define GETREQ 0
128 "GetNextRequest",
129 #define GETNEXTREQ 1
130 "GetResponse",
131 #define GETRESP 2
132 "SetRequest",
133 #define SETREQ 3
134 "Trap",
135 #define TRAP 4
136 "GetBulk",
137 #define GETBULKREQ 5
138 "Inform",
139 #define INFORMREQ 6
140 "V2Trap",
141 #define V2TRAP 7
142 "Report"
143 #define REPORT 8
144 };
145
146 #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
147 #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
148 #define WRITE_CLASS(x) (x == SETREQ)
149 #define RESPONSE_CLASS(x) (x == GETRESP)
150 #define INTERNAL_CLASS(x) (x == REPORT)
151
152 /*
153 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
154 */
155 static const char *Exceptions[] = {
156 "noSuchObject",
157 #define NOSUCHOBJECT 0
158 "noSuchInstance",
159 #define NOSUCHINSTANCE 1
160 "endOfMibView",
161 #define ENDOFMIBVIEW 2
162 };
163
164 /*
165 * Private ASN.1 types
166 * The Internet SMI does not specify any
167 */
168 static const char *Private[] = {
169 "P-0"
170 };
171
172 /*
173 * error-status values for any SNMP PDU
174 */
175 static const char *ErrorStatus[] = {
176 "noError",
177 "tooBig",
178 "noSuchName",
179 "badValue",
180 "readOnly",
181 "genErr",
182 "noAccess",
183 "wrongType",
184 "wrongLength",
185 "wrongEncoding",
186 "wrongValue",
187 "noCreation",
188 "inconsistentValue",
189 "resourceUnavailable",
190 "commitFailed",
191 "undoFailed",
192 "authorizationError",
193 "notWritable",
194 "inconsistentName"
195 };
196 #define DECODE_ErrorStatus(e) \
197 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
198 ? ErrorStatus[e] \
199 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
200
201 /*
202 * generic-trap values in the SNMP Trap-PDU
203 */
204 static const char *GenericTrap[] = {
205 "coldStart",
206 "warmStart",
207 "linkDown",
208 "linkUp",
209 "authenticationFailure",
210 "egpNeighborLoss",
211 "enterpriseSpecific"
212 #define GT_ENTERPRISE 6
213 };
214 #define DECODE_GenericTrap(t) \
215 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
216 ? GenericTrap[t] \
217 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
218
219 /*
220 * ASN.1 type class table
221 * Ties together the preceding Universal, Application, Context, and Private
222 * type definitions.
223 */
224 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
225 static const struct {
226 const char *name;
227 const char **Id;
228 int numIDs;
229 } Class[] = {
230 defineCLASS(Universal),
231 #define UNIVERSAL 0
232 defineCLASS(Application),
233 #define APPLICATION 1
234 defineCLASS(Context),
235 #define CONTEXT 2
236 defineCLASS(Private),
237 #define PRIVATE 3
238 defineCLASS(Exceptions),
239 #define EXCEPTIONS 4
240 };
241
242 /*
243 * defined forms for ASN.1 types
244 */
245 static const char *Form[] = {
246 "Primitive",
247 #define PRIMITIVE 0
248 "Constructed",
249 #define CONSTRUCTED 1
250 };
251
252 /*
253 * A structure for the OID tree for the compiled-in MIB.
254 * This is stored as a general-order tree.
255 */
256 struct obj {
257 const char *desc; /* name of object */
258 u_char oid; /* sub-id following parent */
259 u_char type; /* object type (unused) */
260 struct obj *child, *next; /* child and next sibling pointers */
261 } *objp = NULL;
262
263 /*
264 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
265 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
266 * a value for `mibroot'.
267 *
268 * In particular, this is gross, as this is including initialized structures,
269 * and by right shouldn't be an "include" file.
270 */
271 #include "mib.h"
272
273 /*
274 * This defines a list of OIDs which will be abbreviated on output.
275 * Currently, this includes the prefixes for the Internet MIB, the
276 * private enterprises tree, and the experimental tree.
277 */
278 static const struct obj_abrev {
279 const char *prefix; /* prefix for this abrev */
280 struct obj *node; /* pointer into object table */
281 const char *oid; /* ASN.1 encoded OID */
282 } obj_abrev_list[] = {
283 #ifndef NO_ABREV_MIB
284 /* .iso.org.dod.internet.mgmt.mib */
285 { "", &_mib_obj, "\53\6\1\2\1" },
286 #endif
287 #ifndef NO_ABREV_ENTER
288 /* .iso.org.dod.internet.private.enterprises */
289 { "E:", &_enterprises_obj, "\53\6\1\4\1" },
290 #endif
291 #ifndef NO_ABREV_EXPERI
292 /* .iso.org.dod.internet.experimental */
293 { "X:", &_experimental_obj, "\53\6\1\3" },
294 #endif
295 #ifndef NO_ABBREV_SNMPMODS
296 /* .iso.org.dod.internet.snmpV2.snmpModules */
297 { "S:", &_snmpModules_obj, "\53\6\1\6\3" },
298 #endif
299 { 0,0,0 }
300 };
301
302 /*
303 * This is used in the OID print routine to walk down the object tree
304 * rooted at `mibroot'.
305 */
306 #define OBJ_PRINT(o, suppressdot) \
307 { \
308 if (objp) { \
309 do { \
310 if ((o) == objp->oid) \
311 break; \
312 } while ((objp = objp->next) != NULL); \
313 } \
314 if (objp) { \
315 ND_PRINT((ndo, suppressdot?"%s":".%s", objp->desc)); \
316 objp = objp->child; \
317 } else \
318 ND_PRINT((ndo, suppressdot?"%u":".%u", (o))); \
319 }
320
321 /*
322 * This is the definition for the Any-Data-Type storage used purely for
323 * temporary internal representation while decoding an ASN.1 data stream.
324 */
325 struct be {
326 uint32_t asnlen;
327 union {
328 caddr_t raw;
329 int32_t integer;
330 uint32_t uns;
331 const u_char *str;
332 struct {
333 uint32_t high;
334 uint32_t low;
335 } uns64;
336 } data;
337 u_short id;
338 u_char form, class; /* tag info */
339 u_char type;
340 #define BE_ANY 255
341 #define BE_NONE 0
342 #define BE_NULL 1
343 #define BE_OCTET 2
344 #define BE_OID 3
345 #define BE_INT 4
346 #define BE_UNS 5
347 #define BE_STR 6
348 #define BE_SEQ 7
349 #define BE_INETADDR 8
350 #define BE_PDU 9
351 #define BE_UNS64 10
352 #define BE_NOSUCHOBJECT 128
353 #define BE_NOSUCHINST 129
354 #define BE_ENDOFMIBVIEW 130
355 };
356
357 /*
358 * SNMP versions recognized by this module
359 */
360 static const char *SnmpVersion[] = {
361 "SNMPv1",
362 #define SNMP_VERSION_1 0
363 "SNMPv2c",
364 #define SNMP_VERSION_2 1
365 "SNMPv2u",
366 #define SNMP_VERSION_2U 2
367 "SNMPv3"
368 #define SNMP_VERSION_3 3
369 };
370
371 /*
372 * Defaults for SNMP PDU components
373 */
374 #define DEF_COMMUNITY "public"
375
376 /*
377 * constants for ASN.1 decoding
378 */
379 #define OIDMUX 40
380 #define ASNLEN_INETADDR 4
381 #define ASN_SHIFT7 7
382 #define ASN_SHIFT8 8
383 #define ASN_BIT8 0x80
384 #define ASN_LONGLEN 0x80
385
386 #define ASN_ID_BITS 0x1f
387 #define ASN_FORM_BITS 0x20
388 #define ASN_FORM_SHIFT 5
389 #define ASN_CLASS_BITS 0xc0
390 #define ASN_CLASS_SHIFT 6
391
392 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
393
394 /*
395 * This decodes the next ASN.1 object in the stream pointed to by "p"
396 * (and of real-length "len") and stores the intermediate data in the
397 * provided BE object.
398 *
399 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
400 * O/w, this returns the number of bytes parsed from "p".
401 */
402 static int
asn1_parse(netdissect_options * ndo,register const u_char * p,u_int len,struct be * elem)403 asn1_parse(netdissect_options *ndo,
404 register const u_char *p, u_int len, struct be *elem)
405 {
406 u_char form, class, id;
407 int i, hdr;
408
409 elem->asnlen = 0;
410 elem->type = BE_ANY;
411 if (len < 1) {
412 ND_PRINT((ndo, "[nothing to parse]"));
413 return -1;
414 }
415 ND_TCHECK(*p);
416
417 /*
418 * it would be nice to use a bit field, but you can't depend on them.
419 * +---+---+---+---+---+---+---+---+
420 * + class |frm| id |
421 * +---+---+---+---+---+---+---+---+
422 * 7 6 5 4 3 2 1 0
423 */
424 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
425 #ifdef notdef
426 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
427 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
428 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
429 #else
430 form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
431 class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
432 #endif
433 elem->form = form;
434 elem->class = class;
435 elem->id = id;
436 p++; len--; hdr = 1;
437 /* extended tag field */
438 if (id == ASN_ID_EXT) {
439 /*
440 * The ID follows, as a sequence of octets with the
441 * 8th bit set and the remaining 7 bits being
442 * the next 7 bits of the value, terminated with
443 * an octet with the 8th bit not set.
444 *
445 * First, assemble all the octets with the 8th
446 * bit set. XXX - this doesn't handle a value
447 * that won't fit in 32 bits.
448 */
449 for (id = 0; *p & ASN_BIT8; len--, hdr++, p++) {
450 if (len < 1) {
451 ND_PRINT((ndo, "[Xtagfield?]"));
452 return -1;
453 }
454 ND_TCHECK(*p);
455 id = (id << 7) | (*p & ~ASN_BIT8);
456 }
457 if (len < 1) {
458 ND_PRINT((ndo, "[Xtagfield?]"));
459 return -1;
460 }
461 ND_TCHECK(*p);
462 elem->id = id = (id << 7) | *p;
463 --len;
464 ++hdr;
465 ++p;
466 }
467 if (len < 1) {
468 ND_PRINT((ndo, "[no asnlen]"));
469 return -1;
470 }
471 ND_TCHECK(*p);
472 elem->asnlen = *p;
473 p++; len--; hdr++;
474 if (elem->asnlen & ASN_BIT8) {
475 uint32_t noct = elem->asnlen % ASN_BIT8;
476 elem->asnlen = 0;
477 if (len < noct) {
478 ND_PRINT((ndo, "[asnlen? %d<%d]", len, noct));
479 return -1;
480 }
481 ND_TCHECK2(*p, noct);
482 for (; noct-- > 0; len--, hdr++)
483 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
484 }
485 if (len < elem->asnlen) {
486 ND_PRINT((ndo, "[len%d<asnlen%u]", len, elem->asnlen));
487 return -1;
488 }
489 if (form >= sizeof(Form)/sizeof(Form[0])) {
490 ND_PRINT((ndo, "[form?%d]", form));
491 return -1;
492 }
493 if (class >= sizeof(Class)/sizeof(Class[0])) {
494 ND_PRINT((ndo, "[class?%c/%d]", *Form[form], class));
495 return -1;
496 }
497 if ((int)id >= Class[class].numIDs) {
498 ND_PRINT((ndo, "[id?%c/%s/%d]", *Form[form], Class[class].name, id));
499 return -1;
500 }
501
502 switch (form) {
503 case PRIMITIVE:
504 switch (class) {
505 case UNIVERSAL:
506 switch (id) {
507 case STRING:
508 elem->type = BE_STR;
509 elem->data.str = p;
510 break;
511
512 case INTEGER: {
513 register int32_t data;
514 elem->type = BE_INT;
515 data = 0;
516
517 ND_TCHECK2(*p, elem->asnlen);
518 if (*p & ASN_BIT8) /* negative */
519 data = -1;
520 for (i = elem->asnlen; i-- > 0; p++)
521 data = (data << ASN_SHIFT8) | *p;
522 elem->data.integer = data;
523 break;
524 }
525
526 case OBJECTID:
527 elem->type = BE_OID;
528 elem->data.raw = (caddr_t)p;
529 break;
530
531 case ASN_NULL:
532 elem->type = BE_NULL;
533 elem->data.raw = NULL;
534 break;
535
536 default:
537 elem->type = BE_OCTET;
538 elem->data.raw = (caddr_t)p;
539 ND_PRINT((ndo, "[P/U/%s]", Class[class].Id[id]));
540 break;
541 }
542 break;
543
544 case APPLICATION:
545 switch (id) {
546 case IPADDR:
547 elem->type = BE_INETADDR;
548 elem->data.raw = (caddr_t)p;
549 break;
550
551 case COUNTER:
552 case GAUGE:
553 case TIMETICKS: {
554 register uint32_t data;
555 ND_TCHECK2(*p, elem->asnlen);
556 elem->type = BE_UNS;
557 data = 0;
558 for (i = elem->asnlen; i-- > 0; p++)
559 data = (data << 8) + *p;
560 elem->data.uns = data;
561 break;
562 }
563
564 case COUNTER64: {
565 register uint32_t high, low;
566 ND_TCHECK2(*p, elem->asnlen);
567 elem->type = BE_UNS64;
568 high = 0, low = 0;
569 for (i = elem->asnlen; i-- > 0; p++) {
570 high = (high << 8) |
571 ((low & 0xFF000000) >> 24);
572 low = (low << 8) | *p;
573 }
574 elem->data.uns64.high = high;
575 elem->data.uns64.low = low;
576 break;
577 }
578
579 default:
580 elem->type = BE_OCTET;
581 elem->data.raw = (caddr_t)p;
582 ND_PRINT((ndo, "[P/A/%s]",
583 Class[class].Id[id]));
584 break;
585 }
586 break;
587
588 case CONTEXT:
589 switch (id) {
590 case NOSUCHOBJECT:
591 elem->type = BE_NOSUCHOBJECT;
592 elem->data.raw = NULL;
593 break;
594
595 case NOSUCHINSTANCE:
596 elem->type = BE_NOSUCHINST;
597 elem->data.raw = NULL;
598 break;
599
600 case ENDOFMIBVIEW:
601 elem->type = BE_ENDOFMIBVIEW;
602 elem->data.raw = NULL;
603 break;
604 }
605 break;
606
607 default:
608 ND_PRINT((ndo, "[P/%s/%s]", Class[class].name, Class[class].Id[id]));
609 ND_TCHECK2(*p, elem->asnlen);
610 elem->type = BE_OCTET;
611 elem->data.raw = (caddr_t)p;
612 break;
613 }
614 break;
615
616 case CONSTRUCTED:
617 switch (class) {
618 case UNIVERSAL:
619 switch (id) {
620 case SEQUENCE:
621 elem->type = BE_SEQ;
622 elem->data.raw = (caddr_t)p;
623 break;
624
625 default:
626 elem->type = BE_OCTET;
627 elem->data.raw = (caddr_t)p;
628 ND_PRINT((ndo, "C/U/%s", Class[class].Id[id]));
629 break;
630 }
631 break;
632
633 case CONTEXT:
634 elem->type = BE_PDU;
635 elem->data.raw = (caddr_t)p;
636 break;
637
638 default:
639 elem->type = BE_OCTET;
640 elem->data.raw = (caddr_t)p;
641 ND_PRINT((ndo, "C/%s/%s", Class[class].name, Class[class].Id[id]));
642 break;
643 }
644 break;
645 }
646 p += elem->asnlen;
647 len -= elem->asnlen;
648 return elem->asnlen + hdr;
649
650 trunc:
651 ND_PRINT((ndo, "%s", tstr));
652 return -1;
653 }
654
655 /*
656 * Display the ASN.1 object represented by the BE object.
657 * This used to be an integral part of asn1_parse() before the intermediate
658 * BE form was added.
659 */
660 static int
asn1_print(netdissect_options * ndo,struct be * elem)661 asn1_print(netdissect_options *ndo,
662 struct be *elem)
663 {
664 u_char *p = (u_char *)elem->data.raw;
665 uint32_t asnlen = elem->asnlen;
666 uint32_t i;
667
668 switch (elem->type) {
669
670 case BE_OCTET:
671 ND_TCHECK2(*p, asnlen);
672 for (i = asnlen; i-- > 0; p++)
673 ND_PRINT((ndo, "_%.2x", *p));
674 break;
675
676 case BE_NULL:
677 break;
678
679 case BE_OID: {
680 int o = 0, first = -1, i = asnlen;
681
682 if (!ndo->ndo_sflag && !ndo->ndo_nflag && asnlen > 2) {
683 const struct obj_abrev *a = &obj_abrev_list[0];
684 size_t a_len = strlen(a->oid);
685 for (; a->node; a++) {
686 ND_TCHECK2(*p, a_len);
687 if (memcmp(a->oid, (char *)p, a_len) == 0) {
688 objp = a->node->child;
689 i -= strlen(a->oid);
690 p += strlen(a->oid);
691 ND_PRINT((ndo, "%s", a->prefix));
692 first = 1;
693 break;
694 }
695 }
696 }
697
698 for (; !ndo->ndo_sflag && i-- > 0; p++) {
699 ND_TCHECK(*p);
700 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
701 if (*p & ASN_LONGLEN)
702 continue;
703
704 /*
705 * first subitem encodes two items with 1st*OIDMUX+2nd
706 * (see X.690:1997 clause 8.19 for the details)
707 */
708 if (first < 0) {
709 int s;
710 if (!ndo->ndo_nflag)
711 objp = mibroot;
712 first = 0;
713 s = o / OIDMUX;
714 if (s > 2) s = 2;
715 OBJ_PRINT(s, first);
716 o -= s * OIDMUX;
717 }
718 OBJ_PRINT(o, first);
719 if (--first < 0)
720 first = 0;
721 o = 0;
722 }
723 break;
724 }
725
726 case BE_INT:
727 ND_PRINT((ndo, "%d", elem->data.integer));
728 break;
729
730 case BE_UNS:
731 ND_PRINT((ndo, "%u", elem->data.uns));
732 break;
733
734 case BE_UNS64: { /* idea borrowed from by Marshall Rose */
735 double d;
736 int j, carry;
737 char *cpf, *cpl, last[6], first[30];
738 if (elem->data.uns64.high == 0) {
739 ND_PRINT((ndo, "%u", elem->data.uns64.low));
740 break;
741 }
742 d = elem->data.uns64.high * 4294967296.0; /* 2^32 */
743 if (elem->data.uns64.high <= 0x1fffff) {
744 d += elem->data.uns64.low;
745 #if 0 /*is looks illegal, but what is the intention?*/
746 ND_PRINT((ndo, "%.f", d));
747 #else
748 ND_PRINT((ndo, "%f", d));
749 #endif
750 break;
751 }
752 d += (elem->data.uns64.low & 0xfffff000);
753 #if 0 /*is looks illegal, but what is the intention?*/
754 snprintf(first, sizeof(first), "%.f", d);
755 #else
756 snprintf(first, sizeof(first), "%f", d);
757 #endif
758 snprintf(last, sizeof(last), "%5.5d",
759 elem->data.uns64.low & 0xfff);
760 for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4;
761 cpl >= last;
762 cpf--, cpl--) {
763 j = carry + (*cpf - '0') + (*cpl - '0');
764 if (j > 9) {
765 j -= 10;
766 carry = 1;
767 } else {
768 carry = 0;
769 }
770 *cpf = j + '0';
771 }
772 ND_PRINT((ndo, "%s", first));
773 break;
774 }
775
776 case BE_STR: {
777 register int printable = 1, first = 1;
778 const u_char *p = elem->data.str;
779 ND_TCHECK2(*p, asnlen);
780 for (i = asnlen; printable && i-- > 0; p++)
781 printable = ND_ISPRINT(*p);
782 p = elem->data.str;
783 if (printable) {
784 ND_PRINT((ndo, "\""));
785 if (fn_printn(ndo, p, asnlen, ndo->ndo_snapend)) {
786 ND_PRINT((ndo, "\""));
787 goto trunc;
788 }
789 ND_PRINT((ndo, "\""));
790 } else
791 for (i = asnlen; i-- > 0; p++) {
792 ND_PRINT((ndo, first ? "%.2x" : "_%.2x", *p));
793 first = 0;
794 }
795 break;
796 }
797
798 case BE_SEQ:
799 ND_PRINT((ndo, "Seq(%u)", elem->asnlen));
800 break;
801
802 case BE_INETADDR:
803 if (asnlen != ASNLEN_INETADDR)
804 ND_PRINT((ndo, "[inetaddr len!=%d]", ASNLEN_INETADDR));
805 ND_TCHECK2(*p, asnlen);
806 for (i = asnlen; i-- != 0; p++) {
807 ND_PRINT((ndo, (i == asnlen-1) ? "%u" : ".%u", *p));
808 }
809 break;
810
811 case BE_NOSUCHOBJECT:
812 case BE_NOSUCHINST:
813 case BE_ENDOFMIBVIEW:
814 ND_PRINT((ndo, "[%s]", Class[EXCEPTIONS].Id[elem->id]));
815 break;
816
817 case BE_PDU:
818 ND_PRINT((ndo, "%s(%u)", Class[CONTEXT].Id[elem->id], elem->asnlen));
819 break;
820
821 case BE_ANY:
822 ND_PRINT((ndo, "[BE_ANY!?]"));
823 break;
824
825 default:
826 ND_PRINT((ndo, "[be!?]"));
827 break;
828 }
829 return 0;
830
831 trunc:
832 ND_PRINT((ndo, "%s", tstr));
833 return -1;
834 }
835
836 #ifdef notdef
837 /*
838 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
839 * This will work for any ASN.1 stream, not just an SNMP PDU.
840 *
841 * By adding newlines and spaces at the correct places, this would print in
842 * Rose-Normal-Form.
843 *
844 * This is not currently used.
845 */
846 static void
asn1_decode(u_char * p,u_int length)847 asn1_decode(u_char *p, u_int length)
848 {
849 struct be elem;
850 int i = 0;
851
852 while (i >= 0 && length > 0) {
853 i = asn1_parse(ndo, p, length, &elem);
854 if (i >= 0) {
855 ND_PRINT((ndo, " "));
856 if (asn1_print(ndo, &elem) < 0)
857 return;
858 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
859 ND_PRINT((ndo, " {"));
860 asn1_decode(elem.data.raw, elem.asnlen);
861 ND_PRINT((ndo, " }"));
862 }
863 length -= i;
864 p += i;
865 }
866 }
867 }
868 #endif
869
870 #ifdef USE_LIBSMI
871
872 struct smi2be {
873 SmiBasetype basetype;
874 int be;
875 };
876
877 static const struct smi2be smi2betab[] = {
878 { SMI_BASETYPE_INTEGER32, BE_INT },
879 { SMI_BASETYPE_OCTETSTRING, BE_STR },
880 { SMI_BASETYPE_OCTETSTRING, BE_INETADDR },
881 { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID },
882 { SMI_BASETYPE_UNSIGNED32, BE_UNS },
883 { SMI_BASETYPE_INTEGER64, BE_NONE },
884 { SMI_BASETYPE_UNSIGNED64, BE_UNS64 },
885 { SMI_BASETYPE_FLOAT32, BE_NONE },
886 { SMI_BASETYPE_FLOAT64, BE_NONE },
887 { SMI_BASETYPE_FLOAT128, BE_NONE },
888 { SMI_BASETYPE_ENUM, BE_INT },
889 { SMI_BASETYPE_BITS, BE_STR },
890 { SMI_BASETYPE_UNKNOWN, BE_NONE }
891 };
892
893 static int
smi_decode_oid(netdissect_options * ndo,struct be * elem,unsigned int * oid,unsigned int oidsize,unsigned int * oidlen)894 smi_decode_oid(netdissect_options *ndo,
895 struct be *elem, unsigned int *oid,
896 unsigned int oidsize, unsigned int *oidlen)
897 {
898 u_char *p = (u_char *)elem->data.raw;
899 uint32_t asnlen = elem->asnlen;
900 int o = 0, first = -1, i = asnlen;
901 unsigned int firstval;
902
903 for (*oidlen = 0; ndo->ndo_sflag && i-- > 0; p++) {
904 ND_TCHECK(*p);
905 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
906 if (*p & ASN_LONGLEN)
907 continue;
908
909 /*
910 * first subitem encodes two items with 1st*OIDMUX+2nd
911 * (see X.690:1997 clause 8.19 for the details)
912 */
913 if (first < 0) {
914 first = 0;
915 firstval = o / OIDMUX;
916 if (firstval > 2) firstval = 2;
917 o -= firstval * OIDMUX;
918 if (*oidlen < oidsize) {
919 oid[(*oidlen)++] = firstval;
920 }
921 }
922 if (*oidlen < oidsize) {
923 oid[(*oidlen)++] = o;
924 }
925 o = 0;
926 }
927 return 0;
928
929 trunc:
930 ND_PRINT((ndo, "%s", tstr));
931 return -1;
932 }
933
smi_check_type(SmiBasetype basetype,int be)934 static int smi_check_type(SmiBasetype basetype, int be)
935 {
936 int i;
937
938 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
939 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
940 return 1;
941 }
942 }
943
944 return 0;
945 }
946
smi_check_a_range(SmiType * smiType,SmiRange * smiRange,struct be * elem)947 static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
948 struct be *elem)
949 {
950 int ok = 1;
951
952 switch (smiType->basetype) {
953 case SMI_BASETYPE_OBJECTIDENTIFIER:
954 case SMI_BASETYPE_OCTETSTRING:
955 if (smiRange->minValue.value.unsigned32
956 == smiRange->maxValue.value.unsigned32) {
957 ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
958 } else {
959 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
960 && elem->asnlen <= smiRange->maxValue.value.unsigned32);
961 }
962 break;
963
964 case SMI_BASETYPE_INTEGER32:
965 ok = (elem->data.integer >= smiRange->minValue.value.integer32
966 && elem->data.integer <= smiRange->maxValue.value.integer32);
967 break;
968
969 case SMI_BASETYPE_UNSIGNED32:
970 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
971 && elem->data.uns <= smiRange->maxValue.value.unsigned32);
972 break;
973
974 case SMI_BASETYPE_UNSIGNED64:
975 /* XXX */
976 break;
977
978 /* case SMI_BASETYPE_INTEGER64: SMIng */
979 /* case SMI_BASETYPE_FLOAT32: SMIng */
980 /* case SMI_BASETYPE_FLOAT64: SMIng */
981 /* case SMI_BASETYPE_FLOAT128: SMIng */
982
983 case SMI_BASETYPE_ENUM:
984 case SMI_BASETYPE_BITS:
985 case SMI_BASETYPE_UNKNOWN:
986 ok = 1;
987 break;
988
989 default:
990 ok = 0;
991 break;
992 }
993
994 return ok;
995 }
996
smi_check_range(SmiType * smiType,struct be * elem)997 static int smi_check_range(SmiType *smiType, struct be *elem)
998 {
999 SmiRange *smiRange;
1000 int ok = 1;
1001
1002 for (smiRange = smiGetFirstRange(smiType);
1003 smiRange;
1004 smiRange = smiGetNextRange(smiRange)) {
1005
1006 ok = smi_check_a_range(smiType, smiRange, elem);
1007
1008 if (ok) {
1009 break;
1010 }
1011 }
1012
1013 if (ok) {
1014 SmiType *parentType;
1015 parentType = smiGetParentType(smiType);
1016 if (parentType) {
1017 ok = smi_check_range(parentType, elem);
1018 }
1019 }
1020
1021 return ok;
1022 }
1023
1024 static SmiNode *
smi_print_variable(netdissect_options * ndo,struct be * elem,int * status)1025 smi_print_variable(netdissect_options *ndo,
1026 struct be *elem, int *status)
1027 {
1028 unsigned int oid[128], oidlen;
1029 SmiNode *smiNode = NULL;
1030 unsigned int i;
1031
1032 *status = smi_decode_oid(ndo, elem, oid, sizeof(oid) / sizeof(unsigned int),
1033 &oidlen);
1034 if (*status < 0)
1035 return NULL;
1036 smiNode = smiGetNodeByOID(oidlen, oid);
1037 if (! smiNode) {
1038 *status = asn1_print(ndo, elem);
1039 return NULL;
1040 }
1041 if (ndo->ndo_vflag) {
1042 ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
1043 }
1044 ND_PRINT((ndo, "%s", smiNode->name));
1045 if (smiNode->oidlen < oidlen) {
1046 for (i = smiNode->oidlen; i < oidlen; i++) {
1047 ND_PRINT((ndo, ".%u", oid[i]));
1048 }
1049 }
1050 *status = 0;
1051 return smiNode;
1052 }
1053
1054 static int
smi_print_value(netdissect_options * ndo,SmiNode * smiNode,u_char pduid,struct be * elem)1055 smi_print_value(netdissect_options *ndo,
1056 SmiNode *smiNode, u_char pduid, struct be *elem)
1057 {
1058 unsigned int i, oid[128], oidlen;
1059 SmiType *smiType;
1060 SmiNamedNumber *nn;
1061 int done = 0;
1062
1063 if (! smiNode || ! (smiNode->nodekind
1064 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
1065 return asn1_print(ndo, elem);
1066 }
1067
1068 if (elem->type == BE_NOSUCHOBJECT
1069 || elem->type == BE_NOSUCHINST
1070 || elem->type == BE_ENDOFMIBVIEW) {
1071 return asn1_print(ndo, elem);
1072 }
1073
1074 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
1075 ND_PRINT((ndo, "[notNotifyable]"));
1076 }
1077
1078 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
1079 ND_PRINT((ndo, "[notReadable]"));
1080 }
1081
1082 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
1083 ND_PRINT((ndo, "[notWritable]"));
1084 }
1085
1086 if (RESPONSE_CLASS(pduid)
1087 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1088 ND_PRINT((ndo, "[noAccess]"));
1089 }
1090
1091 smiType = smiGetNodeType(smiNode);
1092 if (! smiType) {
1093 return asn1_print(ndo, elem);
1094 }
1095
1096 if (! smi_check_type(smiType->basetype, elem->type)) {
1097 ND_PRINT((ndo, "[wrongType]"));
1098 }
1099
1100 if (! smi_check_range(smiType, elem)) {
1101 ND_PRINT((ndo, "[outOfRange]"));
1102 }
1103
1104 /* resolve bits to named bits */
1105
1106 /* check whether instance identifier is valid */
1107
1108 /* apply display hints (integer, octetstring) */
1109
1110 /* convert instance identifier to index type values */
1111
1112 switch (elem->type) {
1113 case BE_OID:
1114 if (smiType->basetype == SMI_BASETYPE_BITS) {
1115 /* print bit labels */
1116 } else {
1117 smi_decode_oid(ndo, elem, oid,
1118 sizeof(oid)/sizeof(unsigned int),
1119 &oidlen);
1120 smiNode = smiGetNodeByOID(oidlen, oid);
1121 if (smiNode) {
1122 if (ndo->ndo_vflag) {
1123 ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
1124 }
1125 ND_PRINT((ndo, "%s", smiNode->name));
1126 if (smiNode->oidlen < oidlen) {
1127 for (i = smiNode->oidlen;
1128 i < oidlen; i++) {
1129 ND_PRINT((ndo, ".%u", oid[i]));
1130 }
1131 }
1132 done++;
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((ndo, "%s", nn->name));
1145 ND_PRINT((ndo, "(%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
varbind_print(netdissect_options * ndo,u_char pduid,const u_char * np,u_int length)1198 varbind_print(netdissect_options *ndo,
1199 u_char pduid, const u_char *np, u_int length)
1200 {
1201 struct be elem;
1202 int count = 0, ind;
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((ndo, "[!SEQ of varbind]"));
1213 asn1_print(ndo, &elem);
1214 return;
1215 }
1216 if ((u_int)count < length)
1217 ND_PRINT((ndo, "[%d extra after SEQ of varbind]", length - count));
1218 /* descend */
1219 length = elem.asnlen;
1220 np = (u_char *)elem.data.raw;
1221
1222 for (ind = 1; length > 0; ind++) {
1223 const u_char *vbend;
1224 u_int vblength;
1225
1226 ND_PRINT((ndo, " "));
1227
1228 /* Sequence */
1229 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1230 return;
1231 if (elem.type != BE_SEQ) {
1232 ND_PRINT((ndo, "[!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 = (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((ndo, "[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((ndo, "="));
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((ndo, "[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
snmppdu_print(netdissect_options * ndo,u_short pduid,const u_char * np,u_int length)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;
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((ndo, "[reqId!=INT]"));
1306 asn1_print(ndo, &elem);
1307 return;
1308 }
1309 if (ndo->ndo_vflag)
1310 ND_PRINT((ndo, "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((ndo, "[errorStatus!=INT]"));
1319 asn1_print(ndo, &elem);
1320 return;
1321 }
1322 error = 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((ndo, "[errorStatus(%s)!=0]",
1328 DECODE_ErrorStatus(elem.data.integer)));
1329 } else if (pduid == GETBULKREQ) {
1330 ND_PRINT((ndo, " N=%d", elem.data.integer));
1331 } else if (elem.data.integer != 0) {
1332 char errbuf[20];
1333 ND_PRINT((ndo, " %s", DECODE_ErrorStatus(elem.data.integer)));
1334 error = 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((ndo, "[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((ndo, "[errorIndex(%d)!=0]", elem.data.integer));
1351 else if (pduid == GETBULKREQ)
1352 ND_PRINT((ndo, " M=%d", elem.data.integer));
1353 else if (elem.data.integer != 0) {
1354 if (!error)
1355 ND_PRINT((ndo, "[errorIndex(%d) w/o errorStatus]", elem.data.integer));
1356 else {
1357 ND_PRINT((ndo, "@%d", elem.data.integer));
1358 error = elem.data.integer;
1359 }
1360 } else if (error) {
1361 ND_PRINT((ndo, "[errorIndex==0]"));
1362 error = 0;
1363 }
1364 length -= count;
1365 np += count;
1366
1367 varbind_print(ndo, pduid, np, length);
1368 return;
1369 }
1370
1371 /*
1372 * Decode SNMP Trap PDU
1373 */
1374 static void
trappdu_print(netdissect_options * ndo,const u_char * np,u_int length)1375 trappdu_print(netdissect_options *ndo,
1376 const u_char *np, u_int length)
1377 {
1378 struct be elem;
1379 int count = 0, generic;
1380
1381 ND_PRINT((ndo, " "));
1382
1383 /* enterprise (oid) */
1384 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1385 return;
1386 if (elem.type != BE_OID) {
1387 ND_PRINT((ndo, "[enterprise!=OID]"));
1388 asn1_print(ndo, &elem);
1389 return;
1390 }
1391 if (asn1_print(ndo, &elem) < 0)
1392 return;
1393 length -= count;
1394 np += count;
1395
1396 ND_PRINT((ndo, " "));
1397
1398 /* agent-addr (inetaddr) */
1399 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1400 return;
1401 if (elem.type != BE_INETADDR) {
1402 ND_PRINT((ndo, "[agent-addr!=INETADDR]"));
1403 asn1_print(ndo, &elem);
1404 return;
1405 }
1406 if (asn1_print(ndo, &elem) < 0)
1407 return;
1408 length -= count;
1409 np += count;
1410
1411 /* generic-trap (Integer) */
1412 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1413 return;
1414 if (elem.type != BE_INT) {
1415 ND_PRINT((ndo, "[generic-trap!=INT]"));
1416 asn1_print(ndo, &elem);
1417 return;
1418 }
1419 generic = elem.data.integer;
1420 {
1421 char buf[20];
1422 ND_PRINT((ndo, " %s", DECODE_GenericTrap(generic)));
1423 }
1424 length -= count;
1425 np += count;
1426
1427 /* specific-trap (Integer) */
1428 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1429 return;
1430 if (elem.type != BE_INT) {
1431 ND_PRINT((ndo, "[specific-trap!=INT]"));
1432 asn1_print(ndo, &elem);
1433 return;
1434 }
1435 if (generic != GT_ENTERPRISE) {
1436 if (elem.data.integer != 0)
1437 ND_PRINT((ndo, "[specific-trap(%d)!=0]", elem.data.integer));
1438 } else
1439 ND_PRINT((ndo, " s=%d", elem.data.integer));
1440 length -= count;
1441 np += count;
1442
1443 ND_PRINT((ndo, " "));
1444
1445 /* time-stamp (TimeTicks) */
1446 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1447 return;
1448 if (elem.type != BE_UNS) { /* XXX */
1449 ND_PRINT((ndo, "[time-stamp!=TIMETICKS]"));
1450 asn1_print(ndo, &elem);
1451 return;
1452 }
1453 if (asn1_print(ndo, &elem) < 0)
1454 return;
1455 length -= count;
1456 np += count;
1457
1458 varbind_print(ndo, TRAP, np, length);
1459 return;
1460 }
1461
1462 /*
1463 * Decode arbitrary SNMP PDUs.
1464 */
1465 static void
pdu_print(netdissect_options * ndo,const u_char * np,u_int length,int version)1466 pdu_print(netdissect_options *ndo,
1467 const u_char *np, u_int length, int version)
1468 {
1469 struct be pdu;
1470 int count = 0;
1471
1472 /* PDU (Context) */
1473 if ((count = asn1_parse(ndo, np, length, &pdu)) < 0)
1474 return;
1475 if (pdu.type != BE_PDU) {
1476 ND_PRINT((ndo, "[no PDU]"));
1477 return;
1478 }
1479 if ((u_int)count < length)
1480 ND_PRINT((ndo, "[%d extra after PDU]", length - count));
1481 if (ndo->ndo_vflag) {
1482 ND_PRINT((ndo, "{ "));
1483 }
1484 if (asn1_print(ndo, &pdu) < 0)
1485 return;
1486 ND_PRINT((ndo, " "));
1487 /* descend into PDU */
1488 length = pdu.asnlen;
1489 np = (u_char *)pdu.data.raw;
1490
1491 if (version == SNMP_VERSION_1 &&
1492 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1493 pdu.id == V2TRAP || pdu.id == REPORT)) {
1494 ND_PRINT((ndo, "[v2 PDU in v1 message]"));
1495 return;
1496 }
1497
1498 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1499 ND_PRINT((ndo, "[v1 PDU in v2 message]"));
1500 return;
1501 }
1502
1503 switch (pdu.id) {
1504 case TRAP:
1505 trappdu_print(ndo, np, length);
1506 break;
1507 case GETREQ:
1508 case GETNEXTREQ:
1509 case GETRESP:
1510 case SETREQ:
1511 case GETBULKREQ:
1512 case INFORMREQ:
1513 case V2TRAP:
1514 case REPORT:
1515 snmppdu_print(ndo, pdu.id, np, length);
1516 break;
1517 }
1518
1519 if (ndo->ndo_vflag) {
1520 ND_PRINT((ndo, " } "));
1521 }
1522 }
1523
1524 /*
1525 * Decode a scoped SNMP PDU.
1526 */
1527 static void
scopedpdu_print(netdissect_options * ndo,const u_char * np,u_int length,int version)1528 scopedpdu_print(netdissect_options *ndo,
1529 const u_char *np, u_int length, int version)
1530 {
1531 struct be elem;
1532 int i, count = 0;
1533
1534 /* Sequence */
1535 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1536 return;
1537 if (elem.type != BE_SEQ) {
1538 ND_PRINT((ndo, "[!scoped PDU]"));
1539 asn1_print(ndo, &elem);
1540 return;
1541 }
1542 length = elem.asnlen;
1543 np = (u_char *)elem.data.raw;
1544
1545 /* contextEngineID (OCTET STRING) */
1546 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1547 return;
1548 if (elem.type != BE_STR) {
1549 ND_PRINT((ndo, "[contextEngineID!=STR]"));
1550 asn1_print(ndo, &elem);
1551 return;
1552 }
1553 length -= count;
1554 np += count;
1555
1556 ND_PRINT((ndo, "E= "));
1557 for (i = 0; i < (int)elem.asnlen; i++) {
1558 ND_PRINT((ndo, "0x%02X", elem.data.str[i]));
1559 }
1560 ND_PRINT((ndo, " "));
1561
1562 /* contextName (OCTET STRING) */
1563 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1564 return;
1565 if (elem.type != BE_STR) {
1566 ND_PRINT((ndo, "[contextName!=STR]"));
1567 asn1_print(ndo, &elem);
1568 return;
1569 }
1570 length -= count;
1571 np += count;
1572
1573 ND_PRINT((ndo, "C=%.*s ", (int)elem.asnlen, elem.data.str));
1574
1575 pdu_print(ndo, np, length, version);
1576 }
1577
1578 /*
1579 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1580 */
1581 static void
community_print(netdissect_options * ndo,const u_char * np,u_int length,int version)1582 community_print(netdissect_options *ndo,
1583 const u_char *np, u_int length, int version)
1584 {
1585 struct be elem;
1586 int count = 0;
1587
1588 /* Community (String) */
1589 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1590 return;
1591 if (elem.type != BE_STR) {
1592 ND_PRINT((ndo, "[comm!=STR]"));
1593 asn1_print(ndo, &elem);
1594 return;
1595 }
1596 /* default community */
1597 if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
1598 strncmp((char *)elem.data.str, DEF_COMMUNITY,
1599 sizeof(DEF_COMMUNITY) - 1) == 0))
1600 /* ! "public" */
1601 ND_PRINT((ndo, "C=%.*s ", (int)elem.asnlen, elem.data.str));
1602 length -= count;
1603 np += count;
1604
1605 pdu_print(ndo, np, length, version);
1606 }
1607
1608 /*
1609 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1610 */
1611 static void
usm_print(netdissect_options * ndo,const u_char * np,u_int length)1612 usm_print(netdissect_options *ndo,
1613 const u_char *np, u_int length)
1614 {
1615 struct be elem;
1616 int count = 0;
1617
1618 /* Sequence */
1619 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1620 return;
1621 if (elem.type != BE_SEQ) {
1622 ND_PRINT((ndo, "[!usm]"));
1623 asn1_print(ndo, &elem);
1624 return;
1625 }
1626 length = elem.asnlen;
1627 np = (u_char *)elem.data.raw;
1628
1629 /* msgAuthoritativeEngineID (OCTET STRING) */
1630 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1631 return;
1632 if (elem.type != BE_STR) {
1633 ND_PRINT((ndo, "[msgAuthoritativeEngineID!=STR]"));
1634 asn1_print(ndo, &elem);
1635 return;
1636 }
1637 length -= count;
1638 np += count;
1639
1640 /* msgAuthoritativeEngineBoots (INTEGER) */
1641 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1642 return;
1643 if (elem.type != BE_INT) {
1644 ND_PRINT((ndo, "[msgAuthoritativeEngineBoots!=INT]"));
1645 asn1_print(ndo, &elem);
1646 return;
1647 }
1648 if (ndo->ndo_vflag)
1649 ND_PRINT((ndo, "B=%d ", elem.data.integer));
1650 length -= count;
1651 np += count;
1652
1653 /* msgAuthoritativeEngineTime (INTEGER) */
1654 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1655 return;
1656 if (elem.type != BE_INT) {
1657 ND_PRINT((ndo, "[msgAuthoritativeEngineTime!=INT]"));
1658 asn1_print(ndo, &elem);
1659 return;
1660 }
1661 if (ndo->ndo_vflag)
1662 ND_PRINT((ndo, "T=%d ", elem.data.integer));
1663 length -= count;
1664 np += count;
1665
1666 /* msgUserName (OCTET STRING) */
1667 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1668 return;
1669 if (elem.type != BE_STR) {
1670 ND_PRINT((ndo, "[msgUserName!=STR]"));
1671 asn1_print(ndo, &elem);
1672 return;
1673 }
1674 length -= count;
1675 np += count;
1676
1677 ND_PRINT((ndo, "U=%.*s ", (int)elem.asnlen, elem.data.str));
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((ndo, "[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((ndo, "[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((ndo, "[%d extra after usm SEQ]", length - count));
1703 }
1704
1705 /*
1706 * Decode SNMPv3 Message Header (SNMPv3)
1707 */
1708 static void
v3msg_print(netdissect_options * ndo,const u_char * np,u_int length)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((ndo, "[!message]"));
1724 asn1_print(ndo, &elem);
1725 return;
1726 }
1727 length = elem.asnlen;
1728 np = (u_char *)elem.data.raw;
1729
1730 if (ndo->ndo_vflag) {
1731 ND_PRINT((ndo, "{ "));
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((ndo, "[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((ndo, "[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((ndo, "[msgFlags!=STR]"));
1761 asn1_print(ndo, &elem);
1762 return;
1763 }
1764 if (elem.asnlen != 1) {
1765 ND_PRINT((ndo, "[msgFlags size %d]", elem.asnlen));
1766 return;
1767 }
1768 flags = elem.data.str[0];
1769 if (flags != 0x00 && flags != 0x01 && flags != 0x03
1770 && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1771 ND_PRINT((ndo, "[msgFlags=0x%02X]", flags));
1772 return;
1773 }
1774 length -= count;
1775 np += count;
1776
1777 ND_PRINT((ndo, "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((ndo, "[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((ndo, "[%d extra after message SEQ]", length - count));
1796
1797 if (ndo->ndo_vflag) {
1798 ND_PRINT((ndo, "} "));
1799 }
1800
1801 if (model == 3) {
1802 if (ndo->ndo_vflag) {
1803 ND_PRINT((ndo, "{ USM "));
1804 }
1805 } else {
1806 ND_PRINT((ndo, "[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((ndo, "[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((ndo, "} "));
1828 }
1829 }
1830
1831 if (ndo->ndo_vflag) {
1832 ND_PRINT((ndo, "{ ScopedPDU "));
1833 }
1834
1835 scopedpdu_print(ndo, np, length, 3);
1836
1837 if (ndo->ndo_vflag) {
1838 ND_PRINT((ndo, "} "));
1839 }
1840 }
1841
1842 /*
1843 * Decode SNMP header and pass on to PDU printing routines
1844 */
1845 void
snmp_print(netdissect_options * ndo,const u_char * np,u_int length)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 ND_PRINT((ndo, " "));
1854
1855 /* initial Sequence */
1856 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1857 return;
1858 if (elem.type != BE_SEQ) {
1859 ND_PRINT((ndo, "[!init SEQ]"));
1860 asn1_print(ndo, &elem);
1861 return;
1862 }
1863 if ((u_int)count < length)
1864 ND_PRINT((ndo, "[%d extra after iSEQ]", length - count));
1865 /* descend */
1866 length = elem.asnlen;
1867 np = (u_char *)elem.data.raw;
1868
1869 /* Version (INTEGER) */
1870 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1871 return;
1872 if (elem.type != BE_INT) {
1873 ND_PRINT((ndo, "[version!=INT]"));
1874 asn1_print(ndo, &elem);
1875 return;
1876 }
1877
1878 switch (elem.data.integer) {
1879 case SNMP_VERSION_1:
1880 case SNMP_VERSION_2:
1881 case SNMP_VERSION_3:
1882 if (ndo->ndo_vflag)
1883 ND_PRINT((ndo, "{ %s ", SnmpVersion[elem.data.integer]));
1884 break;
1885 default:
1886 ND_PRINT((ndo, "[version = %d]", elem.data.integer));
1887 return;
1888 }
1889 version = elem.data.integer;
1890 length -= count;
1891 np += count;
1892
1893 switch (version) {
1894 case SNMP_VERSION_1:
1895 case SNMP_VERSION_2:
1896 community_print(ndo, np, length, version);
1897 break;
1898 case SNMP_VERSION_3:
1899 v3msg_print(ndo, np, length);
1900 break;
1901 default:
1902 ND_PRINT((ndo, "[version = %d]", elem.data.integer));
1903 break;
1904 }
1905
1906 if (ndo->ndo_vflag) {
1907 ND_PRINT((ndo, "} "));
1908 }
1909 }
1910