diff options
author | harti <harti@FreeBSD.org> | 2003-11-10 08:53:38 +0000 |
---|---|---|
committer | harti <harti@FreeBSD.org> | 2003-11-10 08:53:38 +0000 |
commit | ea9d8683bc24e904e026c05abd5768f41c3b551e (patch) | |
tree | 150e45ef74a56ce93475bd8e0436d6da856d4a18 /contrib/bsnmp/snmp_mibII | |
download | FreeBSD-src-ea9d8683bc24e904e026c05abd5768f41c3b551e.zip FreeBSD-src-ea9d8683bc24e904e026c05abd5768f41c3b551e.tar.gz |
Virgin import of bsnmp 1.4
Diffstat (limited to 'contrib/bsnmp/snmp_mibII')
-rw-r--r-- | contrib/bsnmp/snmp_mibII/mibII.c | 1564 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/mibII.h | 238 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/mibII_ifmib.c | 80 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/mibII_ifstack.c | 109 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/mibII_interfaces.c | 524 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/mibII_ip.c | 497 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/mibII_ipaddr.c | 351 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/mibII_nettomedia.c | 154 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/mibII_rcvaddr.c | 138 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/mibII_route.c | 299 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/mibII_tcp.c | 361 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/mibII_tree.def | 248 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/mibII_udp.c | 257 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/snmp_mibII.3 | 348 | ||||
-rw-r--r-- | contrib/bsnmp/snmp_mibII/snmp_mibII.h | 167 |
15 files changed, 5335 insertions, 0 deletions
diff --git a/contrib/bsnmp/snmp_mibII/mibII.c b/contrib/bsnmp/snmp_mibII/mibII.c new file mode 100644 index 0000000..7481794 --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/mibII.c @@ -0,0 +1,1564 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation 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 or documentation 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS 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 + * FRAUNHOFER FOKUS OR ITS 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. + * + * $Begemot: bsnmp/snmp_mibII/mibII.c,v 1.16 2003/01/28 13:44:34 hbb Exp $ + * + * Implementation of the standard interfaces and ip MIB. + */ +#include "mibII.h" +#include "mibII_oid.h" +#include <net/if_types.h> + + +/*****************************/ + +/* our module */ +static struct lmodule *module; + +/* routing socket */ +static int route; +static void *route_fd; + +/* if-index allocator */ +static u_int32_t next_if_index = 1; + +/* re-fetch arp table */ +static int update_arp; +static int in_update_arp; + +/* OR registrations */ +static u_int ifmib_reg; +static u_int ipmib_reg; +static u_int tcpmib_reg; +static u_int udpmib_reg; +static u_int ipForward_reg; + +/*****************************/ + +/* list of all IP addresses */ +struct mibifa_list mibifa_list = TAILQ_HEAD_INITIALIZER(mibifa_list); + +/* list of all interfaces */ +struct mibif_list mibif_list = TAILQ_HEAD_INITIALIZER(mibif_list); + +/* list of dynamic interface names */ +struct mibdynif_list mibdynif_list = SLIST_HEAD_INITIALIZER(mibdynif_list); + +/* list of all interface index mappings */ +struct mibindexmap_list mibindexmap_list = STAILQ_HEAD_INITIALIZER(mibindexmap_list); + +/* list of all stacking entries */ +struct mibifstack_list mibifstack_list = TAILQ_HEAD_INITIALIZER(mibifstack_list); + +/* list of all receive addresses */ +struct mibrcvaddr_list mibrcvaddr_list = TAILQ_HEAD_INITIALIZER(mibrcvaddr_list); + +/* list of all NetToMedia entries */ +struct mibarp_list mibarp_list = TAILQ_HEAD_INITIALIZER(mibarp_list); + +/* number of interfaces */ +int32_t mib_if_number; + +/* last change of table */ +u_int32_t mib_iftable_last_change; + +/* last change of stack table */ +u_int32_t mib_ifstack_last_change; + +/* if this is set, one of our lists may be bad. refresh them when idle */ +int mib_iflist_bad; + +/* network socket */ +int mib_netsock; + +/* last time refreshed */ +u_int32_t mibarpticks; + +/* info on system clocks */ +struct clockinfo clockinfo; + +/* list of all New if registrations */ +static struct newifreg_list newifreg_list = TAILQ_HEAD_INITIALIZER(newifreg_list); + +/*****************************/ + +static const struct asn_oid oid_ifMIB = OIDX_ifMIB; +static const struct asn_oid oid_ipMIB = OIDX_ipMIB; +static const struct asn_oid oid_tcpMIB = OIDX_tcpMIB; +static const struct asn_oid oid_udpMIB = OIDX_udpMIB; +static const struct asn_oid oid_ipForward = OIDX_ipForward; +static const struct asn_oid oid_linkDown = OIDX_linkDown; +static const struct asn_oid oid_linkUp = OIDX_linkUp; +static const struct asn_oid oid_ifIndex = OIDX_ifIndex; + +/*****************************/ + +/* + * Find an interface + */ +struct mibif * +mib_find_if(u_int idx) +{ + struct mibif *ifp; + + TAILQ_FOREACH(ifp, &mibif_list, link) + if (ifp->index == idx) + return (ifp); + return (NULL); +} + +struct mibif * +mib_find_if_sys(u_int sysindex) +{ + struct mibif *ifp; + + TAILQ_FOREACH(ifp, &mibif_list, link) + if (ifp->sysindex == sysindex) + return (ifp); + return (NULL); +} + +struct mibif * +mib_find_if_name(const char *name) +{ + struct mibif *ifp; + + TAILQ_FOREACH(ifp, &mibif_list, link) + if (strcmp(ifp->name, name) == 0) + return (ifp); + return (NULL); +} + +/* + * Check whether an interface is dynamic. The argument may include the + * unit number. This assumes, that the name part does NOT contain digits. + */ +int +mib_if_is_dyn(const char *name) +{ + size_t len; + struct mibdynif *d; + + for (len = 0; name[len] != '\0' && isalpha(name[len]) ; len++) + ; + SLIST_FOREACH(d, &mibdynif_list, link) + if (strlen(d->name) == len && strncmp(d->name, name, len) == 0) + return (1); + return (0); +} + +/* set an interface name to dynamic mode */ +void +mib_if_set_dyn(const char *name) +{ + struct mibdynif *d; + + SLIST_FOREACH(d, &mibdynif_list, link) + if (strcmp(name, d->name) == 0) + return; + if ((d = malloc(sizeof(*d))) == NULL) + err(1, NULL); + strcpy(d->name, name); + SLIST_INSERT_HEAD(&mibdynif_list, d, link); +} + +/* + * register for interface creations + */ +int +mib_register_newif(int (*func)(struct mibif *), const struct lmodule *mod) +{ + struct newifreg *reg; + + TAILQ_FOREACH(reg, &newifreg_list, link) + if (reg->mod == mod) { + reg->func = func; + return (0); + } + if ((reg = malloc(sizeof(*reg))) == NULL) { + syslog(LOG_ERR, "newifreg: %m"); + return (-1); + } + reg->mod = mod; + reg->func = func; + TAILQ_INSERT_TAIL(&newifreg_list, reg, link); + + return (0); +} + +void +mib_unregister_newif(const struct lmodule *mod) +{ + struct newifreg *reg; + + TAILQ_FOREACH(reg, &newifreg_list, link) + if (reg->mod == mod) { + TAILQ_REMOVE(&newifreg_list, reg, link); + free(reg); + return; + } + +} + +struct mibif * +mib_first_if(void) +{ + return (TAILQ_FIRST(&mibif_list)); +} +struct mibif * +mib_next_if(const struct mibif *ifp) +{ + return (TAILQ_NEXT(ifp, link)); +} + +/* + * Change the admin status of an interface + */ +int +mib_if_admin(struct mibif *ifp, int up) +{ + struct ifreq ifr; + + strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); + if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr) == -1) { + syslog(LOG_ERR, "SIOCGIFFLAGS(%s): %m", ifp->name); + return (-1); + } + if (up) + ifr.ifr_flags |= IFF_UP; + else + ifr.ifr_flags &= ~IFF_UP; + if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) { + syslog(LOG_ERR, "SIOCSIFFLAGS(%s): %m", ifp->name); + return (-1); + } + + (void)mib_fetch_ifmib(ifp); + + return (0); +} + +/* + * Generate a link up/down trap + */ +static void +link_trap(struct mibif *ifp, int up) +{ + struct snmp_value ifindex; + + ifindex.var = oid_ifIndex; + ifindex.var.subs[ifindex.var.len++] = ifp->index; + ifindex.syntax = SNMP_SYNTAX_INTEGER; + ifindex.v.integer = ifp->index; + + snmp_send_trap(up ? &oid_linkUp : &oid_linkDown, &ifindex, NULL); +} + +/* + * Fetch new MIB data. + */ +int +mib_fetch_ifmib(struct mibif *ifp) +{ + int name[6]; + size_t len; + void *newmib; + struct ifmibdata oldmib = ifp->mib; + + name[0] = CTL_NET; + name[1] = PF_LINK; + name[2] = NETLINK_GENERIC; + name[3] = IFMIB_IFDATA; + name[4] = ifp->sysindex; + name[5] = IFDATA_GENERAL; + + len = sizeof(ifp->mib); + if (sysctl(name, 6, &ifp->mib, &len, NULL, 0) == -1) { + if (errno != ENOENT) + syslog(LOG_WARNING, "sysctl(ifmib, %s) failed %m", + ifp->name); + return (-1); + } + + if (ifp->trap_enable) { + if (!(oldmib.ifmd_flags & IFF_UP)) { + if (ifp->mib.ifmd_flags & IFF_UP) + link_trap(ifp, 1); + } else { + if (!(ifp->mib.ifmd_flags & IFF_UP)) + link_trap(ifp, 0); + } + } + + ifp->flags &= ~(MIBIF_HIGHSPEED | MIBIF_VERYHIGHSPEED); + if (ifp->mib.ifmd_data.ifi_baudrate > 20000000) { + ifp->flags |= MIBIF_HIGHSPEED; + if (ifp->mib.ifmd_data.ifi_baudrate > 650000000) + ifp->flags |= MIBIF_VERYHIGHSPEED; + } + + /* + * linkspecific MIB + */ + name[5] = IFDATA_LINKSPECIFIC; + if (sysctl(name, 6, NULL, &len, NULL, 0) == -1) { + syslog(LOG_WARNING, "sysctl linkmib estimate (%s): %m", + ifp->name); + if (ifp->specmib != NULL) { + ifp->specmib = NULL; + ifp->specmiblen = 0; + } + goto out; + } + if (len == 0) { + if (ifp->specmib != NULL) { + ifp->specmib = NULL; + ifp->specmiblen = 0; + } + goto out; + } + + if (ifp->specmiblen != len) { + if ((newmib = realloc(ifp->specmib, len)) == NULL) { + ifp->specmib = NULL; + ifp->specmiblen = 0; + goto out; + } + ifp->specmib = newmib; + ifp->specmiblen = len; + } + if (sysctl(name, 6, ifp->specmib, &len, NULL, 0) == -1) { + syslog(LOG_WARNING, "sysctl linkmib (%s): %m", ifp->name); + if (ifp->specmib != NULL) { + ifp->specmib = NULL; + ifp->specmiblen = 0; + } + } + + out: + ifp->mibtick = get_ticks(); + return (0); +} + +/* find first/next address for a given interface */ +struct mibifa * +mib_first_ififa(const struct mibif *ifp) +{ + struct mibifa *ifa; + + TAILQ_FOREACH(ifa, &mibifa_list, link) + if (ifp->index == ifa->ifindex) + return (ifa); + return (NULL); +} + +struct mibifa * +mib_next_ififa(struct mibifa *ifa0) +{ + struct mibifa *ifa; + + ifa = ifa0; + while ((ifa = TAILQ_NEXT(ifa, link)) != NULL) + if (ifa->ifindex == ifa0->ifindex) + return (ifa); + return (NULL); +} + +/* + * Allocate a new IFA + */ +static struct mibifa * +alloc_ifa(u_int ifindex, struct in_addr addr) +{ + struct mibifa *ifa; + u_int32_t ha; + + if ((ifa = malloc(sizeof(struct mibifa))) == NULL) { + syslog(LOG_ERR, "ifa: %m"); + return (NULL); + } + ifa->inaddr = addr; + ifa->ifindex = ifindex; + + ha = ntohl(ifa->inaddr.s_addr); + ifa->index.len = 4; + ifa->index.subs[0] = (ha >> 24) & 0xff; + ifa->index.subs[1] = (ha >> 16) & 0xff; + ifa->index.subs[2] = (ha >> 8) & 0xff; + ifa->index.subs[3] = (ha >> 0) & 0xff; + + ifa->flags = 0; + ifa->inbcast.s_addr = 0; + ifa->inmask.s_addr = 0xffffffff; + + INSERT_OBJECT_OID(ifa, &mibifa_list); + + return (ifa); +} + +/* + * Delete an interface address + */ +static void +destroy_ifa(struct mibifa *ifa) +{ + TAILQ_REMOVE(&mibifa_list, ifa, link); + free(ifa); +} + + +/* + * Helper routine to extract the sockaddr structures from a routing + * socket message. + */ +void +mib_extract_addrs(int addrs, u_char *info, struct sockaddr **out) +{ + u_int i; + + for (i = 0; i < RTAX_MAX; i++) { + if ((addrs & (1 << i)) != 0) { + *out = (struct sockaddr *)info; + info += roundup((*out)->sa_len, sizeof(long)); + } else + *out = NULL; + out++; + } +} + +/* + * save the phys address of an interface. Handle receive address entries here. + */ +static void +get_physaddr(struct mibif *ifp, struct sockaddr_dl *sdl, u_char *ptr) +{ + u_char *np; + struct mibrcvaddr *rcv; + + if (sdl->sdl_alen == 0) { + /* no address */ + if (ifp->physaddrlen != NULL) { + if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr, + ifp->physaddrlen)) != NULL) + mib_rcvaddr_delete(rcv); + free(ifp->physaddr); + ifp->physaddr = NULL; + ifp->physaddrlen = 0; + } + return; + } + + if (ifp->physaddrlen != sdl->sdl_alen) { + /* length changed */ + if (ifp->physaddrlen) { + /* delete olf receive address */ + if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr, + ifp->physaddrlen)) != NULL) + mib_rcvaddr_delete(rcv); + } + if ((np = realloc(ifp->physaddr, sdl->sdl_alen)) == NULL) { + free(ifp->physaddr); + ifp->physaddr = NULL; + ifp->physaddrlen = 0; + return; + } + ifp->physaddr = np; + ifp->physaddrlen = sdl->sdl_alen; + + } else if (memcmp(ifp->physaddr, ptr, ifp->physaddrlen) == 0) { + /* no change */ + return; + + } else { + /* address changed */ + + /* delete olf receive address */ + if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr, + ifp->physaddrlen)) != NULL) + mib_rcvaddr_delete(rcv); + } + + memcpy(ifp->physaddr, ptr, ifp->physaddrlen); + + /* make new receive address */ + if ((rcv = mib_rcvaddr_create(ifp, ifp->physaddr, ifp->physaddrlen)) != NULL) + rcv->flags |= MIBRCVADDR_HW; +} + +/* + * Free an interface + */ +static void +mibif_free(struct mibif *ifp) +{ + struct mibindexmap *map; + struct mibifa *ifa, *ifa1; + struct mibrcvaddr *rcv, *rcv1; + struct mibarp *at, *at1; + + if (ifp->xnotify != NULL) + (*ifp->xnotify)(ifp, MIBIF_NOTIFY_DESTROY, ifp->xnotify_data); + + (void)mib_ifstack_delete(ifp, NULL); + (void)mib_ifstack_delete(NULL, ifp); + + TAILQ_REMOVE(&mibif_list, ifp, link); + if (ifp->physaddr != NULL) + free(ifp->physaddr); + if (ifp->specmib != NULL) + free(ifp->specmib); + + STAILQ_FOREACH(map, &mibindexmap_list, link) + if (map->mibif == ifp) { + map->mibif = NULL; + break; + } + + /* purge interface addresses */ + ifa = TAILQ_FIRST(&mibifa_list); + while (ifa != NULL) { + ifa1 = TAILQ_NEXT(ifa, link); + if (ifa->ifindex == ifp->index) + destroy_ifa(ifa); + ifa = ifa1; + } + + /* purge receive addresses */ + rcv = TAILQ_FIRST(&mibrcvaddr_list); + while (rcv != NULL) { + rcv1 = TAILQ_NEXT(rcv, link); + if (rcv->ifindex == ifp->index) + mib_rcvaddr_delete(rcv); + rcv = rcv1; + } + + /* purge ARP entries */ + at = TAILQ_FIRST(&mibarp_list); + while (at != NULL) { + at1 = TAILQ_NEXT(at, link); + if (at->index.subs[0] == ifp->index) + mib_arp_delete(at); + at = at1; + } + + + free(ifp); + mib_if_number--; + mib_iftable_last_change = this_tick; +} + +/* + * Create a new interface + */ +static struct mibif * +mibif_create(u_int sysindex, const char *name) +{ + struct mibif *ifp; + struct mibindexmap *map; + + if ((ifp = malloc(sizeof(*ifp))) == NULL) { + syslog(LOG_WARNING, "%s: %m", __func__); + return (NULL); + } + memset(ifp, 0, sizeof(*ifp)); + ifp->sysindex = sysindex; + strcpy(ifp->name, name); + strcpy(ifp->descr, name); + + map = NULL; + if (!mib_if_is_dyn(ifp->name)) { + /* non-dynamic. look whether we know the interface */ + STAILQ_FOREACH(map, &mibindexmap_list, link) + if (strcmp(map->name, ifp->name) == 0) { + ifp->index = map->ifindex; + map->mibif = ifp; + break; + } + /* assume it has a connector if it is not dynamic */ + ifp->has_connector = 1; + ifp->trap_enable = 1; + } + if (map == NULL) { + /* new interface - get new index */ + if (next_if_index > 0x7fffffff) + errx(1, "ifindex wrap"); + + if ((map = malloc(sizeof(*map))) == NULL) { + syslog(LOG_ERR, "ifmap: %m"); + free(ifp); + return (NULL); + } + map->ifindex = next_if_index++; + map->sysindex = ifp->sysindex; + strcpy(map->name, ifp->name); + map->mibif = ifp; + STAILQ_INSERT_TAIL(&mibindexmap_list, map, link); + } else { + /* re-instantiate. Introduce a counter discontinuity */ + ifp->counter_disc = get_ticks(); + } + ifp->index = map->ifindex; + + INSERT_OBJECT_INT(ifp, &mibif_list); + mib_if_number++; + mib_iftable_last_change = this_tick; + + /* instantiate default ifStack entries */ + (void)mib_ifstack_create(ifp, NULL); + (void)mib_ifstack_create(NULL, ifp); + + return (ifp); +} + +/* + * Inform all interested parties about a new interface + */ +static void +notify_newif(struct mibif *ifp) +{ + struct newifreg *reg; + + TAILQ_FOREACH(reg, &newifreg_list, link) + if ((*reg->func)(ifp)) + return; +} + +/* + * This is called for new interfaces after we have fetched the interface + * MIB. If this is a broadcast interface try to guess the broadcast address + * depending on the interface type. + */ +static void +check_llbcast(struct mibif *ifp) +{ + static u_char ether_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + static u_char arcnet_bcast = 0; + struct mibrcvaddr *rcv; + + if (!(ifp->mib.ifmd_flags & IFF_BROADCAST)) + return; + + switch (ifp->mib.ifmd_data.ifi_type) { + + case IFT_ETHER: + case IFT_FDDI: + case IFT_ISO88025: + if (mib_find_rcvaddr(ifp->index, ether_bcast, 6) == NULL && + (rcv = mib_rcvaddr_create(ifp, ether_bcast, 6)) != NULL) + rcv->flags |= MIBRCVADDR_BCAST; + break; + + case IFT_ARCNET: + if (mib_find_rcvaddr(ifp->index, &arcnet_bcast, 1) == NULL && + (rcv = mib_rcvaddr_create(ifp, &arcnet_bcast, 1)) != NULL) + rcv->flags |= MIBRCVADDR_BCAST; + break; + } +} + + +/* + * Retrieve the current interface list from the system. + */ +void +mib_refresh_iflist(void) +{ + struct mibif *ifp, *ifp1; + size_t len; + u_short idx; + int name[6]; + int count; + struct ifmibdata mib; + + TAILQ_FOREACH(ifp, &mibif_list, link) + ifp->flags &= ~MIBIF_FOUND; + + len = sizeof(count); + if (sysctlbyname("net.link.generic.system.ifcount", &count, &len, + NULL, 0) == -1) { + syslog(LOG_ERR, "ifcount: %m"); + return; + } + name[0] = CTL_NET; + name[1] = PF_LINK; + name[2] = NETLINK_GENERIC; + name[3] = IFMIB_IFDATA; + name[5] = IFDATA_GENERAL; + for (idx = 1; idx <= count; idx++) { + name[4] = idx; + len = sizeof(mib); + if (sysctl(name, 6, &mib, &len, NULL, 0) == -1) { + if (errno == ENOENT) + continue; + syslog(LOG_ERR, "ifmib(%u): %m", idx); + return; + } + if ((ifp = mib_find_if_sys(idx)) != NULL) { + ifp->flags |= MIBIF_FOUND; + continue; + } + /* Unknown interface - create */ + if ((ifp = mibif_create(idx, mib.ifmd_name)) != NULL) { + ifp->flags |= MIBIF_FOUND; + (void)mib_fetch_ifmib(ifp); + check_llbcast(ifp); + notify_newif(ifp); + } + } + + /* + * Purge interfaces that disappeared + */ + ifp = TAILQ_FIRST(&mibif_list); + while (ifp != NULL) { + ifp1 = TAILQ_NEXT(ifp, link); + if (!(ifp->flags & MIBIF_FOUND)) + mibif_free(ifp); + ifp = ifp1; + } +} + +/* + * Find an interface address + */ +struct mibifa * +mib_find_ifa(struct in_addr addr) +{ + struct mibifa *ifa; + + TAILQ_FOREACH(ifa, &mibifa_list, link) + if (ifa->inaddr.s_addr == addr.s_addr) + return (ifa); + return (NULL); +} + +/* + * Process a new ARP entry + */ +static void +process_arp(const struct rt_msghdr *rtm, const struct sockaddr_dl *sdl, + const struct sockaddr_in *sa) +{ + struct mibif *ifp; + struct mibarp *at; + + /* IP arp table entry */ + if (sdl->sdl_alen == 0) { + update_arp = 1; + return; + } + if ((ifp = mib_find_if_sys(sdl->sdl_index)) == NULL) + return; + /* have a valid entry */ + if ((at = mib_find_arp(ifp, sa->sin_addr)) == NULL && + (at = mib_arp_create(ifp, sa->sin_addr, + sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) + return; + + if (rtm->rtm_rmx.rmx_expire == 0) + at->flags |= MIBARP_PERM; + else + at->flags &= ~MIBARP_PERM; + at->flags |= MIBARP_FOUND; +} + +/* + * Handle a routing socket message. + */ +static void +handle_rtmsg(struct rt_msghdr *rtm) +{ + struct sockaddr *addrs[RTAX_MAX]; + struct if_msghdr *ifm; + struct ifa_msghdr *ifam; + struct ifma_msghdr *ifmam; +#ifdef RTM_IFANNOUNCE + struct if_announcemsghdr *ifan; +#endif + struct mibif *ifp; + struct sockaddr_dl *sdl; + struct sockaddr_in *sa; + struct mibifa *ifa; + struct mibrcvaddr *rcv; + u_char *ptr; + + if (rtm->rtm_version != RTM_VERSION) { + syslog(LOG_ERR, "Bogus RTM version %u", rtm->rtm_version); + return; + } + + switch (rtm->rtm_type) { + + case RTM_NEWADDR: + ifam = (struct ifa_msghdr *)rtm; + mib_extract_addrs(ifam->ifam_addrs, (u_char *)(ifam + 1), addrs); + if (addrs[RTAX_IFA] == NULL || addrs[RTAX_NETMASK] == NULL) + break; + + sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA]; + if ((ifa = mib_find_ifa(sa->sin_addr)) == NULL) { + /* unknown address */ + if ((ifp = mib_find_if_sys(ifam->ifam_index)) == NULL) { + syslog(LOG_WARNING, "RTM_NEWADDR for unknown " + "interface %u", ifam->ifam_index); + break; + } + if ((ifa = alloc_ifa(ifp->index, sa->sin_addr)) == NULL) + break; + } + sa = (struct sockaddr_in *)(void *)addrs[RTAX_NETMASK]; + ifa->inmask = sa->sin_addr; + + if (addrs[RTAX_BRD] != NULL) { + sa = (struct sockaddr_in *)(void *)addrs[RTAX_BRD]; + ifa->inbcast = sa->sin_addr; + } + ifa->flags |= MIBIFA_FOUND; + break; + + case RTM_DELADDR: + ifam = (struct ifa_msghdr *)rtm; + mib_extract_addrs(ifam->ifam_addrs, (u_char *)(ifam + 1), addrs); + if (addrs[RTAX_IFA] == NULL) + break; + + sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA]; + if ((ifa = mib_find_ifa(sa->sin_addr)) != NULL) { + ifa->flags |= MIBIFA_FOUND; + if (!(ifa->flags & MIBIFA_DESTROYED)) + destroy_ifa(ifa); + } + break; + + case RTM_NEWMADDR: + ifmam = (struct ifma_msghdr *)rtm; + mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs); + if (addrs[RTAX_IFA] == NULL || + addrs[RTAX_IFA]->sa_family != AF_LINK) + break; + sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA]; + if ((rcv = mib_find_rcvaddr(sdl->sdl_index, + sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) { + /* unknown address */ + if ((ifp = mib_find_if_sys(sdl->sdl_index)) == NULL) { + syslog(LOG_WARNING, "RTM_NEWMADDR for unknown " + "interface %u", sdl->sdl_index); + break; + } + if ((rcv = mib_rcvaddr_create(ifp, + sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) + break; + rcv->flags |= MIBRCVADDR_VOLATILE; + } + rcv->flags |= MIBRCVADDR_FOUND; + break; + + case RTM_DELMADDR: + ifmam = (struct ifma_msghdr *)rtm; + mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs); + if (addrs[RTAX_IFA] == NULL || + addrs[RTAX_IFA]->sa_family != AF_LINK) + break; + sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA]; + if ((rcv = mib_find_rcvaddr(sdl->sdl_index, + sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) != NULL) + mib_rcvaddr_delete(rcv); + break; + + case RTM_IFINFO: + ifm = (struct if_msghdr *)rtm; + mib_extract_addrs(ifm->ifm_addrs, (u_char *)(ifm + 1), addrs); + if ((ifp = mib_find_if_sys(ifm->ifm_index)) == NULL) + break; + if (addrs[RTAX_IFP] != NULL && + addrs[RTAX_IFP]->sa_family == AF_LINK) { + sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFP]; + ptr = sdl->sdl_data + sdl->sdl_nlen; + get_physaddr(ifp, sdl, ptr); + } + (void)mib_fetch_ifmib(ifp); + break; + +#ifdef RTM_IFANNOUNCE + case RTM_IFANNOUNCE: + ifan = (struct if_announcemsghdr *)rtm; + ifp = mib_find_if_sys(ifan->ifan_index); + + switch (ifan->ifan_what) { + + case IFAN_ARRIVAL: + if (ifp == NULL && (ifp = mibif_create(ifan->ifan_index, + ifan->ifan_name)) != NULL) { + (void)mib_fetch_ifmib(ifp); + check_llbcast(ifp); + notify_newif(ifp); + } + break; + + case IFAN_DEPARTURE: + if (ifp != NULL) + mibif_free(ifp); + break; + } + break; +#endif + + case RTM_GET: + mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs); + if (rtm->rtm_flags & RTF_LLINFO) { + if (addrs[RTAX_DST] == NULL || + addrs[RTAX_GATEWAY] == NULL || + addrs[RTAX_DST]->sa_family != AF_INET || + addrs[RTAX_GATEWAY]->sa_family != AF_LINK) + break; + process_arp(rtm, + (struct sockaddr_dl *)(void *)addrs[RTAX_GATEWAY], + (struct sockaddr_in *)(void *)addrs[RTAX_DST]); + } + break; + + case RTM_ADD: + mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs); + if (rtm->rtm_flags & RTF_LLINFO) { + if (addrs[RTAX_DST] == NULL || + addrs[RTAX_GATEWAY] == NULL || + addrs[RTAX_DST]->sa_family != AF_INET || + addrs[RTAX_GATEWAY]->sa_family != AF_LINK) + break; + process_arp(rtm, + (struct sockaddr_dl *)(void *)addrs[RTAX_GATEWAY], + (struct sockaddr_in *)(void *)addrs[RTAX_DST]); + } + break; + } +} + +/* + * Fetch the routing table via sysctl + */ +u_char * +mib_fetch_rtab(int af, int info, int arg, size_t *lenp) +{ + int name[6]; + u_char *buf; + + name[0] = CTL_NET; + name[1] = PF_ROUTE; + name[2] = 0; + name[3] = af; + name[4] = info; + name[5] = arg; + + if (sysctl(name, 6, NULL, lenp, NULL, 0) == -1) { + syslog(LOG_ERR, "sysctl estimate (%d,%d,%d,%d,%d,%d): %m", + name[0], name[1], name[2], name[3], name[4], name[5]); + return (NULL); + } + + if ((buf = malloc(*lenp)) == NULL) { + syslog(LOG_ERR, "sysctl buffer: %m"); + return (NULL); + } + + if (sysctl(name, 6, buf, lenp, NULL, 0) == -1) { + syslog(LOG_ERR, "sysctl get: %m"); + free(buf); + return (NULL); + } + + return (buf); +} + +/* + * Update the following info: interface, interface addresses, interface + * receive addresses, arp-table. + * This does not change the interface list itself. + */ +static void +update_ifa_info(void) +{ + u_char *buf, *next; + struct rt_msghdr *rtm; + struct mibifa *ifa, *ifa1; + struct mibrcvaddr *rcv, *rcv1; + size_t needed; + static const int infos[][3] = { + { 0, NET_RT_IFLIST, 0 }, +#ifdef NET_RT_IFMALIST + { AF_LINK, NET_RT_IFMALIST, 0 }, +#endif + }; + u_int i; + + TAILQ_FOREACH(ifa, &mibifa_list, link) + ifa->flags &= ~MIBIFA_FOUND; + TAILQ_FOREACH(rcv, &mibrcvaddr_list, link) + rcv->flags &= ~MIBRCVADDR_FOUND; + + for (i = 0; i < sizeof(infos) / sizeof(infos[0]); i++) { + if ((buf = mib_fetch_rtab(infos[i][0], infos[i][1], infos[i][2], + &needed)) == NULL) + continue; + + next = buf; + while (next < buf + needed) { + rtm = (struct rt_msghdr *)(void *)next; + next += rtm->rtm_msglen; + handle_rtmsg(rtm); + } + free(buf); + } + + /* + * Purge the address list of unused entries. These may happen for + * interface aliases that are on the same subnet. We don't receive + * routing socket messages for them. + */ + ifa = TAILQ_FIRST(&mibifa_list); + while (ifa != NULL) { + ifa1 = TAILQ_NEXT(ifa, link); + if (!(ifa->flags & MIBIFA_FOUND)) + destroy_ifa(ifa); + ifa = ifa1; + } + + rcv = TAILQ_FIRST(&mibrcvaddr_list); + while (rcv != NULL) { + rcv1 = TAILQ_NEXT(rcv, link); + if (!(rcv->flags & (MIBRCVADDR_FOUND | MIBRCVADDR_BCAST | + MIBRCVADDR_HW))) + mib_rcvaddr_delete(rcv); + rcv = rcv1; + } +} + +/* + * Update arp table + */ +void +mib_arp_update(void) +{ + struct mibarp *at, *at1; + size_t needed; + u_char *buf, *next; + struct rt_msghdr *rtm; + + if (in_update_arp) + return; /* Aaargh */ + in_update_arp = 1; + + TAILQ_FOREACH(at, &mibarp_list, link) + at->flags &= ~MIBARP_FOUND; + + if ((buf = mib_fetch_rtab(AF_INET, NET_RT_FLAGS, RTF_LLINFO, &needed)) == NULL) { + in_update_arp = 0; + return; + } + + next = buf; + while (next < buf + needed) { + rtm = (struct rt_msghdr *)(void *)next; + next += rtm->rtm_msglen; + handle_rtmsg(rtm); + } + free(buf); + + at = TAILQ_FIRST(&mibarp_list); + while (at != NULL) { + at1 = TAILQ_NEXT(at, link); + if (!(at->flags & MIBARP_FOUND)) + mib_arp_delete(at); + at = at1; + } + mibarpticks = get_ticks(); + update_arp = 0; + in_update_arp = 0; +} + + +/* + * Intput on the routing socket. + */ +static void +route_input(int fd, void *udata __unused) +{ + u_char buf[1024 * 16]; + ssize_t n; + struct rt_msghdr *rtm; + + if ((n = read(fd, buf, sizeof(buf))) == -1) + err(1, "read(rt_socket)"); + + if (n == 0) + errx(1, "EOF on rt_socket"); + + rtm = (struct rt_msghdr *)(void *)buf; + if ((size_t)n != rtm->rtm_msglen) + errx(1, "n=%zu, rtm_msglen=%u", (size_t)n, rtm->rtm_msglen); + + handle_rtmsg(rtm); +} + +/* + * execute and SIOCAIFADDR + */ +static int +siocaifaddr(char *ifname, struct in_addr addr, struct in_addr mask, + struct in_addr bcast) +{ + struct ifaliasreq addreq; + struct sockaddr_in *sa; + + memset(&addreq, 0, sizeof(addreq)); + strncpy(addreq.ifra_name, ifname, sizeof(addreq.ifra_name)); + + sa = (struct sockaddr_in *)(void *)&addreq.ifra_addr; + sa->sin_family = AF_INET; + sa->sin_len = sizeof(*sa); + sa->sin_addr = addr; + + sa = (struct sockaddr_in *)(void *)&addreq.ifra_mask; + sa->sin_family = AF_INET; + sa->sin_len = sizeof(*sa); + sa->sin_addr = mask; + + sa = (struct sockaddr_in *)(void *)&addreq.ifra_broadaddr; + sa->sin_family = AF_INET; + sa->sin_len = sizeof(*sa); + sa->sin_addr = bcast; + + return (ioctl(mib_netsock, SIOCAIFADDR, &addreq)); +} + +/* + * Exececute a SIOCDIFADDR + */ +static int +siocdifaddr(const char *ifname, struct in_addr addr) +{ + struct ifreq delreq; + struct sockaddr_in *sa; + + memset(&delreq, 0, sizeof(delreq)); + strncpy(delreq.ifr_name, ifname, sizeof(delreq.ifr_name)); + sa = (struct sockaddr_in *)(void *)&delreq.ifr_addr; + sa->sin_family = AF_INET; + sa->sin_len = sizeof(*sa); + sa->sin_addr = addr; + + return (ioctl(mib_netsock, SIOCDIFADDR, &delreq)); +} + +/* + * Verify an interface address without fetching the entire list + */ +static int +verify_ifa(const char *name, struct mibifa *ifa) +{ + struct ifreq req; + struct sockaddr_in *sa; + + memset(&req, 0, sizeof(req)); + strncpy(req.ifr_name, name, sizeof(req.ifr_name)); + sa = (struct sockaddr_in *)(void *)&req.ifr_addr; + sa->sin_family = AF_INET; + sa->sin_len = sizeof(*sa); + sa->sin_addr = ifa->inaddr; + + if (ioctl(mib_netsock, SIOCGIFADDR, &req) == -1) + return (-1); + if (ifa->inaddr.s_addr != sa->sin_addr.s_addr) { + syslog(LOG_ERR, "%s: address mismatch", __func__); + return (-1); + } + + if (ioctl(mib_netsock, SIOCGIFNETMASK, &req) == -1) + return (-1); + if (ifa->inmask.s_addr != sa->sin_addr.s_addr) { + syslog(LOG_ERR, "%s: netmask mismatch", __func__); + return (-1); + } + return (0); +} + +/* + * Restore a deleted interface address. Don't wait for the routing socket + * to update us. + */ +void +mib_undestroy_ifa(struct mibifa *ifa) +{ + struct mibif *ifp; + + if ((ifp = mib_find_if(ifa->ifindex)) == NULL) + /* keep it destroyed */ + return; + + if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) + /* keep it destroyed */ + return; + + ifa->flags &= ~MIBIFA_DESTROYED; +} + +/* + * Destroy an interface address + */ +int +mib_destroy_ifa(struct mibifa *ifa) +{ + struct mibif *ifp; + + if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { + /* ups. */ + mib_iflist_bad = 1; + return (-1); + } + if (siocdifaddr(ifp->name, ifa->inaddr)) { + /* ups. */ + syslog(LOG_ERR, "SIOCDIFADDR: %m"); + mib_iflist_bad = 1; + return (-1); + } + ifa->flags |= MIBIFA_DESTROYED; + return (0); +} + +/* + * Rollback the modification of an address. Don't bother to wait for + * the routing socket. + */ +void +mib_unmodify_ifa(struct mibifa *ifa) +{ + struct mibif *ifp; + + if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { + /* ups. */ + mib_iflist_bad = 1; + return; + } + + if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { + /* ups. */ + mib_iflist_bad = 1; + return; + } +} + +/* + * Modify an IFA. + */ +int +mib_modify_ifa(struct mibifa *ifa) +{ + struct mibif *ifp; + + if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { + /* ups. */ + mib_iflist_bad = 1; + return (-1); + } + + if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { + /* ups. */ + mib_iflist_bad = 1; + return (-1); + } + + if (verify_ifa(ifp->name, ifa)) { + /* ups. */ + mib_iflist_bad = 1; + return (-1); + } + + return (0); +} + +/* + * Destroy a freshly created interface address. Don't bother to wait for + * the routing socket. + */ +void +mib_uncreate_ifa(struct mibifa *ifa) +{ + struct mibif *ifp; + + if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { + /* ups. */ + mib_iflist_bad = 1; + return; + } + if (siocdifaddr(ifp->name, ifa->inaddr)) { + /* ups. */ + mib_iflist_bad = 1; + return; + } + + destroy_ifa(ifa); +} + +/* + * Create a new ifa and verify it + */ +struct mibifa * +mib_create_ifa(u_int ifindex, struct in_addr addr, struct in_addr mask, + struct in_addr bcast) +{ + struct mibif *ifp; + struct mibifa *ifa; + + if ((ifp = mib_find_if(ifindex)) == NULL) + return (NULL); + if ((ifa = alloc_ifa(ifindex, addr)) == NULL) + return (NULL); + ifa->inmask = mask; + ifa->inbcast = bcast; + + if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { + syslog(LOG_ERR, "%s: %m", __func__); + destroy_ifa(ifa); + return (NULL); + } + if (verify_ifa(ifp->name, ifa)) { + destroy_ifa(ifa); + return (NULL); + } + return (ifa); +} + +/* + * Get all cloning interfaces and make them dynamic. + * Hah! Whe should probably do this on a periodic basis (XXX). + */ +static void +get_cloners(void) +{ + struct if_clonereq req; + char *buf, *cp; + int i; + + memset(&req, 0, sizeof(req)); + if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) { + syslog(LOG_ERR, "get cloners: %m"); + return; + } + if ((buf = malloc(req.ifcr_total * IFNAMSIZ)) == NULL) { + syslog(LOG_ERR, "%m"); + return; + } + req.ifcr_count = req.ifcr_total; + req.ifcr_buffer = buf; + if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) { + syslog(LOG_ERR, "get cloners: %m"); + free(buf); + return; + } + for (cp = buf, i = 0; i < req.ifcr_total; i++, cp += IFNAMSIZ) + mib_if_set_dyn(cp); + free(buf); +} + +/* + * Idle function + */ +static void +mibII_idle(void) +{ + struct mibifa *ifa; + + if (mib_iflist_bad) { + TAILQ_FOREACH(ifa, &mibifa_list, link) + ifa->flags &= ~MIBIFA_DESTROYED; + + /* assume, that all cloning interfaces are dynamic */ + get_cloners(); + + mib_refresh_iflist(); + update_ifa_info(); + mib_arp_update(); + mib_iflist_bad = 0; + } + if (update_arp) + mib_arp_update(); +} + + +/* + * Start the module + */ +static void +mibII_start(void) +{ + if ((route_fd = fd_select(route, route_input, NULL, module)) == NULL) { + syslog(LOG_ERR, "fd_select(route): %m"); + return; + } + mib_refresh_iflist(); + update_ifa_info(); + mib_arp_update(); + mib_iftable_last_change = 0; + mib_ifstack_last_change = 0; + + ifmib_reg = or_register(&oid_ifMIB, + "The MIB module to describe generic objects for network interface" + " sub-layers.", module); + + ipmib_reg = or_register(&oid_ipMIB, + "The MIB module for managing IP and ICMP implementations, but " + "excluding their management of IP routes.", module); + + tcpmib_reg = or_register(&oid_tcpMIB, + "The MIB module for managing TCP implementations.", module); + + udpmib_reg = or_register(&oid_udpMIB, + "The MIB module for managing UDP implementations.", module); + + ipForward_reg = or_register(&oid_ipForward, + "The MIB module for the display of CIDR multipath IP Routes.", + module); +} + +/* + * Initialize the module + */ +static int +mibII_init(struct lmodule *mod, int argc __unused, char *argv[] __unused) +{ + size_t len; + + module = mod; + + len = sizeof(clockinfo); + if (sysctlbyname("kern.clockrate", &clockinfo, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "kern.clockrate: %m"); + return (-1); + } + if (len != sizeof(clockinfo)) { + syslog(LOG_ERR, "kern.clockrate: wrong size"); + return (-1); + } + + if ((route = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) == -1) { + syslog(LOG_ERR, "PF_ROUTE: %m"); + return (-1); + } + (void)shutdown(route, SHUT_WR); + + if ((mib_netsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "PF_INET: %m"); + (void)close(route); + return (-1); + } + (void)shutdown(mib_netsock, SHUT_RDWR); + + /* assume, that all cloning interfaces are dynamic */ + get_cloners(); + + return (0); +} + +static int +mibII_fini(void) +{ + if (route_fd != NULL) + fd_deselect(route_fd); + if (route != -1) + (void)close(route); + if (mib_netsock != -1) + (void)close(mib_netsock); + /* XXX free memory */ + + or_unregister(ipForward_reg); + or_unregister(udpmib_reg); + or_unregister(tcpmib_reg); + or_unregister(ipmib_reg); + or_unregister(ifmib_reg); + + return (0); +} + +static void +mibII_loading(const struct lmodule *mod, int loaded) +{ + struct mibif *ifp; + + if (loaded == 1) + return; + + TAILQ_FOREACH(ifp, &mibif_list, link) + if (ifp->xnotify_mod == mod) { + ifp->xnotify_mod = NULL; + ifp->xnotify_data = NULL; + ifp->xnotify = NULL; + } + + mib_unregister_newif(mod); +} + +const struct snmp_module config = { + "This module implements the interface and ip groups.", + mibII_init, + mibII_fini, + mibII_idle, /* idle */ + NULL, /* dump */ + NULL, /* config */ + mibII_start, + NULL, + mibII_ctree, + mibII_CTREE_SIZE, + mibII_loading +}; + +/* + * Should have a list of these attached to each interface. + */ +void * +mibif_notify(struct mibif *ifp, const struct lmodule *mod, + mibif_notify_f func, void *data) +{ + ifp->xnotify = func; + ifp->xnotify_data = data; + ifp->xnotify_mod = mod; + + return (ifp); +} + +void +mibif_unnotify(void *arg) +{ + struct mibif *ifp = arg; + + ifp->xnotify = NULL; + ifp->xnotify_data = NULL; + ifp->xnotify_mod = NULL; +} diff --git a/contrib/bsnmp/snmp_mibII/mibII.h b/contrib/bsnmp/snmp_mibII/mibII.h new file mode 100644 index 0000000..89ccd05 --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/mibII.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation 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 or documentation 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS 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 + * FRAUNHOFER FOKUS OR ITS 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. + * + * $Begemot: bsnmp/snmp_mibII/mibII.h,v 1.11 2002/03/21 10:43:06 hbb Exp $ + * + * Implementation of the interfaces and IP groups of MIB-II. + */ +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/syslog.h> +#include <sys/time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <err.h> +#include <ctype.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_mib.h> +#include <net/route.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "asn1.h" +#include "snmp.h" +#include "snmpmod.h" +#include "snmp_mibII.h" +#include "mibII_tree.h" + + +/* + * Interface list and flags. + */ +TAILQ_HEAD(mibif_list, mibif); +enum { + MIBIF_FOUND = 0x0001, + MIBIF_HIGHSPEED = 0x0002, + MIBIF_VERYHIGHSPEED = 0x0004, +}; +#define hc_inoctets mib.ifmd_data.ifi_ibytes +#define hc_outoctets mib.ifmd_data.ifi_obytes +#define hc_omcasts mib.ifmd_data.ifi_omcasts +#define hc_opackets mib.ifmd_data.ifi_opackets +#define hc_imcasts mib.ifmd_data.ifi_imcasts +#define hc_ipackets mib.ifmd_data.ifi_ipackets + +/* + * Interface addresses. + */ +TAILQ_HEAD(mibifa_list, mibifa); +enum { + MIBIFA_FOUND = 0x0001, + MIBIFA_DESTROYED = 0x0002, +}; + +/* + * Receive addresses + */ +TAILQ_HEAD(mibrcvaddr_list, mibrcvaddr); +enum { + MIBRCVADDR_FOUND = 0x00010000, +}; + +/* + * Interface index mapping. The problem here is, that if the same interface + * is reinstantiated (for examble by unloading and loading the hardware driver) + * we must use the same index for this interface. For dynamic interfaces + * (clip, lane) we must use a fresh index, each time a new interface is created. + * To differentiate between these types of interfaces we use the following table + * which contains an entry for each dynamic interface type. All other interface + * types are supposed to be static. The mibindexmap contains an entry for + * all interfaces. The mibif pointer is NULL, if the interface doesn't exist + * anymore. + */ +struct mibdynif { + SLIST_ENTRY(mibdynif) link; + char name[IFNAMSIZ]; +}; +SLIST_HEAD(mibdynif_list, mibdynif); + +struct mibindexmap { + STAILQ_ENTRY(mibindexmap) link; + u_short sysindex; + u_int ifindex; + struct mibif *mibif; /* may be NULL */ + char name[IFNAMSIZ]; +}; +STAILQ_HEAD(mibindexmap_list, mibindexmap); + +/* + * Interface stacking. The generic code cannot know how the interfaces stack. + * For this reason it instantiates only the x.0 and 0.x table elements. All + * others have to be instantiated by the interface specific modules. + * The table is read-only. + */ +struct mibifstack { + TAILQ_ENTRY(mibifstack) link; + struct asn_oid index; +}; +TAILQ_HEAD(mibifstack_list, mibifstack); + +/* + * NetToMediaTable (ArpTable) + */ +struct mibarp { + TAILQ_ENTRY(mibarp) link; + struct asn_oid index; /* contains both the ifindex and addr */ + u_char phys[128]; /* the physical address */ + u_int physlen; /* and its length */ + u_int flags; +}; +TAILQ_HEAD(mibarp_list, mibarp); +enum { + MIBARP_FOUND = 0x00010000, + MIBARP_PERM = 0x00000001, +}; + +/* + * New if registrations + */ +struct newifreg { + TAILQ_ENTRY(newifreg) link; + const struct lmodule *mod; + int (*func)(struct mibif *); +}; +TAILQ_HEAD(newifreg_list, newifreg); + +/* list of all IP addresses */ +extern struct mibifa_list mibifa_list; + +/* list of all interfaces */ +extern struct mibif_list mibif_list; + +/* list of dynamic interface names */ +extern struct mibdynif_list mibdynif_list; + +/* list of all interface index mappings */ +extern struct mibindexmap_list mibindexmap_list; + +/* list of all stacking entries */ +extern struct mibifstack_list mibifstack_list; + +/* list of all receive addresses */ +extern struct mibrcvaddr_list mibrcvaddr_list; + +/* list of all NetToMedia entries */ +extern struct mibarp_list mibarp_list; + +/* number of interfaces */ +extern int32_t mib_if_number; + +/* last change of interface table */ +extern u_int32_t mib_iftable_last_change; + +/* last change of stack table */ +extern u_int32_t mib_ifstack_last_change; + +/* if this is set, one of our lists may be bad. refresh them when idle */ +extern int mib_iflist_bad; + +/* last time refreshed */ +extern u_int32_t mibarpticks; + +/* info on system clocks */ +extern struct clockinfo clockinfo; + +/* get interfaces and interface addresses. */ +void mib_fetch_interfaces(void); + +/* check whether this interface(type) is dynamic */ +int mib_if_is_dyn(const char *name); + +/* destroy an interface address */ +int mib_destroy_ifa(struct mibifa *); + +/* restituate a deleted interface address */ +void mib_undestroy_ifa(struct mibifa *); + +/* change interface address */ +int mib_modify_ifa(struct mibifa *); + +/* undo if address modification */ +void mib_unmodify_ifa(struct mibifa *); + +/* create an interface address */ +struct mibifa * mib_create_ifa(u_int ifindex, struct in_addr addr, struct in_addr mask, struct in_addr bcast); + +/* delete a freshly created address */ +void mib_uncreate_ifa(struct mibifa *); + +/* create/delete arp entries */ +struct mibarp *mib_arp_create(const struct mibif *, struct in_addr, const u_char *, size_t); +void mib_arp_delete(struct mibarp *); + +/* find arp entry */ +struct mibarp *mib_find_arp(const struct mibif *, struct in_addr); + +/* update arp table */ +void mib_arp_update(void); + +/* fetch routing table */ +u_char *mib_fetch_rtab(int af, int info, int arg, size_t *lenp); + +/* extract addresses from routing message */ +void mib_extract_addrs(int, u_char *, struct sockaddr **); diff --git a/contrib/bsnmp/snmp_mibII/mibII_ifmib.c b/contrib/bsnmp/snmp_mibII/mibII_ifmib.c new file mode 100644 index 0000000..1f09d59 --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/mibII_ifmib.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation 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 or documentation 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS 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 + * FRAUNHOFER FOKUS OR ITS 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. + * + * $Begemot: bsnmp/snmp_mibII/mibII_ifmib.c,v 1.7 2003/01/28 13:44:35 hbb Exp $ + * + * Interfaces group. + */ +#include "mibII.h" +#include "mibII_oid.h" + +/* + * Scalars + */ +int +op_ifmib(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int idx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_ifTableLastChange: + if (mib_iftable_last_change > start_tick) + value->v.uint32 = mib_iftable_last_change - start_tick; + else + value->v.uint32 = 0; + break; + + case LEAF_ifStackLastChange: + if (mib_ifstack_last_change > start_tick) + value->v.uint32 = mib_ifstack_last_change - start_tick; + else + value->v.uint32 = 0; + break; + } + return (SNMP_ERR_NOERROR); +} diff --git a/contrib/bsnmp/snmp_mibII/mibII_ifstack.c b/contrib/bsnmp/snmp_mibII/mibII_ifstack.c new file mode 100644 index 0000000..93aa259 --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/mibII_ifstack.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation 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 or documentation 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS 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 + * FRAUNHOFER FOKUS OR ITS 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. + * + * $Begemot: bsnmp/snmp_mibII/mibII_ifstack.c,v 1.5 2003/01/28 13:44:35 hbb Exp $ + * + * ifStackTable. Read-only. + */ +#include "mibII.h" + +int +mib_ifstack_create(const struct mibif *lower, const struct mibif *upper) +{ + struct mibifstack *stack; + + if ((stack = malloc(sizeof(*stack))) == NULL) + return (-1); + + stack->index.len = 2; + stack->index.subs[0] = upper ? upper->index : 0; + stack->index.subs[1] = lower ? lower->index : 0; + + INSERT_OBJECT_OID(stack, &mibifstack_list); + + mib_ifstack_last_change = get_ticks(); + + return (0); +} + +void +mib_ifstack_delete(const struct mibif *lower, const struct mibif *upper) +{ + struct mibifstack *stack; + + TAILQ_FOREACH(stack, &mibifstack_list, link) + if (stack->index.subs[0] == (upper ? upper->index : 0) && + stack->index.subs[1] == (lower ? lower->index : 0)) { + TAILQ_REMOVE(&mibifstack_list, stack, link); + free(stack); + mib_ifstack_last_change = get_ticks(); + return; + } +} + +int +op_ifstack(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + struct mibifstack *stack; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((stack = NEXT_OBJECT_OID(&mibifstack_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &stack->index); + break; + + case SNMP_OP_GET: + if ((stack = FIND_OBJECT_OID(&mibifstack_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if ((stack = FIND_OBJECT_OID(&mibifstack_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NO_CREATION); + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_ifStackStatus: + value->v.integer = 1; + break; + } + return (SNMP_ERR_NOERROR); +} diff --git a/contrib/bsnmp/snmp_mibII/mibII_interfaces.c b/contrib/bsnmp/snmp_mibII/mibII_interfaces.c new file mode 100644 index 0000000..02a90ca --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/mibII_interfaces.c @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation 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 or documentation 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS 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 + * FRAUNHOFER FOKUS OR ITS 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. + * + * $Begemot: bsnmp/snmp_mibII/mibII_interfaces.c,v 1.9 2003/01/28 13:44:35 hbb Exp $ + * + * Interfaces group. + */ +#include "mibII.h" +#include "mibII_oid.h" + +/* + * This structure catches all changes to a interface entry + */ +struct ifchange { + struct snmp_dependency dep; + + u_int ifindex; + + u_int32_t set; + int promisc; + int admin; + int traps; + + u_int32_t rb; + int rb_flags; + int rb_traps; +}; +#define IFC_PROMISC 0x0001 +#define IFC_ADMIN 0x0002 +#define IFC_TRAPS 0x0004 +#define IFRB_FLAGS 0x0001 +#define IFRB_TRAPS 0x0002 + +static const struct asn_oid + oid_ifTable = OIDX_ifTable; + +/* + * This function handles all changes to the interface table and interface + * extension table. + */ +static int +ifchange_func(struct snmp_context *ctx __unused, struct snmp_dependency *dep, + enum snmp_depop op) +{ + struct ifchange *ifc = (struct ifchange *)dep; + struct mibif *ifp; + struct ifreq ifr, ifr1; + + if ((ifp = mib_find_if(ifc->ifindex)) == NULL) + return (SNMP_ERR_NO_CREATION); + + switch (op) { + + case SNMP_DEPOP_COMMIT: + strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); + if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr) == -1) { + syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name); + return (SNMP_ERR_GENERR); + } + if (ifc->set & IFC_PROMISC) { + ifr.ifr_flags &= ~IFF_PROMISC; + if (ifc->promisc) + ifr.ifr_flags |= IFF_PROMISC; + ifc->rb |= IFRB_FLAGS; + } + if (ifc->set & IFC_ADMIN) { + ifr.ifr_flags &= ~IFF_UP; + if (ifc->admin) + ifr.ifr_flags |= IFF_UP; + ifc->rb |= IFRB_FLAGS; + } + if (ifc->rb & IFRB_FLAGS) { + strncpy(ifr1.ifr_name, ifp->name, sizeof(ifr1.ifr_name)); + if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr1) == -1) { + syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name); + return (SNMP_ERR_GENERR); + } + ifc->rb_flags = ifr1.ifr_flags; + if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) { + syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name); + return (SNMP_ERR_GENERR); + } + (void)mib_fetch_ifmib(ifp); + } + if (ifc->set & IFC_TRAPS) { + ifc->rb |= IFRB_TRAPS; + ifc->rb_traps = ifp->trap_enable; + ifp->trap_enable = ifc->traps; + } + return (SNMP_ERR_NOERROR); + + case SNMP_DEPOP_ROLLBACK: + if (ifc->rb & IFRB_FLAGS) { + strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); + ifr.ifr_flags = ifc->rb_flags; + if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) { + syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name); + return (SNMP_ERR_UNDO_FAILED); + } + (void)mib_fetch_ifmib(ifp); + } + if (ifc->rb & IFRB_TRAPS) + ifp->trap_enable = ifc->rb_traps; + return (SNMP_ERR_NOERROR); + + } + abort(); +} + +static u_int32_t +ticks_get_timeval(struct timeval *tv) +{ + u_int32_t v; + + if (tv->tv_sec != 0 || tv->tv_usec != 0) { + v = 100 * tv->tv_sec + tv->tv_usec / 10000; + if (v > start_tick) + return (v - start_tick); + } + return (0); +} + +/* + * Scalars + */ +int +op_interfaces(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int idx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_ifNumber: + value->v.integer = mib_if_number; + break; + } + return (SNMP_ERR_NOERROR); +} + +/* + * Iftable entry + */ +int +op_ifentry(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + struct mibif *ifp = NULL; + int ret; + struct ifchange *ifc; + struct asn_oid idx; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + value->var.len = sub + 1; + value->var.subs[sub] = ifp->index; + break; + + case SNMP_OP_GET: + if (value->var.len - sub != 1) + return (SNMP_ERR_NOSUCHNAME); + if ((ifp = mib_find_if(value->var.subs[sub])) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if (value->var.len - sub != 1) + return (SNMP_ERR_NO_CREATION); + if ((ifp = mib_find_if(value->var.subs[sub])) == NULL) + return (SNMP_ERR_NO_CREATION); + if (value->var.subs[sub - 1] != LEAF_ifAdminStatus) + return (SNMP_ERR_NOT_WRITEABLE); + + idx.len = 1; + idx.subs[0] = ifp->index; + + if (value->v.integer != 1 && value->v.integer != 2) + return (SNMP_ERR_WRONG_VALUE); + + if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx, + &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL) + return (SNMP_ERR_RES_UNAVAIL); + ifc->ifindex = ifp->index; + + if (ifc->set & IFC_ADMIN) + return (SNMP_ERR_INCONS_VALUE); + ifc->set |= IFC_ADMIN; + ifc->admin = (value->v.integer == 1) ? 1 : 0; + + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + return (SNMP_ERR_NOERROR); + } + + if (ifp->mibtick < this_tick) + (void)mib_fetch_ifmib(ifp); + + ret = SNMP_ERR_NOERROR; + switch (value->var.subs[sub - 1]) { + + case LEAF_ifIndex: + value->v.integer = ifp->index; + break; + + case LEAF_ifDescr: + ret = string_get(value, ifp->descr, -1); + break; + + case LEAF_ifType: + value->v.integer = ifp->mib.ifmd_data.ifi_type; + break; + + case LEAF_ifMtu: + value->v.integer = ifp->mib.ifmd_data.ifi_mtu; + break; + + case LEAF_ifSpeed: + value->v.integer = ifp->mib.ifmd_data.ifi_baudrate; + break; + + case LEAF_ifPhysAddress: + ret = string_get(value, ifp->physaddr, + ifp->physaddrlen); + break; + + case LEAF_ifAdminStatus: + value->v.integer = + (ifp->mib.ifmd_flags & IFF_UP) ? 1 : 2; + break; + + case LEAF_ifOperStatus: + value->v.integer = + (ifp->mib.ifmd_flags & IFF_RUNNING) ? 1 : 2; + break; + + case LEAF_ifLastChange: + value->v.uint32 = + ticks_get_timeval(&ifp->mib.ifmd_data.ifi_lastchange); + break; + + case LEAF_ifInOctets: + value->v.uint32 = ifp->mib.ifmd_data.ifi_ibytes; + break; + + case LEAF_ifInUcastPkts: + value->v.uint32 = ifp->mib.ifmd_data.ifi_ipackets - + ifp->mib.ifmd_data.ifi_imcasts; + break; + + case LEAF_ifInNUcastPkts: + value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts; + break; + + case LEAF_ifInDiscards: + value->v.uint32 = ifp->mib.ifmd_data.ifi_iqdrops; + break; + + case LEAF_ifInErrors: + value->v.uint32 = ifp->mib.ifmd_data.ifi_ierrors; + break; + + case LEAF_ifInUnknownProtos: + value->v.uint32 = ifp->mib.ifmd_data.ifi_noproto; + break; + + case LEAF_ifOutOctets: + value->v.uint32 = ifp->mib.ifmd_data.ifi_obytes; + break; + + case LEAF_ifOutUcastPkts: + value->v.uint32 = ifp->mib.ifmd_data.ifi_opackets - + ifp->mib.ifmd_data.ifi_omcasts; + break; + + case LEAF_ifOutNUcastPkts: + value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts; + break; + + case LEAF_ifOutDiscards: + value->v.uint32 = ifp->mib.ifmd_snd_drops; + break; + + case LEAF_ifOutErrors: + value->v.uint32 = ifp->mib.ifmd_data.ifi_oerrors; + break; + + case LEAF_ifOutQLen: + value->v.uint32 = ifp->mib.ifmd_snd_len; + break; + + case LEAF_ifSpecific: + value->v.oid = oid_zeroDotZero; + break; + } + return (SNMP_ERR_NOERROR); +} + +/* + * IfXtable entry + */ +int +op_ifxtable(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + struct mibif *ifp = NULL; + int ret; + struct ifchange *ifc; + struct asn_oid idx; + + switch (op) { + + again: + if (op != SNMP_OP_GETNEXT) + return (SNMP_ERR_NOSUCHNAME); + /* FALLTHROUGH */ + + case SNMP_OP_GETNEXT: + if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + value->var.len = sub + 1; + value->var.subs[sub] = ifp->index; + break; + + case SNMP_OP_GET: + if (value->var.len - sub != 1) + return (SNMP_ERR_NOSUCHNAME); + if ((ifp = mib_find_if(value->var.subs[sub])) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if (value->var.len - sub != 1) + return (SNMP_ERR_NO_CREATION); + if ((ifp = mib_find_if(value->var.subs[sub])) == NULL) + return (SNMP_ERR_NO_CREATION); + + idx.len = 1; + idx.subs[0] = ifp->index; + + if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx, + &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL) + return (SNMP_ERR_RES_UNAVAIL); + ifc->ifindex = ifp->index; + + switch (value->var.subs[sub - 1]) { + + case LEAF_ifLinkUpDownTrapEnable: + if (value->v.integer != 1 && value->v.integer != 2) + return (SNMP_ERR_WRONG_VALUE); + if (ifc->set & IFC_TRAPS) + return (SNMP_ERR_INCONS_VALUE); + ifc->set |= IFC_TRAPS; + ifc->traps = (value->v.integer == 1) ? 1 : 0; + return (SNMP_ERR_NOERROR); + + case LEAF_ifPromiscuousMode: + if (value->v.integer != 1 && value->v.integer != 2) + return (SNMP_ERR_WRONG_VALUE); + if (ifc->set & IFC_PROMISC) + return (SNMP_ERR_INCONS_VALUE); + ifc->set |= IFC_PROMISC; + ifc->promisc = (value->v.integer == 1) ? 1 : 0; + return (SNMP_ERR_NOERROR); + } + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + return (SNMP_ERR_NOERROR); + } + + if (ifp->mibtick < this_tick) + (void)mib_fetch_ifmib(ifp); + + ret = SNMP_ERR_NOERROR; + switch (value->var.subs[sub - 1]) { + + case LEAF_ifName: + ret = string_get(value, ifp->name, -1); + break; + + case LEAF_ifInMulticastPkts: + value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts; + break; + + case LEAF_ifInBroadcastPkts: + value->v.uint32 = 0; + break; + + case LEAF_ifOutMulticastPkts: + value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts; + break; + + case LEAF_ifOutBroadcastPkts: + value->v.uint32 = 0; + break; + + case LEAF_ifHCInOctets: + if (!(ifp->flags & MIBIF_HIGHSPEED)) + goto again; + value->v.counter64 = ifp->hc_inoctets; + break; + + case LEAF_ifHCInUcastPkts: + if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) + goto again; + value->v.counter64 = ifp->hc_ipackets - ifp->hc_imcasts; + break; + + case LEAF_ifHCInMulticastPkts: + if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) + goto again; + value->v.counter64 = ifp->hc_imcasts; + break; + + case LEAF_ifHCInBroadcastPkts: + if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) + goto again; + value->v.counter64 = 0; + break; + + case LEAF_ifHCOutOctets: + if (!(ifp->flags & MIBIF_HIGHSPEED)) + goto again; + value->v.counter64 = ifp->hc_inoctets; + break; + + case LEAF_ifHCOutUcastPkts: + if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) + goto again; + value->v.counter64 = ifp->hc_opackets - ifp->hc_omcasts; + break; + + case LEAF_ifHCOutMulticastPkts: + if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) + goto again; + value->v.counter64 = ifp->hc_omcasts; + break; + + case LEAF_ifHCOutBroadcastPkts: + if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) + goto again; + value->v.counter64 = 0; + break; + + case LEAF_ifLinkUpDownTrapEnable: + value->v.integer = ifp->trap_enable ? 1 : 2; + break; + + case LEAF_ifHighSpeed: + value->v.integer = + (ifp->mib.ifmd_data.ifi_baudrate + 499999) / 1000000; + break; + + case LEAF_ifPromiscuousMode: + value->v.integer = + (ifp->mib.ifmd_flags & IFF_PROMISC) ? 1 : 2; + break; + + case LEAF_ifConnectorPresent: + value->v.integer = ifp->has_connector ? 1 : 2; + break; + + case LEAF_ifAlias: + ret = string_get(value, "", -1); + break; + + case LEAF_ifCounterDiscontinuityTime: + if (ifp->counter_disc > start_tick) + value->v.uint32 = ifp->counter_disc - start_tick; + else + value->v.uint32 = 0; + break; + } + return (ret); +} diff --git a/contrib/bsnmp/snmp_mibII/mibII_ip.c b/contrib/bsnmp/snmp_mibII/mibII_ip.c new file mode 100644 index 0000000..d0d2590 --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/mibII_ip.c @@ -0,0 +1,497 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation 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 or documentation 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS 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 + * FRAUNHOFER FOKUS OR ITS 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. + * + * $Begemot: bsnmp/snmp_mibII/mibII_ip.c,v 1.8 2003/01/28 13:44:35 hbb Exp $ + * + * ip group scalars. + */ +#include "mibII.h" +#include "mibII_oid.h" +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/ip_icmp.h> +#include <netinet/icmp_var.h> + +static struct ipstat ipstat; +static u_int ip_idrop; +static struct icmpstat icmpstat; + +static int ip_forwarding; +static int ip_defttl; +static u_int32_t ip_tick; + +static u_int32_t ipstat_tick; + +static int +fetch_ipstat(void) +{ + size_t len; + + len = sizeof(ipstat); + if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.ip.stats: %m"); + return (-1); + } + if (len != sizeof(ipstat)) { + syslog(LOG_ERR, "net.inet.ip.stats: wrong size"); + return (-1); + } + len = sizeof(ip_idrop); + if (sysctlbyname("net.inet.ip.intr_queue_drops", &ip_idrop, &len, NULL, 0) == -1) + syslog(LOG_WARNING, "net.inet.ip.intr_queue_drops: %m"); + if (len != sizeof(ip_idrop)) { + syslog(LOG_WARNING, "net.inet.ip.intr_queue_drops: wrong size"); + ip_idrop = 0; + } + len = sizeof(icmpstat); + if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.icmp.stats: %m"); + return (-1); + } + if (len != sizeof(icmpstat)) { + syslog(LOG_ERR, "net.inet.icmp.stats: wrong size"); + return (-1); + } + + ipstat_tick = get_ticks(); + return (0); +} + +static int +fetch_ip(void) +{ + size_t len; + + len = sizeof(ip_forwarding); + if (sysctlbyname("net.inet.ip.forwarding", &ip_forwarding, &len, + NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.ip.forwarding: %m"); + return (-1); + } + if (len != sizeof(ip_forwarding)) { + syslog(LOG_ERR, "net.inet.ip.forwarding: wrong size"); + return (-1); + } + + len = sizeof(ip_defttl); + if (sysctlbyname("net.inet.ip.ttl", &ip_defttl, &len, + NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.ip.ttl: %m"); + return (-1); + } + if (len != sizeof(ip_defttl)) { + syslog(LOG_ERR, "net.inet.ip.ttl: wrong size"); + return (-1); + } + + ip_tick = get_ticks(); + return (0); +} + +static int +ip_forward(int forw, int *old) +{ + size_t olen; + + olen = sizeof(*old); + if (sysctlbyname("net.inet.ip.forwarding", old, old ? &olen : NULL, + &forw, sizeof(forw)) == -1) { + syslog(LOG_ERR, "set net.inet.ip.forwarding: %m"); + return (-1); + } + ip_forwarding = forw; + return (0); +} + +static int +ip_setttl(int ttl, int *old) +{ + size_t olen; + + olen = sizeof(*old); + if (sysctlbyname("net.inet.ip.ttl", old, old ? &olen : NULL, + &ttl, sizeof(ttl)) == -1) { + syslog(LOG_ERR, "set net.inet.ip.ttl: %m"); + return (-1); + } + ip_defttl = ttl; + return (0); +} + +/* + * READ/WRITE ip group. + */ +int +op_ip(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int idx __unused, enum snmp_op op) +{ + int old; + + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + if (ip_tick < this_tick) + if (fetch_ip() == -1) + return (SNMP_ERR_GENERR); + + switch (value->var.subs[sub - 1]) { + + case LEAF_ipForwarding: + ctx->scratch->int1 = ip_forwarding ? 1 : 2; + ctx->scratch->int2 = value->v.integer; + if (value->v.integer == 1) { + if (!ip_forwarding && ip_forward(1, &old)) + return (SNMP_ERR_GENERR); + ctx->scratch->int1 = old ? 1 : 2; + } else if (value->v.integer == 2) { + if (ip_forwarding && ip_forward(0, &old)) + return (SNMP_ERR_GENERR); + ctx->scratch->int1 = old; + } else + return (SNMP_ERR_WRONG_VALUE); + break; + + case LEAF_ipDefaultTTL: + ctx->scratch->int1 = ip_defttl; + ctx->scratch->int2 = value->v.integer; + if (value->v.integer < 1 || value->v.integer > 255) + return (SNMP_ERR_WRONG_VALUE); + if (ip_defttl != value->v.integer && + ip_setttl(value->v.integer, &old)) + return (SNMP_ERR_GENERR); + ctx->scratch->int1 = old; + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + switch (value->var.subs[sub - 1]) { + + case LEAF_ipForwarding: + if (ctx->scratch->int1 == 1) { + if (ctx->scratch->int2 == 2) + (void)ip_forward(1, NULL); + } else { + if (ctx->scratch->int2 == 1) + (void)ip_forward(0, NULL); + } + break; + + case LEAF_ipDefaultTTL: + if (ctx->scratch->int1 != ctx->scratch->int2) + (void)ip_setttl(ctx->scratch->int1, NULL); + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + return (SNMP_ERR_NOERROR); + } + + if (ip_tick < this_tick) + if (fetch_ip() == -1) + return (SNMP_ERR_GENERR); + + switch (value->var.subs[sub - 1]) { + + case LEAF_ipForwarding: + value->v.integer = ip_forwarding ? 1 : 2; + break; + + case LEAF_ipDefaultTTL: + value->v.integer = ip_defttl; + break; + } + return (SNMP_ERR_NOERROR); +} + +/* + * READ-ONLY statistics ip group. + */ +int +op_ipstat(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int idx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + if (ipstat_tick < this_tick) + fetch_ipstat(); + + switch (value->var.subs[sub - 1]) { + + case LEAF_ipInReceives: + value->v.uint32 = ipstat.ips_total; + break; + + case LEAF_ipInHdrErrors: + value->v.uint32 = ipstat.ips_badsum + ipstat.ips_tooshort + + ipstat.ips_toosmall + ipstat.ips_badhlen + + ipstat.ips_badlen + ipstat.ips_badvers + + + ipstat.ips_toolong; + break; + + case LEAF_ipInAddrErrors: + value->v.uint32 = ipstat.ips_cantforward; + break; + + case LEAF_ipForwDatagrams: + value->v.uint32 = ipstat.ips_forward; + break; + + case LEAF_ipInUnknownProtos: + value->v.uint32 = ipstat.ips_noproto; + break; + + case LEAF_ipInDiscards: + value->v.uint32 = ip_idrop; + break; + + case LEAF_ipInDelivers: + value->v.uint32 = ipstat.ips_delivered; + break; + + case LEAF_ipOutRequests: + value->v.uint32 = ipstat.ips_localout; + break; + + case LEAF_ipOutDiscards: + value->v.uint32 = ipstat.ips_odropped; + break; + + case LEAF_ipOutNoRoutes: + value->v.uint32 = ipstat.ips_noroute; + break; + + case LEAF_ipReasmTimeout: + value->v.integer = IPFRAGTTL; + break; + + case LEAF_ipReasmReqds: + value->v.uint32 = ipstat.ips_fragments; + break; + + case LEAF_ipReasmOKs: + value->v.uint32 = ipstat.ips_reassembled; + break; + + case LEAF_ipReasmFails: + value->v.uint32 = ipstat.ips_fragdropped + + ipstat.ips_fragtimeout; + break; + + case LEAF_ipFragOKs: + value->v.uint32 = ipstat.ips_fragmented; + break; + + case LEAF_ipFragFails: + value->v.uint32 = ipstat.ips_cantfrag; + break; + + case LEAF_ipFragCreates: + value->v.uint32 = ipstat.ips_ofragments; + break; + } + return (SNMP_ERR_NOERROR); +} + +/* + * READ-ONLY statistics icmp group. + */ +int +op_icmpstat(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int idx __unused, enum snmp_op op) +{ + u_int i; + + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + if (ipstat_tick < this_tick) + fetch_ipstat(); + + switch (value->var.subs[sub - 1]) { + + case LEAF_icmpInMsgs: + value->v.integer = 0; + for (i = 0; i <= ICMP_MAXTYPE; i++) + value->v.integer += icmpstat.icps_inhist[i]; + value->v.integer += icmpstat.icps_tooshort + + icmpstat.icps_checksum; + /* missing: bad type and packets on faith */ + break; + + case LEAF_icmpInErrors: + value->v.integer = icmpstat.icps_tooshort + + icmpstat.icps_checksum + + icmpstat.icps_badlen + + icmpstat.icps_badcode + + icmpstat.icps_bmcastecho + + icmpstat.icps_bmcasttstamp; + break; + + case LEAF_icmpInDestUnreachs: + value->v.integer = icmpstat.icps_inhist[ICMP_UNREACH]; + break; + + case LEAF_icmpInTimeExcds: + value->v.integer = icmpstat.icps_inhist[ICMP_TIMXCEED]; + break; + + case LEAF_icmpInParmProbs: + value->v.integer = icmpstat.icps_inhist[ICMP_PARAMPROB]; + break; + + case LEAF_icmpInSrcQuenchs: + value->v.integer = icmpstat.icps_inhist[ICMP_SOURCEQUENCH]; + break; + + case LEAF_icmpInRedirects: + value->v.integer = icmpstat.icps_inhist[ICMP_REDIRECT]; + break; + + case LEAF_icmpInEchos: + value->v.integer = icmpstat.icps_inhist[ICMP_ECHO]; + break; + + case LEAF_icmpInEchoReps: + value->v.integer = icmpstat.icps_inhist[ICMP_ECHOREPLY]; + break; + + case LEAF_icmpInTimestamps: + value->v.integer = icmpstat.icps_inhist[ICMP_TSTAMP]; + break; + + case LEAF_icmpInTimestampReps: + value->v.integer = icmpstat.icps_inhist[ICMP_TSTAMPREPLY]; + break; + + case LEAF_icmpInAddrMasks: + value->v.integer = icmpstat.icps_inhist[ICMP_MASKREQ]; + break; + + case LEAF_icmpInAddrMaskReps: + value->v.integer = icmpstat.icps_inhist[ICMP_MASKREPLY]; + break; + + case LEAF_icmpOutMsgs: + value->v.integer = 0; + for (i = 0; i <= ICMP_MAXTYPE; i++) + value->v.integer += icmpstat.icps_outhist[i]; + value->v.integer += icmpstat.icps_badaddr + + icmpstat.icps_noroute; + break; + + case LEAF_icmpOutErrors: + value->v.integer = icmpstat.icps_badaddr + + icmpstat.icps_noroute; + break; + + case LEAF_icmpOutDestUnreachs: + value->v.integer = icmpstat.icps_outhist[ICMP_UNREACH]; + break; + + case LEAF_icmpOutTimeExcds: + value->v.integer = icmpstat.icps_outhist[ICMP_TIMXCEED]; + break; + + case LEAF_icmpOutParmProbs: + value->v.integer = icmpstat.icps_outhist[ICMP_PARAMPROB]; + break; + + case LEAF_icmpOutSrcQuenchs: + value->v.integer = icmpstat.icps_outhist[ICMP_SOURCEQUENCH]; + break; + + case LEAF_icmpOutRedirects: + value->v.integer = icmpstat.icps_outhist[ICMP_REDIRECT]; + break; + + case LEAF_icmpOutEchos: + value->v.integer = icmpstat.icps_outhist[ICMP_ECHO]; + break; + + case LEAF_icmpOutEchoReps: + value->v.integer = icmpstat.icps_outhist[ICMP_ECHOREPLY]; + break; + + case LEAF_icmpOutTimestamps: + value->v.integer = icmpstat.icps_outhist[ICMP_TSTAMP]; + break; + + case LEAF_icmpOutTimestampReps: + value->v.integer = icmpstat.icps_outhist[ICMP_TSTAMPREPLY]; + break; + + case LEAF_icmpOutAddrMasks: + value->v.integer = icmpstat.icps_outhist[ICMP_MASKREQ]; + break; + + case LEAF_icmpOutAddrMaskReps: + value->v.integer = icmpstat.icps_outhist[ICMP_MASKREPLY]; + break; + } + return (SNMP_ERR_NOERROR); +} diff --git a/contrib/bsnmp/snmp_mibII/mibII_ipaddr.c b/contrib/bsnmp/snmp_mibII/mibII_ipaddr.c new file mode 100644 index 0000000..0cc5936 --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/mibII_ipaddr.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2001-2002 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation 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 or documentation 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS 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 + * FRAUNHOFER FOKUS OR ITS 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. + * + * $Begemot: bsnmp/snmp_mibII/mibII_ipaddr.c,v 1.6 2003/01/28 13:44:35 hbb Exp $ + * + * IP address table. This table is writeable! + * + * Writing to this table will add a new IP address to the interface. + * An address can be deleted with writing the interface index 0. + */ +#include "mibII.h" +#include "mibII_oid.h" + +static const struct asn_oid + oid_ipAddrTable = OIDX_ipAddrTable; + +/* + * Be careful not to hold any pointers during the SET processing - the + * interface and address lists can be relocated at any time. + */ +struct update { + struct snmp_dependency dep; + + u_int32_t set; + struct in_addr addr; + struct in_addr mask; + int bcast; + u_int ifindex; + + u_int32_t rb; + struct in_addr rb_mask; + struct in_addr rb_bcast; +}; +#define UPD_IFINDEX 0x0001 +#define UPD_MASK 0x0002 +#define UPD_BCAST 0x0004 +#define RB_CREATE 0x0001 +#define RB_DESTROY 0x0002 +#define RB_MODIFY 0x0004 + +/* + * Create a new interface address + */ +static int +create(struct update *upd) +{ + struct in_addr bcast; + struct mibifa *ifa; + + if (!(upd->set & UPD_MASK)) { + if (IN_CLASSA(ntohl(upd->addr.s_addr))) + upd->mask.s_addr = htonl(IN_CLASSA_NET); + else if (IN_CLASSB(ntohl(upd->addr.s_addr))) + upd->mask.s_addr = htonl(IN_CLASSB_NET); + else if (IN_CLASSC(ntohl(upd->addr.s_addr))) + upd->mask.s_addr = htonl(IN_CLASSC_NET); + else + upd->mask.s_addr = 0xffffffff; + } + + bcast.s_addr = upd->addr.s_addr & upd->mask.s_addr; + if (!(upd->set & UPD_BCAST) || upd->bcast) + bcast.s_addr |= htonl(0xffffffff & ~ntohl(upd->mask.s_addr)); + + if ((ifa = mib_create_ifa(upd->ifindex, upd->addr, upd->mask, bcast)) == NULL) + return (SNMP_ERR_GENERR); + + upd->rb |= RB_CREATE; + return (SNMP_ERR_NOERROR); +} + +/* + * Modify the netmask or broadcast address. The ifindex cannot be + * changed (obviously). + */ +static int +modify(struct update *upd, struct mibifa *ifa) +{ + struct mibif *ifp; + + if ((ifp = mib_find_if(ifa->ifindex)) == NULL) + return (SNMP_ERR_WRONG_VALUE); + if ((upd->set & UPD_IFINDEX) && upd->ifindex != ifa->ifindex) + return (SNMP_ERR_INCONS_VALUE); + + upd->rb_mask = ifa->inmask; + upd->rb_bcast = ifa->inbcast; + if (((upd->set & UPD_MASK) && upd->mask.s_addr != ifa->inmask.s_addr) || + (upd->set & UPD_BCAST)) { + if (upd->set & UPD_MASK) + ifa->inmask = upd->mask; + if (upd->set & UPD_BCAST) { + ifa->inbcast.s_addr = ifa->inaddr.s_addr + & ifa->inmask.s_addr; + if (upd->bcast) + ifa->inbcast.s_addr |= 0xffffffff + & ~ifa->inmask.s_addr; + } + if (mib_modify_ifa(ifa)) { + syslog(LOG_ERR, "set netmask/bcast: %m"); + ifa->inmask = upd->rb_mask; + ifa->inbcast = upd->rb_bcast; + mib_unmodify_ifa(ifa); + return (SNMP_ERR_GENERR); + } + upd->rb |= RB_MODIFY; + } + return (SNMP_ERR_NOERROR); +} + +/* + * Remove an IP address from an interface. This is called when + * the SET finishes. + */ +static void +destroy_func(struct snmp_context *ctx __unused, int fail __unused, void *arg) +{ + struct mibifa *ifa = arg; + + if (ifa->flags & MIBIFA_DESTROYED) { + TAILQ_REMOVE(&mibifa_list, ifa, link); + free(ifa); + } +} + +/* + * Destroy the given row in the table. We remove the address from the + * system, but keep the structure around for the COMMIT. It's deleted + * only in the finish function. + */ +static int +destroy(struct snmp_context *ctx, struct update *upd, struct mibifa *ifa) +{ + if (mib_destroy_ifa(ifa)) + return (SNMP_ERR_GENERR); + if (snmp_set_atfinish(ctx, destroy_func, ifa)) { + syslog(LOG_ERR, "atfinish: %m"); + mib_undestroy_ifa(ifa); + return (SNMP_ERR_GENERR); + } + upd->rb |= RB_DESTROY; + return (SNMP_ERR_NOERROR); +} + +/* + * This function is called to commit/rollback a SET on an IpAddrEntry + */ +static int +update_func(struct snmp_context *ctx, struct snmp_dependency *dep, + enum snmp_depop op) +{ + struct update *upd = (struct update *)dep; + struct mibifa *ifa; + + switch (op) { + + case SNMP_DEPOP_COMMIT: + if ((ifa = mib_find_ifa(upd->addr)) == NULL) { + /* non existing entry - must have ifindex */ + if (!(upd->set & UPD_IFINDEX)) + return (SNMP_ERR_INCONS_NAME); + return (create(upd)); + } + /* existing entry */ + if ((upd->set & UPD_IFINDEX) && upd->ifindex == 0) { + /* delete */ + return (destroy(ctx, upd, ifa)); + } + /* modify entry */ + return (modify(upd, ifa)); + + case SNMP_DEPOP_ROLLBACK: + if ((ifa = mib_find_ifa(upd->addr)) == NULL) { + /* ups */ + mib_iflist_bad = 1; + return (SNMP_ERR_NOERROR); + } + if (upd->rb & RB_CREATE) { + mib_uncreate_ifa(ifa); + return (SNMP_ERR_NOERROR); + } + if (upd->rb & RB_DESTROY) { + mib_undestroy_ifa(ifa); + return (SNMP_ERR_NOERROR); + } + if (upd->rb & RB_MODIFY) { + ifa->inmask = upd->rb_mask; + ifa->inbcast = upd->rb_bcast; + mib_unmodify_ifa(ifa); + return (SNMP_ERR_NOERROR); + } + return (SNMP_ERR_NOERROR); + } + abort(); +} + +/**********************************************************************/ +/* + * ACTION + */ +int +op_ipaddr(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which; + struct mibifa *ifa; + struct update *upd; + struct asn_oid idx; + u_char ipaddr[4]; + + which = value->var.subs[sub - 1]; + + ifa = NULL; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((ifa = NEXT_OBJECT_OID(&mibifa_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &ifa->index); + break; + + case SNMP_OP_GET: + if ((ifa = FIND_OBJECT_OID(&mibifa_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if (index_decode(&value->var, sub, iidx, ipaddr)) + return (SNMP_ERR_NO_CREATION); + ifa = FIND_OBJECT_OID(&mibifa_list, &value->var, sub); + idx.len = 4; + idx.subs[0] = ipaddr[0]; + idx.subs[1] = ipaddr[1]; + idx.subs[2] = ipaddr[2]; + idx.subs[3] = ipaddr[3]; + + if ((upd = (struct update *)snmp_dep_lookup(ctx, + &oid_ipAddrTable, &idx, sizeof(*upd), update_func)) == NULL) + return (SNMP_ERR_RES_UNAVAIL); + + upd->addr.s_addr = htonl((ipaddr[0] << 24) | (ipaddr[1] << 16) | + (ipaddr[2] << 8) | (ipaddr[3] << 0)); + + switch (which) { + + case LEAF_ipAdEntIfIndex: + if (upd->set & UPD_IFINDEX) + return (SNMP_ERR_INCONS_VALUE); + if (value->v.integer < 0 || + value->v.integer > 0x07fffffff) + return (SNMP_ERR_WRONG_VALUE); + if (ifa != NULL) { + if (ifa->ifindex != (u_int)value->v.integer && + value->v.integer != 0) + return (SNMP_ERR_INCONS_VALUE); + } + upd->set |= UPD_IFINDEX; + upd->ifindex = (u_int)value->v.integer; + break; + + case LEAF_ipAdEntNetMask: + if (upd->set & UPD_MASK) + return (SNMP_ERR_INCONS_VALUE); + upd->mask.s_addr = htonl((value->v.ipaddress[0] << 24) + | (value->v.ipaddress[1] << 16) + | (value->v.ipaddress[2] << 8) + | (value->v.ipaddress[3] << 0)); + upd->set |= UPD_MASK; + break; + + case LEAF_ipAdEntBcastAddr: + if (upd->set & UPD_BCAST) + return (SNMP_ERR_INCONS_VALUE); + if (value->v.integer != 0 && value->v.integer != 1) + return (SNMP_ERR_WRONG_VALUE); + upd->bcast = value->v.integer; + upd->set |= UPD_BCAST; + break; + + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + return (SNMP_ERR_NOERROR); + } + + switch (which) { + + case LEAF_ipAdEntAddr: + value->v.ipaddress[0] = ifa->index.subs[0]; + value->v.ipaddress[1] = ifa->index.subs[1]; + value->v.ipaddress[2] = ifa->index.subs[2]; + value->v.ipaddress[3] = ifa->index.subs[3]; + break; + + case LEAF_ipAdEntIfIndex: + if (ifa->flags & MIBIFA_DESTROYED) + value->v.integer = 0; + else + value->v.integer = ifa->ifindex; + break; + + case LEAF_ipAdEntNetMask: + value->v.ipaddress[0] = (ntohl(ifa->inmask.s_addr) >> 24) & 0xff; + value->v.ipaddress[1] = (ntohl(ifa->inmask.s_addr) >> 16) & 0xff; + value->v.ipaddress[2] = (ntohl(ifa->inmask.s_addr) >> 8) & 0xff; + value->v.ipaddress[3] = (ntohl(ifa->inmask.s_addr) >> 0) & 0xff; + break; + + case LEAF_ipAdEntBcastAddr: + value->v.integer = ntohl(ifa->inbcast.s_addr) & 1; + break; + + + case LEAF_ipAdEntReasmMaxSize: + value->v.integer = 65535; + break; + } + return (SNMP_ERR_NOERROR); +} diff --git a/contrib/bsnmp/snmp_mibII/mibII_nettomedia.c b/contrib/bsnmp/snmp_mibII/mibII_nettomedia.c new file mode 100644 index 0000000..e8a7919 --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/mibII_nettomedia.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation 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 or documentation 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS 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 + * FRAUNHOFER FOKUS OR ITS 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. + * + * $Begemot: bsnmp/snmp_mibII/mibII_nettomedia.c,v 1.6 2003/01/28 13:44:35 hbb Exp $ + * + * Read-only implementation of the Arp table (ipNetToMediaTable) + * + * The problem with the table is, that we don't receive routing message + * when a) an arp table entry is resolved and b) when an arp table entry is + * deleted automatically. Therefor we need to poll the table from time to + * time. + */ +#include "mibII.h" +#include "mibII_oid.h" + +#define ARPREFRESH 30 + +struct mibarp * +mib_find_arp(const struct mibif *ifp, struct in_addr in) +{ + struct mibarp *at; + u_int32_t a = ntohl(in.s_addr); + + if (get_ticks() >= mibarpticks + ARPREFRESH) + mib_arp_update(); + + TAILQ_FOREACH(at, &mibarp_list, link) + if (at->index.subs[0] == ifp->index && + (at->index.subs[1] == ((a >> 24) & 0xff)) && + (at->index.subs[2] == ((a >> 16) & 0xff)) && + (at->index.subs[3] == ((a >> 8) & 0xff)) && + (at->index.subs[4] == ((a >> 0) & 0xff))) + return (at); + return (NULL); +} + +struct mibarp * +mib_arp_create(const struct mibif *ifp, struct in_addr in, const u_char *phys, + size_t physlen) +{ + struct mibarp *at; + u_int32_t a = ntohl(in.s_addr); + + if ((at = malloc(sizeof(*at))) == NULL) + return (NULL); + at->flags = 0; + + at->index.len = 5; + at->index.subs[0] = ifp->index; + at->index.subs[1] = (a >> 24) & 0xff; + at->index.subs[2] = (a >> 16) & 0xff; + at->index.subs[3] = (a >> 8) & 0xff; + at->index.subs[4] = (a >> 0) & 0xff; + if ((at->physlen = physlen) > sizeof(at->phys)) + at->physlen = sizeof(at->phys); + memcpy(at->phys, phys, at->physlen); + + INSERT_OBJECT_OID(at, &mibarp_list); + + return (at); +} + +void +mib_arp_delete(struct mibarp *at) +{ + TAILQ_REMOVE(&mibarp_list, at, link); + free(at); +} + +int +op_nettomedia(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + struct mibarp *at; + + at = NULL; /* gcc */ + + if (get_ticks() >= mibarpticks + ARPREFRESH) + mib_arp_update(); + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((at = NEXT_OBJECT_OID(&mibarp_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &at->index); + break; + + case SNMP_OP_GET: + if ((at = FIND_OBJECT_OID(&mibarp_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if ((at = FIND_OBJECT_OID(&mibarp_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NO_CREATION); + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_ipNetToMediaIfIndex: + value->v.integer = at->index.subs[0]; + break; + + case LEAF_ipNetToMediaPhysAddress: + return (string_get(value, at->phys, at->physlen)); + + case LEAF_ipNetToMediaNetAddress: + value->v.ipaddress[0] = at->index.subs[1]; + value->v.ipaddress[1] = at->index.subs[2]; + value->v.ipaddress[2] = at->index.subs[3]; + value->v.ipaddress[3] = at->index.subs[4]; + break; + + case LEAF_ipNetToMediaType: + value->v.integer = (at->flags & MIBARP_PERM) ? 4 : 3; + break; + } + return (SNMP_ERR_NOERROR); +} diff --git a/contrib/bsnmp/snmp_mibII/mibII_rcvaddr.c b/contrib/bsnmp/snmp_mibII/mibII_rcvaddr.c new file mode 100644 index 0000000..7226e10 --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/mibII_rcvaddr.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation 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 or documentation 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS 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 + * FRAUNHOFER FOKUS OR ITS 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. + * + * $Begemot: bsnmp/snmp_mibII/mibII_rcvaddr.c,v 1.7 2003/01/28 13:44:35 hbb Exp $ + * + * Interface receive address table. + */ +#include "mibII.h" +#include "mibII_oid.h" + +/* + * find receive address + */ +struct mibrcvaddr * +mib_find_rcvaddr(u_int ifindex, const u_char *addr, size_t addrlen) +{ + struct mibrcvaddr *rcv; + + TAILQ_FOREACH(rcv, &mibrcvaddr_list, link) + if (rcv->ifindex == ifindex && + rcv->addrlen == addrlen && + memcmp(rcv->addr, addr, addrlen) == 0) + return (rcv); + return (NULL); +} + +/* + * Create receive address + */ +struct mibrcvaddr * +mib_rcvaddr_create(struct mibif *ifp, const u_char *addr, size_t addrlen) +{ + struct mibrcvaddr *rcv; + u_int i; + + if (addrlen + OIDLEN_ifRcvAddressEntry + 1 > ASN_MAXOIDLEN) + return (NULL); + + if ((rcv = malloc(sizeof(*rcv))) == NULL) + return (NULL); + rcv->ifindex = ifp->index; + rcv->addrlen = addrlen; + memcpy(rcv->addr, addr, addrlen); + rcv->flags = 0; + + rcv->index.len = addrlen + 2; + rcv->index.subs[0] = ifp->index; + rcv->index.subs[1] = addrlen; + for (i = 0; i < addrlen; i++) + rcv->index.subs[i + 2] = addr[i]; + + INSERT_OBJECT_OID(rcv, &mibrcvaddr_list); + + return (rcv); +} + +/* + * Delete a receive address + */ +void +mib_rcvaddr_delete(struct mibrcvaddr *rcv) +{ + TAILQ_REMOVE(&mibrcvaddr_list, rcv, link); + free(rcv); +} + +int +op_rcvaddr(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + struct mibrcvaddr *rcv; + + rcv = NULL; /* make compiler happy */ + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((rcv = NEXT_OBJECT_OID(&mibrcvaddr_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &rcv->index); + break; + + case SNMP_OP_GET: + if ((rcv = FIND_OBJECT_OID(&mibrcvaddr_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if ((rcv = FIND_OBJECT_OID(&mibrcvaddr_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NO_CREATION); + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_ifRcvAddressStatus: + value->v.integer = 1; + break; + + case LEAF_ifRcvAddressType: + value->v.integer = (rcv->flags & MIBRCVADDR_VOLATILE) ? 2 : 3; + break; + } + return (SNMP_ERR_NOERROR); +} diff --git a/contrib/bsnmp/snmp_mibII/mibII_route.c b/contrib/bsnmp/snmp_mibII/mibII_route.c new file mode 100644 index 0000000..d2683ce --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/mibII_route.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation 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 or documentation 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS 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 + * FRAUNHOFER FOKUS OR ITS 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. + * + * $Begemot: bsnmp/snmp_mibII/mibII_route.c,v 1.3 2003/01/28 13:44:35 hbb Exp $ + * + * Routing table + */ +#include "mibII.h" +#include "mibII_oid.h" + +struct sroute { + TAILQ_ENTRY(sroute) link; + struct asn_oid index; + u_int ifindex; + u_int type; + u_int proto; +}; +static TAILQ_HEAD(, sroute) sroute_list = TAILQ_HEAD_INITIALIZER(sroute_list); + +static u_int32_t route_tick; +static u_int route_total; + +static int +fetch_route(void) +{ + u_char *rtab, *next; + size_t len; + struct sroute *r; + struct rt_msghdr *rtm; + struct sockaddr *addrs[RTAX_MAX]; + struct sockaddr_in *sa, *gw; + struct in_addr mask, nhop; + in_addr_t ha; + struct mibif *ifp; + + while ((r = TAILQ_FIRST(&sroute_list)) != NULL) { + TAILQ_REMOVE(&sroute_list, r, link); + free(r); + } + route_total = 0; + + if ((rtab = mib_fetch_rtab(AF_INET, NET_RT_DUMP, 0, &len)) == NULL) + return (-1); + + next = rtab; + for (next = rtab; next < rtab + len; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)(void *)next; + if (rtm->rtm_type != RTM_GET || + !(rtm->rtm_flags & RTF_UP)) + continue; + mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs); + + if (addrs[RTAX_DST] == NULL || addrs[RTAX_GATEWAY] == NULL || + addrs[RTAX_DST]->sa_family != AF_INET) + continue; + + sa = (struct sockaddr_in *)(void *)addrs[RTAX_DST]; + + if (rtm->rtm_flags & RTF_HOST) { + mask.s_addr = 0xffffffff; + } else { + if (addrs[RTAX_NETMASK] == NULL || + addrs[RTAX_NETMASK]->sa_len == 0) + mask.s_addr = 0; + else + mask = ((struct sockaddr_in *)(void *) + addrs[RTAX_NETMASK])->sin_addr; + } + if (addrs[RTAX_GATEWAY] == NULL) { + nhop.s_addr = 0; + } else if (rtm->rtm_flags & RTF_LLINFO) { + nhop = sa->sin_addr; + } else { + gw = (struct sockaddr_in *)(void *)addrs[RTAX_GATEWAY]; + if (gw->sin_family != AF_INET) + continue; + nhop = gw->sin_addr; + } + if ((ifp = mib_find_if_sys(rtm->rtm_index)) == NULL) { + mib_iflist_bad = 1; + continue; + } + + if ((r = malloc(sizeof(*r))) == NULL) { + syslog(LOG_ERR, "%m"); + continue; + } + + route_total++; + + r->index.len = 13; + ha = ntohl(sa->sin_addr.s_addr); + r->index.subs[0] = (ha >> 24) & 0xff; + r->index.subs[1] = (ha >> 16) & 0xff; + r->index.subs[2] = (ha >> 8) & 0xff; + r->index.subs[3] = (ha >> 0) & 0xff; + ha = ntohl(mask.s_addr); + r->index.subs[4] = (ha >> 24) & 0xff; + r->index.subs[5] = (ha >> 16) & 0xff; + r->index.subs[6] = (ha >> 8) & 0xff; + r->index.subs[7] = (ha >> 0) & 0xff; + + r->index.subs[8] = 0; + + ha = ntohl(nhop.s_addr); + r->index.subs[9] = (ha >> 24) & 0xff; + r->index.subs[10] = (ha >> 16) & 0xff; + r->index.subs[11] = (ha >> 8) & 0xff; + r->index.subs[12] = (ha >> 0) & 0xff; + + r->ifindex = ifp->index; + + r->type = (rtm->rtm_flags & RTF_LLINFO) ? 3 : + (rtm->rtm_flags & RTF_REJECT) ? 2 : 4; + + /* cannot really know, what protocol it runs */ + r->proto = (rtm->rtm_flags & RTF_LOCAL) ? 2 : + (rtm->rtm_flags & RTF_STATIC) ? 3 : + (rtm->rtm_flags & RTF_DYNAMIC) ? 4 : 10; + + INSERT_OBJECT_OID(r, &sroute_list); + } + + free(rtab); + route_tick = get_ticks(); + + return (0); +} + +/* + * Table + */ +int +op_route_table(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + static struct sroute *r; + + if (route_tick < this_tick) + if (fetch_route() == -1) + return (SNMP_ERR_GENERR); + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((r = NEXT_OBJECT_OID(&sroute_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &r->index); + break; + + case SNMP_OP_GET: + if ((r = FIND_OBJECT_OID(&sroute_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if ((r = FIND_OBJECT_OID(&sroute_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NO_CREATION); + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + + default: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_ipCidrRouteDest: + value->v.ipaddress[0] = r->index.subs[0]; + value->v.ipaddress[1] = r->index.subs[1]; + value->v.ipaddress[2] = r->index.subs[2]; + value->v.ipaddress[3] = r->index.subs[3]; + break; + + case LEAF_ipCidrRouteMask: + value->v.ipaddress[0] = r->index.subs[4]; + value->v.ipaddress[1] = r->index.subs[5]; + value->v.ipaddress[2] = r->index.subs[6]; + value->v.ipaddress[3] = r->index.subs[7]; + break; + + case LEAF_ipCidrRouteTos: + value->v.integer = r->index.subs[8]; + break; + + case LEAF_ipCidrRouteNextHop: + value->v.ipaddress[0] = r->index.subs[9]; + value->v.ipaddress[1] = r->index.subs[10]; + value->v.ipaddress[2] = r->index.subs[11]; + value->v.ipaddress[3] = r->index.subs[12]; + break; + + case LEAF_ipCidrRouteIfIndex: + value->v.integer = r->ifindex; + break; + + case LEAF_ipCidrRouteType: + value->v.integer = r->type; + break; + + case LEAF_ipCidrRouteProto: + value->v.integer = r->proto; + break; + + case LEAF_ipCidrRouteAge: + value->v.integer = 0; + break; + + case LEAF_ipCidrRouteInfo: + value->v.oid = oid_zeroDotZero; + break; + + case LEAF_ipCidrRouteNextHopAS: + value->v.integer = 0; + break; + + case LEAF_ipCidrRouteMetric1: + case LEAF_ipCidrRouteMetric2: + case LEAF_ipCidrRouteMetric3: + case LEAF_ipCidrRouteMetric4: + case LEAF_ipCidrRouteMetric5: + value->v.integer = -1; + break; + + case LEAF_ipCidrRouteStatus: + value->v.integer = 1; + break; + } + return (SNMP_ERR_NOERROR); +} + +/* + * scalars + */ +int +op_route(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + if (route_tick < this_tick) + if (fetch_route() == -1) + return (SNMP_ERR_GENERR); + + switch (value->var.subs[sub - 1]) { + + case LEAF_ipCidrRouteNumber: + value->v.uint32 = route_total; + break; + + } + return (SNMP_ERR_NOERROR); +} diff --git a/contrib/bsnmp/snmp_mibII/mibII_tcp.c b/contrib/bsnmp/snmp_mibII/mibII_tcp.c new file mode 100644 index 0000000..f4509f9 --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/mibII_tcp.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation 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 or documentation 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS 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 + * FRAUNHOFER FOKUS OR ITS 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. + * + * $Begemot: bsnmp/snmp_mibII/mibII_tcp.c,v 1.4 2003/01/28 13:44:35 hbb Exp $ + * + * tcp + */ +#include "mibII.h" +#include "mibII_oid.h" +#include <sys/socketvar.h> +#include <netinet/in_pcb.h> +#include <netinet/tcp.h> +#include <netinet/tcp_var.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_fsm.h> + +struct tcp_index { + struct asn_oid index; + struct xtcpcb *tp; +}; + +static u_int32_t tcp_tick; +static struct tcpstat tcpstat; +static struct xinpgen *xinpgen; +static size_t xinpgen_len; +static u_int tcp_count; +static u_int tcp_total; + +static u_int oidnum; +static struct tcp_index *tcpoids; + +static int +tcp_compare(const void *p1, const void *p2) +{ + const struct tcp_index *t1 = p1; + const struct tcp_index *t2 = p2; + + return (asn_compare_oid(&t1->index, &t2->index)); +} + +static int +fetch_tcp(void) +{ + size_t len; + struct xinpgen *ptr; + struct xtcpcb *tp; + struct tcp_index *oid; + in_addr_t inaddr; + + len = sizeof(tcpstat); + if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.tcp.stats: %m"); + return (-1); + } + if (len != sizeof(tcpstat)) { + syslog(LOG_ERR, "net.inet.tcp.stats: wrong size"); + return (-1); + } + + len = 0; + if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.tcp.pcblist: %m"); + return (-1); + } + if (len > xinpgen_len) { + if ((ptr = realloc(xinpgen, len)) == NULL) { + syslog(LOG_ERR, "%zu: %m", len); + return (-1); + } + xinpgen = ptr; + xinpgen_len = len; + } + if (sysctlbyname("net.inet.tcp.pcblist", xinpgen, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.tcp.pcblist: %m"); + return (-1); + } + + tcp_tick = get_ticks(); + + tcp_count = 0; + tcp_total = 0; + for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len); + ptr->xig_len > sizeof(struct xinpgen); + ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) { + tp = (struct xtcpcb *)ptr; + if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen || + (tp->xt_inp.inp_vflag & INP_IPV4) == 0) + continue; + + tcp_total++; + if (tp->xt_tp.t_state == TCPS_ESTABLISHED || + tp->xt_tp.t_state == TCPS_CLOSE_WAIT) + tcp_count++; + } + + if (oidnum < tcp_total) { + oid = realloc(tcpoids, tcp_total * sizeof(tcpoids[0])); + if (oid == NULL) { + free(tcpoids); + oidnum = 0; + return (0); + } + tcpoids = oid; + oidnum = tcp_total; + } + + oid = tcpoids; + for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len); + ptr->xig_len > sizeof(struct xinpgen); + ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) { + tp = (struct xtcpcb *)ptr; + if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen || + (tp->xt_inp.inp_vflag & INP_IPV4) == 0) + continue; + oid->tp = tp; + oid->index.len = 10; + inaddr = ntohl(tp->xt_inp.inp_laddr.s_addr); + oid->index.subs[0] = (inaddr >> 24) & 0xff; + oid->index.subs[1] = (inaddr >> 16) & 0xff; + oid->index.subs[2] = (inaddr >> 8) & 0xff; + oid->index.subs[3] = (inaddr >> 0) & 0xff; + oid->index.subs[4] = ntohs(tp->xt_inp.inp_lport); + inaddr = ntohl(tp->xt_inp.inp_faddr.s_addr); + oid->index.subs[5] = (inaddr >> 24) & 0xff; + oid->index.subs[6] = (inaddr >> 16) & 0xff; + oid->index.subs[7] = (inaddr >> 8) & 0xff; + oid->index.subs[8] = (inaddr >> 0) & 0xff; + oid->index.subs[9] = ntohs(tp->xt_inp.inp_fport); + oid++; + } + + qsort(tcpoids, tcp_total, sizeof(tcpoids[0]), tcp_compare); + + return (0); +} + +/* + * Scalars + */ +int +op_tcp(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + if (tcp_tick < this_tick) + if (fetch_tcp() == -1) + return (SNMP_ERR_GENERR); + + switch (value->var.subs[sub - 1]) { + + case LEAF_tcpRtoAlgorithm: + value->v.integer = 4; /* Van Jacobson */ + break; + +#define hz clockinfo.hz + + case LEAF_tcpRtoMin: + value->v.integer = 1000 * TCPTV_MIN / hz; + break; + + case LEAF_tcpRtoMax: + value->v.integer = 1000 * TCPTV_REXMTMAX / hz; + break; +#undef hz + + case LEAF_tcpMaxConn: + value->v.integer = -1; + break; + + case LEAF_tcpActiveOpens: + value->v.uint32 = tcpstat.tcps_connattempt; + break; + + case LEAF_tcpPassiveOpens: + value->v.uint32 = tcpstat.tcps_accepts; + break; + + case LEAF_tcpAttemptFails: + value->v.uint32 = tcpstat.tcps_conndrops; + break; + + case LEAF_tcpEstabResets: + value->v.uint32 = tcpstat.tcps_drops; + break; + + case LEAF_tcpCurrEstab: + value->v.uint32 = tcp_count; + break; + + case LEAF_tcpInSegs: + value->v.uint32 = tcpstat.tcps_rcvtotal; + break; + + case LEAF_tcpOutSegs: + value->v.uint32 = tcpstat.tcps_sndtotal - + tcpstat.tcps_sndrexmitpack; + break; + + case LEAF_tcpRetransSegs: + value->v.uint32 = tcpstat.tcps_sndrexmitpack; + break; + + case LEAF_tcpInErrs: + value->v.uint32 = tcpstat.tcps_rcvbadsum + + tcpstat.tcps_rcvbadoff + + tcpstat.tcps_rcvshort; + break; + } + return (SNMP_ERR_NOERROR); +} + +int +op_tcpconn(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + u_int i; + + if (tcp_tick < this_tick) + if (fetch_tcp() == -1) + return (SNMP_ERR_GENERR); + + switch (op) { + + case SNMP_OP_GETNEXT: + for (i = 0; i < tcp_total; i++) + if (index_compare(&value->var, sub, &tcpoids[i].index) < 0) + break; + if (i == tcp_total) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &tcpoids[i].index); + break; + + case SNMP_OP_GET: + for (i = 0; i < tcp_total; i++) + if (index_compare(&value->var, sub, &tcpoids[i].index) == 0) + break; + if (i == tcp_total) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + default: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_tcpConnState: + switch (tcpoids[i].tp->xt_tp.t_state) { + + case TCPS_CLOSED: + value->v.integer = 1; + break; + case TCPS_LISTEN: + value->v.integer = 2; + break; + case TCPS_SYN_SENT: + value->v.integer = 3; + break; + case TCPS_SYN_RECEIVED: + value->v.integer = 4; + break; + case TCPS_ESTABLISHED: + value->v.integer = 5; + break; + case TCPS_CLOSE_WAIT: + value->v.integer = 8; + break; + case TCPS_FIN_WAIT_1: + value->v.integer = 6; + break; + case TCPS_CLOSING: + value->v.integer = 10; + break; + case TCPS_LAST_ACK: + value->v.integer = 9; + break; + case TCPS_FIN_WAIT_2: + value->v.integer = 7; + break; + case TCPS_TIME_WAIT: + value->v.integer = 11; + break; + default: + value->v.integer = 0; + break; + } + break; + + case LEAF_tcpConnLocalAddress: + value->v.ipaddress[0] = tcpoids[i].index.subs[0]; + value->v.ipaddress[1] = tcpoids[i].index.subs[1]; + value->v.ipaddress[2] = tcpoids[i].index.subs[2]; + value->v.ipaddress[3] = tcpoids[i].index.subs[3]; + break; + + case LEAF_tcpConnLocalPort: + value->v.integer = tcpoids[i].index.subs[4]; + break; + + case LEAF_tcpConnRemAddress: + value->v.ipaddress[0] = tcpoids[i].index.subs[5]; + value->v.ipaddress[1] = tcpoids[i].index.subs[6]; + value->v.ipaddress[2] = tcpoids[i].index.subs[7]; + value->v.ipaddress[3] = tcpoids[i].index.subs[8]; + break; + + case LEAF_tcpConnRemPort: + value->v.integer = tcpoids[i].index.subs[9]; + break; + } + return (SNMP_ERR_NOERROR); +} diff --git a/contrib/bsnmp/snmp_mibII/mibII_tree.def b/contrib/bsnmp/snmp_mibII/mibII_tree.def new file mode 100644 index 0000000..6384264 --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/mibII_tree.def @@ -0,0 +1,248 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Author: Harti Brandt <harti@freebsd.org> +# +# Redistribution of this software and documentation 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 or documentation 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. +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS +# AND ITS 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 +# FRAUNHOFER FOKUS OR ITS 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. +# +# $Begemot: bsnmp/snmp_mibII/mibII_tree.def,v 1.10 2002/02/06 12:43:51 hbb Exp $ +# +# Definition of the standard interfaces and ip trees. +# +(1 internet + (2 mgmt + (1 mib2 + (2 interfaces + (1 ifNumber INTEGER op_interfaces GET) + (2 ifTable + (1 ifEntry : INTEGER op_ifentry + (1 ifIndex INTEGER GET) + (2 ifDescr OCTETSTRING GET) + (3 ifType INTEGER GET) + (4 ifMtu INTEGER32 GET) + (5 ifSpeed GAUGE GET) + (6 ifPhysAddress OCTETSTRING GET) + (7 ifAdminStatus INTEGER GET SET) + (8 ifOperStatus INTEGER GET) + (9 ifLastChange TIMETICKS GET) + (10 ifInOctets COUNTER GET) + (11 ifInUcastPkts COUNTER GET) + (12 ifInNUcastPkts COUNTER GET) + (13 ifInDiscards COUNTER GET) + (14 ifInErrors COUNTER GET) + (15 ifInUnknownProtos COUNTER GET) + (16 ifOutOctets COUNTER GET) + (17 ifOutUcastPkts COUNTER GET) + (18 ifOutNUcastPkts COUNTER GET) + (19 ifOutDiscards COUNTER GET) + (20 ifOutErrors COUNTER GET) + (21 ifOutQLen GAUGE GET) + (22 ifSpecific OID GET) + )) + ) + (4 ip + (1 ipForwarding INTEGER op_ip GET SET) + (2 ipDefaultTTL INTEGER op_ip GET SET) + (3 ipInReceives COUNTER op_ipstat GET) + (4 ipInHdrErrors COUNTER op_ipstat GET) + (5 ipInAddrErrors COUNTER op_ipstat GET) + (6 ipForwDatagrams COUNTER op_ipstat GET) + (7 ipInUnknownProtos COUNTER op_ipstat GET) + (8 ipInDiscards COUNTER op_ipstat GET) + (9 ipInDelivers COUNTER op_ipstat GET) + (10 ipOutRequests COUNTER op_ipstat GET) + (11 ipOutDiscards COUNTER op_ipstat GET) + (12 ipOutNoRoutes COUNTER op_ipstat GET) + (13 ipReasmTimeout INTEGER32 op_ipstat GET) + (14 ipReasmReqds COUNTER op_ipstat GET) + (15 ipReasmOKs COUNTER op_ipstat GET) + (16 ipReasmFails COUNTER op_ipstat GET) + (17 ipFragOKs COUNTER op_ipstat GET) + (18 ipFragFails COUNTER op_ipstat GET) + (19 ipFragCreates COUNTER op_ipstat GET) + (20 ipAddrTable + (1 ipAddrEntry : IPADDRESS op_ipaddr + (1 ipAdEntAddr IPADDRESS GET) + (2 ipAdEntIfIndex INTEGER GET SET) + (3 ipAdEntNetMask IPADDRESS GET SET) + (4 ipAdEntBcastAddr INTEGER GET SET) + (5 ipAdEntReasmMaxSize INTEGER GET) + )) + (22 ipNetToMediaTable + (1 ipNetToMediaEntry : INTEGER IPADDRESS op_nettomedia + (1 ipNetToMediaIfIndex INTEGER GET) + (2 ipNetToMediaPhysAddress OCTETSTRING GET) + (3 ipNetToMediaNetAddress IPADDRESS GET) + (4 ipNetToMediaType INTEGER GET) + )) + (23 ipRoutingDiscards INTEGER op_ipstat) # not available + (24 ipForward + (3 ipCidrRouteNumber GAUGE op_route GET) + (4 ipCidrRouteTable + (1 ipCidrRouteEntry : IPADDRESS IPADDRESS INTEGER IPADDRESS op_route_table + (1 ipCidrRouteDest IPADDRESS GET) + (2 ipCidrRouteMask IPADDRESS GET) + (3 ipCidrRouteTos INTEGER GET) + (4 ipCidrRouteNextHop IPADDRESS GET) + (5 ipCidrRouteIfIndex INTEGER GET) # SET + (6 ipCidrRouteType INTEGER GET) # SET + (7 ipCidrRouteProto INTEGER GET) + (8 ipCidrRouteAge INTEGER GET) + (9 ipCidrRouteInfo OID GET) # SET + (10 ipCidrRouteNextHopAS INTEGER GET) # SET + (11 ipCidrRouteMetric1 INTEGER GET) # SET + (12 ipCidrRouteMetric2 INTEGER GET) # SET + (13 ipCidrRouteMetric3 INTEGER GET) # SET + (14 ipCidrRouteMetric4 INTEGER GET) # SET + (15 ipCidrRouteMetric5 INTEGER GET) # SET + (16 ipCidrRouteStatus INTEGER GET) # SET + )) + ) + ) + (5 icmp + (1 icmpInMsgs COUNTER op_icmpstat GET) + (2 icmpInErrors COUNTER op_icmpstat GET) + (3 icmpInDestUnreachs COUNTER op_icmpstat GET) + (4 icmpInTimeExcds COUNTER op_icmpstat GET) + (5 icmpInParmProbs COUNTER op_icmpstat GET) + (6 icmpInSrcQuenchs COUNTER op_icmpstat GET) + (7 icmpInRedirects COUNTER op_icmpstat GET) + (8 icmpInEchos COUNTER op_icmpstat GET) + (9 icmpInEchoReps COUNTER op_icmpstat GET) + (10 icmpInTimestamps COUNTER op_icmpstat GET) + (11 icmpInTimestampReps COUNTER op_icmpstat GET) + (12 icmpInAddrMasks COUNTER op_icmpstat GET) + (13 icmpInAddrMaskReps COUNTER op_icmpstat GET) + (14 icmpOutMsgs COUNTER op_icmpstat GET) + (15 icmpOutErrors COUNTER op_icmpstat GET) + (16 icmpOutDestUnreachs COUNTER op_icmpstat GET) + (17 icmpOutTimeExcds COUNTER op_icmpstat GET) + (18 icmpOutParmProbs COUNTER op_icmpstat GET) + (19 icmpOutSrcQuenchs COUNTER op_icmpstat GET) + (20 icmpOutRedirects COUNTER op_icmpstat GET) + (21 icmpOutEchos COUNTER op_icmpstat GET) + (22 icmpOutEchoReps COUNTER op_icmpstat GET) + (23 icmpOutTimestamps COUNTER op_icmpstat GET) + (24 icmpOutTimestampReps COUNTER op_icmpstat GET) + (25 icmpOutAddrMasks COUNTER op_icmpstat GET) + (26 icmpOutAddrMaskReps COUNTER op_icmpstat GET) + ) + (6 tcp + (1 tcpRtoAlgorithm INTEGER op_tcp GET) + (2 tcpRtoMin INTEGER32 op_tcp GET) + (3 tcpRtoMax INTEGER32 op_tcp GET) + (4 tcpMaxConn INTEGER32 op_tcp GET) + (5 tcpActiveOpens COUNTER op_tcp GET) + (6 tcpPassiveOpens COUNTER op_tcp GET) + (7 tcpAttemptFails COUNTER op_tcp GET) + (8 tcpEstabResets COUNTER op_tcp GET) + (9 tcpCurrEstab GAUGE op_tcp GET) + (10 tcpInSegs COUNTER op_tcp GET) + (11 tcpOutSegs COUNTER op_tcp GET) + (12 tcpRetransSegs COUNTER op_tcp GET) + (13 tcpConnTable + (1 tcpConnEntry : IPADDRESS INTEGER IPADDRESS INTEGER op_tcpconn + (1 tcpConnState INTEGER GET) + (2 tcpConnLocalAddress IPADDRESS GET) + (3 tcpConnLocalPort INTEGER GET) + (4 tcpConnRemAddress IPADDRESS GET) + (5 tcpConnRemPort INTEGER GET) + )) + (14 tcpInErrs COUNTER op_tcp GET) + (15 tcpOutRsts COUNTER op_tcp) # don't know + ) + (7 udp + (1 udpInDatagrams COUNTER op_udp GET) + (2 udpNoPorts COUNTER op_udp GET) + (3 udpInErrors COUNTER op_udp GET) + (4 udpOutDatagrams COUNTER op_udp GET) + (5 udpTable + (1 udpEntry : IPADDRESS INTEGER op_udptable + (1 udpLocalAddress IPADDRESS GET) + (2 udpLocalPort INTEGER GET) + )) + ) + (31 ifMIB + (1 ifMIBObjects + (1 ifXTable + (1 ifXEntry : INTEGER op_ifxtable + (1 ifName OCTETSTRING GET) + (2 ifInMulticastPkts COUNTER GET) + (3 ifInBroadcastPkts COUNTER GET) + (4 ifOutMulticastPkts COUNTER GET) + (5 ifOutBroadcastPkts COUNTER GET) + (6 ifHCInOctets COUNTER64 GET) + (7 ifHCInUcastPkts COUNTER64 GET) + (8 ifHCInMulticastPkts COUNTER64 GET) + (9 ifHCInBroadcastPkts COUNTER64 GET) + (10 ifHCOutOctets COUNTER64 GET) + (11 ifHCOutUcastPkts COUNTER64 GET) + (12 ifHCOutMulticastPkts COUNTER64 GET) + (13 ifHCOutBroadcastPkts COUNTER64 GET) + (14 ifLinkUpDownTrapEnable INTEGER GET SET) + (15 ifHighSpeed GAUGE GET) + (16 ifPromiscuousMode INTEGER GET SET) + (17 ifConnectorPresent INTEGER GET) + (18 ifAlias OCTETSTRING GET) + (19 ifCounterDiscontinuityTime TIMETICKS GET) + )) + (2 ifStackTable + (1 ifStackEntry : INTEGER INTEGER op_ifstack + (1 ifStackHigherLayer INTEGER) + (2 ifStackLowerLayer INTEGER) + (3 ifStackStatus INTEGER GET) + )) + (4 ifRcvAddressTable + (1 ifRcvAddressEntry : INTEGER OCTETSTRING op_rcvaddr + (1 ifRcvAddressAddress OCTETSTRING) + (2 ifRcvAddressStatus INTEGER GET) + (3 ifRcvAddressType INTEGER GET) + )) + (5 ifTableLastChange TIMETICKS op_ifmib GET) + (6 ifStackLastChange TIMETICKS op_ifmib GET) + ) + ) + (48 ipMIB + ) + (49 tcpMIB + ) + (50 udpMIB + ) + )) + (6 snmpV2 + (3 snmpModules + (1 snmpMIB + (1 snmpMIBObjects + (5 snmpTraps + (3 linkDown OID op_snmp_trap) + (4 linkUp OID op_snmp_trap) + ) + ) + ) + )) +) diff --git a/contrib/bsnmp/snmp_mibII/mibII_udp.c b/contrib/bsnmp/snmp_mibII/mibII_udp.c new file mode 100644 index 0000000..232bc45 --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/mibII_udp.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation 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 or documentation 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS 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 + * FRAUNHOFER FOKUS OR ITS 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. + * + * $Begemot: bsnmp/snmp_mibII/mibII_udp.c,v 1.4 2003/01/28 13:44:35 hbb Exp $ + * + * udp + */ +#include "mibII.h" +#include "mibII_oid.h" +#include <sys/socketvar.h> +#include <netinet/in_pcb.h> +#include <netinet/udp.h> +#include <netinet/ip_var.h> +#include <netinet/udp_var.h> + +struct udp_index { + struct asn_oid index; + struct xinpcb *inp; +}; + +static u_int32_t udp_tick; +static struct udpstat udpstat; +static struct xinpgen *xinpgen; +static size_t xinpgen_len; +static u_int udp_total; + +static u_int oidnum; +static struct udp_index *udpoids; + +static int +udp_compare(const void *p1, const void *p2) +{ + const struct udp_index *t1 = p1; + const struct udp_index *t2 = p2; + + return (asn_compare_oid(&t1->index, &t2->index)); +} + +static int +fetch_udp(void) +{ + size_t len; + struct xinpgen *ptr; + struct xinpcb *inp; + struct udp_index *oid; + in_addr_t inaddr; + + len = sizeof(udpstat); + if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.udp.stats: %m"); + return (-1); + } + if (len != sizeof(udpstat)) { + syslog(LOG_ERR, "net.inet.udp.stats: wrong size"); + return (-1); + } + + udp_tick = get_ticks(); + + len = 0; + if (sysctlbyname("net.inet.udp.pcblist", NULL, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.udp.pcblist: %m"); + return (-1); + } + if (len > xinpgen_len) { + if ((ptr = realloc(xinpgen, len)) == NULL) { + syslog(LOG_ERR, "%zu: %m", len); + return (-1); + } + xinpgen = ptr; + xinpgen_len = len; + } + if (sysctlbyname("net.inet.udp.pcblist", xinpgen, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.udp.pcblist: %m"); + return (-1); + } + + udp_total = 0; + for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len); + ptr->xig_len > sizeof(struct xinpgen); + ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) { + inp = (struct xinpcb *)ptr; + if (inp->xi_inp.inp_gencnt > xinpgen->xig_gen || + (inp->xi_inp.inp_vflag & INP_IPV4) == 0) + continue; + + udp_total++; + } + + if (oidnum < udp_total) { + oid = realloc(udpoids, udp_total * sizeof(udpoids[0])); + if (oid == NULL) { + free(udpoids); + oidnum = 0; + return (0); + } + udpoids = oid; + oidnum = udp_total; + } + + oid = udpoids; + for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len); + ptr->xig_len > sizeof(struct xinpgen); + ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) { + inp = (struct xinpcb *)ptr; + if (inp->xi_inp.inp_gencnt > xinpgen->xig_gen || + (inp->xi_inp.inp_vflag & INP_IPV4) == 0) + continue; + oid->inp = inp; + oid->index.len = 5; + inaddr = ntohl(inp->xi_inp.inp_laddr.s_addr); + oid->index.subs[0] = (inaddr >> 24) & 0xff; + oid->index.subs[1] = (inaddr >> 16) & 0xff; + oid->index.subs[2] = (inaddr >> 8) & 0xff; + oid->index.subs[3] = (inaddr >> 0) & 0xff; + oid->index.subs[4] = ntohs(inp->xi_inp.inp_lport); + oid++; + } + + qsort(udpoids, udp_total, sizeof(udpoids[0]), udp_compare); + + return (0); +} + +int +op_udp(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + if (udp_tick < this_tick) + if (fetch_udp() == -1) + return (SNMP_ERR_GENERR); + + switch (value->var.subs[sub - 1]) { + + case LEAF_udpInDatagrams: + value->v.uint32 = udpstat.udps_ipackets; + break; + + case LEAF_udpNoPorts: + value->v.uint32 = udpstat.udps_noport + + udpstat.udps_noportbcast + + udpstat.udps_noportmcast; + break; + + case LEAF_udpInErrors: + value->v.uint32 = udpstat.udps_hdrops + + udpstat.udps_badsum + + udpstat.udps_badlen + + udpstat.udps_fullsock; + break; + + case LEAF_udpOutDatagrams: + value->v.uint32 = udpstat.udps_opackets; + break; + } + return (SNMP_ERR_NOERROR); +} + +int +op_udptable(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + u_int i; + + if (udp_tick < this_tick) + if (fetch_udp() == -1) + return (SNMP_ERR_GENERR); + + switch (op) { + + case SNMP_OP_GETNEXT: + for (i = 0; i < udp_total; i++) + if (index_compare(&value->var, sub, &udpoids[i].index) < 0) + break; + if (i == udp_total) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &udpoids[i].index); + break; + + case SNMP_OP_GET: + for (i = 0; i < udp_total; i++) + if (index_compare(&value->var, sub, &udpoids[i].index) == 0) + break; + if (i == udp_total) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + default: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_udpLocalAddress: + value->v.ipaddress[0] = udpoids[i].index.subs[0]; + value->v.ipaddress[1] = udpoids[i].index.subs[1]; + value->v.ipaddress[2] = udpoids[i].index.subs[2]; + value->v.ipaddress[3] = udpoids[i].index.subs[3]; + break; + + case LEAF_udpLocalPort: + value->v.integer = udpoids[i].index.subs[4]; + break; + + } + return (SNMP_ERR_NOERROR); +} diff --git a/contrib/bsnmp/snmp_mibII/snmp_mibII.3 b/contrib/bsnmp/snmp_mibII/snmp_mibII.3 new file mode 100644 index 0000000..62b354d --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/snmp_mibII.3 @@ -0,0 +1,348 @@ +.\" +.\" Copyright (c) 2001-2003 +.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). +.\" All rights reserved. +.\" +.\" Author: Harti Brandt <harti@freebsd.org> +.\" +.\" Redistribution of this software and documentation 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 or documentation 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. +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS +.\" AND ITS 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 +.\" FRAUNHOFER FOKUS OR ITS 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. +.\" +.\" $Begemot: bsnmp/snmp_mibII/snmp_mibII.3,v 1.1 2002/08/19 09:30:14 hbb Exp $ +.\" +.Dd August 19, 2002 +.Dt snmp_mibII 3 +.Os +.Sh NAME +.Nm mibif_notify_f , +.Nm mib_netsock , +.Nm mib_if_set_dyn , +.Nm mib_refresh_iflist , +.Nm mib_find_if , +.Nm mib_find_if_sys , +.Nm mib_find_if_name , +.Nm mib_first_if , +.Nm mib_next_if , +.Nm mib_register_newif , +.Nm mib_unregister_newif , +.Nm mib_fetch_ifmib , +.Nm mib_if_admin , +.Nm mib_find_ifa , +.Nm mib_first_ififa , +.Nm mib_next_ififa , +.Nm mib_ifstack_create , +.Nm mib_ifstack_delete , +.Nm mib_find_rcvaddr , +.Nm mib_rcvaddr_create , +.Nm mib_rcvaddr_delete , +.Nm mibif_notify , +.Nm mibif_unnotify +.Nd "mib-2 module for snmpd. +.Sh LIBRARY +.Pq begemotSnmpdModulePath."mibII" = "/usr/local/lib/snmp_mibII.so" +.Sh SYNOPSIS +.In bsnmp/snmpmod.h +.In bsnmp/snmp_mibII.h +.Ft typedef void +.Fn (*mibif_notify_f) "struct mibif *ifp" "enum mibif_notify event" "void *uarg" +.Vt extern int mib_netsock ; +.Ft void +.Fn mib_if_set_dyn "const char *ifname" +.Ft void +.Fn mib_refresh_iflist "void" +.Ft struct mibif * +.Fn mib_find_if "u_int ifindex" +.Ft struct mibif * +.Fn mib_find_if_sys "u_int sysindex" +.Ft struct mibif * +.Fn mib_find_if_name "const char *ifname" +.Ft struct mibif * +.Fn mib_first_if "void" +.Ft struct mibif * +.Fn mib_next_if "const struct mibif *ifp" +.Ft int +.Fn mib_register_newif "int (*func)(struct mibif *)" "const struct lmodule *mod" +.Ft void +.Fn mib_unregister_newif "const struct lmodule *mod" +.Ft int +.Fn mib_fetch_ifmib "struct mibif *ifp" +.Ft int +.Fn mib_if_admin "struct mibif *ifp" "int up" +.Ft struct mibifa * +.Fn mib_find_ifa "struct in_addr ipa" +.Ft struct mibifa * +.Fn mib_first_ififa "const struct mibif *ifp" +.Ft struct mibifa * +.Fn mib_next_ififa "struct mibifa *ifa" +.Ft int +.Fn mib_ifstack_create "const struct mibif *lower" "const struct mibif *upper" +.Ft void +.Fn mib_ifstack_delete "const struct mibif *lower" "const struct mibif *upper" +.Ft struct mibrcvaddr * +.Fn mib_find_rcvaddr "u_int ifindex" "const u_char *addr" "size_t addrlen" +.Ft struct mibrcvaddr * +.Fn mib_rcvaddr_create "struct mibif *ifp" "const u_char *addr" "size_t addrlen" +.Ft void +.Fn mib_rcvaddr_delete "struct mibrcvaddr *addr" +.Ft void * +.Fn mibif_notify "struct mibif *ifp" "const struct lmodule *mod" "mibif_notify_f func" "void *uarg" +.Ft void +.Fn mibif_unnotify "void *reg" +.Sh DESCRIPTION +The +.Nm snmp_mibII +module implements parts of the internet standard MIB-2. Most of the relevant +MIBs are implemented. Some of the tables are restricted to be read-only +instead of read-write. The exact current implementation can be found in +.Pa /usr/local/include/bsnmp/mibII_tree.def . +The module also exports a number of functions and global variables for use +by other modules, that need to handle network interfaces. This man page describes +these functions. +.Ss DIRECT NETWORK ACCESS +The +.Nm +module opens a socket that is used to execute all network related +.Xr ioctl 2 +functions. This socket is globally available under the name +.Va mib_netsock . +.Ss NETWORK INTERFACES +The +.Nm +module handles a list of all currently existing network interfaces. It allows +other modules to handle their own interface lists with special information +by providing a mechanism to register to events that change the interface list +(see below). The basic data structure is the interface structure: +.Bd -literal -offset indent +struct mibif { + TAILQ_ENTRY(mibif) link; + u_int flags; + u_int index; /* logical ifindex */ + u_int sysindex; + char name[IFNAMSIZ]; + char descr[256]; + struct ifmibdata mib; + u_int32_t mibtick; + void *specmib; + size_t specmiblen; + u_char *physaddr; + u_int physaddrlen; + int has_connector; + int trap_enable; + u_int32_t counter_disc; + mibif_notify_f xnotify; + void *xnotify_data; + const struct lmodule *xnotify_mod; +}; +.Ed +.Pp +The +.Nm +module tries to implement the semantic if +.Va ifIndex +as described in RFC-2863. This RFC states, that an interface indexes may not +be reused. That means, for example, if +.Pa tun +is a synthetic interface type and the system creates the interface +.Pa tun0 , +destroys this interfaces and again creates a +.Pa tun 0 , +then these interfaces must have different interface indexes, because in fact +they are different interfaces. If, on the other hand, there is a hardware +interface +.Pa xl0 +and this interface disappears, because its driver is unloaded and appears +again, because the driver is loaded again, the interface index must stay +the same. +.Nm +implements this by differentiating between real and synthetic (dynamic) +interfaces. An interface type can be declared dynamic by calling the function +.Fn mib_if_set_dyn +with the name if the interface type (for example +.Qq tun ). +For real interfaces, the module keeps the mapping between the interface name +and its +.Va ifIndex +in a special list, if the interface is unloaded. For dynamic interfaces +a new +.Va ifIndex +is generated each time the interface comes into existance. This +means, that the interface index as seen by SNMP is not the same index +as used by the system. The SNMP +.Va ifIndex +is held in field +.Va index , +the system's interface index is +.Va sysindex . +.Pp +A call to +.Nm mib_refresh_iflist +causes the entire interface list to be re-created. +.Pp +The interface list can be traversed with the functions +.Fn mib_first_if +and +.Fn mib_next_if . +Be sure not to change the interface list while traversing the list with +these two calls. +.Pp +There are three functions to find an interface by name or index. +.Fn mib_find_if +finds an interface by searching for an SNMP +.Va ifIndex , +.Fn mib_find_if_sys +finds an interface by searching for a system interface index and +.Fn mib_find_if_name +finds an interface by looking for an interface name. Each of the +function returns +.Li NULL +if the interface cannot be found. +.Pp +The function +.Fn mib_fetch_ifmib +causes the interface MIB to be refreshed from the kernel. +.Pp +The function +.Fn mib_if_admin +can be used to change the interface administrative state to up +(argument is 1) or down (argument is 0). +.Ss INTERFACE EVENTS +A module can register itself to receive a notification when a new entry is +created in the interface list. This is done by calling +.Fn mib_register_newif . +A module can register only one function, a second call to +.Fn mib_register_newif +causes the registration to be overwritten. The registration can be removed +with a call to +.Fn mib_unregister_newif . +If is unregistered automatically, when the registering module is unloaded. +.Pp +A module can also register to events on a specific interface. This is done +by calling +.Fn mibif_notify . +This causes the given callback +.Fa func +to be called with the interface pointer, a notification code and +the user argument +.Fa uarg +when any of the following events occur: +.Bl -tag -width "XXXXX" +.It Li MIBIF_NOTIFY_DESTROY +The interface is destroyed. +.El +.Pp +This mechanism can be used to implement interface type specific MIB parts +in other modules. The registration can be removed with +.Fn mib_unnotify +which the return value from +.Fa mib_notify . +Any notification registration is removed automatically when the interface +is destroyed or the registering module is unloaded. +.Em Note that only one module can register to any given interface . +.Ss INTERFACE ADDRESSES +The +.Nm +module handles a table of interface IP-addresses. These addresses are held +in a +.Bd -literal -offset indent +struct mibifa { + TAILQ_ENTRY(mibifa) link; + struct in_addr inaddr; + struct in_addr inmask; + struct in_addr inbcast; + struct asn_oid index; + u_int ifindex; + u_int flags; +}; +.Ed +.Pp +The (ordered) list of IP-addresses on a given interface can be traversed by +calling +.Fn mib_first_ififa +and +.Fn mib_next_ififa . +The list should not be considered read-only. +.Ss INTERFACE RECEIVE ADDRESSES +The internet MIB-2 contains a table of interface receive addresses. These +addresses are handled in: +.Bd -literal -offset indent +struct mibrcvaddr { + TAILQ_ENTRY(mibrcvaddr) link; + struct asn_oid index; + u_int ifindex; + u_char addr[ASN_MAXOIDLEN]; + size_t addrlen; + u_int flags; +}; +enum { + MIBRCVADDR_VOLATILE = 0x00000001, + MIBRCVADDR_BCAST = 0x00000002, + MIBRCVADDR_HW = 0x00000004, +}; +.Ed +.Pp +Note, that the assignment of +.Li MIBRCVADDR_BCAST +is based on a list of known interface types. The flags should be handled +by modules inplementing interface type specific MIBs. +.Pp +A receive address can be created with +.Fn mib_rcvaddr_create +and deleted with +.Fn mib_rcvaddr_delete . +This needs to be done only for addresses that are not automatically handled +by the system. +.Pp +A receive address can be found with +.Fn mib_find_rcvaddr . +.Ss INTERFACE STACK TABLE +The +.Nm +module maintains also the interface stack table. Because for complex stacks, +there is no system supported generic way of getting this information, interface +type specific modules need to help setting up stack entries. The +.Nm +module handles only the top and bottom entries. +.Pp +A table entry is created with +.Fn mib_ifstack_create +and deleted with +.Fn mib_ifstack_delete . +Both functions need the pointers to the interfaces. Entries are automatically +deleted if any of the interfaces of the entry is destroyed. The functions handle +both the stack table and the reverse stack table. +.Sh FILES +.Bl -tag -width ".It Pa /usr/local/include/bsnmp/mibII_tree.def" -compact +.It Pa /usr/local/include/bsnmp/mibII_tree.def +The description of the MIB tree implemented by +.Nm . +.It Pa /usr/local/share/snmp/mibs +The various internet MIBs. +.Sh SEE ALSO +.Xr snmpmod 3 , +.Xr gensnmptree 1 +.Sh STANDARDS +This implementation conforms to the applicable IETF RFCs. +.Sh AUTHORS +.An Hartmut Brandt Aq brandt@fokus.gmd.de diff --git a/contrib/bsnmp/snmp_mibII/snmp_mibII.h b/contrib/bsnmp/snmp_mibII/snmp_mibII.h new file mode 100644 index 0000000..79423cb --- /dev/null +++ b/contrib/bsnmp/snmp_mibII/snmp_mibII.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation 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 or documentation 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS 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 + * FRAUNHOFER FOKUS OR ITS 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. + * + * $Begemot: bsnmp/snmp_mibII/snmp_mibII.h,v 1.13 2002/03/21 11:18:51 hbb Exp $ + * + * Implementation of the interfaces and IP groups of MIB-II. + */ +#ifndef snmp_mibII_h_ +#define snmp_mibII_h_ + +/* forward declaration */ +struct mibif; + +enum mibif_notify { + MIBIF_NOTIFY_DESTROY +}; + +typedef void (*mibif_notify_f)(struct mibif *, enum mibif_notify, void *); + +/* + * Interfaces. This structure describes one interface as seen in the MIB. + * Interfaces are indexed by ifindex. This is not the same as the index + * used by the system because of the rules in RFC-2863 section 3.1.5. This + * RFC requires, that an ifindex is not to be re-used for ANOTHER dynamically + * interfaces once the interface was deleted. The system's ifindex is in + * sysindex. Mapping is via the mapping table below. + */ +struct mibif { + TAILQ_ENTRY(mibif) link; + u_int flags; + u_int index; /* the logical ifindex */ + u_int sysindex; + char name[IFNAMSIZ]; + char descr[256]; + struct ifmibdata mib; + u_int32_t mibtick; + void *specmib; + size_t specmiblen; + u_char *physaddr; + u_int physaddrlen; + int has_connector; + int trap_enable; + u_int32_t counter_disc; + + /* + * This is needed to handle interface type specific information + * in sub-modules. It contains a function pointer which handles + * notifications and a data pointer to arbitrary data. + * Should be set via the mibif_notify function. + */ + mibif_notify_f xnotify; + void *xnotify_data; + const struct lmodule *xnotify_mod; +}; + +/* + * Interface IP-address table. + */ +struct mibifa { + TAILQ_ENTRY(mibifa) link; + struct in_addr inaddr; + struct in_addr inmask; + struct in_addr inbcast; + struct asn_oid index; /* index for table search */ + u_int ifindex; + u_int flags; +}; + +/* + * Interface receive addresses. Interface link-level multicast, broadcast + * and hardware addresses are handled automatically. + */ +struct mibrcvaddr { + TAILQ_ENTRY(mibrcvaddr) link; + struct asn_oid index; + u_int ifindex; + u_char addr[ASN_MAXOIDLEN]; + size_t addrlen; + u_int flags; +}; +enum { + MIBRCVADDR_VOLATILE = 0x00000001, + MIBRCVADDR_BCAST = 0x00000002, + MIBRCVADDR_HW = 0x00000004, +}; + +/* network socket */ +extern int mib_netsock; + +/* set an interface name to dynamic mode */ +void mib_if_set_dyn(const char *); + +/* re-read the systems interface list */ +void mib_refresh_iflist(void); + +/* find interface by index */ +struct mibif *mib_find_if(u_int); +struct mibif *mib_find_if_sys(u_int); +struct mibif *mib_find_if_name(const char *); + +/* iterate through all interfaces */ +struct mibif *mib_first_if(void); +struct mibif *mib_next_if(const struct mibif *); + +/* register for interface creations */ +int mib_register_newif(int (*)(struct mibif *), const struct lmodule *); +void mib_unregister_newif(const struct lmodule *); + +/* get fresh MIB data */ +int mib_fetch_ifmib(struct mibif *); + +/* change the ADMIN status of an interface and refresh the MIB */ +int mib_if_admin(struct mibif *, int up); + +/* find interface address by address */ +struct mibifa *mib_find_ifa(struct in_addr); + +/* find first/next address for a given interface */ +struct mibifa *mib_first_ififa(const struct mibif *); +struct mibifa *mib_next_ififa(struct mibifa *); + +/* create/delete stacking entries */ +int mib_ifstack_create(const struct mibif *lower, const struct mibif *upper); +void mib_ifstack_delete(const struct mibif *lower, const struct mibif *upper); + +/* find receive address */ +struct mibrcvaddr *mib_find_rcvaddr(u_int, const u_char *, size_t); + +/* create/delete receive addresses */ +struct mibrcvaddr *mib_rcvaddr_create(struct mibif *, const u_char *, size_t); +void mib_rcvaddr_delete(struct mibrcvaddr *); + +/* register for interface notification */ +void *mibif_notify(struct mibif *, const struct lmodule *, mibif_notify_f, + void *); +void mibif_unnotify(void *); + +#endif |