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