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