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