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