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