/*
 * snmptrapd.c - receive and log snmp traps
 *
 */
/***********************************************************
	Copyright 1989 by Carnegie Mellon University

                      All Rights Reserved

Permission to use, copy, modify, and distribute this software and its 
documentation for any purpose and without fee is hereby granted, 
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in 
supporting documentation, and that the name of CMU not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.  

CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/param.h>
#include <errno.h>
#include <syslog.h>

#include "snmp.h"
#include "asn1.h"
#include "snmp_impl.h"
#include "snmp_api.h"
#include "snmp_client.h"
#include "event.h"
#include "objectClass.h"

#ifndef BSD4_3
#define BSD4_2
#endif

#ifndef BSD4_3

typedef long	fd_mask;
#define NFDBITS	(sizeof(fd_mask) * NBBY)	/* bits per mask */

#define	FD_SET(n, p)	((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
#define	FD_CLR(n, p)	((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
#define	FD_ISSET(n, p)	((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
#define FD_ZERO(p)	bzero((char *)(p), sizeof(*(p)))
#endif

extern int  errno;
int	snmp_dump_packet = 0;
int Print = 0;
int Syslog = 0;

char *
trap_description(trap)
    int trap;
{
    switch(trap){
	case SNMP_TRAP_COLDSTART:
	    return "Cold Start";
	case SNMP_TRAP_WARMSTART:
	    return "Warm Start";
	case SNMP_TRAP_LINKDOWN:
	    return "Link Down";
	case SNMP_TRAP_LINKUP:
	    return "Link Up";
	case SNMP_TRAP_AUTHFAIL:
	    return "Authentication Failure";
	case SNMP_TRAP_EGPNEIGHBORLOSS:
	    return "EGP Neighbor Loss";
	case SNMP_TRAP_ENTERPRISESPECIFIC:
	    return "Enterprise Specific";
	default:
	    return "Unknown Type";
    }
}

char *
uptime_string(timeticks, buf)
    register u_long timeticks;
    char *buf;
{
    int	seconds, minutes, hours, days;

    timeticks /= 100;
    days = timeticks / (60 * 60 * 24);
    timeticks %= (60 * 60 * 24);

    hours = timeticks / (60 * 60);
    timeticks %= (60 * 60);

    minutes = timeticks / 60;
    seconds = timeticks % 60;

    if (days == 0){
	sprintf(buf, "%d:%02d:%02d", hours, minutes, seconds);
    } else if (days == 1) {
	sprintf(buf, "%d day, %d:%02d:%02d", days, hours, minutes, seconds);
    } else {
	sprintf(buf, "%d days, %d:%02d:%02d", days, hours, minutes, seconds);
    }
    return buf;
}

enterpriseSpecificTrap(ep, pdu)
    struct event *ep;
    struct snmp_pdu *pdu;
{
    struct objectClass *ocp;

    ocp = objectClassByName(pdu->enterprise, pdu->enterprise_length);
    if (!ocp)
	return NULL;
    switch(ocp->type){
	case CLASS_LANTERN:
	    lanternTrap(ep, pdu, ocp);
	    break;
	default:
	    return;
    }
}

lanternTrap(ep, pdu, ocp)
    struct event *ep;
    struct snmp_pdu *pdu;
    struct objectClass *ocp;
{
    char text[1024];
    struct variable_list *vars;
    int count, better = 0;
    static int utilization_handle = 0,
		error_handle = 0,
		collision_handle = 0,
		broadcast_handle = 0;
    struct timeval now;
    int value;

    gettimeofday(&now, (struct timezone *)NULL);		

    for (vars = pdu->variables, count = 0; vars && count < 3; vars = vars->next_variable, count++)
	;
    value = *(vars->val.integer);
    switch(pdu->specific_type){
	case 3:	/* dup IP addr */
	    ep->event_alarmType = PROCESSINGERROR;
	    ep->event_probableCause = CORRUPTDATA;
	    ep->event_specificProblem = pdu->specific_type + 10;
	    ep->event_perceivedSeverity = SEVERITY_WARNING;
	    ep->event_trendIndication = TREND_MORESEVERE; /* ??? */

	    ep->event_operState = STATE_UP;
	    ep->event_adminState = STATE_UP;

	    sprintf(text, "This event can be ignored unless problems are reported accessing the IP address given.");
	    ep->event_proposedRepairAction = (char *)malloc(strlen(text)+1);
	    ep->event_proposedRepairActionLength = strlen(text);
	    strcpy(ep->event_proposedRepairAction, text);

	    sprintf(text, "A duplicate IP address was discovered.  This could be a temporary routing problem, or more seriously, a misconfigured machine");
	    ep->event_problemText = (char *)malloc(strlen(text)+1);
	    ep->event_problemTextLength = strlen(text);
	    strcpy(ep->event_problemText, text);

	    ep->event_credibility = 1000;
	    event_add(ep, STATUS_NOTPENDING, now.tv_sec + 30);
	    break;
	case 4:	/* utilization */
	    if (value < 350)
		better = 1;
	    ep->event_alarmType = QUALITYOFSERVICEERROR;
	    ep->event_probableCause = BANDWIDTHREDUCED;
	    ep->event_specificProblem = pdu->specific_type + 10;
	    if (better){
		ep->event_perceivedSeverity = SEVERITY_CLEARED;
		ep->event_trendIndication = TREND_LESSSEVERE; /* ??? */
	    } else {
		ep->event_perceivedSeverity = SEVERITY_WARNING;
		ep->event_trendIndication = TREND_MORESEVERE; /* ??? */
	    }

	    ep->event_operState = STATE_UP;
	    ep->event_adminState = STATE_UP;

	    sprintf(text, "This event can be ignored unless problems are reported on the backbone.");
	    ep->event_proposedRepairAction = (char *)malloc(strlen(text)+1);
	    ep->event_proposedRepairActionLength = strlen(text);
	    strcpy(ep->event_proposedRepairAction, text);

	    if (better)
		sprintf(text, "The ethernet utilization has averaged %d%% for the last 10 seconds.  It has fallen below it's threshold of 35%% utilization", value/10);
	    else
		sprintf(text, "The ethernet utilization has averaged %d%% for the last 10 seconds.  The threshold is 35%%", value/10);
	    ep->event_problemText = (char *)malloc(strlen(text)+1);
	    ep->event_problemTextLength = strlen(text);
	    strcpy(ep->event_problemText, text);

	    if (better){
		ep->event_credibility = 1100;
		event_correlate(event_add(ep, STATUS_NOTPENDING, now.tv_sec + 900), utilization_handle);
	    } else {
		ep->event_credibility = 1000;
		utilization_handle = event_add(ep, STATUS_NOTPENDING, now.tv_sec + 900);
	    }
	    break;
	case 5:	/* errors */
	    if (value < 10)
		better = 1;
	    ep->event_alarmType = QUALITYOFSERVICEERROR;
	    ep->event_probableCause = RETRANSMISSIONRATEEXCESSIVE;
	    ep->event_specificProblem = pdu->specific_type + 10;
	    if (better){
		ep->event_perceivedSeverity = SEVERITY_CLEARED;
		ep->event_trendIndication = TREND_LESSSEVERE; /* ??? */
	    } else {
		ep->event_perceivedSeverity = SEVERITY_WARNING;
		ep->event_trendIndication = TREND_MORESEVERE; /* ??? */
	    }

	    ep->event_operState = STATE_UP;
	    ep->event_adminState = STATE_UP;

	    sprintf(text, "This event can be ignored unless problems are reported on the backbone.");
	    ep->event_proposedRepairAction = (char *)malloc(strlen(text)+1);
	    ep->event_proposedRepairActionLength = strlen(text);
	    strcpy(ep->event_proposedRepairAction, text);

	    if (better)
		sprintf(text, "The ethernet error rate has averaged %d%% for the last 10 seconds.  It has fallen below an upper threshold of 1%%", value/10);
	    else
		sprintf(text, "The ethernet error rate has averaged %d%% for the last 10 seconds.  It has risen above an upper threshold of 1%%", value/10);
	    ep->event_problemText = (char *)malloc(strlen(text)+1);
	    ep->event_problemTextLength = strlen(text);
	    strcpy(ep->event_problemText, text);

	    if (better){
		ep->event_credibility = 1100;
		event_correlate(event_add(ep, STATUS_NOTPENDING, now.tv_sec + 900), error_handle);
	    } else {
		ep->event_credibility = 1000;
		error_handle = event_add(ep, STATUS_NOTPENDING, now.tv_sec + 900);
	    }
	    break;
	case 6:	/* broadcasts */
	    if (value < 25)
		better = 1;
	    ep->event_alarmType = QUALITYOFSERVICEERROR;
	    ep->event_probableCause = QUEUESIZEEXCEEDED;
	    ep->event_specificProblem = pdu->specific_type + 10;
	    if (better){
		ep->event_perceivedSeverity = SEVERITY_CLEARED;
		ep->event_trendIndication = TREND_LESSSEVERE; /* ??? */
	    } else {
		ep->event_perceivedSeverity = SEVERITY_WARNING;
		ep->event_trendIndication = TREND_MORESEVERE; /* ??? */
	    }

	    ep->event_operState = STATE_UP;
	    ep->event_adminState = STATE_UP;

	    sprintf(text, "This event can be ignored unless problems are reported on the backbone.");
	    ep->event_proposedRepairAction = (char *)malloc(strlen(text)+1);
	    ep->event_proposedRepairActionLength = strlen(text);
	    strcpy(ep->event_proposedRepairAction, text);

	    if (better)
		sprintf(text, "The ethernet broadcast rate has averaged %d%% for the last 10 seconds.  It has fallen below an upper threshold of 2.5%%", value/10);
	    else
		sprintf(text, "The ethernet broadcast rate has averaged %d%% for the last 10 seconds.  It has risen above an upper threshold of 2.5%%", value/10);
	    ep->event_problemText = (char *)malloc(strlen(text)+1);
	    ep->event_problemTextLength = strlen(text);
	    strcpy(ep->event_problemText, text);

	    if (better){
		ep->event_credibility = 1100;
		event_correlate(event_add(ep, STATUS_NOTPENDING, now.tv_sec + 900), broadcast_handle);
	    } else {
		ep->event_credibility = 1000;
		broadcast_handle = event_add(ep, STATUS_NOTPENDING, now.tv_sec + 900);
	    }
	    break;
	case 7:	/* collisions */
	    if (value < 100)
		better = 1;
	    ep->event_alarmType = QUALITYOFSERVICEERROR;
	    ep->event_probableCause = RETRANSMISSIONRATEEXCESSIVE;
	    ep->event_specificProblem = pdu->specific_type + 10;
	    ep->event_perceivedSeverity = SEVERITY_WARNING;
	    ep->event_trendIndication = TREND_MORESEVERE; /* ??? */

	    ep->event_operState = STATE_UP;
	    ep->event_adminState = STATE_UP;

	    sprintf(text, "This event can be ignored unless problems are reported on the backbone.");
	    ep->event_proposedRepairAction = (char *)malloc(strlen(text)+1);
	    ep->event_proposedRepairActionLength = strlen(text);
	    strcpy(ep->event_proposedRepairAction, text);

	    if (better)
		sprintf(text, "The ethernet collision rate has averaged %d%% for the last 10 seconds.  It has fallen below an upper threshold of 10%%", value/10);
	    else
		sprintf(text, "The ethernet collision rate has averaged %d%% for the last 10 seconds.  It has risen above an upper threshold of 10%%", value/10);
	    sprintf(text, "More than 10%% of the packets experienced collisions in the last 10 seconds");
	    ep->event_problemText = (char *)malloc(strlen(text)+1);
	    ep->event_problemTextLength = strlen(text);
	    strcpy(ep->event_problemText, text);

	    if (better){
		ep->event_credibility = 1100;
		event_correlate(event_add(ep, STATUS_NOTPENDING, now.tv_sec + 900), collision_handle);
	    } else {
		ep->event_credibility = 1000;
		collision_handle = event_add(ep, STATUS_NOTPENDING, now.tv_sec + 900);
	    }
	    break;
	default:
	    return;
    }
}



trapEvent(pdu)
    struct snmp_pdu *pdu;
{
    struct event *ep;
    char text[1024], *cp;
    struct timeval now;
    struct variable_list *vars;

    gettimeofday(&now, (struct timezone *)NULL);

    ep = event_createNull();
    ep->event_objectClass = (oid *)malloc(pdu->enterprise_length * sizeof(oid));
    ep->event_objectClassLength = pdu->enterprise_length * sizeof(oid);
    bcopy((char *)pdu->enterprise, (char *)ep->event_objectClass, ep->event_objectClassLength);

    ep->event_objectInstance = (u_char *)malloc(sizeof(pdu->agent_addr.sin_addr.s_addr));
    ep->event_objectInstanceLength = sizeof(pdu->agent_addr.sin_addr.s_addr);
    bcopy((char *)&pdu->agent_addr.sin_addr.s_addr, (char *)ep->event_objectInstance, sizeof(pdu->agent_addr.sin_addr.s_addr));

    ep->event_time = now.tv_sec;
    ep->event_backUpStatus = BACKUP_UNKNOWN;
    ep->event_backUpObjectInstanceLength = 0;
    ep->event_correlatedNotificationsLength = 0;

    cp = text;
    for(vars = pdu->variables; vars; vars = vars->next_variable){
	sprint_variable(cp, vars->name, vars->name_length, vars);
	cp += strlen(cp);
    }
    ep->event_problemData = (u_char *)malloc(strlen(text)+1);
    ep->event_problemDataLength = strlen(text);
    strcpy(ep->event_problemData, text);
    

    if (pdu->trap_type == SNMP_TRAP_COLDSTART || pdu->trap_type == SNMP_TRAP_WARMSTART
	|| pdu->trap_type == SNMP_TRAP_LINKUP){
	ep->event_alarmType = COMMUNICATIONERROR;
	ep->event_probableCause = LOSSOFSIGNAL;
	ep->event_specificProblem = pdu->trap_type;
	ep->event_perceivedSeverity = SEVERITY_CLEARED;
	ep->event_trendIndication = TREND_LESSSEVERE; /* ??? */

	ep->event_operState = STATE_UP;
	ep->event_adminState = STATE_UP;

	sprintf(text, "This condition seems to have repaired itself");
	ep->event_proposedRepairAction = (char *)malloc(strlen(text)+1);
	ep->event_proposedRepairActionLength = strlen(text);
	strcpy(ep->event_proposedRepairAction, text);

	sprintf(text, "%s has reported that %s .", inet_ntoa(pdu->agent_addr.sin_addr /* .s_addr */),
	    pdu->trap_type == SNMP_TRAP_COLDSTART ? "it has just performed a cold reboot" :
	    pdu->trap_type == SNMP_TRAP_WARMSTART ? "it has just performed a warm reboot" :
	    "it's link has just become operational");
	ep->event_problemText = (char *)malloc(strlen(text)+1);
	ep->event_problemTextLength = strlen(text);
	strcpy(ep->event_problemText, text);

	ep->event_credibility = 2700;
	event_add(ep, STATUS_NOTPENDING, now.tv_sec + 900);
    } else if (pdu->trap_type == SNMP_TRAP_LINKDOWN || pdu->trap_type == SNMP_TRAP_EGPNEIGHBORLOSS){
	ep->event_alarmType = COMMUNICATIONERROR;
	ep->event_probableCause = LOSSOFSIGNAL;
	ep->event_specificProblem = pdu->trap_type;
	ep->event_perceivedSeverity = SEVERITY_CRITICAL;
	ep->event_trendIndication = TREND_MORESEVERE; /* ??? */

	ep->event_operState = STATE_UP;
	ep->event_adminState = STATE_UP;

	sprintf(text, "Check to see if all interfaces on %s are up.  If not, reset or power-cycle it.  This is probably a beaconing token ring so a technician may need to be dispatched to fix the ring", inet_ntoa(pdu->agent_addr.sin_addr /* .s_addr */));
	ep->event_proposedRepairAction = (char *)malloc(strlen(text)+1);
	ep->event_proposedRepairActionLength = strlen(text);
	strcpy(ep->event_proposedRepairAction, text);

	sprintf(text, "%s has reported that %s .", inet_ntoa(pdu->agent_addr.sin_addr /* .s_addr */),
	    pdu->trap_type == SNMP_TRAP_LINKDOWN ? "it's link has just gone down" :
	    "it's EGP peer has gone down");
	ep->event_problemText = (char *)malloc(strlen(text)+1);
	ep->event_problemTextLength = strlen(text);
	strcpy(ep->event_problemText, text);

	ep->event_credibility = 2700;
	event_add(ep, STATUS_NOTPENDING, now.tv_sec + 900);
    } else if (pdu->trap_type == SNMP_TRAP_AUTHFAIL){
	ep->event_alarmType = PROCESSINGERROR;
	ep->event_probableCause = CORRUPTDATA;
	ep->event_specificProblem = pdu->trap_type;
	ep->event_perceivedSeverity = SEVERITY_MINOR;
	ep->event_trendIndication = TREND_MORESEVERE; /* ??? */

	ep->event_operState = STATE_UP;
	ep->event_adminState = STATE_UP;

	sprintf(text, "This can be ignored unless it seems as if persistent attempts are being made to break security.");
	ep->event_proposedRepairAction = (char *)malloc(strlen(text)+1);
	ep->event_proposedRepairActionLength = strlen(text);
	strcpy(ep->event_proposedRepairAction, text);

	sprintf(text, "An SNMP authentication failure occured on %s.", inet_ntoa(pdu->agent_addr.sin_addr /* .s_addr */));
	ep->event_problemText = (char *)malloc(strlen(text)+1);
	ep->event_problemTextLength = strlen(text);
	strcpy(ep->event_problemText, text);

	ep->event_credibility = 2700;
	event_add(ep, STATUS_NOTPENDING, now.tv_sec + 900);
    } else if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC){
	enterpriseSpecificTrap(ep, pdu);
    }
}



int snmp_input(op, session, reqid, pdu, magic)
    int op;
    struct snmp_session *session;
    int reqid;
    struct snmp_pdu *pdu;
    void *magic;
{
    struct variable_list *vars;
    char buf[64];

    if (op == RECEIVED_MESSAGE && pdu->command == TRP_REQ_MSG){
	if (Print){
	    printf("%s: %s Trap (%d) Uptime: %s\n", inet_ntoa(pdu->agent_addr.sin_addr /* .s_addr */),
		trap_description(pdu->trap_type), pdu->specific_type, uptime_string(pdu->time, buf));
	    for(vars = pdu->variables; vars; vars = vars->next_variable)
		print_variable(vars->name, vars->name_length, vars);
	}
	if (Syslog){
	    syslog(LOG_WARNING, "%s: %s Trap (%d) Uptime: %s\n", inet_ntoa(pdu->agent_addr.sin_addr /* .s_addr */),
		trap_description(pdu->trap_type), pdu->specific_type, uptime_string(pdu->time, buf));
	}
	trapEvent(pdu);
    } else if (op == TIMED_OUT){
	printf("Timeout: This shouldn't happen!\n");
    }
}


main(argc, argv)
    int	    argc;
    char    *argv[];
{
    struct snmp_session session, *ss;
    int	arg;
    int count, numfds, block;
    fd_set fdset;
    struct timeval timeout, *tvp;
    int sd;
    struct sockaddr_in me;
    struct timeval now;


    init_syslog();
    init_mib();
    /*
     * usage: snmptrapd [-p]
     */
    for(arg = 1; arg < argc; arg++){
	if (argv[arg][0] == '-'){
	    switch(argv[arg][1]){
		case 'd':
		    snmp_dump_packet++;
		    break;
		case 'p':
		    Print++;
		    break;
		case 's':
		    Syslog++;
		    break;
		default:
		    printf("invalid option: -%c\n", argv[arg][1]);
		    printf("Usage: snmptrapd [-p ]\n");
		    break;
	    }
	    continue;
	}
    }

    bzero((char *)&session, sizeof(struct snmp_session));
    session.peername = NULL;
    session.community = NULL;
    session.community_len = 0;
    session.retries = SNMP_DEFAULT_RETRIES;
    session.timeout = SNMP_DEFAULT_TIMEOUT;
    session.authenticator = NULL;
    session.callback = snmp_input;
    session.callback_magic = NULL;
    session.local_port = SNMP_TRAP_PORT;
    ss = snmp_open(&session);
    if (ss == NULL){
	printf("Couldn't open snmp\n");
	exit(-1);
    }

    /* Set up connections */
    sd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sd < 0){
	perror("socket");
	return 0;
    }
    me.sin_family = AF_INET;
    me.sin_addr.s_addr = INADDR_ANY;
    me.sin_port = htons(163);
    if (bind(sd, (struct sockaddr *)&me, sizeof(me)) != 0){
	perror("bind");
	return 0;
    }

    while(1){
	gettimeofday(&now, (struct timezone *)NULL);
	event_timer(now.tv_sec);
	numfds = sd + 1;
	FD_ZERO(&fdset);
	FD_SET(sd, &fdset);
	block = 0;
	tvp = &timeout;
	timerclear(tvp);
	tvp->tv_sec = 15;
	snmp_select_info(&numfds, &fdset, tvp, &block);
	if (block == 1)
	    tvp = NULL;	/* block without timeout */
	count = select(numfds, &fdset, 0, 0, tvp);
	if (count > 0){
	    if (FD_ISSET(sd, &fdset))
		snmp_agent_read(sd);
	    else
		snmp_read(&fdset);
	} else switch(count){
	    case 0:
		snmp_timeout();
		break;
	    case -1:
		if (errno == EINTR){
		    continue;
		} else {
		    perror("select");
		}
		return -1;
	    default:
		printf("select returned %d\n", count);
		return -1;
	}
    }
}

snmp_agent_read(sd)
    int sd;
{
    struct sockaddr_in	from;
    int length, out_length, fromlength;
    u_char  packet[4500], outpacket[4500];

    fromlength = sizeof from;
    length = recvfrom(sd, packet, 4500, 0, (struct sockaddr *)&from, &fromlength);
    if (length == -1)
	perror("recvfrom");
    if (snmp_dump_packet){
	int count;

	printf("recieved %d bytes from %s:\n", length, inet_ntoa(from.sin_addr /* .s_addr */));
	for(count = 0; count < length; count++){
	    printf("%02X ", packet[count]);
	    if ((count % 16) == 15)
		printf("\n");
	}
	printf("\n\n");
    }
    out_length = 4500;
    if (snmp_agent_parse(packet, length, outpacket, &out_length, from.sin_addr)){
	if (snmp_dump_packet){
	    int count;

	    printf("sent %d bytes to %s:\n", out_length, inet_ntoa(from.sin_addr /*.s_addr */));
	    for(count = 0; count < out_length; count++){
		printf("%02X ", outpacket[count]);
		if ((count % 16) == 15)
		    printf("\n");
	    }
	    printf("\n\n");
	}
	if (sendto(sd, (char *)outpacket, out_length, 0, (struct sockaddr *)&from,
	    sizeof(from)) < 0){
		perror("sendto");
		return 0;
	}

    }
    
}
init_syslog(){
/*
 * These definitions handle 4.2 systems without additional syslog facilities.
 */
#ifndef LOG_CONS
#define LOG_CONS	0	/* Don't bother if not defined... */
#endif
#ifndef LOG_LOCAL0
#define LOG_LOCAL0	0
#endif
    /*
     * All messages will be logged to the local0 facility and will be sent to
     * the console if syslog doesn't work.
     */
    openlog("snmptrapd", LOG_CONS, LOG_LOCAL0);
    syslog(LOG_INFO, "Starting snmptrapd");
}
