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