1 /*_############################################################################
6 _## -----------------------------------------------
7 _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
9 _## This software is based on SNMP++2.6 from Hewlett Packard:
11 _## Copyright (c) 1996
12 _## Hewlett-Packard Company
14 _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
15 _## Permission to use, copy, modify, distribute and/or sell this software
16 _## and/or its documentation is hereby granted without fee. User agrees
17 _## to display the above copyright notice and this license notice in all
18 _## copies of the software and any documentation of the software. User
19 _## agrees to assume all liability for the use of the software;
20 _## Hewlett-Packard and Jochen Katz make no representations about the
21 _## suitability of this software for any purpose. It is provided
22 _## "AS-IS" without warranty of any kind, either express or implied. User
23 _## hereby grants a royalty-free license to any and all derivatives based
24 _## upon this software code base.
26 _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
28 _##########################################################################*/
29 /*===================================================================
32 Hewlett-Packard Company
34 ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
35 Permission to use, copy, modify, distribute and/or sell this software
36 and/or its documentation is hereby granted without fee. User agrees
37 to display the above copyright notice and this license notice in all
38 copies of the software and any documentation of the software. User
39 agrees to assume all liability for the use of the software; Hewlett-Packard
40 makes no representations about the suitability of this software for any
41 purpose. It is provided "AS-IS" without warranty of any kind,either express
42 or implied. User hereby grants a royalty-free license to any and all
43 derivatives based upon this software code base.
45 SNMP++ S N M P M S G . C P P
47 SNMPMESSAGE CLASS DEFINITION
49 DESIGN + AUTHOR: Peter E Mellquist
51 DESCRIPTION: ASN.1 encoding / decoding class
52 =====================================================================*/
53 char snmpmsg_cpp_version[]="#(@) SNMP++ $Id: snmpmsg.cpp 1542 2009-05-29 11:38:48Z katz $";
58 #if defined(__APPLE__)
60 #include <netinet/in.h>
61 #include <arpa/inet.h>
65 #include "snmp_pp/config_snmp_pp.h"
66 #include "snmp_pp/snmpmsg.h" // header file for SnmpMessage
67 #include "snmp_pp/oid_def.h" // changed (Frank Fock)
68 #include "snmp_pp/log.h"
69 #include "snmp_pp/vb.h"
70 #include "snmp_pp/usm_v3.h"
72 #ifdef SNMP_PP_NAMESPACE
76 #define MAX_LEN_COMMUNITY 254
78 const coldStartOid coldStart;
79 const warmStartOid warmStart;
80 const linkDownOid linkDown;
81 const linkUpOid linkUp;
82 const authenticationFailureOid authenticationFailure;
83 const egpNeighborLossOid egpNeighborLoss;
84 const snmpTrapEnterpriseOid snmpTrapEnterprise;
86 //------------[ convert SNMP++ VB to WinSNMP smiVALUE ]----------------
87 int convertVbToSmival( const Vb &tempvb, SmiVALUE *smival )
89 smival->syntax = tempvb.get_syntax();
90 switch ( smival->syntax ) {
92 // case sNMP_SYNTAX_NULL
93 case sNMP_SYNTAX_NULL:
94 case sNMP_SYNTAX_NOSUCHOBJECT:
95 case sNMP_SYNTAX_NOSUCHINSTANCE:
96 case sNMP_SYNTAX_ENDOFMIBVIEW:
99 // case sNMP_SYNTAX_INT32:
100 case sNMP_SYNTAX_INT:
101 tempvb.get_value(smival->value.sNumber);
104 // case sNMP_SYNTAX_UINT32:
105 case sNMP_SYNTAX_GAUGE32:
106 case sNMP_SYNTAX_CNTR32:
107 case sNMP_SYNTAX_TIMETICKS:
108 // case sNMP_SYNTAX_UINT32:
109 tempvb.get_value(smival->value.uNumber);
113 case sNMP_SYNTAX_CNTR64:
116 tempvb.get_value(c64);
117 smival->value.hNumber.hipart = c64.high();
118 smival->value.hNumber.lopart = c64.low();
122 case sNMP_SYNTAX_BITS:
123 case sNMP_SYNTAX_OCTETS:
124 case sNMP_SYNTAX_OPAQUE:
125 case sNMP_SYNTAX_IPADDR:
128 tempvb.get_value(os);
129 smival->value.string.ptr = NULL;
130 smival->value.string.len = os.len();
131 if ( smival->value.string.len > 0 )
133 smival->value.string.ptr
134 = (SmiLPBYTE) new unsigned char [smival->value.string.len];
135 if ( smival->value.string.ptr )
137 for (int i=0; i<(int) smival->value.string.len ; i++)
138 smival->value.string.ptr[i] = os[i];
142 smival->syntax = sNMP_SYNTAX_NULL; // invalidate the smival
143 return SNMP_CLASS_RESOURCE_UNAVAIL;
149 case sNMP_SYNTAX_OID:
152 tempvb.get_value(oid);
153 smival->value.oid.ptr = NULL;
154 smival->value.oid.len = oid.len();
155 if ( smival->value.oid.len > 0 )
157 smival->value.oid.ptr
158 = (SmiLPUINT32) new unsigned long [ smival->value.oid.len];
159 if ( smival->value.oid.ptr )
161 for (int i=0; i<(int)smival->value.oid.len ; i++)
162 smival->value.oid.ptr[i] = oid[i];
166 smival->syntax = sNMP_SYNTAX_NULL; // invalidate the smival
167 return SNMP_CLASS_RESOURCE_UNAVAIL;
174 return SNMP_CLASS_INTERNAL_ERROR;
176 return SNMP_CLASS_SUCCESS;
180 void freeSmivalDescriptor( SmiVALUE *smival )
182 switch ( smival->syntax ) {
183 case sNMP_SYNTAX_OCTETS:
184 case sNMP_SYNTAX_OPAQUE:
185 case sNMP_SYNTAX_IPADDR:
186 case sNMP_SYNTAX_BITS: // obsoleted in SNMPv2 Draft Std
187 delete [] smival->value.string.ptr;
190 case sNMP_SYNTAX_OID:
191 delete [] smival->value.oid.ptr;
194 smival->syntax = sNMP_SYNTAX_NULL;
199 int SnmpMessage::unloadv3( Pdu &pdu, // Pdu returned
200 snmp_version &version, // version
201 OctetStr &engine_id, // optional v3
202 OctetStr &security_name, // optional v3
203 long int &security_model,
204 UdpAddress &from_addr,
208 return unload(pdu, tmp, version, &engine_id,
209 &security_name, &security_model, &from_addr, &snmp_session);
214 int SnmpMessage::load(const Pdu &cpdu,
215 const OctetStr &community,
216 const snmp_version version,
217 const OctetStr* engine_id,
218 const OctetStr* security_name,
219 const int security_model)
222 const Pdu *pdu = &cpdu;
225 // make sure pdu is valid
227 return SNMP_CLASS_INVALID_PDU;
231 raw_pdu = snmp_pdu_create( (int) pdu->get_type());
236 raw_pdu->reqid = pdu->get_request_id();
238 raw_pdu->msgid = pdu->get_message_id();
240 raw_pdu->errstat= (unsigned long) pdu->get_error_status();
241 raw_pdu->errindex= (unsigned long) pdu->get_error_index();
243 // if its a V1 trap then load up other values
244 // for v2, use normal pdu format
245 if (raw_pdu->command == sNMP_PDU_V1TRAP)
247 // DON'T forget about the v1 trap agent address (changed by Frank Fock)
250 int addr_set = FALSE;
252 if (pdu->get_v1_trap_address(gen_addr))
254 /* User did set the v1 trap address */
255 if ((gen_addr.get_type() != Address::type_ip) &&
256 (gen_addr.get_type() != Address::type_udp) )
258 LOG_BEGIN(ERROR_LOG | 4);
259 LOG("SNMPMessage: Bad v1 trap address type in pdu");
260 LOG(gen_addr.get_type());
263 snmp_free_pdu( raw_pdu);
264 return SNMP_CLASS_INVALID_PDU;
268 if (!ip_addr.valid())
270 LOG_BEGIN(ERROR_LOG | 1);
271 LOG("SNMPMessage: Copied v1 trap address not valid");
274 snmp_free_pdu( raw_pdu);
275 return SNMP_CLASS_RESOURCE_UNAVAIL;
281 /* User did not set the v1 trap address */
282 char addrString[256];
283 if (gethostname(addrString, 255) == 0)
285 ip_addr = addrString;
289 struct sockaddr_in agent_addr; // agent address socket struct
290 // prepare the agent address
291 memset(&agent_addr, 0, sizeof(agent_addr));
292 agent_addr.sin_family = AF_INET;
295 agent_addr.sin_addr.s_addr
296 = inet_addr(((IpAddress &)ip_addr).IpAddress::get_printable());
297 LOG_BEGIN(INFO_LOG | 7);
298 LOG("SNMPMessage: Setting v1 trap address");
299 LOG(((IpAddress &)ip_addr).IpAddress::get_printable());
302 raw_pdu->agent_addr = agent_addr;
304 //-----[ compute generic trap value ]-------------------------------
305 // determine the generic value
310 // 4 - authentication failure
311 // 5 - egpneighborloss
312 // 6 - enterprise specific
314 pdu->get_notify_id( trapid);
315 if ( !trapid.valid() || trapid.len() < 2 )
317 snmp_free_pdu( raw_pdu);
318 return SNMP_CLASS_INVALID_NOTIFYID;
320 raw_pdu->specific_type=0;
321 if ( trapid == coldStart)
322 raw_pdu->trap_type = 0; // cold start
323 else if ( trapid == warmStart)
324 raw_pdu->trap_type = 1; // warm start
325 else if( trapid == linkDown)
326 raw_pdu->trap_type = 2; // link down
327 else if ( trapid == linkUp)
328 raw_pdu->trap_type = 3; // link up
329 else if ( trapid == authenticationFailure )
330 raw_pdu->trap_type = 4; // authentication failure
331 else if ( trapid == egpNeighborLoss)
332 raw_pdu->trap_type = 5; // egp neighbor loss
334 raw_pdu->trap_type = 6; // enterprise specific
335 // last oid subid is the specific value
336 // if 2nd to last subid is "0", remove it
337 // enterprise is always the notify oid prefix
338 raw_pdu->specific_type = (int) trapid[(int) (trapid.len()-1)];
341 if ( trapid[(int)(trapid.len()-1)] == 0 )
346 if ( raw_pdu->trap_type !=6)
347 pdu->get_notify_enterprise( enterprise);
348 if ( enterprise.len() >0) {
350 // these are hooks into an SNMP++ oid
351 // and therefor the raw_pdu enterprise
352 // should not free them. null them out!!
354 rawOid = enterprise.oidval();
355 raw_pdu->enterprise = rawOid->ptr;
356 raw_pdu->enterprise_length = (int) rawOid->len;
361 pdu->get_notify_timestamp( timestamp);
362 raw_pdu->time = ( unsigned long) timestamp;
366 // if its a v2 trap then we need to make a few adjustments
367 // vb #1 is the timestamp
368 // vb #2 is the id, represented as an Oid
369 if (( raw_pdu->command == sNMP_PDU_TRAP) ||
370 ( raw_pdu->command == sNMP_PDU_INFORM))
375 temppdu.trim(temppdu.get_vb_count());
377 // vb #1 is the timestamp
379 tempvb.set_oid(SNMP_MSG_OID_SYSUPTIME); // sysuptime
380 pdu->get_notify_timestamp( timestamp);
381 tempvb.set_value ( timestamp);
386 tempvb.set_oid(SNMP_MSG_OID_TRAPID);
387 pdu->get_notify_id( trapid);
388 tempvb.set_value( trapid);
391 // append the remaining vbs
392 for (int z=0; z<pdu->get_vb_count(); z++) {
393 pdu->get_vb( tempvb,z);
397 pdu = &temppdu; // reassign the pdu to the temp one
399 // load up the payload
400 // for all Vbs in list, add them to the pdu
407 vb_count = pdu->get_vb_count();
408 for (int z=0;z<vb_count;z++) {
409 pdu->get_vb( tempvb,z);
410 tempvb.get_oid( tempoid);
411 smioid = tempoid.oidval();
412 // clear the value portion, in case its
413 // not already been done so by the app writer
414 // only do it in the case its a get,next or bulk
415 if ((raw_pdu->command == sNMP_PDU_GET) ||
416 (raw_pdu->command == sNMP_PDU_GETNEXT) ||
417 (raw_pdu->command == sNMP_PDU_GETBULK))
419 status = convertVbToSmival( tempvb, &smival );
420 if ( status != SNMP_CLASS_SUCCESS) {
421 snmp_free_pdu( raw_pdu);
424 // add the vb to the raw pdu
425 snmp_add_var( raw_pdu, smioid->ptr, (int) smioid->len, &smival);
427 freeSmivalDescriptor( &smival);
430 // ASN1 encode the pdu
432 if (version == version3)
434 if ((!engine_id) || (!security_name))
436 LOG_BEGIN(ERROR_LOG | 4);
437 LOG("SNMPMessage: Need security name and engine id for v3 message");
440 // prevention of SNMP++ Enterprise Oid death
441 if ( enterprise.len() >0) {
442 raw_pdu->enterprise = 0;
443 raw_pdu->enterprise_length=0;
445 snmp_free_pdu( raw_pdu);
446 return SNMP_CLASS_INVALID_TARGET;
449 status = v3MP::I->snmp_build(raw_pdu, databuff, (int *)&bufflen,
450 *engine_id, *security_name, security_model,
451 pdu->get_security_level(),
452 pdu->get_context_engine_id(),
453 pdu->get_context_name());
454 if (status == SNMPv3_MP_OK) {
455 if ((pdu->get_type() == sNMP_PDU_RESPONSE) &&
456 ((int)pdu->get_maxsize_scopedpdu() < pdu->get_asn1_length())) {
458 LOG_BEGIN(ERROR_LOG | 1);
459 LOG("SNMPMessage: *BUG*: Serialized response pdu is too big (len) (max)");
460 LOG(pdu->get_asn1_length());
461 LOG(pdu->get_maxsize_scopedpdu());
464 // prevention of SNMP++ Enterprise Oid death
465 if ( enterprise.len() >0) {
466 raw_pdu->enterprise = 0;
467 raw_pdu->enterprise_length=0;
469 snmp_free_pdu( raw_pdu);
470 return SNMP_ERROR_TOO_BIG;
476 status = snmp_build( raw_pdu, databuff, (int *) &bufflen, version,
477 community.data(), (int) community.len());
479 LOG_BEGIN(DEBUG_LOG | 4);
480 LOG("SNMPMessage: return value for build message");
486 && ((version != version3) || (status != SNMPv3_MP_OK))
490 // prevention of SNMP++ Enterprise Oid death
491 if ( enterprise.len() >0) {
492 raw_pdu->enterprise = 0;
493 raw_pdu->enterprise_length=0;
495 snmp_free_pdu( raw_pdu);
497 if (version == version3)
501 // NOTE: This is an assumption - in most cases during normal
502 // operation the reason is a tooBig - another could be a
503 // damaged variable binding.
504 return SNMP_ERROR_TOO_BIG;
508 // prevention of SNMP++ Enterprise Oid death
509 if ( enterprise.len() >0) {
510 raw_pdu->enterprise = 0;
511 raw_pdu->enterprise_length=0;
514 snmp_free_pdu( raw_pdu);
516 return SNMP_CLASS_SUCCESS;
519 // load up a SnmpMessage
520 int SnmpMessage::load( unsigned char *data,
523 bufflen = MAX_SNMP_PACKET;
526 if (len <= MAX_SNMP_PACKET)
528 memcpy( (unsigned char *) databuff, (unsigned char *) data,
534 return SNMP_ERROR_WRONG_LENGTH;
536 return SNMP_CLASS_SUCCESS;
539 // unload the data into SNMP++ objects
540 int SnmpMessage::unload(Pdu &pdu, // Pdu object
541 OctetStr &community, // community object
542 snmp_version &version, // SNMP version #
543 OctetStr *engine_id, // optional v3
544 OctetStr *security_name, // optional v3
545 long int *security_model,
546 UdpAddress *from_addr,
552 return SNMP_CLASS_INVALID;
555 raw_pdu = snmp_pdu_create(0); // do a "snmp_free_pdu( raw_pdu)" before return
560 OctetStr context_engine_id;
561 OctetStr context_name;
562 long int security_level = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
564 if ((security_model) && (security_name) && (engine_id) && (snmp_session)) {
565 status = v3MP::I->snmp_parse(snmp_session, raw_pdu,
566 databuff, (int)bufflen, *engine_id,
567 *security_name, context_engine_id, context_name,
568 security_level, *security_model, version, *from_addr);
569 if (status != SNMPv3_MP_OK) {
570 pdu.set_request_id( raw_pdu->reqid);
571 pdu.set_type( raw_pdu->command);
572 snmp_free_pdu( raw_pdu);
575 pdu.set_context_engine_id(context_engine_id);
576 pdu.set_context_name(context_name);
577 pdu.set_security_level(security_level);
578 pdu.set_message_id(raw_pdu->msgid);
579 pdu.set_maxsize_scopedpdu(raw_pdu->maxsize_scopedpdu);
583 unsigned char community_name[MAX_LEN_COMMUNITY + 1];
584 int community_len = MAX_LEN_COMMUNITY + 1;
586 status = snmp_parse(raw_pdu, databuff, (int) bufflen,
587 community_name, community_len, version);
588 if (status != SNMP_CLASS_SUCCESS) {
589 snmp_free_pdu(raw_pdu);
592 community.set_data( community_name, community_len);
597 // load up the SNMP++ variables
598 pdu.set_request_id(raw_pdu->reqid);
599 pdu.set_error_status((int) raw_pdu->errstat);
600 pdu.set_error_index((int) raw_pdu->errindex);
601 pdu.set_type( raw_pdu->command);
603 // deal with traps a little different
604 if ( raw_pdu->command == sNMP_PDU_V1TRAP) {
607 timestamp = raw_pdu->time;
608 pdu.set_notify_timestamp( timestamp);
610 // set the agent address
611 IpAddress agent_addr(inet_ntoa(raw_pdu->agent_addr.sin_addr));
612 if (agent_addr != "0.0.0.0")
614 pdu.set_v1_trap_address(agent_addr);
616 LOG_BEGIN(DEBUG_LOG | 4);
617 LOG("SNMPMessage: Trap address of received v1 trap");
618 LOG(agent_addr.get_printable());
622 // set enterprise, notifyid
625 if (raw_pdu->enterprise_length >0) {
626 for (int i=0; i< raw_pdu->enterprise_length; i++) {
627 enterprise += (int) (raw_pdu->enterprise[i]);
629 pdu.set_notify_enterprise(enterprise);
631 switch (raw_pdu->trap_type) {
633 pdu.set_notify_id(coldStart);
637 pdu.set_notify_id(warmStart);
641 pdu.set_notify_id(linkDown);
645 pdu.set_notify_id(linkUp);
649 pdu.set_notify_id(authenticationFailure);
653 pdu.set_notify_id(egpNeighborLoss);
656 case 6: { // enterprise specific
657 // base id + specific #
658 Oid eOid = enterprise;
660 eOid += raw_pdu->specific_type;
661 pdu.set_notify_id( eOid);
666 LOG_BEGIN(WARNING_LOG | 3);
667 LOG("SNMPMessage: Received trap with illegal trap type");
668 LOG(raw_pdu->trap_type);
677 struct variable_list *vp;
680 for(vp = raw_pdu->variables; vp; vp = vp->next_variable, vb_nr++) {
682 // extract the oid portion
683 tempoid.set_data( (unsigned long *)vp->name,
684 ( unsigned int) vp->name_length);
685 tempvb.set_oid( tempoid);
687 // extract the value portion
691 case sNMP_SYNTAX_OCTETS:
693 OctetStr octets( (unsigned char *) vp->val.string,
694 (unsigned long) vp->val_len);
695 tempvb.set_value( octets);
698 case sNMP_SYNTAX_OPAQUE:
700 OpaqueStr octets( (unsigned char *) vp->val.string,
701 (unsigned long) vp->val_len);
702 tempvb.set_value( octets);
707 case sNMP_SYNTAX_OID:
709 Oid oid( (unsigned long*) vp->val.objid,
711 tempvb.set_value( oid);
713 ((raw_pdu->command == sNMP_PDU_TRAP) ||
714 (raw_pdu->command == sNMP_PDU_INFORM)) &&
715 (tempoid == SNMP_MSG_OID_TRAPID))
718 pdu.set_notify_id(oid);
719 continue; // don't add vb to pdu
725 case sNMP_SYNTAX_TIMETICKS:
727 TimeTicks timeticks( (unsigned long) *(vp->val.integer));
728 tempvb.set_value( timeticks);
730 ((raw_pdu->command == sNMP_PDU_TRAP) ||
731 (raw_pdu->command == sNMP_PDU_INFORM)) &&
732 (tempoid == SNMP_MSG_OID_SYSUPTIME))
734 // set notify_timestamp
735 pdu.set_notify_timestamp( timeticks);
736 continue; // don't add vb to pdu
742 case sNMP_SYNTAX_CNTR32:
744 Counter32 counter32( (unsigned long) *(vp->val.integer));
745 tempvb.set_value( counter32);
750 case sNMP_SYNTAX_GAUGE32:
752 Gauge32 gauge32( (unsigned long) *(vp->val.integer));
753 tempvb.set_value( gauge32);
758 case sNMP_SYNTAX_IPADDR:
762 if (vp->val_len == 16)
763 sprintf( buffer, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
764 "%02x%02x:%02x%02x:%02x%02x:%02x%02x",
765 vp->val.string[ 0], vp->val.string[ 1], vp->val.string[ 2],
766 vp->val.string[ 3], vp->val.string[ 4], vp->val.string[ 5],
767 vp->val.string[ 6], vp->val.string[ 7], vp->val.string[ 8],
768 vp->val.string[ 9], vp->val.string[10], vp->val.string[11],
769 vp->val.string[12], vp->val.string[13], vp->val.string[14],
772 sprintf( buffer,"%d.%d.%d.%d",
773 vp->val.string[0], vp->val.string[1],
774 vp->val.string[2], vp->val.string[3]);
775 IpAddress ipaddress( buffer);
776 tempvb.set_value( ipaddress);
781 case sNMP_SYNTAX_INT:
783 SnmpInt32 int32( (long) *(vp->val.integer));
784 tempvb.set_value( int32);
788 // 32 bit unsigned integer
789 /* Not distinguishable from Gauge32
790 case sNMP_SYNTAX_UINT32:
792 SnmpUInt32 uint32( (unsigned long) *(vp->val.integer));
793 tempvb.set_value( uint32);
798 case sNMP_SYNTAX_CNTR64:
799 { // Frank Fock (was empty before)
800 Counter64 c64(((counter64*)vp->val.counter64)->high,
801 ((counter64*)vp->val.counter64)->low);
802 tempvb.set_value( c64);
805 case sNMP_SYNTAX_NULL:
810 case sNMP_SYNTAX_NOSUCHOBJECT:
811 case sNMP_SYNTAX_NOSUCHINSTANCE:
812 case sNMP_SYNTAX_ENDOFMIBVIEW:
813 tempvb.set_exception_status(vp->type);
821 // append the vb to the pdu
825 snmp_free_pdu( raw_pdu);
827 return SNMP_CLASS_SUCCESS;
830 #ifdef SNMP_PP_NAMESPACE
831 }; // end of namespace Snmp_pp