blob: d61b2a8a9e4e94682a196625cd804890ef432e04 [file] [log] [blame]
/* agent_trap.c: define trap generation routines for mib modules, etc,
to use */
#include <config.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include "asn1.h"
#include "snmp_api.h"
#include "snmp_impl.h"
#include "snmp_client.h"
#include "snmp.h"
#include "system.h"
#include "read_config.h"
#include "snmp_debug.h"
struct trap_sink {
struct snmp_session *sesp;
struct trap_sink *next;
int pdutype;
int version;
};
struct trap_sink *sinks = NULL;
extern struct timeval starttime;
#define OID_LENGTH(x) (sizeof(x)/sizeof(x[0]))
oid objid_enterprisetrap[] = { EXTENSIBLEMIB, 251, 0, 0 };
oid version_id[] = { EXTENSIBLEMIB, AGENTID, OSTYPE };
int enterprisetrap_len = OID_LENGTH( objid_enterprisetrap );
int version_id_len = OID_LENGTH( version_id );
#define SNMPV2_TRAPS_PREFIX 1,3,6,1,6,3,1,1,5
oid cold_start_oid[] = { SNMPV2_TRAPS_PREFIX, 1 }; /* SNMPv2-MIB */
oid warm_start_oid[] = { SNMPV2_TRAPS_PREFIX, 2 }; /* SNMPv2-MIB */
oid link_down_oid[] = { SNMPV2_TRAPS_PREFIX, 3 }; /* IF-MIB */
oid link_up_oid[] = { SNMPV2_TRAPS_PREFIX, 4 }; /* IF-MIB */
oid auth_fail_oid[] = { SNMPV2_TRAPS_PREFIX, 5 }; /* SNMPv2-MIB */
oid egp_xxx_oid[] = { SNMPV2_TRAPS_PREFIX, 99 }; /* ??? */
#define SNMPV2_TRAP_OBJS_PREFIX 1,3,6,1,6,3,1,1,4
oid snmptrap_oid[] = { SNMPV2_TRAP_OBJS_PREFIX, 1 };
oid snmptrapenterprise_oid[] = { SNMPV2_TRAP_OBJS_PREFIX, 3 };
oid sysuptime_oid[] = { 1,3,6,1,2,1,1,3,0 };
int snmptrap_oid_len = OID_LENGTH(snmptrap_oid);
int snmptrapenterprise_oid_len = OID_LENGTH(snmptrapenterprise_oid);
int sysuptime_oid_len = OID_LENGTH(sysuptime_oid);
#define SNMP_AUTHENTICATED_TRAPS_ENABLED 1
#define SNMP_AUTHENTICATED_TRAPS_DISABLED 2
int snmp_enableauthentraps = SNMP_AUTHENTICATED_TRAPS_DISABLED;
char *snmp_trapcommunity = NULL;
/* Prototypes */
/*
static int create_v1_trap_session (const char *, const char *);
static int create_v2_trap_session (const char *, const char *);
static int create_v2_inform_session (const char *, const char *);
static void free_trap_session (struct trap_sink *sp);
static void send_v1_trap (struct snmp_session *, int, int);
static void send_v2_trap (struct snmp_session *, int, int, int);
*/
/*******************
*
* Trap session handling
*
*******************/
int add_trap_session( struct snmp_session *ss, int pdutype, int version )
{
struct trap_sink *new_sink =
(struct trap_sink *) malloc (sizeof (*new_sink));
if ( new_sink == NULL )
return 0;
new_sink->sesp = ss;
new_sink->pdutype = pdutype;
new_sink->version = version;
new_sink->next = sinks;
sinks = new_sink;
return 1;
}
int create_trap_session (char *sink,
char *com,
int version, int pdutype)
{
struct snmp_session session, *sesp;
memset (&session, 0, sizeof (struct snmp_session));
session.peername = sink;
session.version = version;
if (com) {
session.community = (u_char *)com;
session.community_len = strlen (com);
}
session.remote_port = SNMP_TRAP_PORT;
sesp = snmp_open (&session);
if (sesp) {
return( add_trap_session( sesp, pdutype, version ));
}
/* diagnose snmp_open errors with the input struct snmp_session pointer */
snmp_sess_perror("snmpd: create_trap_session", &session);
return 0;
}
static int create_v1_trap_session (char *sink,
char *com)
{
return create_trap_session( sink, com, SNMP_VERSION_1, SNMP_MSG_TRAP );
}
static int create_v2_trap_session (char *sink,
char *com)
{
return create_trap_session( sink, com, SNMP_VERSION_2c, SNMP_MSG_TRAP2 );
}
static int create_v2_inform_session (char *sink,
char *com)
{
return create_trap_session( sink, com, SNMP_VERSION_2c, SNMP_MSG_INFORM );
}
static void free_trap_session (struct trap_sink *sp)
{
snmp_close(sp->sesp);
free (sp);
}
void snmpd_free_trapsinks (void)
{
struct trap_sink *sp = sinks;
while (sp) {
sinks = sinks->next;
free_trap_session(sp);
sp = sinks;
}
}
/*******************
*
* Trap handling
*
*******************/
void send_trap_vars (int trap,
int specific,
struct variable_list *vars)
{
struct variable_list uptime_var, snmptrap_var, enterprise_var;
struct variable_list *v2_vars, *last_var=NULL;
struct snmp_pdu *template_pdu, *pdu;
struct timeval now;
int uptime;
struct sockaddr_in *pduIp;
struct trap_sink *sink;
/*
* Initialise SNMPv2 required variables
*/
gettimeofday(&now, NULL);
uptime = calculate_time_diff(&now, &starttime);
memset (&uptime_var, 0, sizeof (struct variable_list));
snmp_set_var_objid( &uptime_var, sysuptime_oid, OID_LENGTH(sysuptime_oid));
snmp_set_var_value( &uptime_var, (char *)&uptime, sizeof(uptime) );
uptime_var.type = ASN_TIMETICKS;
uptime_var.next_variable = &snmptrap_var;
memset (&snmptrap_var, 0, sizeof (struct variable_list));
snmp_set_var_objid( &snmptrap_var, snmptrap_oid, OID_LENGTH(snmptrap_oid));
/* value set later .... */
snmptrap_var.type = ASN_OBJECT_ID;
if ( vars )
snmptrap_var.next_variable = vars;
else
snmptrap_var.next_variable = &enterprise_var;
/* find end of provided varbind list,
ready to append the enterprise info if necessary */
last_var = vars;
while ( last_var && last_var->next_variable )
last_var = last_var->next_variable;
memset (&enterprise_var, 0, sizeof (struct variable_list));
snmp_set_var_objid( &enterprise_var,
snmptrapenterprise_oid, OID_LENGTH(snmptrapenterprise_oid));
snmp_set_var_value( &enterprise_var, (char *)version_id, sizeof(version_id));
enterprise_var.type = ASN_OBJECT_ID;
enterprise_var.next_variable = NULL;
v2_vars = &uptime_var;
/*
* Create a template PDU, ready for sending
*/
template_pdu = snmp_pdu_create( SNMP_MSG_TRAP );
if ( template_pdu == NULL )
return;
template_pdu->trap_type = trap;
template_pdu->specific_type = specific;
template_pdu->enterprise = version_id;
template_pdu->enterprise_length = OID_LENGTH(version_id);
template_pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY;
pduIp = (struct sockaddr_in *)&template_pdu->agent_addr;
pduIp->sin_family = AF_INET;
pduIp->sin_addr.s_addr = get_myaddr();
template_pdu->time = uptime;
/*
* Now use the parameters to determine
* which v2 variables are needed,
* and what values they should take.
*/
switch ( trap ) {
case -1: /*
* SNMPv2 only
* Check to see whether the variables provided
* are sufficient for SNMPv2 notifications
*/
if (vars && snmp_oid_compare(vars->name, vars->name_length,
sysuptime_oid, OID_LENGTH(sysuptime_oid)) == 0 )
v2_vars = vars;
else
if (vars && snmp_oid_compare(vars->name, vars->name_length,
snmptrap_oid, OID_LENGTH(snmptrap_oid)) == 0 )
uptime_var.next_variable = vars;
else {
/* Hmmm... we don't seem to have a value - oops! */
snmptrap_var.next_variable = vars;
}
last_var = NULL; /* Don't need enterprise info */
break;
/* "Standard" SNMPv1 traps */
case SNMP_TRAP_COLDSTART:
snmp_set_var_value( &snmptrap_var,
(char *)cold_start_oid,
sizeof(cold_start_oid));
break;
case SNMP_TRAP_WARMSTART:
snmp_set_var_value( &snmptrap_var,
(char *)warm_start_oid,
sizeof(warm_start_oid));
break;
case SNMP_TRAP_LINKDOWN:
snmp_set_var_value( &snmptrap_var,
(char *)link_down_oid,
sizeof(link_down_oid));
break;
case SNMP_TRAP_LINKUP:
snmp_set_var_value( &snmptrap_var,
(char *)link_up_oid,
sizeof(link_up_oid));
break;
case SNMP_TRAP_AUTHFAIL:
if (snmp_enableauthentraps == SNMP_AUTHENTICATED_TRAPS_DISABLED)
return;
snmp_set_var_value( &snmptrap_var,
(char *)auth_fail_oid,
sizeof(auth_fail_oid));
break;
case SNMP_TRAP_EGPNEIGHBORLOSS:
snmp_set_var_value( &snmptrap_var,
(char *)egp_xxx_oid,
sizeof(egp_xxx_oid));
break;
case SNMP_TRAP_ENTERPRISESPECIFIC:
/* Point to the ucdTrap subtree instead */
template_pdu->enterprise = objid_enterprisetrap;
template_pdu->enterprise_length = enterprisetrap_len -2;
snmp_set_var_value( &snmptrap_var,
(char *)objid_enterprisetrap,
sizeof(objid_enterprisetrap));
snmptrap_var.val.objid[ enterprisetrap_len-1 ] = specific;
snmptrap_var.next_variable = vars;
last_var = NULL; /* Don't need version info */
break;
}
/*
* Now loop through the list of trap sinks,
* sending an appropriately formatted PDU to each
*/
for ( sink = sinks ; sink ; sink=sink->next ) {
if ( sink->version == SNMP_VERSION_1 && trap == -1 )
continue; /* Skip v1 sinks for v2 only traps */
template_pdu->version = sink->version;
template_pdu->command = sink->pdutype;
if ( sink->version != SNMP_VERSION_1 ) {
template_pdu->variables = v2_vars;
if ( last_var )
last_var->next_variable = &enterprise_var;
}
else
template_pdu->variables = vars;
pdu = snmp_clone_pdu( template_pdu );
pdu->sessid = sink->sesp->sessid; /* AgentX only ? */
if ( snmp_send( sink->sesp, pdu) == 0 ) {
snmp_sess_perror ("snmpd: send_trap", sink->sesp);
snmp_free_pdu( pdu );
}
else
snmp_increment_statistic(STAT_SNMPOUTTRAPS);
if ( sink->version != SNMP_VERSION_1 && last_var )
last_var->next_variable = NULL;
}
}
void send_easy_trap (int trap,
int specific)
{
send_trap_vars( trap, specific, NULL );
}
void send_v2trap ( struct variable_list *vars)
{
send_trap_vars( -1, -1, vars );
}
void
send_trap_pdu(struct snmp_pdu *pdu)
{
send_trap_vars( -1, -1, pdu->variables );
}
/*******************
*
* Config file handling
*
*******************/
void snmpd_parse_config_authtrap(char *token,
char *cptr)
{
int i;
i = atoi(cptr);
if ( i == 0 ) {
if ( !strcmp( cptr, "enable" ))
i = SNMP_AUTHENTICATED_TRAPS_ENABLED;
else if ( !strcmp( cptr, "disable" ))
i = SNMP_AUTHENTICATED_TRAPS_DISABLED;
}
if (i < 1 || i > 2)
config_perror("authtrapenable must be 1 or 2");
else
snmp_enableauthentraps = i;
}
void snmpd_parse_config_trapsink(char *token,
char *cptr)
{
char tmpbuf[1024];
char *sp, *cp;
if (!snmp_trapcommunity) snmp_trapcommunity = strdup("public");
sp = strtok(cptr, " \t\n");
cp = strtok(NULL, " \t\n");
if (create_v1_trap_session(sp, cp ? cp : snmp_trapcommunity) == 0) {
sprintf(tmpbuf,"cannot create trapsink: %s", cptr);
config_perror(tmpbuf);
}
}
void
snmpd_parse_config_trap2sink(char *word, char *cptr)
{
char tmpbuf[1024];
char *sp, *cp;
if (!snmp_trapcommunity) snmp_trapcommunity = strdup("public");
sp = strtok(cptr, " \t\n");
cp = strtok(NULL, " \t\n");
if (create_v2_trap_session(sp, cp ? cp : snmp_trapcommunity) == 0) {
sprintf(tmpbuf,"cannot create trap2sink: %s", cptr);
config_perror(tmpbuf);
}
}
void
snmpd_parse_config_informsink(char *word, char *cptr)
{
char tmpbuf[1024];
char *sp, *cp;
if (!snmp_trapcommunity) snmp_trapcommunity = strdup("public");
sp = strtok(cptr, " \t\n");
cp = strtok(NULL, " \t\n");
if (create_v2_inform_session(sp, cp ? cp : snmp_trapcommunity) == 0) {
sprintf(tmpbuf,"cannot create informsink: %s", cptr);
config_perror(tmpbuf);
}
}
void
snmpd_parse_config_trapcommunity(char *word, char *cptr)
{
if (snmp_trapcommunity) free(snmp_trapcommunity);
snmp_trapcommunity = malloc (strlen(cptr)+1);
copy_word(cptr, snmp_trapcommunity);
}
void snmpd_free_trapcommunity (void)
{
if (snmp_trapcommunity) {
free(snmp_trapcommunity);
snmp_trapcommunity = NULL;
}
}