1 /* 2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by John Robert LoVerso. 11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 12 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 13 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 * 15 * This implementation has been influenced by the CMU SNMP release, 16 * by Steve Waldbusser. However, this shares no code with that system. 17 * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_. 18 * Earlier forms of this implementation were derived and/or inspired by an 19 * awk script originally written by C. Philip Wood of LANL (but later 20 * heavily modified by John Robert LoVerso). The copyright notice for 21 * that work is preserved below, even though it may not rightly apply 22 * to this file. 23 * 24 * This started out as a very simple program, but the incremental decoding 25 * (into the BE structure) complicated things. 26 * 27 # Los Alamos National Laboratory 28 # 29 # Copyright, 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 3.10 91/01/17 01:18:13 loverso Exp Locker: loverso $ (jlv)"; 45 #endif 46 47 #include <sys/param.h> 48 #include <sys/time.h> 49 50 #include <stdio.h> 51 #include <ctype.h> 52 #include <string.h> 53 54 #include "interface.h" 55 #include "addrtoname.h" 56 57 /* 58 * Universal ASN.1 types 59 * (we only care about the tag values for those allowed in the Internet SMI) 60 */ 61 char *Universal[] = { 62 "U-0", 63 "Boolean", 64 "Integer", 65 #define INTEGER 2 66 "Bitstring", 67 "String", 68 #define STRING 4 69 "Null", 70 #define ASN_NULL 5 71 "ObjID", 72 #define OBJECTID 6 73 "ObjectDes", 74 "U-8","U-9","U-10","U-11", /* 8-11 */ 75 "U-12","U-13","U-14","U-15", /* 12-15 */ 76 "Sequence", 77 #define SEQUENCE 16 78 "Set" 79 }; 80 81 /* 82 * Application-wide ASN.1 types from the Internet SMI and their tags 83 */ 84 char *Application[] = { 85 "IpAddress", 86 #define IPADDR 0 87 "Counter", 88 #define COUNTER 1 89 "Gauge", 90 #define GAUGE 2 91 "TimeTicks", 92 #define TIMETICKS 3 93 "Opaque" 94 }; 95 96 /* 97 * Context-specific ASN.1 types for the SNMP PDUs and their tags 98 */ 99 char *Context[] = { 100 "GetRequest", 101 #define GETREQ 0 102 "GetNextRequest", 103 #define GETNEXTREQ 1 104 "GetResponse", 105 #define GETRESP 2 106 "SetRequest", 107 #define SETREQ 3 108 "Trap" 109 #define TRAP 4 110 }; 111 112 /* 113 * Private ASN.1 types 114 * The Internet SMI does not specify any 115 */ 116 char *Private[] = { 117 "P-0" 118 }; 119 120 /* 121 * error-status values for any SNMP PDU 122 */ 123 char *ErrorStatus[] = { 124 "noError", 125 "tooBig", 126 "noSuchName", 127 "badValue", 128 "readOnly", 129 "genErr" 130 }; 131 #define DECODE_ErrorStatus(e) \ 132 ( e >= 0 && e <= sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \ 133 ? ErrorStatus[e] : (sprintf(errbuf, "err=%u", e), errbuf)) 134 135 /* 136 * generic-trap values in the SNMP Trap-PDU 137 */ 138 char *GenericTrap[] = { 139 "coldStart", 140 "warmStart", 141 "linkDown", 142 "linkUp", 143 "authenticationFailure", 144 "egpNeighborLoss", 145 "enterpriseSpecific" 146 #define GT_ENTERPRISE 7 147 }; 148 #define DECODE_GenericTrap(t) \ 149 ( t >= 0 && t <= sizeof(GenericTrap)/sizeof(GenericTrap[0]) \ 150 ? GenericTrap[t] : (sprintf(buf, "gt=%d", t), buf)) 151 152 /* 153 * ASN.1 type class table 154 * Ties together the preceding Universal, Application, Context, and Private 155 * type definitions. 156 */ 157 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */ 158 struct { 159 char *name; 160 char **Id; 161 int numIDs; 162 } Class[] = { 163 defineCLASS(Universal), 164 #define UNIVERSAL 0 165 defineCLASS(Application), 166 #define APPLICATION 1 167 defineCLASS(Context), 168 #define CONTEXT 2 169 defineCLASS(Private), 170 #define PRIVATE 3 171 }; 172 173 /* 174 * defined forms for ASN.1 types 175 */ 176 char *Form[] = { 177 "Primitive", 178 #define PRIMITIVE 0 179 "Constructed", 180 #define CONSTRUCTED 1 181 }; 182 183 /* 184 * A structure for the OID tree for the compiled-in MIB. 185 * This is stored as a general-order tree. 186 */ 187 struct obj { 188 char *desc; /* name of object */ 189 u_char oid; /* sub-id following parent */ 190 u_char type; /* object type (unused) */ 191 struct obj *child, *next; /* child and next sibling pointers */ 192 } *objp = NULL; 193 194 /* 195 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding 196 * RFC-1156 format files into "makemib". "mib.h" MUST define at least 197 * a value for `mibroot'. 198 * 199 * In particular, this is gross, as this is including initialized structures, 200 * and by right shouldn't be an "include" file. 201 */ 202 #include "mib.h" 203 204 /* 205 * This defines a list of OIDs which will be abbreviated on output. 206 * Currently, this includes the prefixes for the Internet MIB, the 207 * private enterprises tree, and the experimental tree. 208 */ 209 struct obj_abrev { 210 char *prefix; /* prefix for this abrev */ 211 struct obj *node; /* pointer into object table */ 212 char *oid; /* ASN.1 encoded OID */ 213 } obj_abrev_list[] = { 214 #ifndef NO_ABREV_MIB 215 /* .iso.org.dod.internet.mgmt.mib */ 216 { "", &_mib_obj, "\53\6\1\2\1" }, 217 #endif 218 #ifndef NO_ABREV_ENTER 219 /* .iso.org.dod.internet.private.enterprises */ 220 { "E:", &_enterprises_obj, "\53\6\1\4\1" }, 221 #endif 222 #ifndef NO_ABREV_EXPERI 223 /* .iso.org.dod.internet.experimental */ 224 { "X:", &_experimental_obj, "\53\6\1\3" }, 225 #endif 226 { 0,0,0 } 227 }; 228 229 /* 230 * This is used in the OID print routine to walk down the object tree 231 * rooted at `mibroot'. 232 */ 233 #define OBJ_PRINT(o, suppressdot) \ 234 { \ 235 if (objp) { \ 236 do { \ 237 if ((o) == objp->oid) \ 238 break; \ 239 } while ((objp = objp->next) != NULL); \ 240 } \ 241 if (objp) { \ 242 printf(suppressdot?"%s":".%s", objp->desc); \ 243 objp = objp->child; \ 244 } else \ 245 printf(suppressdot?"%u":".%u", (o)); \ 246 } 247 248 /* 249 * This is the definition for the Any-Data-Type storage used purely for 250 * temporary internal representation while decoding an ASN.1 data stream. 251 */ 252 struct be { 253 u_int32_t asnlen; 254 union { 255 caddr_t raw; 256 int32_t integer; 257 u_int32_t uns; 258 const u_char *str; 259 } data; 260 u_short id; 261 u_char form, class; /* tag info */ 262 u_char type; 263 #define BE_ANY 255 264 #define BE_NONE 0 265 #define BE_NULL 1 266 #define BE_OCTET 2 267 #define BE_OID 3 268 #define BE_INT 4 269 #define BE_UNS 5 270 #define BE_STR 6 271 #define BE_SEQ 7 272 #define BE_INETADDR 8 273 #define BE_PDU 9 274 }; 275 276 /* 277 * Defaults for SNMP PDU components 278 */ 279 #define DEF_COMMUNITY "public" 280 #define DEF_VERSION 0 281 282 /* 283 * constants for ASN.1 decoding 284 */ 285 #define OIDMUX 40 286 #define ASNLEN_INETADDR 4 287 #define ASN_SHIFT7 7 288 #define ASN_SHIFT8 8 289 #define ASN_BIT8 0x80 290 #define ASN_LONGLEN 0x80 291 292 #define ASN_ID_BITS 0x1f 293 #define ASN_FORM_BITS 0x20 294 #define ASN_FORM_SHIFT 5 295 #define ASN_CLASS_BITS 0xc0 296 #define ASN_CLASS_SHIFT 6 297 298 #define ASN_ID_EXT 0x1f /* extension ID in tag field */ 299 300 /* 301 * truncated==1 means the packet was complete, but we don't have all of 302 * it to decode. 303 */ 304 static int truncated; 305 #define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else 306 307 /* 308 * This decodes the next ASN.1 object in the stream pointed to by "p" 309 * (and of real-length "len") and stores the intermediate data in the 310 * provided BE object. 311 * 312 * This returns -l if it fails (i.e., the ASN.1 stream is not valid). 313 * O/w, this returns the number of bytes parsed from "p". 314 */ 315 static int 316 asn1_parse(register const u_char *p, u_int len, struct be *elem) 317 { 318 u_char form, class, id; 319 int i, hdr; 320 321 elem->asnlen = 0; 322 elem->type = BE_ANY; 323 if (len < 1) { 324 ifNotTruncated puts("[nothing to parse], stdout"); 325 return -1; 326 } 327 328 /* 329 * it would be nice to use a bit field, but you can't depend on them. 330 * +---+---+---+---+---+---+---+---+ 331 * + class |frm| id | 332 * +---+---+---+---+---+---+---+---+ 333 * 7 6 5 4 3 2 1 0 334 */ 335 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */ 336 #ifdef notdef 337 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */ 338 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */ 339 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */ 340 #else 341 form = (*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT; 342 class = (*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT; 343 #endif 344 elem->form = form; 345 elem->class = class; 346 elem->id = id; 347 if (vflag) 348 printf("|%.2x", *p); 349 p++; len--; hdr = 1; 350 /* extended tag field */ 351 if (id == ASN_ID_EXT) { 352 for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) { 353 if (vflag) 354 printf("|%.2x", *p); 355 id = (id << 7) | (*p & ~ASN_BIT8); 356 } 357 if (len == 0 && *p & ASN_BIT8) { 358 ifNotTruncated fputs("[Xtagfield?]", stdout); 359 return -1; 360 } 361 elem->id = id = (id << 7) | *p; 362 --len; 363 ++hdr; 364 ++p; 365 } 366 if (len < 1) { 367 ifNotTruncated fputs("[no asnlen]", stdout); 368 return -1; 369 } 370 elem->asnlen = *p; 371 if (vflag) 372 printf("|%.2x", *p); 373 p++; len--; hdr++; 374 if (elem->asnlen & ASN_BIT8) { 375 int noct = elem->asnlen % ASN_BIT8; 376 elem->asnlen = 0; 377 if (len < noct) { 378 ifNotTruncated printf("[asnlen? %d<%d]", len, noct); 379 return -1; 380 } 381 for (; noct-- > 0; len--, hdr++) { 382 if (vflag) 383 printf("|%.2x", *p); 384 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++; 385 } 386 } 387 if (len < elem->asnlen) { 388 if (!truncated) { 389 printf("[len%d<asnlen%u]", len, elem->asnlen); 390 return -1; 391 } 392 /* maybe should check at least 4? */ 393 elem->asnlen = len; 394 } 395 if (form >= sizeof(Form)/sizeof(Form[0])) { 396 ifNotTruncated printf("[form?%d]", form); 397 return -1; 398 } 399 if (class >= sizeof(Class)/sizeof(Class[0])) { 400 ifNotTruncated printf("[class?%c/%d]", *Form[form], class); 401 return -1; 402 } 403 if (id >= Class[class].numIDs) { 404 ifNotTruncated printf("[id?%c/%s/%d]", *Form[form], 405 Class[class].name, id); 406 return -1; 407 } 408 409 switch (form) { 410 case PRIMITIVE: 411 switch (class) { 412 case UNIVERSAL: 413 switch (id) { 414 case STRING: 415 elem->type = BE_STR; 416 elem->data.str = p; 417 break; 418 419 case INTEGER: { 420 register int32_t data; 421 elem->type = BE_INT; 422 data = 0; 423 424 if (*p & ASN_BIT8) /* negative */ 425 data = -1; 426 for (i = elem->asnlen; i-- > 0; p++) 427 data = (data << ASN_SHIFT8) | *p; 428 elem->data.integer = data; 429 break; 430 } 431 432 case OBJECTID: 433 elem->type = BE_OID; 434 elem->data.raw = (caddr_t)p; 435 break; 436 437 case ASN_NULL: 438 elem->type = BE_NULL; 439 elem->data.raw = NULL; 440 break; 441 442 default: 443 elem->type = BE_OCTET; 444 elem->data.raw = (caddr_t)p; 445 printf("[P/U/%s]", 446 Class[class].Id[id]); 447 break; 448 } 449 break; 450 451 case APPLICATION: 452 switch (id) { 453 case IPADDR: 454 elem->type = BE_INETADDR; 455 elem->data.raw = (caddr_t)p; 456 break; 457 458 case COUNTER: 459 case GAUGE: 460 case TIMETICKS: { 461 register u_int32_t data; 462 elem->type = BE_UNS; 463 data = 0; 464 for (i = elem->asnlen; i-- > 0; p++) 465 data = (data << 8) + *p; 466 elem->data.uns = data; 467 break; 468 } 469 470 default: 471 elem->type = BE_OCTET; 472 elem->data.raw = (caddr_t)p; 473 printf("[P/A/%s]", 474 Class[class].Id[id]); 475 break; 476 } 477 break; 478 479 default: 480 elem->type = BE_OCTET; 481 elem->data.raw = (caddr_t)p; 482 printf("[P/%s/%s]", 483 Class[class].name, Class[class].Id[id]); 484 break; 485 } 486 break; 487 488 case CONSTRUCTED: 489 switch (class) { 490 case UNIVERSAL: 491 switch (id) { 492 case SEQUENCE: 493 elem->type = BE_SEQ; 494 elem->data.raw = (caddr_t)p; 495 break; 496 497 default: 498 elem->type = BE_OCTET; 499 elem->data.raw = (caddr_t)p; 500 printf("C/U/%s", Class[class].Id[id]); 501 break; 502 } 503 break; 504 505 case CONTEXT: 506 elem->type = BE_PDU; 507 elem->data.raw = (caddr_t)p; 508 break; 509 510 default: 511 elem->type = BE_OCTET; 512 elem->data.raw = (caddr_t)p; 513 printf("C/%s/%s", 514 Class[class].name, Class[class].Id[id]); 515 break; 516 } 517 break; 518 } 519 p += elem->asnlen; 520 len -= elem->asnlen; 521 return elem->asnlen + hdr; 522 } 523 524 /* 525 * Display the ASN.1 object represented by the BE object. 526 * This used to be an integral part of asn1_parse() before the intermediate 527 * BE form was added. 528 */ 529 static void 530 asn1_print(struct be *elem) 531 { 532 u_char *p = (u_char *)elem->data.raw; 533 u_int32_t asnlen = elem->asnlen; 534 int i; 535 536 switch (elem->type) { 537 538 case BE_OCTET: 539 for (i = asnlen; i-- > 0; p++); 540 printf("_%.2x", *p); 541 break; 542 543 case BE_NULL: 544 break; 545 546 case BE_OID: { 547 int o = 0, first = -1, i = asnlen; 548 549 if (!nflag && asnlen > 2) { 550 struct obj_abrev *a = &obj_abrev_list[0]; 551 for (; a->node; a++) { 552 if (!memcmp(a->oid, (char *)p, 553 strlen(a->oid))) { 554 objp = a->node->child; 555 i -= strlen(a->oid); 556 p += strlen(a->oid); 557 fputs(a->prefix, stdout); 558 first = 1; 559 break; 560 } 561 } 562 } 563 for (; i-- > 0; p++) { 564 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8); 565 if (*p & ASN_LONGLEN) 566 continue; 567 568 /* 569 * first subitem encodes two items with 1st*OIDMUX+2nd 570 */ 571 if (first < 0) { 572 if (!nflag) 573 objp = mibroot; 574 first = 0; 575 OBJ_PRINT(o/OIDMUX, first); 576 o %= OIDMUX; 577 } 578 OBJ_PRINT(o, first); 579 if (--first < 0) 580 first = 0; 581 o = 0; 582 } 583 break; 584 } 585 586 case BE_INT: 587 printf("%d", elem->data.integer); 588 break; 589 590 case BE_UNS: 591 printf("%d", elem->data.uns); 592 break; 593 594 case BE_STR: { 595 register int printable = 1, first = 1; 596 const u_char *p = elem->data.str; 597 for (i = asnlen; printable && i-- > 0; p++) 598 printable = isprint(*p) || isspace(*p); 599 p = elem->data.str; 600 if (printable) { 601 putchar('"'); 602 (void)fn_print(p, p + asnlen); 603 putchar('"'); 604 } else 605 for (i = asnlen; i-- > 0; p++) { 606 printf(first ? "%.2x" : "_%.2x", *p); 607 first = 0; 608 } 609 break; 610 } 611 612 case BE_SEQ: 613 printf("Seq(%u)", elem->asnlen); 614 break; 615 616 case BE_INETADDR: { 617 char sep; 618 if (asnlen != ASNLEN_INETADDR) 619 printf("[inetaddr len!=%d]", ASNLEN_INETADDR); 620 sep='['; 621 for (i = asnlen; i-- > 0; p++) { 622 printf("%c%u", sep, *p); 623 sep='.'; 624 } 625 putchar(']'); 626 break; 627 } 628 629 case BE_PDU: 630 printf("%s(%u)", 631 Class[CONTEXT].Id[elem->id], elem->asnlen); 632 break; 633 634 case BE_ANY: 635 fputs("[BE_ANY!?]", stdout); 636 break; 637 638 default: 639 fputs("[be!?]", stdout); 640 break; 641 } 642 } 643 644 #ifdef notdef 645 /* 646 * This is a brute force ASN.1 printer: recurses to dump an entire structure. 647 * This will work for any ASN.1 stream, not just an SNMP PDU. 648 * 649 * By adding newlines and spaces at the correct places, this would print in 650 * Rose-Normal-Form. 651 * 652 * This is not currently used. 653 */ 654 static void 655 asn1_decode(u_char *p, u_int length) 656 { 657 struct be elem; 658 int i = 0; 659 660 while (i >= 0 && length > 0) { 661 i = asn1_parse(p, length, &elem); 662 if (i >= 0) { 663 fputs(" ", stdout); 664 asn1_print(&elem); 665 if (elem.type == BE_SEQ || elem.type == BE_PDU) { 666 fputs(" {", stdout); 667 asn1_decode(elem.data.raw, elem.asnlen); 668 fputs(" }", stdout); 669 } 670 length -= i; 671 p += i; 672 } 673 } 674 } 675 #endif 676 677 /* 678 * General SNMP header 679 * SEQUENCE { 680 * version INTEGER {version-1(0)}, 681 * community OCTET STRING, 682 * data ANY -- PDUs 683 * } 684 * PDUs for all but Trap: (see rfc1157 from page 15 on) 685 * SEQUENCE { 686 * request-id INTEGER, 687 * error-status INTEGER, 688 * error-index INTEGER, 689 * varbindlist SEQUENCE OF 690 * SEQUENCE { 691 * name ObjectName, 692 * value ObjectValue 693 * } 694 * } 695 * PDU for Trap: 696 * SEQUENCE { 697 * enterprise OBJECT IDENTIFIER, 698 * agent-addr NetworkAddress, 699 * generic-trap INTEGER, 700 * specific-trap INTEGER, 701 * time-stamp TimeTicks, 702 * varbindlist SEQUENCE OF 703 * SEQUENCE { 704 * name ObjectName, 705 * value ObjectValue 706 * } 707 * } 708 */ 709 710 /* 711 * Decode SNMP varBind 712 */ 713 static void 714 varbind_print(u_char pduid, const u_char *np, u_int length, int error) 715 { 716 struct be elem; 717 int count = 0, ind; 718 719 /* Sequence of varBind */ 720 if ((count = asn1_parse(np, length, &elem)) < 0) 721 return; 722 if (elem.type != BE_SEQ) { 723 fputs("[!SEQ of varbind]", stdout); 724 asn1_print(&elem); 725 return; 726 } 727 if (count < length) 728 printf("[%d extra after SEQ of varbind]", length - count); 729 /* descend */ 730 length = elem.asnlen; 731 np = (u_char *)elem.data.raw; 732 733 for (ind = 1; length > 0; ind++) { 734 const u_char *vbend; 735 u_int vblength; 736 737 if (!error || ind == error) 738 fputs(" ", stdout); 739 740 /* Sequence */ 741 if ((count = asn1_parse(np, length, &elem)) < 0) 742 return; 743 if (elem.type != BE_SEQ) { 744 fputs("[!varbind]", stdout); 745 asn1_print(&elem); 746 return; 747 } 748 vbend = np + count; 749 vblength = length - count; 750 /* descend */ 751 length = elem.asnlen; 752 np = (u_char *)elem.data.raw; 753 754 /* objName (OID) */ 755 if ((count = asn1_parse(np, length, &elem)) < 0) 756 return; 757 if (elem.type != BE_OID) { 758 fputs("[objName!=OID]", stdout); 759 asn1_print(&elem); 760 return; 761 } 762 if (!error || ind == error) 763 asn1_print(&elem); 764 length -= count; 765 np += count; 766 767 if (pduid != GETREQ && pduid != GETNEXTREQ && !error) 768 fputs("=", stdout); 769 770 /* objVal (ANY) */ 771 if ((count = asn1_parse(np, length, &elem)) < 0) 772 return; 773 if (pduid == GETREQ || pduid == GETNEXTREQ) { 774 if (elem.type != BE_NULL) { 775 fputs("[objVal!=NULL]", stdout); 776 asn1_print(&elem); 777 } 778 } else 779 if (error && ind == error && elem.type != BE_NULL) 780 fputs("[err objVal!=NULL]", stdout); 781 if (!error || ind == error) 782 asn1_print(&elem); 783 784 length = vblength; 785 np = vbend; 786 } 787 } 788 789 /* 790 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, and SetRequest 791 */ 792 static void 793 snmppdu_print(u_char pduid, const u_char *np, u_int length) 794 { 795 struct be elem; 796 int count = 0, error; 797 798 /* reqId (Integer) */ 799 if ((count = asn1_parse(np, length, &elem)) < 0) 800 return; 801 if (elem.type != BE_INT) { 802 fputs("[reqId!=INT]", stdout); 803 asn1_print(&elem); 804 return; 805 } 806 /* ignore the reqId */ 807 length -= count; 808 np += count; 809 810 /* errorStatus (Integer) */ 811 if ((count = asn1_parse(np, length, &elem)) < 0) 812 return; 813 if (elem.type != BE_INT) { 814 fputs("[errorStatus!=INT]", stdout); 815 asn1_print(&elem); 816 return; 817 } 818 error = 0; 819 if ((pduid == GETREQ || pduid == GETNEXTREQ) 820 && elem.data.integer != 0) { 821 char errbuf[10]; 822 printf("[errorStatus(%s)!=0]", 823 DECODE_ErrorStatus(elem.data.integer)); 824 } else if (elem.data.integer != 0) { 825 char errbuf[10]; 826 printf(" %s", DECODE_ErrorStatus(elem.data.integer)); 827 error = elem.data.integer; 828 } 829 length -= count; 830 np += count; 831 832 /* errorIndex (Integer) */ 833 if ((count = asn1_parse(np, length, &elem)) < 0) 834 return; 835 if (elem.type != BE_INT) { 836 fputs("[errorIndex!=INT]", stdout); 837 asn1_print(&elem); 838 return; 839 } 840 if ((pduid == GETREQ || pduid == GETNEXTREQ) 841 && elem.data.integer != 0) 842 printf("[errorIndex(%d)!=0]", elem.data.integer); 843 else if (elem.data.integer != 0) { 844 if (!error) 845 printf("[errorIndex(%d) w/o errorStatus]", 846 elem.data.integer); 847 else { 848 printf("@%d", elem.data.integer); 849 error = elem.data.integer; 850 } 851 } else if (error) { 852 fputs("[errorIndex==0]", stdout); 853 error = 0; 854 } 855 length -= count; 856 np += count; 857 858 varbind_print(pduid, np, length, error); 859 return; 860 } 861 862 /* 863 * Decode SNMP Trap PDU 864 */ 865 static void 866 trap_print(const u_char *np, u_int length) 867 { 868 struct be elem; 869 int count = 0, generic; 870 871 putchar(' '); 872 873 /* enterprise (oid) */ 874 if ((count = asn1_parse(np, length, &elem)) < 0) 875 return; 876 if (elem.type != BE_OID) { 877 fputs("[enterprise!=OID]", stdout); 878 asn1_print(&elem); 879 return; 880 } 881 asn1_print(&elem); 882 length -= count; 883 np += count; 884 885 putchar(' '); 886 887 /* agent-addr (inetaddr) */ 888 if ((count = asn1_parse(np, length, &elem)) < 0) 889 return; 890 if (elem.type != BE_INETADDR) { 891 fputs("[agent-addr!=INETADDR]", stdout); 892 asn1_print(&elem); 893 return; 894 } 895 asn1_print(&elem); 896 length -= count; 897 np += count; 898 899 /* generic-trap (Integer) */ 900 if ((count = asn1_parse(np, length, &elem)) < 0) 901 return; 902 if (elem.type != BE_INT) { 903 fputs("[generic-trap!=INT]", stdout); 904 asn1_print(&elem); 905 return; 906 } 907 generic = elem.data.integer; 908 { 909 char buf[10]; 910 printf(" %s", DECODE_GenericTrap(generic)); 911 } 912 length -= count; 913 np += count; 914 915 /* specific-trap (Integer) */ 916 if ((count = asn1_parse(np, length, &elem)) < 0) 917 return; 918 if (elem.type != BE_INT) { 919 fputs("[specific-trap!=INT]", stdout); 920 asn1_print(&elem); 921 return; 922 } 923 if (generic != GT_ENTERPRISE) { 924 if (elem.data.integer != 0) 925 printf("[specific-trap(%d)!=0]", elem.data.integer); 926 } else 927 printf(" s=%d", elem.data.integer); 928 length -= count; 929 np += count; 930 931 putchar(' '); 932 933 /* time-stamp (TimeTicks) */ 934 if ((count = asn1_parse(np, length, &elem)) < 0) 935 return; 936 if (elem.type != BE_UNS) { /* XXX */ 937 fputs("[time-stamp!=TIMETICKS]", stdout); 938 asn1_print(&elem); 939 return; 940 } 941 asn1_print(&elem); 942 length -= count; 943 np += count; 944 945 varbind_print (TRAP, np, length, 0); 946 return; 947 } 948 949 /* 950 * Decode SNMP header and pass on to PDU printing routines 951 */ 952 void 953 snmp_print(const u_char *np, u_int length) 954 { 955 struct be elem, pdu; 956 int count = 0; 957 958 truncated = 0; 959 960 /* truncated packet? */ 961 if (np + length > snapend) { 962 truncated = 1; 963 length = snapend - np; 964 } 965 966 putchar(' '); 967 968 /* initial Sequence */ 969 if ((count = asn1_parse(np, length, &elem)) < 0) 970 return; 971 if (elem.type != BE_SEQ) { 972 fputs("[!init SEQ]", stdout); 973 asn1_print(&elem); 974 return; 975 } 976 if (count < length) 977 printf("[%d extra after iSEQ]", length - count); 978 /* descend */ 979 length = elem.asnlen; 980 np = (u_char *)elem.data.raw; 981 /* Version (Integer) */ 982 if ((count = asn1_parse(np, length, &elem)) < 0) 983 return; 984 if (elem.type != BE_INT) { 985 fputs("[version!=INT]", stdout); 986 asn1_print(&elem); 987 return; 988 } 989 /* only handle version==0 */ 990 if (elem.data.integer != DEF_VERSION) { 991 printf("[version(%d)!=0]", elem.data.integer); 992 return; 993 } 994 length -= count; 995 np += count; 996 997 /* Community (String) */ 998 if ((count = asn1_parse(np, length, &elem)) < 0) 999 return; 1000 if (elem.type != BE_STR) { 1001 fputs("[comm!=STR]", stdout); 1002 asn1_print(&elem); 1003 return; 1004 } 1005 /* default community */ 1006 if (strncmp((char *)elem.data.str, DEF_COMMUNITY, 1007 sizeof(DEF_COMMUNITY) - 1)) 1008 /* ! "public" */ 1009 printf("C=%.*s ", (int)elem.asnlen, elem.data.str); 1010 length -= count; 1011 np += count; 1012 1013 /* PDU (Context) */ 1014 if ((count = asn1_parse(np, length, &pdu)) < 0) 1015 return; 1016 if (pdu.type != BE_PDU) { 1017 fputs("[no PDU]", stdout); 1018 return; 1019 } 1020 if (count < length) 1021 printf("[%d extra after PDU]", length - count); 1022 asn1_print(&pdu); 1023 /* descend into PDU */ 1024 length = pdu.asnlen; 1025 np = (u_char *)pdu.data.raw; 1026 1027 switch (pdu.id) { 1028 case TRAP: 1029 trap_print(np, length); 1030 break; 1031 case GETREQ: 1032 case GETNEXTREQ: 1033 case GETRESP: 1034 case SETREQ: 1035 snmppdu_print(pdu.id, np, length); 1036 break; 1037 } 1038 return; 1039 } 1040