From 9f4eac6af5c6a145e3fa3e1545bc0e3bc6774ee8 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Wed, 29 Mar 2006 22:37:35 +0000 Subject: Initial import --- AUTHORS | 1 + COPYING | 38 +++ ChangeLog | 0 Makefile.am | 4 + NEWS | 1 + README | 0 configure.in | 40 +++ module/Makefile.am | 16 + module/bsnmp-ping.c | 832 +++++++++++++++++++++++++++++++++++++++++++++++++++ module/ping-tree.def | 26 ++ module/usuals.h | 32 ++ 11 files changed, 990 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 configure.in create mode 100644 module/Makefile.am create mode 100644 module/bsnmp-ping.c create mode 100644 module/ping-tree.def create mode 100644 module/usuals.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..0cc01a2 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +nielsen@memberwebs.com \ No newline at end of file diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..a636b2c --- /dev/null +++ b/COPYING @@ -0,0 +1,38 @@ +LICENSE + +Copyright (c) 2004, Nate Nielsen +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + * 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. + * The names of contributors to this software may not be + used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 +COPYRIGHT OWNER OR CONTRIBUTORS 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. + + +SUPPORT + +Send bug reports to: + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..9bb1356 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,4 @@ +# EXTRA_DIST = BUGS +SUBDIRS = module + + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..c7ab92a --- /dev/null +++ b/NEWS @@ -0,0 +1 @@ +See ChangeLog \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..e69de29 diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..eae4aaa --- /dev/null +++ b/configure.in @@ -0,0 +1,40 @@ +# Process this file with autoconf to produce a configure script. +AC_INIT(bsnmp-ping, 0.1, nielsen@memberwebs.com) +AM_INIT_AUTOMAKE(bsnmp-ping, 0.1) + +AC_CONFIG_SRCDIR([module/bsnmp-ping.c]) +AM_CONFIG_HEADER([config.h]) + +LDFLAGS="$LDFLAGS -L/usr/local/lib" +CFLAGS="$CFLAGS -I/usr/local/include" + +# Checks for programs. +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LIBTOOL + +# Debug mode +AC_ARG_ENABLE(debug, + AC_HELP_STRING([--enable-debug], + [Compile binaries in debug mode])) + +if test "$enable_debug" = "yes"; then + CFLAGS="$CFLAGS -g -O0 -Wall" + AC_DEFINE_UNQUOTED(_DEBUG, 1, [In debug mode]) + echo "enabling debug compile mode" +fi + +# Checks for header files. +AC_HEADER_STDC + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_MEMCMP +dnl TODO AC_CHECK_FUNCS([atexit inet_ntoa inet_pton memset strerror strspn strtol]) + +AC_CONFIG_FILES([Makefile module/Makefile]) +AC_OUTPUT diff --git a/module/Makefile.am b/module/Makefile.am new file mode 100644 index 0000000..c1b6d41 --- /dev/null +++ b/module/Makefile.am @@ -0,0 +1,16 @@ + +INCLUDES = -DCONF_PREFIX=\"$(sysconfdir)\" + +moduledir = $(prefix)/lib +module_LTLIBRARIES = snmp_ping.la + +snmp_ping_la_LDFLAGS = -module +snmp_ping_la_SOURCES = ping_tree.c ping_tree.h ping_oid.h \ + bsnmp-ping.c + +ping_tree.c: ping-tree.def + gensnmptree -p ping_ < ping-tree.def + gensnmptree -e pingData > ping_oid.h < ping-tree.def + +CLEANFILES = ping_tree.* \ + ping_oid.h diff --git a/module/bsnmp-ping.c b/module/bsnmp-ping.c new file mode 100644 index 0000000..029acdb --- /dev/null +++ b/module/bsnmp-ping.c @@ -0,0 +1,832 @@ +/* + * Copyright (c) 2006, Nate Nielsen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * 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. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 + * COPYRIGHT OWNER OR CONTRIBUTORS 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. + * + * + * CONTRIBUTORS + * Nate Nielsen + */ + +#include "usuals.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "ping_tree.h" +#include "ping_oid.h" + +/* our module handle */ +static struct lmodule *module; + +/* OIDs */ +static const struct asn_oid oid_ping = OIDX_pingData; + +/* the Object Resource registration index */ +static u_int reg_index = 0; + +enum { + RESPONSE_ERR = -1, + RESPONSE_NONE = 0, + RESPONSE_REPLY = 1 +}; + +#define A(t, bit) (t)[(bit)>>3] /* identify byte in array */ +#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ +#define SET(t, bit) (A((t), bit) |= B(bit)) +#define CLR(t, bit) (A((t), bit) &= (~B(bit))) +#define TST(t, bit) (A((t), bit) & B(bit)) +#define MAX_DUP_CHK 8 * 64 + +struct pinger { + uint32_t index; + TAILQ_ENTRY(pinger) link; + + /* Configuration */ + u_char *host; + struct sockaddr_in addr; + u_int interval; + u_int history; + + /* Stats gathered */ + u_int at; + int *latencies; + + /* For generating and filtering pings */ + void *timer; + u_int transmitted; + u_int received; + char ck_table[MAX_DUP_CHK / 8]; +}; + +TAILQ_HEAD(pinger_list, pinger); + +/* list of regexes */ +static struct pinger_list pingers = TAILQ_HEAD_INITIALIZER(pingers); +static u_int pinger_count = 0; + +/* The ICMP socket */ +static int icmp_sock = -1; +static void *icmp_sel = NULL; + +/* The ICMP packet */ +static u_char icmp_packet[IP_MAXPACKET]; + +/* ----------------------------------------------------------------------------- + * HELPERS + */ + +static void +emsg(const char *format, ...) +{ + va_list va; + va_start(va, format); + vsyslog(LOG_ERR, format, va); + va_end(va); +} + +/* ----------------------------------------------------------------------------- + * ICMP STUFF + */ + +static void +process_icmp (u_char *packet, int len, struct sockaddr_in *from) +{ + struct pinger *ping; + struct icmp *icp; + struct ip *ip; + uint64_t ptime; + uint64_t ctime; + const void *tp; + int triptime; + int hlen, seq; + + /* Check the IP header */ + ip = (struct ip*)packet; + hlen = ip->ip_hl << 2; + if (len < hlen + ICMP_MINLEN) + return; + + /* Now the ICMP part */ + len -= hlen; + icp = (struct icmp *)(packet + hlen); + + if (icp->icmp_type != ICMP_ECHOREPLY) + return; /* An error or some such */ + + for (ping = TAILQ_FIRST (&pingers); ping; + ping = TAILQ_NEXT (ping, link)) { + if (ping->index == icp->icmp_id) + break; + } + + if (!ping) + return; /* 'Twas not our ECHO */ + + seq = ntohs (icp->icmp_seq); + if (TST (ping->ck_table, seq % MAX_DUP_CHK)) + return; + SET(ping->ck_table, seq % MAX_DUP_CHK); + seq %= ping->history; + + ping->received++; + triptime = -1; + + + ctime = get_ticks (); + +#ifndef icmp_data + tp = &icp->icmp_ip; +#else + tp = icp->icmp_data; +#endif + if (len - ICMP_MINLEN >= sizeof (ptime)) { + /* Copy to avoid alignment problems: */ + memcpy(&ptime, tp, sizeof(ptime)); + triptime = ((int)(ctime - ptime)); + + /* Some small rounding adjustments */ + if (triptime == 0) + triptime = 1; + if (triptime < 0) + triptime = 0; + } + + if (ping->latencies) + ping->latencies[seq] = triptime; +} + +static void +close_socket () +{ + if (icmp_sel) + fd_deselect (icmp_sel); + icmp_sel = NULL; + + if (icmp_sock != -1) + close (icmp_sock); + icmp_sock = -1; +} + +static void +io_icmp (int fd, void *unused) +{ + struct sockaddr_in from; + socklen_t fromlen; + int len; + + ASSERT (fd == icmp_sock); + + fromlen = sizeof (from); + len = recvfrom (icmp_sock, icmp_packet, sizeof (icmp_packet), 0, + (struct sockaddr*)&from, &fromlen); + if (len < 0) { + if (errno == EINTR) + return; + emsg ("couldn't receive packet: %s", strerror (errno)); + } + + process_icmp (icmp_packet, len, &from); +} + +static int +open_socket () +{ + int hold; + + close_socket (); + + icmp_sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (icmp_sock == -1) { + emsg ("couldn't open ICMP socket: %s", strerror (errno)); + return errno; + } + + hold = IP_MAXPACKET + 128; + setsockopt(icmp_sock, SOL_SOCKET, SO_RCVBUF, (char*)&hold, sizeof(hold)); + setsockopt(icmp_sock, SOL_SOCKET, SO_SNDBUF, (char*)&hold, sizeof(hold)); + + icmp_sel = fd_select (icmp_sock, io_icmp, NULL, module); + if (!icmp_sel) { + emsg ("couldn't listen on ICMP socket: %s", strerror (errno)); + return errno; + } + + return 0; +} + +static u_short +in_cksum (u_short *addr, int len) +{ + int nleft, sum; + u_short *w; + union { + u_short us; + u_char uc[2]; + } last; + u_short answer; + + nleft = len; + sum = 0; + w = addr; + + while (nleft > 1) { + sum += *w++; + nleft -= 2; + } + + /* mop up an odd byte, if necessary */ + if (nleft == 1) { + last.uc[0] = *(u_char *)w; + last.uc[1] = 0; + sum += last.us; + } + + /* add back carry outs from top 16 bits to low 16 bits */ + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + answer = ~sum; /* truncate to 16 bits */ + return answer ; +} + + +static void +ping_fire (void *user_data) +{ + struct pinger *ping = (struct pinger*)user_data; + uint64_t ptime; + struct icmp *icp; + int cc, i, seq; + + memset (icmp_packet, 0, sizeof (icmp_packet)); + + ping->at = (ping->at + ((ping->transmitted > 1) ? 1 : 0)) % ping->history; + seq = ping->transmitted; + ASSERT (ping->transmitted == 0 || + (ping->transmitted % ping->history) == ((ping->at + 1) % ping->history)); + + if (ping->latencies) + ping->latencies[seq % ping->history] = -1; + + icp = (struct icmp*)icmp_packet; + icp->icmp_type = ICMP_ECHO; + icp->icmp_code = 0; + icp->icmp_cksum = 0; + icp->icmp_seq = htons (seq); + icp->icmp_id = ping->index; /* ID */ + + /* Include the current time in the packet */ + ptime = get_ticks (); + memcpy (icmp_packet + ICMP_MINLEN, &ptime, sizeof (ptime)); + + CLR (ping->ck_table, seq % MAX_DUP_CHK); + + /* compute ICMP checksum here */ + cc = ICMP_MINLEN + sizeof (ptime); + icp->icmp_cksum = in_cksum ((u_short *)icp, cc); + + i = sendto(icmp_sock, icmp_packet, cc, 0, (struct sockaddr*)&(ping->addr), + sizeof (ping->addr)); + + if (i < 0) + emsg ("couldn't send ICMP packet to: %s: %s", ping->host, strerror (errno)); + else if (i != cc) + emsg ("partial write sending ICMP packet to: %", ping->host); + + ping->transmitted++; + + ping->timer = timer_start (ping->interval, ping_fire, ping, module); + if (!ping->timer) + emsg ("couldn't setup timer to ping host: %s", ping->host); +} + +static void +ping_stop () +{ + struct pinger *ping; + + for (ping = TAILQ_FIRST (&pingers); ping; + ping = TAILQ_NEXT (ping, link)) { + + if (ping->timer) + timer_stop (ping->timer); + ping->timer = NULL; + + memset (ping->ck_table, 0, sizeof (ping->ck_table)); + ping->transmitted = 0; + + if (ping->latencies) + memset (ping->latencies, 0, sizeof (u_int) * ping->history); + } +} + +static void +ping_start () +{ + struct pinger *ping; + + ping_stop (); + + for (ping = TAILQ_FIRST (&pingers); ping; + ping = TAILQ_NEXT (ping, link)) { + + /* Need to have an address configured */ + if (!ping->host || !ping->host[0]) + return; + + /* Allocate memory where needed */ + if (!ping->latencies) + ping->latencies = (u_int*)calloc (ping->history, sizeof (u_int)); + if (!ping->latencies) { + emsg ("out of memory"); + continue; + } + + ping->at = 0; + + ping_fire (ping); + } +} + +/* ----------------------------------------------------------------------------- + * CALLBACKS/CONFIG + */ + +static int +calc_average (struct pinger *ping) +{ + double sum = 0; + double num = 0; + int i; + + if (!ping->latencies) + return -1; + + for (i = 0; i < ping->history; i++) { + + /* If not wrapped around yet, then don't wrap around */ + if (ping->transmitted <= ping->history && i >= ping->at) + break; + if (ping->latencies[i] < 0) + continue; + + sum += ping->latencies[i]; + num ++; + } + + return num ? (sum / num) : 0; +} + +static int +calc_minimum (struct pinger *ping) +{ + int min = -1; + int i; + + if (!ping->latencies) + return -1; + + for (i = 0; i < ping->history; i++) { + + /* If not wrapped around yet, then don't wrap around */ + if (ping->transmitted <= ping->history && i >= ping->at) + break; + + if (ping->latencies[i] < 0) + continue; + if (min > 0 && min < ping->latencies[i]) + continue; + + min = ping->latencies[i]; + } + + return min > 0 ? min : 0; +} + +static int +calc_maximum (struct pinger *ping) +{ + int max = -1; + int i; + + if (!ping->latencies) + return -1; + + for (i = 0; i < ping->history; i++) { + + /* If not wrapped around yet, then don't wrap around */ + if (ping->transmitted <= ping->history && i >= ping->at) + break; + if (ping->latencies[i] < 0) + continue; + if (max > ping->latencies[i]) + continue; + + max = ping->latencies[i]; + } + + return max > 0 ? max : 0; +} + +static int +calc_responses (struct pinger *ping) +{ + u_int num = 0; + int i; + + if (!ping->latencies) + return -1; + + for (i = 0; i < ping->history; i++) { + + /* If not wrapped around yet, then don't wrap around */ + if (ping->transmitted <= ping->history && i >= ping->at) + break; + if (ping->latencies[i] < 0) + continue; + + num ++; + } + + return num; +} + +static int +calc_dropped (struct pinger *ping) +{ + u_int num = 0; + int i; + + if (!ping->latencies) + return -1; + + for (i = 0; i < ping->history; i++) { + + /* If not wrapped around yet, then don't wrap around */ + if (ping->transmitted <= ping->history && i >= ping->at) + break; + if (ping->latencies[i] >= 0) + continue; + + num++; + } + + return num; +} + + +static void +free_pinger (struct pinger *ping) +{ + if (ping->host) + free (ping->host); + ping->host = NULL; + + if (ping->latencies) + free (ping->latencies); + ping->latencies = NULL; + + TAILQ_REMOVE (&pingers, ping, link); + free (ping); +} + +static struct pinger* +alloc_pinger (u_int index) +{ + struct pinger *ping; + + ping = (struct pinger*)calloc (1, sizeof (struct pinger)); + if (!ping) + return NULL; + + ping->host = strdup (""); + if (!ping->host) { + free (ping); + return NULL; + } + + ping->interval = 100; + ping->history = 5; + ping->index = index; + ping->addr.sin_family = AF_INET; + ping->addr.sin_len = sizeof (ping->addr); + ping->addr.sin_port = 0; + + INSERT_OBJECT_INT (ping, &pingers); + return ping; +} + +static int +ping_config (struct pinger *ping, struct snmp_context *ctx, + struct snmp_value *value, u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + int index, r; + + /* Just return values, no creation */ + if (op == SNMP_OP_GET || op == SNMP_OP_GETNEXT) { + + if (!ping) + return SNMP_ERR_NOSUCHNAME; + + switch (which) { + case LEAF_pingIndex: + value->v.integer = ping->index; + return SNMP_ERR_NOERROR; + case LEAF_pingHost: + return string_get (value, ping->host, -1); + case LEAF_pingHistory: + value->v.integer = ping->history; + return SNMP_ERR_NOERROR; + case LEAF_pingInterval: + value->v.integer = ping->interval; + return SNMP_ERR_NOERROR; + default: + ASSERT (0); + return SNMP_ERR_NOSUCHNAME; + } + } + + /* Remainder only at initialization */ + if (community != COMM_INITIALIZE) + return ping ? SNMP_ERR_NOT_WRITEABLE : SNMP_ERR_NO_CREATION; + + /* No writing to pingIndex */ + if (which == LEAF_pingIndex) + return SNMP_ERR_NOT_WRITEABLE; + + if (index_decode (&value->var, sub, iidx, &index)) + return SNMP_ERR_NO_CREATION; + + /* Create it if necessary */ + if (!ping) { + ping = alloc_pinger (index); + if (!ping) { + emsg ("out of memory"); + return SNMP_ERR_GENERR; + } + } + + switch (which) { + + /* pingHistory */ + case LEAF_pingHistory: + switch (op) { + case SNMP_OP_SET: + ctx->scratch->int1 = ping->history; + ping->history = value->v.integer; + return SNMP_ERR_NOERROR; + case SNMP_OP_ROLLBACK: + ping->history = ctx->scratch->int1; + return SNMP_ERR_NOERROR; + case SNMP_OP_COMMIT: + return SNMP_ERR_NOERROR; + default: + ASSERT (0); + return SNMP_ERR_GENERR; + } + break; + + /* pingInterval */ + case LEAF_pingInterval: + switch (op) { + case SNMP_OP_SET: + ctx->scratch->int1 = ping->interval; + ping->interval = value->v.integer; + return SNMP_ERR_NOERROR; + case SNMP_OP_ROLLBACK: + ping->interval = ctx->scratch->int1; + return SNMP_ERR_NOERROR; + case SNMP_OP_COMMIT: + return SNMP_ERR_NOERROR; + default: + ASSERT (0); + return SNMP_ERR_GENERR; + } + break; + + /* pingHost */ + case LEAF_pingHost: + switch (op) { + case SNMP_OP_SET: + if ((r = string_save (value, ctx, -1, &ping->host)) == SNMP_ERR_NOERROR) { + if (!inet_aton (ping->host, &(ping->addr.sin_addr))) + r = SNMP_ERR_WRONG_VALUE; + } + if (r != SNMP_ERR_NOERROR) + string_rollback (ctx, &ping->host); + return r; + case SNMP_OP_ROLLBACK: + string_rollback (ctx, &ping->host); + inet_aton (ping->host, &(ping->addr.sin_addr)); + return SNMP_ERR_NOERROR; + case SNMP_OP_COMMIT: + string_commit (ctx); + return SNMP_ERR_NOERROR; + default: + ASSERT (0); + return SNMP_ERR_GENERR; + } + break; + + /* Unknown OID */ + default: + ASSERT (0); + return SNMP_ERR_NOSUCHNAME; + } +} + +int +op_pingentry (struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + struct pinger *ping = NULL; + + switch (op) { + case SNMP_OP_GETNEXT: + ping = NEXT_OBJECT_INT (&pingers, &value->var, sub); + if (ping == NULL) + return SNMP_ERR_NOSUCHNAME; + value->var.len = sub + 1; + value->var.subs[sub] = ping->index; + break; + + case SNMP_OP_GET: + ping = FIND_OBJECT_INT (&pingers, &value->var, sub); + if (ping == NULL) + return SNMP_ERR_NOSUCHNAME; + break; + + default: + ping = FIND_OBJECT_INT (&pingers, &value->var, sub); + break; + } + + /* Send configuration stuff off elsewhere */ + switch (which) { + case LEAF_pingIndex: + case LEAF_pingHost: + case LEAF_pingHistory: + case LEAF_pingInterval: + return ping_config (ping, ctx, value, sub, iidx, op); + } + + if (op != SNMP_OP_GET && op != SNMP_OP_GETNEXT) + return SNMP_ERR_NOT_WRITEABLE; + + switch (which) { + case LEAF_pingLatencyAvg: + value->v.integer = calc_average (ping); + return SNMP_ERR_NOERROR; + case LEAF_pingLatencyMin: + value->v.integer = calc_minimum (ping); + return SNMP_ERR_NOERROR; + case LEAF_pingLatencyMax: + value->v.integer = calc_maximum (ping); + return SNMP_ERR_NOERROR; + case LEAF_pingResponses: + value->v.integer = calc_responses (ping); + return SNMP_ERR_NOERROR; + case LEAF_pingDropped: + value->v.integer = calc_dropped (ping); + return SNMP_ERR_NOERROR; + default: + ASSERT (0); + return SNMP_ERR_NOSUCHNAME; + } +} + +int +op_ping (struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + + switch (op) { + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return SNMP_ERR_NOT_WRITEABLE; + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + return SNMP_ERR_NOERROR; + + default: + ASSERT(0); + break; + } + + switch (which) { + case LEAF_pingCount: + value->v.integer = pinger_count; + break; + + default: + ASSERT(0); + break; + } + + return SNMP_ERR_NOERROR; +} + + +/* ----------------------------------------------------------------------------- + * MODULE + */ + +/* the initialisation function */ +static int +module_init (struct lmodule *mod, int argc, char *argv[]) +{ + module = mod; + + if (argc != 0) { + syslog(LOG_ERR, "bad number of arguments for %s", __func__); + return EINVAL; + } + + return open_socket (); +} + +/* Module is started */ +static void +module_start (void) +{ + reg_index = or_register (&oid_ping, "The MIB for ping data.", module); + + /* Start timers on them all */ + ping_start (); +} + +/* Called, when the module is to be unloaded after it was successfully loaded */ +static int +module_fini (void) +{ + struct pinger *ping; + + if (reg_index) + or_unregister (reg_index); + + while ((ping = TAILQ_FIRST(&pingers)) != NULL) + free_pinger (ping); + + return 0; +} + +const struct snmp_module config = { + .comment = "This module implements SNMP listing of ping responses and latencies", + .init = module_init, + .start = module_start, + .fini = module_fini, + .tree = ping_ctree, + .tree_size = ping_CTREE_SIZE, +}; diff --git a/module/ping-tree.def b/module/ping-tree.def new file mode 100644 index 0000000..3d50578 --- /dev/null +++ b/module/ping-tree.def @@ -0,0 +1,26 @@ +(1 internet + (4 private + (1 enterprises + (12325 fokus + (1 begemot + (204 pingData + (0 pingCount INTEGER op_ping GET) + (1 pingEntry : INTEGER op_pingentry + (0 pingIndex INTEGER GET) + + (1 pingHost OCTETSTRING GET SET) + (2 pingInterval TIMETICKS GET SET) + (3 pingHistory INTEGER GET SET) + + (10 pingResponses INTEGER GET) + (11 pingDropped INTEGER GET) + (12 pingLatencyAvg TIMETICKS GET) + (13 pingLatencyMin TIMETICKS GET) + (14 pingLatencyMax TIMETICKS GET) + ) + ) + ) + ) + ) + ) +) diff --git a/module/usuals.h b/module/usuals.h new file mode 100644 index 0000000..6dc7b08 --- /dev/null +++ b/module/usuals.h @@ -0,0 +1,32 @@ + +#ifndef __USUALS_H__ +#define __USUALS_H__ + +#include + +#include "config.h" + +#include +#include +#include +#include +#include + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define countof(x) (sizeof(x) / sizeof(x[0])) + +#ifdef _DEBUG + #include "assert.h" + #define ASSERT(x) assert(x) +#else + #define ASSERT(x) +#endif + +#endif /* __USUALS_H__ */ -- cgit v1.2.3