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