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