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