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