1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939 |
- /*
- * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
- * John Robert LoVerso. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * This implementation has been influenced by the CMU SNMP release,
- * by Steve Waldbusser. However, this shares no code with that system.
- * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
- * Earlier forms of this implementation were derived and/or inspired by an
- * awk script originally written by C. Philip Wood of LANL (but later
- * heavily modified by John Robert LoVerso). The copyright notice for
- * that work is preserved below, even though it may not rightly apply
- * to this file.
- *
- * Support for SNMPv2c/SNMPv3 and the ability to link the module against
- * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
- *
- * This started out as a very simple program, but the incremental decoding
- * (into the BE structure) complicated things.
- *
- # Los Alamos National Laboratory
- #
- # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
- # This software was produced under a U.S. Government contract
- # (W-7405-ENG-36) by Los Alamos National Laboratory, which is
- # operated by the University of California for the U.S. Department
- # of Energy. The U.S. Government is licensed to use, reproduce,
- # and distribute this software. Permission is granted to the
- # public to copy and use this software without charge, provided
- # that this Notice and any statement of authorship are reproduced
- # on all copies. Neither the Government nor the University makes
- # any warranty, express or implied, or assumes any liability or
- # responsibility for the use of this software.
- # @(#)snmp.awk.x 1.1 (LANL) 1/15/90
- */
- /* \summary: Simple Network Management Protocol (SNMP) printer */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include <netdissect-stdinc.h>
- #include <stdio.h>
- #include <string.h>
- #ifdef USE_LIBSMI
- #include <smi.h>
- #endif
- #include "netdissect.h"
- #undef OPAQUE /* defined in <wingdi.h> */
- static const char tstr[] = "[|snmp]";
- /*
- * Universal ASN.1 types
- * (we only care about the tag values for those allowed in the Internet SMI)
- */
- static const char *Universal[] = {
- "U-0",
- "Boolean",
- "Integer",
- #define INTEGER 2
- "Bitstring",
- "String",
- #define STRING 4
- "Null",
- #define ASN_NULL 5
- "ObjID",
- #define OBJECTID 6
- "ObjectDes",
- "U-8","U-9","U-10","U-11", /* 8-11 */
- "U-12","U-13","U-14","U-15", /* 12-15 */
- "Sequence",
- #define SEQUENCE 16
- "Set"
- };
- /*
- * Application-wide ASN.1 types from the Internet SMI and their tags
- */
- static const char *Application[] = {
- "IpAddress",
- #define IPADDR 0
- "Counter",
- #define COUNTER 1
- "Gauge",
- #define GAUGE 2
- "TimeTicks",
- #define TIMETICKS 3
- "Opaque",
- #define OPAQUE 4
- "C-5",
- "Counter64"
- #define COUNTER64 6
- };
- /*
- * Context-specific ASN.1 types for the SNMP PDUs and their tags
- */
- static const char *Context[] = {
- "GetRequest",
- #define GETREQ 0
- "GetNextRequest",
- #define GETNEXTREQ 1
- "GetResponse",
- #define GETRESP 2
- "SetRequest",
- #define SETREQ 3
- "Trap",
- #define TRAP 4
- "GetBulk",
- #define GETBULKREQ 5
- "Inform",
- #define INFORMREQ 6
- "V2Trap",
- #define V2TRAP 7
- "Report"
- #define REPORT 8
- };
- #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
- #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
- #define WRITE_CLASS(x) (x == SETREQ)
- #define RESPONSE_CLASS(x) (x == GETRESP)
- #define INTERNAL_CLASS(x) (x == REPORT)
- /*
- * Context-specific ASN.1 types for the SNMP Exceptions and their tags
- */
- static const char *Exceptions[] = {
- "noSuchObject",
- #define NOSUCHOBJECT 0
- "noSuchInstance",
- #define NOSUCHINSTANCE 1
- "endOfMibView",
- #define ENDOFMIBVIEW 2
- };
- /*
- * Private ASN.1 types
- * The Internet SMI does not specify any
- */
- static const char *Private[] = {
- "P-0"
- };
- /*
- * error-status values for any SNMP PDU
- */
- static const char *ErrorStatus[] = {
- "noError",
- "tooBig",
- "noSuchName",
- "badValue",
- "readOnly",
- "genErr",
- "noAccess",
- "wrongType",
- "wrongLength",
- "wrongEncoding",
- "wrongValue",
- "noCreation",
- "inconsistentValue",
- "resourceUnavailable",
- "commitFailed",
- "undoFailed",
- "authorizationError",
- "notWritable",
- "inconsistentName"
- };
- #define DECODE_ErrorStatus(e) \
- ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
- ? ErrorStatus[e] \
- : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
- /*
- * generic-trap values in the SNMP Trap-PDU
- */
- static const char *GenericTrap[] = {
- "coldStart",
- "warmStart",
- "linkDown",
- "linkUp",
- "authenticationFailure",
- "egpNeighborLoss",
- "enterpriseSpecific"
- #define GT_ENTERPRISE 6
- };
- #define DECODE_GenericTrap(t) \
- ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
- ? GenericTrap[t] \
- : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
- /*
- * ASN.1 type class table
- * Ties together the preceding Universal, Application, Context, and Private
- * type definitions.
- */
- #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
- static const struct {
- const char *name;
- const char **Id;
- int numIDs;
- } Class[] = {
- defineCLASS(Universal),
- #define UNIVERSAL 0
- defineCLASS(Application),
- #define APPLICATION 1
- defineCLASS(Context),
- #define CONTEXT 2
- defineCLASS(Private),
- #define PRIVATE 3
- defineCLASS(Exceptions),
- #define EXCEPTIONS 4
- };
- /*
- * defined forms for ASN.1 types
- */
- static const char *Form[] = {
- "Primitive",
- #define PRIMITIVE 0
- "Constructed",
- #define CONSTRUCTED 1
- };
- /*
- * A structure for the OID tree for the compiled-in MIB.
- * This is stored as a general-order tree.
- */
- static struct obj {
- const char *desc; /* name of object */
- u_char oid; /* sub-id following parent */
- u_char type; /* object type (unused) */
- struct obj *child, *next; /* child and next sibling pointers */
- } *objp = NULL;
- /*
- * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
- * RFC-1156 format files into "makemib". "mib.h" MUST define at least
- * a value for `mibroot'.
- *
- * In particular, this is gross, as this is including initialized structures,
- * and by right shouldn't be an "include" file.
- */
- #include "mib.h"
- /*
- * This defines a list of OIDs which will be abbreviated on output.
- * Currently, this includes the prefixes for the Internet MIB, the
- * private enterprises tree, and the experimental tree.
- */
- #define OID_FIRST_OCTET(x, y) (((x)*40) + (y)) /* X.690 8.19.4 */
- #ifndef NO_ABREV_MIB
- static const uint8_t mib_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 2, 1 };
- #endif
- #ifndef NO_ABREV_ENTER
- static const uint8_t enterprises_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 4, 1 };
- #endif
- #ifndef NO_ABREV_EXPERI
- static const uint8_t experimental_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 3 };
- #endif
- #ifndef NO_ABBREV_SNMPMODS
- static const uint8_t snmpModules_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 6, 3 };
- #endif
- #define OBJ_ABBREV_ENTRY(prefix, obj) \
- { prefix, &_ ## obj ## _obj, obj ## _oid, sizeof (obj ## _oid) }
- static const struct obj_abrev {
- const char *prefix; /* prefix for this abrev */
- struct obj *node; /* pointer into object table */
- const uint8_t *oid; /* ASN.1 encoded OID */
- size_t oid_len; /* length of OID */
- } obj_abrev_list[] = {
- #ifndef NO_ABREV_MIB
- /* .iso.org.dod.internet.mgmt.mib */
- OBJ_ABBREV_ENTRY("", mib),
- #endif
- #ifndef NO_ABREV_ENTER
- /* .iso.org.dod.internet.private.enterprises */
- OBJ_ABBREV_ENTRY("E:", enterprises),
- #endif
- #ifndef NO_ABREV_EXPERI
- /* .iso.org.dod.internet.experimental */
- OBJ_ABBREV_ENTRY("X:", experimental),
- #endif
- #ifndef NO_ABBREV_SNMPMODS
- /* .iso.org.dod.internet.snmpV2.snmpModules */
- OBJ_ABBREV_ENTRY("S:", snmpModules),
- #endif
- { 0,0,0,0 }
- };
- /*
- * This is used in the OID print routine to walk down the object tree
- * rooted at `mibroot'.
- */
- #define OBJ_PRINT(o, suppressdot) \
- { \
- if (objp) { \
- do { \
- if ((o) == objp->oid) \
- break; \
- } while ((objp = objp->next) != NULL); \
- } \
- if (objp) { \
- ND_PRINT((ndo, suppressdot?"%s":".%s", objp->desc)); \
- objp = objp->child; \
- } else \
- ND_PRINT((ndo, suppressdot?"%u":".%u", (o))); \
- }
- /*
- * This is the definition for the Any-Data-Type storage used purely for
- * temporary internal representation while decoding an ASN.1 data stream.
- */
- struct be {
- uint32_t asnlen;
- union {
- const uint8_t *raw;
- int32_t integer;
- uint32_t uns;
- const u_char *str;
- uint64_t uns64;
- } data;
- u_short id;
- u_char form, class; /* tag info */
- u_char type;
- #define BE_ANY 255
- #define BE_NONE 0
- #define BE_NULL 1
- #define BE_OCTET 2
- #define BE_OID 3
- #define BE_INT 4
- #define BE_UNS 5
- #define BE_STR 6
- #define BE_SEQ 7
- #define BE_INETADDR 8
- #define BE_PDU 9
- #define BE_UNS64 10
- #define BE_NOSUCHOBJECT 128
- #define BE_NOSUCHINST 129
- #define BE_ENDOFMIBVIEW 130
- };
- /*
- * SNMP versions recognized by this module
- */
- static const char *SnmpVersion[] = {
- "SNMPv1",
- #define SNMP_VERSION_1 0
- "SNMPv2c",
- #define SNMP_VERSION_2 1
- "SNMPv2u",
- #define SNMP_VERSION_2U 2
- "SNMPv3"
- #define SNMP_VERSION_3 3
- };
- /*
- * Defaults for SNMP PDU components
- */
- #define DEF_COMMUNITY "public"
- /*
- * constants for ASN.1 decoding
- */
- #define OIDMUX 40
- #define ASNLEN_INETADDR 4
- #define ASN_SHIFT7 7
- #define ASN_SHIFT8 8
- #define ASN_BIT8 0x80
- #define ASN_LONGLEN 0x80
- #define ASN_ID_BITS 0x1f
- #define ASN_FORM_BITS 0x20
- #define ASN_FORM_SHIFT 5
- #define ASN_CLASS_BITS 0xc0
- #define ASN_CLASS_SHIFT 6
- #define ASN_ID_EXT 0x1f /* extension ID in tag field */
- /*
- * This decodes the next ASN.1 object in the stream pointed to by "p"
- * (and of real-length "len") and stores the intermediate data in the
- * provided BE object.
- *
- * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
- * O/w, this returns the number of bytes parsed from "p".
- */
- static int
- asn1_parse(netdissect_options *ndo,
- register const u_char *p, u_int len, struct be *elem)
- {
- u_char form, class, id;
- int i, hdr;
- elem->asnlen = 0;
- elem->type = BE_ANY;
- if (len < 1) {
- ND_PRINT((ndo, "[nothing to parse]"));
- return -1;
- }
- ND_TCHECK(*p);
- /*
- * it would be nice to use a bit field, but you can't depend on them.
- * +---+---+---+---+---+---+---+---+
- * + class |frm| id |
- * +---+---+---+---+---+---+---+---+
- * 7 6 5 4 3 2 1 0
- */
- id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
- #ifdef notdef
- form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
- class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
- form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
- #else
- form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
- class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
- #endif
- elem->form = form;
- elem->class = class;
- elem->id = id;
- p++; len--; hdr = 1;
- /* extended tag field */
- if (id == ASN_ID_EXT) {
- /*
- * The ID follows, as a sequence of octets with the
- * 8th bit set and the remaining 7 bits being
- * the next 7 bits of the value, terminated with
- * an octet with the 8th bit not set.
- *
- * First, assemble all the octets with the 8th
- * bit set. XXX - this doesn't handle a value
- * that won't fit in 32 bits.
- */
- id = 0;
- ND_TCHECK(*p);
- while (*p & ASN_BIT8) {
- if (len < 1) {
- ND_PRINT((ndo, "[Xtagfield?]"));
- return -1;
- }
- id = (id << 7) | (*p & ~ASN_BIT8);
- len--;
- hdr++;
- p++;
- ND_TCHECK(*p);
- }
- if (len < 1) {
- ND_PRINT((ndo, "[Xtagfield?]"));
- return -1;
- }
- ND_TCHECK(*p);
- elem->id = id = (id << 7) | *p;
- --len;
- ++hdr;
- ++p;
- }
- if (len < 1) {
- ND_PRINT((ndo, "[no asnlen]"));
- return -1;
- }
- ND_TCHECK(*p);
- elem->asnlen = *p;
- p++; len--; hdr++;
- if (elem->asnlen & ASN_BIT8) {
- uint32_t noct = elem->asnlen % ASN_BIT8;
- elem->asnlen = 0;
- if (len < noct) {
- ND_PRINT((ndo, "[asnlen? %d<%d]", len, noct));
- return -1;
- }
- ND_TCHECK2(*p, noct);
- for (; noct-- > 0; len--, hdr++)
- elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
- }
- if (len < elem->asnlen) {
- ND_PRINT((ndo, "[len%d<asnlen%u]", len, elem->asnlen));
- return -1;
- }
- if (form >= sizeof(Form)/sizeof(Form[0])) {
- ND_PRINT((ndo, "[form?%d]", form));
- return -1;
- }
- if (class >= sizeof(Class)/sizeof(Class[0])) {
- ND_PRINT((ndo, "[class?%c/%d]", *Form[form], class));
- return -1;
- }
- if ((int)id >= Class[class].numIDs) {
- ND_PRINT((ndo, "[id?%c/%s/%d]", *Form[form], Class[class].name, id));
- return -1;
- }
- ND_TCHECK2(*p, elem->asnlen);
- switch (form) {
- case PRIMITIVE:
- switch (class) {
- case UNIVERSAL:
- switch (id) {
- case STRING:
- elem->type = BE_STR;
- elem->data.str = p;
- break;
- case INTEGER: {
- register int32_t data;
- elem->type = BE_INT;
- data = 0;
- if (elem->asnlen == 0) {
- ND_PRINT((ndo, "[asnlen=0]"));
- return -1;
- }
- if (*p & ASN_BIT8) /* negative */
- data = -1;
- for (i = elem->asnlen; i-- > 0; p++)
- data = (data << ASN_SHIFT8) | *p;
- elem->data.integer = data;
- break;
- }
- case OBJECTID:
- elem->type = BE_OID;
- elem->data.raw = (const uint8_t *)p;
- break;
- case ASN_NULL:
- elem->type = BE_NULL;
- elem->data.raw = NULL;
- break;
- default:
- elem->type = BE_OCTET;
- elem->data.raw = (const uint8_t *)p;
- ND_PRINT((ndo, "[P/U/%s]", Class[class].Id[id]));
- break;
- }
- break;
- case APPLICATION:
- switch (id) {
- case IPADDR:
- elem->type = BE_INETADDR;
- elem->data.raw = (const uint8_t *)p;
- break;
- case COUNTER:
- case GAUGE:
- case TIMETICKS: {
- register uint32_t data;
- elem->type = BE_UNS;
- data = 0;
- for (i = elem->asnlen; i-- > 0; p++)
- data = (data << 8) + *p;
- elem->data.uns = data;
- break;
- }
- case COUNTER64: {
- register uint64_t data64;
- elem->type = BE_UNS64;
- data64 = 0;
- for (i = elem->asnlen; i-- > 0; p++)
- data64 = (data64 << 8) + *p;
- elem->data.uns64 = data64;
- break;
- }
- default:
- elem->type = BE_OCTET;
- elem->data.raw = (const uint8_t *)p;
- ND_PRINT((ndo, "[P/A/%s]",
- Class[class].Id[id]));
- break;
- }
- break;
- case CONTEXT:
- switch (id) {
- case NOSUCHOBJECT:
- elem->type = BE_NOSUCHOBJECT;
- elem->data.raw = NULL;
- break;
- case NOSUCHINSTANCE:
- elem->type = BE_NOSUCHINST;
- elem->data.raw = NULL;
- break;
- case ENDOFMIBVIEW:
- elem->type = BE_ENDOFMIBVIEW;
- elem->data.raw = NULL;
- break;
- }
- break;
- default:
- ND_PRINT((ndo, "[P/%s/%s]", Class[class].name, Class[class].Id[id]));
- elem->type = BE_OCTET;
- elem->data.raw = (const uint8_t *)p;
- break;
- }
- break;
- case CONSTRUCTED:
- switch (class) {
- case UNIVERSAL:
- switch (id) {
- case SEQUENCE:
- elem->type = BE_SEQ;
- elem->data.raw = (const uint8_t *)p;
- break;
- default:
- elem->type = BE_OCTET;
- elem->data.raw = (const uint8_t *)p;
- ND_PRINT((ndo, "C/U/%s", Class[class].Id[id]));
- break;
- }
- break;
- case CONTEXT:
- elem->type = BE_PDU;
- elem->data.raw = (const uint8_t *)p;
- break;
- default:
- elem->type = BE_OCTET;
- elem->data.raw = (const uint8_t *)p;
- ND_PRINT((ndo, "C/%s/%s", Class[class].name, Class[class].Id[id]));
- break;
- }
- break;
- }
- p += elem->asnlen;
- len -= elem->asnlen;
- return elem->asnlen + hdr;
- trunc:
- ND_PRINT((ndo, "%s", tstr));
- return -1;
- }
- static int
- asn1_print_octets(netdissect_options *ndo, struct be *elem)
- {
- const u_char *p = (const u_char *)elem->data.raw;
- uint32_t asnlen = elem->asnlen;
- uint32_t i;
- ND_TCHECK2(*p, asnlen);
- for (i = asnlen; i-- > 0; p++)
- ND_PRINT((ndo, "_%.2x", *p));
- return 0;
- trunc:
- ND_PRINT((ndo, "%s", tstr));
- return -1;
- }
- static int
- asn1_print_string(netdissect_options *ndo, struct be *elem)
- {
- register int printable = 1, first = 1;
- const u_char *p;
- uint32_t asnlen = elem->asnlen;
- uint32_t i;
- p = elem->data.str;
- ND_TCHECK2(*p, asnlen);
- for (i = asnlen; printable && i-- > 0; p++)
- printable = ND_ISPRINT(*p);
- p = elem->data.str;
- if (printable) {
- ND_PRINT((ndo, "\""));
- if (fn_printn(ndo, p, asnlen, ndo->ndo_snapend)) {
- ND_PRINT((ndo, "\""));
- goto trunc;
- }
- ND_PRINT((ndo, "\""));
- } else {
- for (i = asnlen; i-- > 0; p++) {
- ND_PRINT((ndo, first ? "%.2x" : "_%.2x", *p));
- first = 0;
- }
- }
- return 0;
- trunc:
- ND_PRINT((ndo, "%s", tstr));
- return -1;
- }
- /*
- * Display the ASN.1 object represented by the BE object.
- * This used to be an integral part of asn1_parse() before the intermediate
- * BE form was added.
- */
- static int
- asn1_print(netdissect_options *ndo,
- struct be *elem)
- {
- const u_char *p;
- uint32_t asnlen = elem->asnlen;
- uint32_t i;
- switch (elem->type) {
- case BE_OCTET:
- if (asn1_print_octets(ndo, elem) == -1)
- return -1;
- break;
- case BE_NULL:
- break;
- case BE_OID: {
- int o = 0, first = -1;
- p = (const u_char *)elem->data.raw;
- i = asnlen;
- if (!ndo->ndo_nflag && asnlen > 2) {
- const struct obj_abrev *a = &obj_abrev_list[0];
- for (; a->node; a++) {
- if (i < a->oid_len)
- continue;
- if (!ND_TTEST2(*p, a->oid_len))
- continue;
- if (memcmp(a->oid, p, a->oid_len) == 0) {
- objp = a->node->child;
- i -= a->oid_len;
- p += a->oid_len;
- ND_PRINT((ndo, "%s", a->prefix));
- first = 1;
- break;
- }
- }
- }
- for (; i-- > 0; p++) {
- ND_TCHECK(*p);
- o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
- if (*p & ASN_LONGLEN)
- continue;
- /*
- * first subitem encodes two items with
- * 1st*OIDMUX+2nd
- * (see X.690:1997 clause 8.19 for the details)
- */
- if (first < 0) {
- int s;
- if (!ndo->ndo_nflag)
- objp = mibroot;
- first = 0;
- s = o / OIDMUX;
- if (s > 2) s = 2;
- OBJ_PRINT(s, first);
- o -= s * OIDMUX;
- }
- OBJ_PRINT(o, first);
- if (--first < 0)
- first = 0;
- o = 0;
- }
- break;
- }
- case BE_INT:
- ND_PRINT((ndo, "%d", elem->data.integer));
- break;
- case BE_UNS:
- ND_PRINT((ndo, "%u", elem->data.uns));
- break;
- case BE_UNS64:
- ND_PRINT((ndo, "%" PRIu64, elem->data.uns64));
- break;
- case BE_STR:
- if (asn1_print_string(ndo, elem) == -1)
- return -1;
- break;
- case BE_SEQ:
- ND_PRINT((ndo, "Seq(%u)", elem->asnlen));
- break;
- case BE_INETADDR:
- if (asnlen != ASNLEN_INETADDR)
- ND_PRINT((ndo, "[inetaddr len!=%d]", ASNLEN_INETADDR));
- p = (const u_char *)elem->data.raw;
- ND_TCHECK2(*p, asnlen);
- for (i = asnlen; i-- != 0; p++) {
- ND_PRINT((ndo, (i == asnlen-1) ? "%u" : ".%u", *p));
- }
- break;
- case BE_NOSUCHOBJECT:
- case BE_NOSUCHINST:
- case BE_ENDOFMIBVIEW:
- ND_PRINT((ndo, "[%s]", Class[EXCEPTIONS].Id[elem->id]));
- break;
- case BE_PDU:
- ND_PRINT((ndo, "%s(%u)", Class[CONTEXT].Id[elem->id], elem->asnlen));
- break;
- case BE_ANY:
- ND_PRINT((ndo, "[BE_ANY!?]"));
- break;
- default:
- ND_PRINT((ndo, "[be!?]"));
- break;
- }
- return 0;
- trunc:
- ND_PRINT((ndo, "%s", tstr));
- return -1;
- }
- #ifdef notdef
- /*
- * This is a brute force ASN.1 printer: recurses to dump an entire structure.
- * This will work for any ASN.1 stream, not just an SNMP PDU.
- *
- * By adding newlines and spaces at the correct places, this would print in
- * Rose-Normal-Form.
- *
- * This is not currently used.
- */
- static void
- asn1_decode(u_char *p, u_int length)
- {
- struct be elem;
- int i = 0;
- while (i >= 0 && length > 0) {
- i = asn1_parse(ndo, p, length, &elem);
- if (i >= 0) {
- ND_PRINT((ndo, " "));
- if (asn1_print(ndo, &elem) < 0)
- return;
- if (elem.type == BE_SEQ || elem.type == BE_PDU) {
- ND_PRINT((ndo, " {"));
- asn1_decode(elem.data.raw, elem.asnlen);
- ND_PRINT((ndo, " }"));
- }
- length -= i;
- p += i;
- }
- }
- }
- #endif
- #ifdef USE_LIBSMI
- struct smi2be {
- SmiBasetype basetype;
- int be;
- };
- static const struct smi2be smi2betab[] = {
- { SMI_BASETYPE_INTEGER32, BE_INT },
- { SMI_BASETYPE_OCTETSTRING, BE_STR },
- { SMI_BASETYPE_OCTETSTRING, BE_INETADDR },
- { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID },
- { SMI_BASETYPE_UNSIGNED32, BE_UNS },
- { SMI_BASETYPE_INTEGER64, BE_NONE },
- { SMI_BASETYPE_UNSIGNED64, BE_UNS64 },
- { SMI_BASETYPE_FLOAT32, BE_NONE },
- { SMI_BASETYPE_FLOAT64, BE_NONE },
- { SMI_BASETYPE_FLOAT128, BE_NONE },
- { SMI_BASETYPE_ENUM, BE_INT },
- { SMI_BASETYPE_BITS, BE_STR },
- { SMI_BASETYPE_UNKNOWN, BE_NONE }
- };
- static int
- smi_decode_oid(netdissect_options *ndo,
- struct be *elem, unsigned int *oid,
- unsigned int oidsize, unsigned int *oidlen)
- {
- const u_char *p = (const u_char *)elem->data.raw;
- uint32_t asnlen = elem->asnlen;
- int o = 0, first = -1, i = asnlen;
- unsigned int firstval;
- for (*oidlen = 0; i-- > 0; p++) {
- ND_TCHECK(*p);
- o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
- if (*p & ASN_LONGLEN)
- continue;
- /*
- * first subitem encodes two items with 1st*OIDMUX+2nd
- * (see X.690:1997 clause 8.19 for the details)
- */
- if (first < 0) {
- first = 0;
- firstval = o / OIDMUX;
- if (firstval > 2) firstval = 2;
- o -= firstval * OIDMUX;
- if (*oidlen < oidsize) {
- oid[(*oidlen)++] = firstval;
- }
- }
- if (*oidlen < oidsize) {
- oid[(*oidlen)++] = o;
- }
- o = 0;
- }
- return 0;
- trunc:
- ND_PRINT((ndo, "%s", tstr));
- return -1;
- }
- static int smi_check_type(SmiBasetype basetype, int be)
- {
- int i;
- for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
- if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
- return 1;
- }
- }
- return 0;
- }
- static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
- struct be *elem)
- {
- int ok = 1;
- switch (smiType->basetype) {
- case SMI_BASETYPE_OBJECTIDENTIFIER:
- case SMI_BASETYPE_OCTETSTRING:
- if (smiRange->minValue.value.unsigned32
- == smiRange->maxValue.value.unsigned32) {
- ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
- } else {
- ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
- && elem->asnlen <= smiRange->maxValue.value.unsigned32);
- }
- break;
- case SMI_BASETYPE_INTEGER32:
- ok = (elem->data.integer >= smiRange->minValue.value.integer32
- && elem->data.integer <= smiRange->maxValue.value.integer32);
- break;
- case SMI_BASETYPE_UNSIGNED32:
- ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
- && elem->data.uns <= smiRange->maxValue.value.unsigned32);
- break;
- case SMI_BASETYPE_UNSIGNED64:
- /* XXX */
- break;
- /* case SMI_BASETYPE_INTEGER64: SMIng */
- /* case SMI_BASETYPE_FLOAT32: SMIng */
- /* case SMI_BASETYPE_FLOAT64: SMIng */
- /* case SMI_BASETYPE_FLOAT128: SMIng */
- case SMI_BASETYPE_ENUM:
- case SMI_BASETYPE_BITS:
- case SMI_BASETYPE_UNKNOWN:
- ok = 1;
- break;
- default:
- ok = 0;
- break;
- }
- return ok;
- }
- static int smi_check_range(SmiType *smiType, struct be *elem)
- {
- SmiRange *smiRange;
- int ok = 1;
- for (smiRange = smiGetFirstRange(smiType);
- smiRange;
- smiRange = smiGetNextRange(smiRange)) {
- ok = smi_check_a_range(smiType, smiRange, elem);
- if (ok) {
- break;
- }
- }
- if (ok) {
- SmiType *parentType;
- parentType = smiGetParentType(smiType);
- if (parentType) {
- ok = smi_check_range(parentType, elem);
- }
- }
- return ok;
- }
- static SmiNode *
- smi_print_variable(netdissect_options *ndo,
- struct be *elem, int *status)
- {
- unsigned int oid[128], oidlen;
- SmiNode *smiNode = NULL;
- unsigned int i;
- if (!nd_smi_module_loaded) {
- *status = asn1_print(ndo, elem);
- return NULL;
- }
- *status = smi_decode_oid(ndo, elem, oid, sizeof(oid) / sizeof(unsigned int),
- &oidlen);
- if (*status < 0)
- return NULL;
- smiNode = smiGetNodeByOID(oidlen, oid);
- if (! smiNode) {
- *status = asn1_print(ndo, elem);
- return NULL;
- }
- if (ndo->ndo_vflag) {
- ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
- }
- ND_PRINT((ndo, "%s", smiNode->name));
- if (smiNode->oidlen < oidlen) {
- for (i = smiNode->oidlen; i < oidlen; i++) {
- ND_PRINT((ndo, ".%u", oid[i]));
- }
- }
- *status = 0;
- return smiNode;
- }
- static int
- smi_print_value(netdissect_options *ndo,
- SmiNode *smiNode, u_short pduid, struct be *elem)
- {
- unsigned int i, oid[128], oidlen;
- SmiType *smiType;
- SmiNamedNumber *nn;
- int done = 0;
- if (! smiNode || ! (smiNode->nodekind
- & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
- return asn1_print(ndo, elem);
- }
- if (elem->type == BE_NOSUCHOBJECT
- || elem->type == BE_NOSUCHINST
- || elem->type == BE_ENDOFMIBVIEW) {
- return asn1_print(ndo, elem);
- }
- if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
- ND_PRINT((ndo, "[notNotifyable]"));
- }
- if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
- ND_PRINT((ndo, "[notReadable]"));
- }
- if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
- ND_PRINT((ndo, "[notWritable]"));
- }
- if (RESPONSE_CLASS(pduid)
- && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
- ND_PRINT((ndo, "[noAccess]"));
- }
- smiType = smiGetNodeType(smiNode);
- if (! smiType) {
- return asn1_print(ndo, elem);
- }
- if (! smi_check_type(smiType->basetype, elem->type)) {
- ND_PRINT((ndo, "[wrongType]"));
- }
- if (! smi_check_range(smiType, elem)) {
- ND_PRINT((ndo, "[outOfRange]"));
- }
- /* resolve bits to named bits */
- /* check whether instance identifier is valid */
- /* apply display hints (integer, octetstring) */
- /* convert instance identifier to index type values */
- switch (elem->type) {
- case BE_OID:
- if (smiType->basetype == SMI_BASETYPE_BITS) {
- /* print bit labels */
- } else {
- if (nd_smi_module_loaded &&
- smi_decode_oid(ndo, elem, oid,
- sizeof(oid)/sizeof(unsigned int),
- &oidlen) == 0) {
- smiNode = smiGetNodeByOID(oidlen, oid);
- if (smiNode) {
- if (ndo->ndo_vflag) {
- ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
- }
- ND_PRINT((ndo, "%s", smiNode->name));
- if (smiNode->oidlen < oidlen) {
- for (i = smiNode->oidlen;
- i < oidlen; i++) {
- ND_PRINT((ndo, ".%u", oid[i]));
- }
- }
- done++;
- }
- }
- }
- break;
- case BE_INT:
- if (smiType->basetype == SMI_BASETYPE_ENUM) {
- for (nn = smiGetFirstNamedNumber(smiType);
- nn;
- nn = smiGetNextNamedNumber(nn)) {
- if (nn->value.value.integer32
- == elem->data.integer) {
- ND_PRINT((ndo, "%s", nn->name));
- ND_PRINT((ndo, "(%d)", elem->data.integer));
- done++;
- break;
- }
- }
- }
- break;
- }
- if (! done) {
- return asn1_print(ndo, elem);
- }
- return 0;
- }
- #endif
- /*
- * General SNMP header
- * SEQUENCE {
- * version INTEGER {version-1(0)},
- * community OCTET STRING,
- * data ANY -- PDUs
- * }
- * PDUs for all but Trap: (see rfc1157 from page 15 on)
- * SEQUENCE {
- * request-id INTEGER,
- * error-status INTEGER,
- * error-index INTEGER,
- * varbindlist SEQUENCE OF
- * SEQUENCE {
- * name ObjectName,
- * value ObjectValue
- * }
- * }
- * PDU for Trap:
- * SEQUENCE {
- * enterprise OBJECT IDENTIFIER,
- * agent-addr NetworkAddress,
- * generic-trap INTEGER,
- * specific-trap INTEGER,
- * time-stamp TimeTicks,
- * varbindlist SEQUENCE OF
- * SEQUENCE {
- * name ObjectName,
- * value ObjectValue
- * }
- * }
- */
- /*
- * Decode SNMP varBind
- */
- static void
- varbind_print(netdissect_options *ndo,
- u_short pduid, const u_char *np, u_int length)
- {
- struct be elem;
- int count = 0, ind;
- #ifdef USE_LIBSMI
- SmiNode *smiNode = NULL;
- #endif
- int status;
- /* Sequence of varBind */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_SEQ) {
- ND_PRINT((ndo, "[!SEQ of varbind]"));
- asn1_print(ndo, &elem);
- return;
- }
- if ((u_int)count < length)
- ND_PRINT((ndo, "[%d extra after SEQ of varbind]", length - count));
- /* descend */
- length = elem.asnlen;
- np = (const u_char *)elem.data.raw;
- for (ind = 1; length > 0; ind++) {
- const u_char *vbend;
- u_int vblength;
- ND_PRINT((ndo, " "));
- /* Sequence */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_SEQ) {
- ND_PRINT((ndo, "[!varbind]"));
- asn1_print(ndo, &elem);
- return;
- }
- vbend = np + count;
- vblength = length - count;
- /* descend */
- length = elem.asnlen;
- np = (const u_char *)elem.data.raw;
- /* objName (OID) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_OID) {
- ND_PRINT((ndo, "[objName!=OID]"));
- asn1_print(ndo, &elem);
- return;
- }
- #ifdef USE_LIBSMI
- smiNode = smi_print_variable(ndo, &elem, &status);
- #else
- status = asn1_print(ndo, &elem);
- #endif
- if (status < 0)
- return;
- length -= count;
- np += count;
- if (pduid != GETREQ && pduid != GETNEXTREQ
- && pduid != GETBULKREQ)
- ND_PRINT((ndo, "="));
- /* objVal (ANY) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (pduid == GETREQ || pduid == GETNEXTREQ
- || pduid == GETBULKREQ) {
- if (elem.type != BE_NULL) {
- ND_PRINT((ndo, "[objVal!=NULL]"));
- if (asn1_print(ndo, &elem) < 0)
- return;
- }
- } else {
- if (elem.type != BE_NULL) {
- #ifdef USE_LIBSMI
- status = smi_print_value(ndo, smiNode, pduid, &elem);
- #else
- status = asn1_print(ndo, &elem);
- #endif
- }
- if (status < 0)
- return;
- }
- length = vblength;
- np = vbend;
- }
- }
- /*
- * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
- * GetBulk, Inform, V2Trap, and Report
- */
- static void
- snmppdu_print(netdissect_options *ndo,
- u_short pduid, const u_char *np, u_int length)
- {
- struct be elem;
- int count = 0, error_status;
- /* reqId (Integer) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_INT) {
- ND_PRINT((ndo, "[reqId!=INT]"));
- asn1_print(ndo, &elem);
- return;
- }
- if (ndo->ndo_vflag)
- ND_PRINT((ndo, "R=%d ", elem.data.integer));
- length -= count;
- np += count;
- /* errorStatus (Integer) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_INT) {
- ND_PRINT((ndo, "[errorStatus!=INT]"));
- asn1_print(ndo, &elem);
- return;
- }
- error_status = 0;
- if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
- || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
- && elem.data.integer != 0) {
- char errbuf[20];
- ND_PRINT((ndo, "[errorStatus(%s)!=0]",
- DECODE_ErrorStatus(elem.data.integer)));
- } else if (pduid == GETBULKREQ) {
- ND_PRINT((ndo, " N=%d", elem.data.integer));
- } else if (elem.data.integer != 0) {
- char errbuf[20];
- ND_PRINT((ndo, " %s", DECODE_ErrorStatus(elem.data.integer)));
- error_status = elem.data.integer;
- }
- length -= count;
- np += count;
- /* errorIndex (Integer) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_INT) {
- ND_PRINT((ndo, "[errorIndex!=INT]"));
- asn1_print(ndo, &elem);
- return;
- }
- if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
- || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
- && elem.data.integer != 0)
- ND_PRINT((ndo, "[errorIndex(%d)!=0]", elem.data.integer));
- else if (pduid == GETBULKREQ)
- ND_PRINT((ndo, " M=%d", elem.data.integer));
- else if (elem.data.integer != 0) {
- if (!error_status)
- ND_PRINT((ndo, "[errorIndex(%d) w/o errorStatus]", elem.data.integer));
- else
- ND_PRINT((ndo, "@%d", elem.data.integer));
- } else if (error_status) {
- ND_PRINT((ndo, "[errorIndex==0]"));
- }
- length -= count;
- np += count;
- varbind_print(ndo, pduid, np, length);
- return;
- }
- /*
- * Decode SNMP Trap PDU
- */
- static void
- trappdu_print(netdissect_options *ndo,
- const u_char *np, u_int length)
- {
- struct be elem;
- int count = 0, generic;
- ND_PRINT((ndo, " "));
- /* enterprise (oid) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_OID) {
- ND_PRINT((ndo, "[enterprise!=OID]"));
- asn1_print(ndo, &elem);
- return;
- }
- if (asn1_print(ndo, &elem) < 0)
- return;
- length -= count;
- np += count;
- ND_PRINT((ndo, " "));
- /* agent-addr (inetaddr) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_INETADDR) {
- ND_PRINT((ndo, "[agent-addr!=INETADDR]"));
- asn1_print(ndo, &elem);
- return;
- }
- if (asn1_print(ndo, &elem) < 0)
- return;
- length -= count;
- np += count;
- /* generic-trap (Integer) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_INT) {
- ND_PRINT((ndo, "[generic-trap!=INT]"));
- asn1_print(ndo, &elem);
- return;
- }
- generic = elem.data.integer;
- {
- char buf[20];
- ND_PRINT((ndo, " %s", DECODE_GenericTrap(generic)));
- }
- length -= count;
- np += count;
- /* specific-trap (Integer) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_INT) {
- ND_PRINT((ndo, "[specific-trap!=INT]"));
- asn1_print(ndo, &elem);
- return;
- }
- if (generic != GT_ENTERPRISE) {
- if (elem.data.integer != 0)
- ND_PRINT((ndo, "[specific-trap(%d)!=0]", elem.data.integer));
- } else
- ND_PRINT((ndo, " s=%d", elem.data.integer));
- length -= count;
- np += count;
- ND_PRINT((ndo, " "));
- /* time-stamp (TimeTicks) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_UNS) { /* XXX */
- ND_PRINT((ndo, "[time-stamp!=TIMETICKS]"));
- asn1_print(ndo, &elem);
- return;
- }
- if (asn1_print(ndo, &elem) < 0)
- return;
- length -= count;
- np += count;
- varbind_print(ndo, TRAP, np, length);
- return;
- }
- /*
- * Decode arbitrary SNMP PDUs.
- */
- static void
- pdu_print(netdissect_options *ndo,
- const u_char *np, u_int length, int version)
- {
- struct be pdu;
- int count = 0;
- /* PDU (Context) */
- if ((count = asn1_parse(ndo, np, length, &pdu)) < 0)
- return;
- if (pdu.type != BE_PDU) {
- ND_PRINT((ndo, "[no PDU]"));
- return;
- }
- if ((u_int)count < length)
- ND_PRINT((ndo, "[%d extra after PDU]", length - count));
- if (ndo->ndo_vflag) {
- ND_PRINT((ndo, "{ "));
- }
- if (asn1_print(ndo, &pdu) < 0)
- return;
- ND_PRINT((ndo, " "));
- /* descend into PDU */
- length = pdu.asnlen;
- np = (const u_char *)pdu.data.raw;
- if (version == SNMP_VERSION_1 &&
- (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
- pdu.id == V2TRAP || pdu.id == REPORT)) {
- ND_PRINT((ndo, "[v2 PDU in v1 message]"));
- return;
- }
- if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
- ND_PRINT((ndo, "[v1 PDU in v2 message]"));
- return;
- }
- switch (pdu.id) {
- case TRAP:
- trappdu_print(ndo, np, length);
- break;
- case GETREQ:
- case GETNEXTREQ:
- case GETRESP:
- case SETREQ:
- case GETBULKREQ:
- case INFORMREQ:
- case V2TRAP:
- case REPORT:
- snmppdu_print(ndo, pdu.id, np, length);
- break;
- }
- if (ndo->ndo_vflag) {
- ND_PRINT((ndo, " } "));
- }
- }
- /*
- * Decode a scoped SNMP PDU.
- */
- static void
- scopedpdu_print(netdissect_options *ndo,
- const u_char *np, u_int length, int version)
- {
- struct be elem;
- int count = 0;
- /* Sequence */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_SEQ) {
- ND_PRINT((ndo, "[!scoped PDU]"));
- asn1_print(ndo, &elem);
- return;
- }
- length = elem.asnlen;
- np = (const u_char *)elem.data.raw;
- /* contextEngineID (OCTET STRING) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_STR) {
- ND_PRINT((ndo, "[contextEngineID!=STR]"));
- asn1_print(ndo, &elem);
- return;
- }
- length -= count;
- np += count;
- ND_PRINT((ndo, "E="));
- if (asn1_print_octets(ndo, &elem) == -1)
- return;
- ND_PRINT((ndo, " "));
- /* contextName (OCTET STRING) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_STR) {
- ND_PRINT((ndo, "[contextName!=STR]"));
- asn1_print(ndo, &elem);
- return;
- }
- length -= count;
- np += count;
- ND_PRINT((ndo, "C="));
- if (asn1_print_string(ndo, &elem) == -1)
- return;
- ND_PRINT((ndo, " "));
- pdu_print(ndo, np, length, version);
- }
- /*
- * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
- */
- static void
- community_print(netdissect_options *ndo,
- const u_char *np, u_int length, int version)
- {
- struct be elem;
- int count = 0;
- /* Community (String) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_STR) {
- ND_PRINT((ndo, "[comm!=STR]"));
- asn1_print(ndo, &elem);
- return;
- }
- /* default community */
- if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
- strncmp((const char *)elem.data.str, DEF_COMMUNITY,
- sizeof(DEF_COMMUNITY) - 1) == 0)) {
- /* ! "public" */
- ND_PRINT((ndo, "C="));
- if (asn1_print_string(ndo, &elem) == -1)
- return;
- ND_PRINT((ndo, " "));
- }
- length -= count;
- np += count;
- pdu_print(ndo, np, length, version);
- }
- /*
- * Decode SNMPv3 User-based Security Message Header (SNMPv3)
- */
- static void
- usm_print(netdissect_options *ndo,
- const u_char *np, u_int length)
- {
- struct be elem;
- int count = 0;
- /* Sequence */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_SEQ) {
- ND_PRINT((ndo, "[!usm]"));
- asn1_print(ndo, &elem);
- return;
- }
- length = elem.asnlen;
- np = (const u_char *)elem.data.raw;
- /* msgAuthoritativeEngineID (OCTET STRING) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_STR) {
- ND_PRINT((ndo, "[msgAuthoritativeEngineID!=STR]"));
- asn1_print(ndo, &elem);
- return;
- }
- length -= count;
- np += count;
- /* msgAuthoritativeEngineBoots (INTEGER) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_INT) {
- ND_PRINT((ndo, "[msgAuthoritativeEngineBoots!=INT]"));
- asn1_print(ndo, &elem);
- return;
- }
- if (ndo->ndo_vflag)
- ND_PRINT((ndo, "B=%d ", elem.data.integer));
- length -= count;
- np += count;
- /* msgAuthoritativeEngineTime (INTEGER) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_INT) {
- ND_PRINT((ndo, "[msgAuthoritativeEngineTime!=INT]"));
- asn1_print(ndo, &elem);
- return;
- }
- if (ndo->ndo_vflag)
- ND_PRINT((ndo, "T=%d ", elem.data.integer));
- length -= count;
- np += count;
- /* msgUserName (OCTET STRING) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_STR) {
- ND_PRINT((ndo, "[msgUserName!=STR]"));
- asn1_print(ndo, &elem);
- return;
- }
- length -= count;
- np += count;
- ND_PRINT((ndo, "U="));
- if (asn1_print_string(ndo, &elem) == -1)
- return;
- ND_PRINT((ndo, " "));
- /* msgAuthenticationParameters (OCTET STRING) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_STR) {
- ND_PRINT((ndo, "[msgAuthenticationParameters!=STR]"));
- asn1_print(ndo, &elem);
- return;
- }
- length -= count;
- np += count;
- /* msgPrivacyParameters (OCTET STRING) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_STR) {
- ND_PRINT((ndo, "[msgPrivacyParameters!=STR]"));
- asn1_print(ndo, &elem);
- return;
- }
- length -= count;
- np += count;
- if ((u_int)count < length)
- ND_PRINT((ndo, "[%d extra after usm SEQ]", length - count));
- }
- /*
- * Decode SNMPv3 Message Header (SNMPv3)
- */
- static void
- v3msg_print(netdissect_options *ndo,
- const u_char *np, u_int length)
- {
- struct be elem;
- int count = 0;
- u_char flags;
- int model;
- const u_char *xnp = np;
- int xlength = length;
- /* Sequence */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_SEQ) {
- ND_PRINT((ndo, "[!message]"));
- asn1_print(ndo, &elem);
- return;
- }
- length = elem.asnlen;
- np = (const u_char *)elem.data.raw;
- if (ndo->ndo_vflag) {
- ND_PRINT((ndo, "{ "));
- }
- /* msgID (INTEGER) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_INT) {
- ND_PRINT((ndo, "[msgID!=INT]"));
- asn1_print(ndo, &elem);
- return;
- }
- length -= count;
- np += count;
- /* msgMaxSize (INTEGER) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_INT) {
- ND_PRINT((ndo, "[msgMaxSize!=INT]"));
- asn1_print(ndo, &elem);
- return;
- }
- length -= count;
- np += count;
- /* msgFlags (OCTET STRING) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_STR) {
- ND_PRINT((ndo, "[msgFlags!=STR]"));
- asn1_print(ndo, &elem);
- return;
- }
- if (elem.asnlen != 1) {
- ND_PRINT((ndo, "[msgFlags size %d]", elem.asnlen));
- return;
- }
- flags = elem.data.str[0];
- if (flags != 0x00 && flags != 0x01 && flags != 0x03
- && flags != 0x04 && flags != 0x05 && flags != 0x07) {
- ND_PRINT((ndo, "[msgFlags=0x%02X]", flags));
- return;
- }
- length -= count;
- np += count;
- ND_PRINT((ndo, "F=%s%s%s ",
- flags & 0x01 ? "a" : "",
- flags & 0x02 ? "p" : "",
- flags & 0x04 ? "r" : ""));
- /* msgSecurityModel (INTEGER) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_INT) {
- ND_PRINT((ndo, "[msgSecurityModel!=INT]"));
- asn1_print(ndo, &elem);
- return;
- }
- model = elem.data.integer;
- length -= count;
- np += count;
- if ((u_int)count < length)
- ND_PRINT((ndo, "[%d extra after message SEQ]", length - count));
- if (ndo->ndo_vflag) {
- ND_PRINT((ndo, "} "));
- }
- if (model == 3) {
- if (ndo->ndo_vflag) {
- ND_PRINT((ndo, "{ USM "));
- }
- } else {
- ND_PRINT((ndo, "[security model %d]", model));
- return;
- }
- np = xnp + (np - xnp);
- length = xlength - (np - xnp);
- /* msgSecurityParameters (OCTET STRING) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_STR) {
- ND_PRINT((ndo, "[msgSecurityParameters!=STR]"));
- asn1_print(ndo, &elem);
- return;
- }
- length -= count;
- np += count;
- if (model == 3) {
- usm_print(ndo, elem.data.str, elem.asnlen);
- if (ndo->ndo_vflag) {
- ND_PRINT((ndo, "} "));
- }
- }
- if (ndo->ndo_vflag) {
- ND_PRINT((ndo, "{ ScopedPDU "));
- }
- scopedpdu_print(ndo, np, length, 3);
- if (ndo->ndo_vflag) {
- ND_PRINT((ndo, "} "));
- }
- }
- /*
- * Decode SNMP header and pass on to PDU printing routines
- */
- void
- snmp_print(netdissect_options *ndo,
- const u_char *np, u_int length)
- {
- struct be elem;
- int count = 0;
- int version = 0;
- ND_PRINT((ndo, " "));
- /* initial Sequence */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_SEQ) {
- ND_PRINT((ndo, "[!init SEQ]"));
- asn1_print(ndo, &elem);
- return;
- }
- if ((u_int)count < length)
- ND_PRINT((ndo, "[%d extra after iSEQ]", length - count));
- /* descend */
- length = elem.asnlen;
- np = (const u_char *)elem.data.raw;
- /* Version (INTEGER) */
- if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
- return;
- if (elem.type != BE_INT) {
- ND_PRINT((ndo, "[version!=INT]"));
- asn1_print(ndo, &elem);
- return;
- }
- switch (elem.data.integer) {
- case SNMP_VERSION_1:
- case SNMP_VERSION_2:
- case SNMP_VERSION_3:
- if (ndo->ndo_vflag)
- ND_PRINT((ndo, "{ %s ", SnmpVersion[elem.data.integer]));
- break;
- default:
- ND_PRINT((ndo, "SNMP [version = %d]", elem.data.integer));
- return;
- }
- version = elem.data.integer;
- length -= count;
- np += count;
- switch (version) {
- case SNMP_VERSION_1:
- case SNMP_VERSION_2:
- community_print(ndo, np, length, version);
- break;
- case SNMP_VERSION_3:
- v3msg_print(ndo, np, length);
- break;
- default:
- ND_PRINT((ndo, "[version = %d]", elem.data.integer));
- break;
- }
- if (ndo->ndo_vflag) {
- ND_PRINT((ndo, "} "));
- }
- }
|