1 /*
2 * Copyright (c) 1990, by John Robert LoVerso.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by John Robert LoVerso.
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
12 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
13 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
14 *
15 * This implementaion has been influenced by the CMU SNMP release,
16 * by Steve Waldbusser. However, this shares no code with that system.
17 * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
18 * Earlier forms of this implemention were derived and/or inspired by an
19 * awk script originally written by C. Philip Wood of LANL (but later
20 * heavily modified by John Robert LoVerso). The copyright notice for
21 * that work is preserved below, even though it may not rightly apply
22 * to this file.
23 *
24 * This started out as a very simple program, but the incremental decoding
25 * (into the BE structure) complicated things.
26 *
27 # Los Alamos National Laboratory
28 #
29 # Copyright, 1990. The Regents of the University of California.
30 # This software was produced under a U.S. Government contract
31 # (W-7405-ENG-36) by Los Alamos National Laboratory, which is
32 # operated by the University of California for the U.S. Department
33 # of Energy. The U.S. Government is licensed to use, reproduce,
34 # and distribute this software. Permission is granted to the
35 # public to copy and use this software without charge, provided
36 # that this Notice and any statement of authorship are reproduced
37 # on all copies. Neither the Government nor the University makes
38 # any warranty, express or implied, or assumes any liability or
39 # responsibility for the use of this software.
40 # @(#)snmp.awk.x 1.1 (LANL) 1/15/90
41 */
42 #ifndef lint
43 static char rcsid[] =
44 "@(#) $Id: print-snmp.c,v 1.4 1993/04/22 20:32:30 martinh Exp $ (UW)";
45 #endif
46
47 #include <sys/param.h>
48 #include <sys/types.h>
49 #include <stdio.h>
50 #include <ctype.h>
51
52 #ifdef TCPVIEW
53 #include "tcpview.h"
54 #endif
55
56 #include "interface.h"
57 #include "addrtoname.h"
58 #include "snmp.h"
59
60 /*
61 * Universal ASN.1 types
62 * (we only care about the tag values for those allowed in the Internet SMI)
63 */
64 static char *Universal[] = {
65 "U-0",
66 "Boolean",
67 "Integer",
68 #define INTEGER 2
69 "Bitstring",
70 "String",
71 #define STRING 4
72 "Null",
73 #define ASN_NULL 5
74 "ObjID",
75 #define OBJECTID 6
76 "ObjectDes",
77 "U-8","U-9","U-10","U-11", /* 8-11 */
78 "U-12","U-13","U-14","U-15", /* 12-15 */
79 "Sequence",
80 #define SEQUENCE 16
81 "Set"
82 };
83
84 /*
85 * Application-wide ASN.1 types from the Internet SMI and their tags
86 */
87 static char *Application[] = {
88 "IpAddress",
89 #define IPADDR 0
90 "Counter",
91 #define COUNTER 1
92 "Gauge",
93 #define GAUGE 2
94 "TimeTicks",
95 #define TIMETICKS 3
96 "Opaque"
97 };
98
99 /*
100 * Context-specific ASN.1 types for the SNMP PDUs and their tags
101 */
102 static char *Context[] = {
103 "GetRequest",
104 /* #define GETREQ 0 */
105 "GetNextRequest",
106 /* #define GETNEXTREQ 1 */
107 "GetResponse",
108 /* #define GETRESP 2 */
109 "SetRequest",
110 /* #define SETREQ 3 */
111 "Trap"
112 /* #define TRAP 4 */
113 };
114
115 /*
116 * Private ASN.1 types
117 * The Internet SMI does not specify any
118 */
119 static char *Private[] = {
120 "P-0"
121 };
122
123 /*
124 * error-status values for any SNMP PDU
125 */
126 static char *ErrorStatus[] = {
127 "noError",
128 "tooBig",
129 "noSuchName",
130 "badValue",
131 "readOnly",
132 "genErr"
133 };
134
135 /*
136 * generic-trap values in the SNMP Trap-PDU
137 */
138 static char *GenericTrap[] = {
139 "coldStart",
140 "warmStart",
141 "linkDown",
142 "linkUp",
143 "authenticationFailure",
144 "egpNeighborLoss",
145 "enterpriseSpecific"
146 };
147
148 /*
149 * ASN.1 type class table
150 * Ties together the preceding Universal, Application, Context, and Private
151 * type definitions.
152 */
153 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
154 static struct {
155 char *name;
156 char **Id;
157 int numIDs;
158 } Class[] = {
159 defineCLASS(Universal),
160 #define UNIVERSAL 0
161 defineCLASS(Application),
162 #define APPLICATION 1
163 defineCLASS(Context),
164 #define CONTEXT 2
165 defineCLASS(Private),
166 #define PRIVATE 3
167 };
168
169 /*
170 * defined forms for ASN.1 types
171 */
172 static char *Form[] = {
173 "Primitive",
174 #define PRIMITIVE 0
175 "Constructed",
176 #define CONSTRUCTED 1
177 };
178
179 /*
180 * A tree in the format of the tree structure of the MIB.
181 */
182 #define MAXLABEL 64 /* max label length */
183 #define MAXTOKEN 64
184 #define HASHSIZE 255
185 static struct tree {
186 struct tree *child_list; /* list of children of this node */
187 struct tree *next_peer; /* Next node in list of peers */
188 struct tree *parent;
189 struct tree *next_hash; /* next hash entry. used by parser */
190 char label[MAXLABEL]; /* This node's textual name */
191 u_long subid; /* This node's integer subidentifier */
192 int type; /* This node's object type */
193 };
194 static struct tree *Mib=NULL;
195 static struct tree *objp=NULL;
196 static void init_mib();
197 static struct tree *read_mib();
198 static struct tree *enter();
199 static struct tree *lookup();
200 static int add_child();
201
202 /*
203 * This defines a list of OIDs which will be abreviated on output.
204 * Currently, this includes the prefixes for the Internet MIB, the
205 * private enterprises tree, and the experimental tree.
206 */
207 static struct obj_abrev {
208 char *prefix; /* prefix for this abrev */
209 struct tree *node; /* pointer into object table */
210 char *name;
211 char *oid; /* ASN.1 encoded OID */
212 } obj_abrev_list[] = {
213 /* .iso.org.dod.internet.mgmt.mib */
214 { "", 0, "mib", "\53\6\1\2\1" },
215 /* .iso.org.dod.internet.private.enterprises */
216 { "E:", 0, "enterprises", "\53\6\1\4\1" },
217 /* .iso.org.dod.internet.experimental */
218 { "X:", 0, "experimental", "\53\6\1\3" },
219 { 0,0,0,0 }
220 };
221
222 /*
223 * This is used in the OID print routine to walk down the object tree
224 * rooted at `Mib'.
225 */
226 #define OBJ_PRINT(o, suppressdot) \
227 { \
228 if (objp) { \
229 do { \
230 if ((o) == objp->subid) \
231 break; \
232 } while (objp = objp->next_peer); \
233 } \
234 if (objp) { \
235 printf(suppressdot?"%s":".%s", objp->label); \
236 objp = objp->child_list; \
237 } else \
238 printf(suppressdot?"%u":".%u", (o)); \
239 }
240
241 /*
242 * Defaults for SNMP PDU components
243 */
244 #define DEF_COMMUNITY "public"
245 #define DEF_VERSION 0
246
247 /*
248 * constants for ASN.1 decoding
249 */
250 #define OIDMUX 40
251 #define ASNLEN_INETADDR 4
252 #define ASN_SHIFT7 7
253 #define ASN_SHIFT8 8
254 #define ASN_BIT8 0x80
255 #define ASN_LONGLEN 0x80
256
257 #define ASN_ID_BITS 0x1f
258 #define ASN_FORM_BITS 0x20
259 #define ASN_FORM_SHIFT 5
260 #define ASN_CLASS_BITS 0xc0
261 #define ASN_CLASS_SHIFT 6
262
263 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
264
265 #ifdef TCPVIEW
266 #define err_print eprint
267 #else
268 #define err_print printf
269 #endif
270
271 static char errbuf[10];
272
DECODE_ErrorStatus(e)273 char *DECODE_ErrorStatus( e )
274 int e;
275 {
276 if( e >= 0 && e <= sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) )
277 return( ErrorStatus[e] );
278 sprintf(errbuf,"err=%d",e);
279 return( errbuf );
280 }
281
DECODE_GenericTrap(e)282 char *DECODE_GenericTrap( e )
283 int e;
284 {
285 if( e >= 0 && e <= sizeof(GenericTrap)/sizeof(GenericTrap[0]) )
286 return( GenericTrap[e] );
287 sprintf(errbuf,"gt=%d",e);
288 return( errbuf );
289 }
290
291 /*
292 * truncated==1 means the packet was complete, but we don't have all of
293 * it to decode.
294 */
295 static int truncated;
296 #define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else
297
298 /*
299 * This decodes the next ASN.1 object in the stream pointed to by "p"
300 * (and of real-length "len") and stores the intermediate data in the
301 * provided BE object.
302 *
303 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
304 * O/w, this returns the number of bytes parsed from "p".
305 */
306 int
asn1_parse(p,len,elem)307 asn1_parse(p, len, elem)
308 register u_char *p;
309 int len;
310 struct be *elem;
311 {
312 unsigned char form, class, id;
313 int indent=0, i, hdr;
314 char *classstr;
315
316 elem->asnlen = 0;
317 elem->type = BE_ANY;
318 if (len < 1) {
319 ifNotTruncated puts("[nothing to parse], stdout");
320 return -1;
321 }
322
323 /*
324 * it would be nice to use a bit field, but you can't depend on them.
325 * +---+---+---+---+---+---+---+---+
326 * + class |frm| id |
327 * +---+---+---+---+---+---+---+---+
328 * 7 6 5 4 3 2 1 0
329 */
330 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
331 #ifdef notdef
332 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
333 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
334 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
335 #else
336 form = (*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
337 class = (*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
338 #endif
339 elem->form = form;
340 elem->class = class;
341 elem->id = id;
342 if (vflag)
343 printf("|%.2x", *p);
344 p++; len--; hdr = 1;
345 /* extended tag field */
346 if (id == ASN_ID_EXT) {
347 for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) {
348 if (vflag)
349 printf("|%.2x", *p);
350 id += *p & ~ASN_BIT8;
351 }
352 if (len == 0 && *p & ASN_BIT8) {
353 ifNotTruncated fputs("[Xtagfield?]", stdout);
354 return -1;
355 }
356 }
357 if (len < 1) {
358 ifNotTruncated fputs("[no asnlen]", stdout);
359 return -1;
360 }
361 elem->asnlen = *p;
362 if (vflag)
363 printf("|%.2x", *p);
364 p++; len--; hdr++;
365 if (elem->asnlen & ASN_BIT8) {
366 int noct = elem->asnlen % ASN_BIT8;
367 elem->asnlen = 0;
368 if (len < noct) {
369 ifNotTruncated printf("[asnlen? %d<%d]", len, noct);
370 return -1;
371 }
372 for (; noct-- > 0; len--, hdr++) {
373 if (vflag)
374 printf("|%.2x", *p);
375 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
376 }
377 }
378 if (len < elem->asnlen) {
379 if (!truncated) {
380 printf("[len%d<asnlen%u]", len, elem->asnlen);
381 return -1;
382 }
383 /* maybe should check at least 4? */
384 elem->asnlen = len;
385 }
386 if (form >= sizeof(Form)/sizeof(Form[0])) {
387 ifNotTruncated printf("[form?%d]", form);
388 return -1;
389 }
390 if (class >= sizeof(Class)/sizeof(Class[0])) {
391 ifNotTruncated printf("[class?%c/%d]", *Form[form], class);
392 return -1;
393 }
394 if (id >= Class[class].numIDs) {
395 ifNotTruncated printf("[id?%c/%s/%d]", *Form[form],
396 Class[class].name, id);
397 return -1;
398 }
399
400 switch (form) {
401 case PRIMITIVE:
402 switch (class) {
403 case UNIVERSAL:
404 switch (id) {
405 case STRING:
406 elem->type = BE_STR;
407 elem->data.str = p;
408 break;
409
410 case INTEGER: {
411 register long data;
412 elem->type = BE_INT;
413 data = 0;
414
415 if (*p & ASN_BIT8) /* negative */
416 data = -1;
417 for (i = elem->asnlen; i-- > 0; p++)
418 data = (data << ASN_SHIFT8) | *p;
419 elem->data.integer = data;
420 break;
421 }
422
423 case OBJECTID:
424 elem->type = BE_OID;
425 elem->data.raw = (caddr_t)p;
426 break;
427
428 case ASN_NULL:
429 elem->type = BE_NULL;
430 elem->data.raw = NULL;
431 break;
432
433 default:
434 elem->type = BE_OCTET;
435 elem->data.raw = (caddr_t)p;
436 printf("[P/U/%s]",
437 Class[class].Id[id]);
438 break;
439 }
440 break;
441
442 case APPLICATION:
443 switch (id) {
444 case IPADDR:
445 elem->type = BE_INETADDR;
446 elem->data.raw = (caddr_t)p;
447 break;
448
449 case COUNTER:
450 case GAUGE:
451 case TIMETICKS: {
452 register unsigned long data;
453 elem->type = BE_UNS;
454 data = 0;
455 for (i = elem->asnlen; i-- > 0; p++)
456 data = (data << 8) + *p;
457 elem->data.uns = data;
458 break;
459 }
460
461 default:
462 elem->type = BE_OCTET;
463 elem->data.raw = (caddr_t)p;
464 printf("[P/A/%s]",
465 Class[class].Id[id]);
466 break;
467 }
468 break;
469
470 default:
471 elem->type = BE_OCTET;
472 elem->data.raw = (caddr_t)p;
473 printf("[P/%s/%s]",
474 Class[class].name, Class[class].Id[id]);
475 break;
476 }
477 break;
478
479 case CONSTRUCTED:
480 switch (class) {
481 case UNIVERSAL:
482 switch (id) {
483 case SEQUENCE:
484 elem->type = BE_SEQ;
485 elem->data.raw = (caddr_t)p;
486 break;
487
488 default:
489 elem->type = BE_OCTET;
490 elem->data.raw = (caddr_t)p;
491 printf("C/U/%s", Class[class].Id[id]);
492 break;
493 }
494 break;
495
496 case CONTEXT:
497 elem->type = BE_PDU;
498 elem->data.raw = (caddr_t)p;
499 break;
500
501 default:
502 elem->type = BE_OCTET;
503 elem->data.raw = (caddr_t)p;
504 printf("C/%s/%s",
505 Class[class].name, Class[class].Id[id]);
506 break;
507 }
508 break;
509 }
510 p += elem->asnlen;
511 len -= elem->asnlen;
512 return elem->asnlen + hdr;
513 }
514
515 /*
516 * Display the ASN.1 object represented by the BE object.
517 */
asn1_print(elem)518 void asn1_print(elem)
519 struct be *elem;
520 {
521 u_char *p = (u_char *)elem->data.raw;
522 u_long asnlen = elem->asnlen;
523 int i;
524
525 switch (elem->type) {
526
527 case BE_OCTET:
528 for (i = asnlen; i-- > 0; p++);
529 printf("_%.2x", *p);
530 break;
531
532 case BE_NULL:
533 break;
534
535 case BE_OID: {
536 int o = 0, first = -1, i = asnlen;
537
538 if (!nflag && asnlen > 2) {
539 struct obj_abrev *a = &obj_abrev_list[0];
540 for (; a->node; a++) {
541 if (!memcmp(a->oid, p, strlen(a->oid))) {
542 objp = a->node->child_list;
543 i -= strlen(a->oid);
544 p += strlen(a->oid);
545 fputs(a->prefix, stdout);
546 first = 1;
547 break;
548 }
549 }
550 }
551
552 for (; i-- > 0; p++) {
553 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
554 if (*p & ASN_LONGLEN)
555 continue;
556
557 /*
558 * first subitem encodes two items with 1st*OIDMUX+2nd
559 */
560 if (first < 0) {
561 if (!nflag)
562 objp = Mib;
563 first = 0;
564 OBJ_PRINT(o/OIDMUX, first);
565 o %= OIDMUX;
566 }
567 OBJ_PRINT(o, first);
568 if (--first < 0)
569 first = 0;
570 o = 0;
571 }
572 break;
573 }
574
575 case BE_INT:
576 printf("%ld", elem->data.integer);
577 break;
578
579 case BE_UNS:
580 printf("%lu", elem->data.uns);
581 break;
582
583 case BE_STR: {
584 register int printable = 1, first = 1;
585 u_char *p = elem->data.str;
586 for (i = asnlen; printable && i-- > 0; p++)
587 printable = isprint(*p) || isspace(*p);
588 p = elem->data.str;
589 if (printable)
590 (void)printfn(p, p+asnlen);
591 else
592 for (i = asnlen; i-- > 0; p++) {
593 printf(first ? "%.2x" : "_%.2x", *p);
594 first = 0;
595 }
596 break;
597 }
598
599 case BE_SEQ:
600 printf("Seq(%d)", elem->asnlen);
601 break;
602
603 case BE_INETADDR: {
604 char sep;
605 if (asnlen != ASNLEN_INETADDR)
606 printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
607 sep='[';
608 for (i = asnlen; i-- > 0; p++) {
609 printf("%c%u", sep, *p);
610 sep='.';
611 }
612 putchar(']');
613 break;
614 }
615
616 case BE_PDU:
617 printf("%s(%d)",
618 Class[CONTEXT].Id[elem->id], elem->asnlen);
619 break;
620
621 case BE_ANY:
622 fputs("[BE_ANY!?]", stdout);
623 break;
624
625 default:
626 fputs("[be!?]", stdout);
627 break;
628 }
629 }
630
631 #ifdef notdef
632 /*
633 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
634 * This will work for any ASN.1 stream, not just an SNMP PDU.
635 *
636 * By adding newlines and spaces at the correct places, this would print in
637 * Rose-Normal-Form.
638 *
639 * This is not currently used.
640 */
641 void
asn1_decode(p,length)642 asn1_decode(p, length)
643 u_char *p;
644 int length;
645 {
646 struct be elem;
647 int i = 0;
648
649 while (i >= 0 && length > 0) {
650 i = asn1_parse(p, length, &elem);
651 if (i >= 0) {
652 fputs(" ", stdout);
653 asn1_print(&elem);
654 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
655 fputs(" {", stdout);
656 asn1_decode(elem.data.raw, elem.asnlen);
657 fputs(" }", stdout);
658 }
659 length -= i;
660 p += i;
661 }
662 }
663 }
664 #endif
665
666 /*
667 * General SNMP header
668 * SEQUENCE {
669 * version INTEGER {version-1(0)},
670 * community OCTET STRING,
671 * data ANY -- PDUs
672 * }
673 * PDUs for all but Trap: (see rfc1157 from page 15 on)
674 * SEQUENCE {
675 * request-id INTEGER,
676 * error-status INTEGER,
677 * error-index INTEGER,
678 * varbindlist SEQUENCE OF
679 * SEQUENCE {
680 * name ObjectName,
681 * value ObjectValue
682 * }
683 * }
684 * PDU for Trap:
685 * SEQUENCE {
686 * enterprise OBJECT IDENTIFIER,
687 * agent-addr NetworkAddress,
688 * generic-trap INTEGER,
689 * specific-trap INTEGER,
690 * time-stamp TimeTicks,
691 * varbindlist SEQUENCE OF
692 * SEQUENCE {
693 * name ObjectName,
694 * value ObjectValue
695 * }
696 * }
697 */
698
699 /*
700 * Decode SNMP varBind
701 */
702 static void
varbind_print(pduid,np,length,error)703 varbind_print (pduid, np, length, error)
704 u_char pduid, *np;
705 int length, error;
706 {
707 struct be elem;
708 int count = 0, index;
709
710 /* Sequence of varBind */
711 if ((count = asn1_parse(np, length, &elem)) < 0)
712 return;
713 if (elem.type != BE_SEQ) {
714 fputs("[!SEQ of varbind]", stdout);
715 asn1_print(&elem);
716 return;
717 }
718 if (count < length)
719 printf("[%d extra after SEQ of varbind]", length - count);
720 /* descend */
721 length = elem.asnlen;
722 np = (u_char *)elem.data.raw;
723
724 for (index = 1; length > 0; index++) {
725 u_char *vbend;
726 int vblength;
727
728 if (!error || index == error)
729 fputs(" ", stdout);
730
731 /* Sequence */
732 if ((count = asn1_parse(np, length, &elem)) < 0)
733 return;
734 if (elem.type != BE_SEQ) {
735 fputs("[!varbind]", stdout);
736 asn1_print(&elem);
737 return;
738 }
739 vbend = np + count;
740 vblength = length - count;
741 /* descend */
742 length = elem.asnlen;
743 np = (u_char *)elem.data.raw;
744
745 /* objName (OID) */
746 if ((count = asn1_parse(np, length, &elem)) < 0)
747 return;
748 if (elem.type != BE_OID) {
749 fputs("[objName!=OID]", stdout);
750 asn1_print(&elem);
751 return;
752 }
753 if (!error || index == error)
754 asn1_print(&elem);
755 length -= count;
756 np += count;
757
758 if (pduid != GETREQ && pduid != GETNEXTREQ && !error)
759 fputs("=", stdout);
760
761 /* objVal (ANY) */
762 if ((count = asn1_parse(np, length, &elem)) < 0)
763 return;
764 if (pduid == GETREQ || pduid == GETNEXTREQ) {
765 if (elem.type != BE_NULL) {
766 fputs("[objVal!=NULL]", stdout);
767 asn1_print(&elem);
768 }
769 } else
770 if (error && index == error && elem.type != BE_NULL)
771 fputs("[err objVal!=NULL]", stdout);
772 if (!error || index == error)
773 asn1_print(&elem);
774
775 length = vblength;
776 np = vbend;
777 }
778 }
779
780 /*
781 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, and SetRequest
782 */
783 static void
snmppdu_print(pduid,np,length)784 snmppdu_print (pduid, np, length)
785 u_char pduid, *np;
786 int length;
787 {
788 struct be elem;
789 int count = 0, error;
790
791 /* reqId (Integer) */
792 if ((count = asn1_parse(np, length, &elem)) < 0)
793 return;
794 if (elem.type != BE_INT) {
795 fputs("[reqId!=INT]", stdout);
796 asn1_print(&elem);
797 return;
798 }
799 /* ignore the reqId */
800 length -= count;
801 np += count;
802
803 /* errorStatus (Integer) */
804 if ((count = asn1_parse(np, length, &elem)) < 0)
805 return;
806 if (elem.type != BE_INT) {
807 fputs("[errorStatus!=INT]", stdout);
808 asn1_print(&elem);
809 return;
810 }
811 error = 0;
812 if ((pduid == GETREQ || pduid == GETNEXTREQ)
813 && elem.data.integer != 0) {
814 printf("[errorStatus(%s)!=0]",
815 DECODE_ErrorStatus(elem.data.integer));
816 } else if (elem.data.integer != 0) {
817 printf(" %s", DECODE_ErrorStatus(elem.data.integer));
818 error = elem.data.integer;
819 }
820 length -= count;
821 np += count;
822
823 /* errorIndex (Integer) */
824 if ((count = asn1_parse(np, length, &elem)) < 0)
825 return;
826 if (elem.type != BE_INT) {
827 fputs("[errorIndex!=INT]", stdout);
828 asn1_print(&elem);
829 return;
830 }
831 if ((pduid == GETREQ || pduid == GETNEXTREQ)
832 && elem.data.integer != 0)
833 printf("[errorIndex(%d)!=0]", elem.data.integer);
834 else if (elem.data.integer != 0) {
835 if (!error)
836 printf("[errorIndex(%d) w/o errorStatus]",
837 elem.data.integer);
838 else {
839 printf("@%d", elem.data.integer);
840 error = elem.data.integer;
841 }
842 } else if (error) {
843 fputs("[errorIndex==0]", stdout);
844 error = 0;
845 }
846 length -= count;
847 np += count;
848
849 varbind_print(pduid, np, length, error);
850 return;
851 }
852
853 /*
854 * Decode SNMP Trap PDU
855 */
856 static void
trap_print(np,length)857 trap_print (np, length)
858 u_char *np;
859 int length;
860 {
861 struct be elem;
862 int count = 0, generic;
863
864 putchar(' ');
865
866 /* enterprise (oid) */
867 if ((count = asn1_parse(np, length, &elem)) < 0)
868 return;
869 if (elem.type != BE_OID) {
870 fputs("[enterprise!=OID]", stdout);
871 asn1_print(&elem);
872 return;
873 }
874 asn1_print(&elem);
875 length -= count;
876 np += count;
877
878 putchar(' ');
879
880 /* agent-addr (inetaddr) */
881 if ((count = asn1_parse(np, length, &elem)) < 0)
882 return;
883 if (elem.type != BE_INETADDR) {
884 fputs("[agent-addr!=INETADDR]", stdout);
885 asn1_print(&elem);
886 return;
887 }
888 asn1_print(&elem);
889 length -= count;
890 np += count;
891
892 /* generic-trap (Integer) */
893 if ((count = asn1_parse(np, length, &elem)) < 0)
894 return;
895 if (elem.type != BE_INT) {
896 fputs("[generic-trap!=INT]", stdout);
897 asn1_print(&elem);
898 return;
899 }
900 generic = elem.data.integer;
901 printf(" %s", DECODE_GenericTrap(generic));
902
903 length -= count;
904 np += count;
905
906 /* specific-trap (Integer) */
907 if ((count = asn1_parse(np, length, &elem)) < 0)
908 return;
909 if (elem.type != BE_INT) {
910 fputs("[specific-trap!=INT]", stdout);
911 asn1_print(&elem);
912 return;
913 }
914 if (generic != GT_ENTERPRISE) {
915 if (elem.data.integer != 0)
916 printf("[specific-trap(%d)!=0]", elem.data.integer);
917 } else
918 printf(" s=%d", elem.data.integer);
919 length -= count;
920 np += count;
921
922 putchar(' ');
923
924 /* time-stamp (TimeTicks) */
925 if ((count = asn1_parse(np, length, &elem)) < 0)
926 return;
927 if (elem.type != BE_UNS) { /* XXX */
928 fputs("[time-stamp!=TIMETICKS]", stdout);
929 asn1_print(&elem);
930 return;
931 }
932 asn1_print(&elem);
933 length -= count;
934 np += count;
935
936 varbind_print (TRAP, np, length, 0);
937 return;
938 }
939
940 /*
941 * Decode SNMP header and pass on to PDU printing routines
942 */
943 void
snmp_print(np,length)944 snmp_print (np, length)
945 u_char *np;
946 int length;
947 {
948 struct be elem, pdu;
949 int count = 0;
950
951 if( Mib == NULL )
952 init_mib();
953
954 truncated = 0;
955
956 /* truncated packet? */
957 if (np + length > snapend) {
958 truncated = 1;
959 length = snapend - np;
960 }
961
962 putchar(' ');
963
964 /* initial Sequence */
965 if ((count = asn1_parse(np, length, &elem)) < 0)
966 return;
967 if (elem.type != BE_SEQ) {
968 fputs("[!init SEQ]", stdout);
969 asn1_print(&elem);
970 return;
971 }
972 if (count < length)
973 printf("[%d extra after iSEQ]", length - count);
974 /* descend */
975 length = elem.asnlen;
976 np = (u_char *)elem.data.raw;
977 /* Version (Integer) */
978 if ((count = asn1_parse(np, length, &elem)) < 0)
979 return;
980 if (elem.type != BE_INT) {
981 fputs("[version!=INT]", stdout);
982 asn1_print(&elem);
983 return;
984 }
985 /* only handle version==0 */
986 if (elem.data.integer != DEF_VERSION) {
987 printf("[version(%d)!=0]", elem.data.integer);
988 return;
989 }
990 length -= count;
991 np += count;
992
993 /* Community (String) */
994 if ((count = asn1_parse(np, length, &elem)) < 0)
995 return;
996 if (elem.type != BE_STR) {
997 fputs("[comm!=STR]", stdout);
998 asn1_print(&elem);
999 return;
1000 }
1001 /* default community */
1002 if (strncmp(elem.data.str, DEF_COMMUNITY, sizeof(DEF_COMMUNITY)-1))
1003 /* ! "public" */
1004 printf("C=%.*s ", elem.asnlen, elem.data.str);
1005 length -= count;
1006 np += count;
1007
1008 /* PDU (Context) */
1009 if ((count = asn1_parse(np, length, &pdu)) < 0)
1010 return;
1011 if (pdu.type != BE_PDU) {
1012 fputs("[no PDU]", stdout);
1013 return;
1014 }
1015 if (count < length)
1016 printf("[%d extra after PDU]", length - count);
1017 asn1_print(&pdu);
1018 /* descend into PDU */
1019 length = pdu.asnlen;
1020 np = (u_char *)pdu.data.raw;
1021
1022 switch (pdu.id) {
1023 case TRAP:
1024 trap_print(np, length);
1025 break;
1026 case GETREQ:
1027 case GETNEXTREQ:
1028 case GETRESP:
1029 case SETREQ:
1030 snmppdu_print(pdu.id, np, length);
1031 break;
1032 }
1033 return;
1034 }
1035
init_mib()1036 static void init_mib()
1037 {
1038 char *file, *getenv();
1039 struct obj_abrev *a = &obj_abrev_list[0];
1040
1041 Mib = 0;
1042 file = getenv("MIBFILE");
1043 if (file)
1044 Mib = read_mib(file);
1045 if (!Mib)
1046 Mib = read_mib("mib.txt");
1047 if (!Mib)
1048 Mib = read_mib("/usr/local/lib/tcpview/mib/mib.txt");
1049 if (!Mib){
1050 err_print("Couldn't find mib file\n");
1051 exit(2);
1052 }
1053
1054 for (; a->name; a++) {
1055 a->node = lookup(a->name);
1056 if( a->node == NULL )
1057 err_print("WARNING: Could not find %s in MIB.\n",a->name);
1058 }
1059 }
1060
1061 static struct tree *Hashtable[HASHSIZE];
1062
read_mib(filename)1063 static struct tree *read_mib(filename)
1064 char *filename;
1065 {
1066 FILE *fp;
1067 struct tree *tp;
1068 struct tree *parent, *hp, *iso;
1069 char buf[256], name[64], *ptr, *stp;
1070 int type=0, access=0;
1071
1072 fp = fopen(filename, "r");
1073 if (fp == NULL)
1074 return NULL;
1075
1076 /* create iso */
1077 iso = enter("iso");
1078 iso->subid = 1;
1079
1080 /* read in mosy file */
1081 while(fgets(buf,sizeof(buf),fp)) {
1082 if(*buf == '#' || isspace(*buf) || (buf[0]=='-' && buf[1]=='-'))
1083 continue;
1084 ptr = buf;
1085 while(!isspace(*ptr))
1086 ptr++;
1087 *ptr++ = 0;
1088 strncpy(name,buf,sizeof(name));
1089 name[sizeof(name)-1]='\0';
1090
1091 while(isspace(*ptr)) ptr++;
1092 stp = ptr;
1093 while(*ptr != '.')
1094 ptr++;
1095 *ptr++ = 0;
1096 parent = lookup(stp);
1097 if(parent==NULL) {
1098 err_print("Couldn't find parent %s of %s\n",stp,name);
1099 exit(0);
1100 }
1101 stp = ptr;
1102 while(!isspace(*ptr)) ptr++;
1103 *ptr++ = 0;
1104
1105 hp = lookup(name);
1106 if(hp==NULL)
1107 hp = enter(name);
1108 else { /* name already exists */
1109 if(hp->parent==parent)
1110 if(hp->subid==atoi(stp))
1111 continue; /* duplicate definition - skip it */
1112 else {
1113 err_print("Error: %s redefined\n",name);
1114 exit(0);
1115 }
1116 else
1117 hp = enter(name);
1118 }
1119 hp->subid = atoi(stp);
1120 add_child(parent,hp);
1121 while(isspace(*ptr)) ptr++;
1122 if(*ptr==0)
1123 continue;
1124 stp = ptr;
1125 while(!isspace(*ptr)) ptr++;
1126 *ptr++ = 0;
1127
1128 if(!strcmp(stp,"INTEGER"))
1129 type = BE_INT;
1130 else if(!strcmp(stp,"Counter"))
1131 type = BE_UNS;
1132 else if(!strcmp(stp,"DisplayString"))
1133 type = BE_STR;
1134 else if(!strcmp(stp,"Gauge"))
1135 type = BE_UNS;
1136 else if(!strcmp(stp,"TimeTicks"))
1137 type = BE_UNS;
1138 else if(!strcmp(stp,"NetworkAddress"))
1139 type = BE_INETADDR;
1140 else if(!strcmp(stp,"IpAddress"))
1141 type = BE_INETADDR;
1142 else if(!strcmp(stp,"OctetString"))
1143 type = BE_OCTET;
1144 else if(!strcmp(stp,"ObjectID"))
1145 type = BE_OID;
1146 else if(!strcmp(stp,"Aggregate"))
1147 type = BE_ANY;
1148 else if(!strcmp(stp,"PhysAddress"))
1149 type = BE_OCTET;
1150 else {
1151 err_print("type %s not recognized\n",stp);
1152 type = BE_ANY;
1153 }
1154 hp->type = type;
1155 }
1156 fclose(fp);
1157 return (iso);
1158 }
1159
1160 /*
1161 ** lookup(name) returns a pointer to "name" in the hash table.
1162 ** returns NULL if the name is not found
1163 */
1164
lookup(name)1165 static struct tree *lookup(name)
1166 char *name;
1167 {
1168 struct tree *hp;
1169 int hash;
1170
1171 hash = (name[0]+name[1]) & HASHSIZE;
1172 hp = Hashtable[hash];
1173 while(hp) {
1174 if (!strcmp(hp->label,name))
1175 return (hp);
1176 hp = hp->next_hash;
1177 }
1178 return(NULL);
1179 }
1180
1181 /*
1182 ** enter() enters a new name in the hash table.
1183 ** New entries are put at the beginning of the hash chain.
1184 */
enter(name)1185 static struct tree *enter(name)
1186 char *name;
1187 {
1188 struct tree *hp;
1189 int hash;
1190
1191 hash = (name[0]+name[1]) & HASHSIZE;
1192 hp = (struct tree *)malloc(sizeof(struct tree));
1193 hp->next_hash = Hashtable[hash];
1194 Hashtable[hash] = hp;
1195 strcpy(hp->label,name);
1196 hp->child_list = hp->next_peer = hp->parent = 0;
1197 hp->type = BE_NONE;
1198 return(hp);
1199
1200 }
1201
1202 /* add a child to a node in the tree */
add_child(parent,child)1203 static int add_child(parent, child)
1204 struct tree *parent, *child;
1205 {
1206 struct tree *t = parent->child_list;
1207
1208 /* fprintf(stderr,"adding %s to %s (%d)\n",child->label,parent->label,child->subid); */
1209 if(t==NULL) {
1210 parent->child_list = child;
1211 child->next_peer = 0;
1212 child->parent = parent;
1213 return 1;
1214 }
1215
1216 while(1) {
1217 if(t->subid==child->subid) {
1218 if(!strcmp(t->label,child->label)) {
1219 return 0;
1220 } else {
1221 err_print("Warning: node %s has 2 children with subid %d!\n",parent->label,child->subid);
1222 return 0;
1223 }
1224 }
1225 if(t->next_peer)
1226 t = t->next_peer;
1227 else
1228 break;
1229 }
1230
1231 t->next_peer = child;
1232 child->next_peer = 0;
1233 child->parent = parent;
1234
1235 return 1;
1236 }
1237
1238
1239
1240