Path: blob/main/contrib/bsnmp/snmp_mibII/mibII_route.c
39478 views
/*1* Copyright (c) 2001-20032* Fraunhofer Institute for Open Communication Systems (FhG Fokus).3* All rights reserved.4*5* Author: Harti Brandt <[email protected]>6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10* 1. Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*28* $Begemot: bsnmp/snmp_mibII/mibII_route.c,v 1.9 2005/10/06 07:15:00 brandt_h Exp $29*30* Routing table31*/3233#ifdef HAVE_SYS_TREE_H34#include <sys/tree.h>35#else36#include "tree.h"37#endif3839#include "mibII.h"40#include "mibII_oid.h"4142struct sroute {43RB_ENTRY(sroute) link;44uint32_t ifindex;45uint8_t index[13];46uint8_t type;47uint8_t proto;48};49static RB_HEAD(sroutes, sroute) sroutes = RB_INITIALIZER(&sroutes);5051RB_PROTOTYPE(sroutes, sroute, link, sroute_compare);5253#define ROUTE_UPDATE_INTERVAL (100 * 60 * 10) /* 10 min */54static uint64_t route_tick;55static u_int route_total;5657/*58* Compare two routes59*/60static int61sroute_compare(struct sroute *s1, struct sroute *s2)62{6364return (memcmp(s1->index, s2->index, 13));65}6667static void68sroute_index_append(struct asn_oid *oid, u_int sub, const struct sroute *s)69{70int i;7172oid->len = sub + 13;73for (i = 0; i < 13; i++)74oid->subs[sub + i] = s->index[i];75}7677#if 078static void79sroute_print(const struct sroute *r)80{81u_int i;8283for (i = 0; i < 13 - 1; i++)84printf("%u.", r->index[i]);85printf("%u proto=%u type=%u", r->index[i], r->proto, r->type);86}87#endif8889/*90* process routing message91*/92void93mib_sroute_process(struct rt_msghdr *rtm, struct sockaddr *gw,94struct sockaddr *dst, struct sockaddr *mask)95{96struct sockaddr_in *in_dst, *in_gw;97struct in_addr in_mask;98struct mibif *ifp;99struct sroute key;100struct sroute *r, *r1;101in_addr_t ha;102103if (dst == NULL || gw == NULL || dst->sa_family != AF_INET ||104gw->sa_family != AF_INET)105return;106107in_dst = (struct sockaddr_in *)(void *)dst;108in_gw = (struct sockaddr_in *)(void *)gw;109110if (rtm->rtm_flags & RTF_HOST)111in_mask.s_addr = 0xffffffff;112else if (mask == NULL || mask->sa_len == 0)113in_mask.s_addr = 0;114else115in_mask = ((struct sockaddr_in *)(void *)mask)->sin_addr;116117/* build the index */118ha = ntohl(in_dst->sin_addr.s_addr);119key.index[0] = (ha >> 24) & 0xff;120key.index[1] = (ha >> 16) & 0xff;121key.index[2] = (ha >> 8) & 0xff;122key.index[3] = (ha >> 0) & 0xff;123124ha = ntohl(in_mask.s_addr);125key.index[4] = (ha >> 24) & 0xff;126key.index[5] = (ha >> 16) & 0xff;127key.index[6] = (ha >> 8) & 0xff;128key.index[7] = (ha >> 0) & 0xff;129130/* ToS */131key.index[8] = 0;132133ha = ntohl(in_gw->sin_addr.s_addr);134key.index[9] = (ha >> 24) & 0xff;135key.index[10] = (ha >> 16) & 0xff;136key.index[11] = (ha >> 8) & 0xff;137key.index[12] = (ha >> 0) & 0xff;138139if (rtm->rtm_type == RTM_DELETE) {140r = RB_FIND(sroutes, &sroutes, &key);141if (r == 0) {142#ifdef DEBUG_ROUTE143syslog(LOG_WARNING, "%s: DELETE: %u.%u.%u.%u "144"%u.%u.%u.%u %u %u.%u.%u.%u not found", __func__,145key.index[0], key.index[1], key.index[2],146key.index[3], key.index[4], key.index[5],147key.index[6], key.index[7], key.index[8],148key.index[9], key.index[10], key.index[11],149key.index[12]);150#endif151return;152}153RB_REMOVE(sroutes, &sroutes, r);154free(r);155route_total--;156#ifdef DEBUG_ROUTE157printf("%s: DELETE: %u.%u.%u.%u "158"%u.%u.%u.%u %u %u.%u.%u.%u\n", __func__,159key.index[0], key.index[1], key.index[2],160key.index[3], key.index[4], key.index[5],161key.index[6], key.index[7], key.index[8],162key.index[9], key.index[10], key.index[11],163key.index[12]);164#endif165return;166}167168/* GET or ADD */169ifp = NULL;170if ((ifp = mib_find_if_sys(rtm->rtm_index)) == NULL) {171if (rtm->rtm_type == RTM_ADD) {172/* make it a get so the kernel fills the index */173mib_send_rtmsg(rtm, gw, dst, mask);174return;175}176mib_iflist_bad = 1;177}178179if ((r = malloc(sizeof(*r))) == NULL) {180syslog(LOG_ERR, "%m");181return;182}183184memcpy(r->index, key.index, sizeof(r->index));185r->ifindex = (ifp == NULL) ? 0 : ifp->index;186187r->type = (rtm->rtm_flags & RTF_REJECT) ? 2 : 4;188189/* cannot really know, what protocol it runs */190r->proto = (rtm->rtm_flags & RTF_LOCAL) ? 2 :191(rtm->rtm_flags & RTF_STATIC) ? 3 :192(rtm->rtm_flags & RTF_DYNAMIC) ? 4 : 10;193194r1 = RB_INSERT(sroutes, &sroutes, r);195if (r1 != NULL) {196#ifdef DEBUG_ROUTE197syslog(LOG_WARNING, "%s: %u.%u.%u.%u "198"%u.%u.%u.%u %u %u.%u.%u.%u duplicate route", __func__,199key.index[0], key.index[1], key.index[2],200key.index[3], key.index[4], key.index[5],201key.index[6], key.index[7], key.index[8],202key.index[9], key.index[10], key.index[11],203key.index[12]);204#endif205r1->ifindex = r->ifindex;206r1->type = r->type;207r1->proto = r->proto;208free(r);209return;210}211212route_total++;213#ifdef DEBUG_ROUTE214printf("%s: ADD/GET: %u.%u.%u.%u "215"%u.%u.%u.%u %u %u.%u.%u.%u\n", __func__,216key.index[0], key.index[1], key.index[2],217key.index[3], key.index[4], key.index[5],218key.index[6], key.index[7], key.index[8],219key.index[9], key.index[10], key.index[11],220key.index[12]);221#endif222}223224int225mib_fetch_route(void)226{227u_char *rtab, *next;228size_t len;229struct sroute *r, *r1;230struct rt_msghdr *rtm;231struct sockaddr *addrs[RTAX_MAX];232233if (route_tick != 0 && route_tick + ROUTE_UPDATE_INTERVAL > this_tick)234return (0);235236/*237* Remove all routes238*/239r = RB_MIN(sroutes, &sroutes);240while (r != NULL) {241r1 = RB_NEXT(sroutes, &sroutes, r);242RB_REMOVE(sroutes, &sroutes, r);243free(r);244r = r1;245}246route_total = 0;247248if ((rtab = mib_fetch_rtab(AF_INET, NET_RT_DUMP, 0, &len)) == NULL)249return (-1);250251next = rtab;252for (next = rtab; next < rtab + len; next += rtm->rtm_msglen) {253rtm = (struct rt_msghdr *)(void *)next;254if (rtm->rtm_type != RTM_GET ||255!(rtm->rtm_flags & RTF_UP))256continue;257mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs);258259260mib_sroute_process(rtm, addrs[RTAX_GATEWAY], addrs[RTAX_DST],261addrs[RTAX_NETMASK]);262}263264#if 0265u_int n = 0;266r = RB_MIN(sroutes, &sroutes);267while (r != NULL) {268printf("%u: ", n++);269sroute_print(r);270printf("\n");271r = RB_NEXT(sroutes, &sroutes, r);272}273#endif274free(rtab);275route_tick = get_ticks();276277return (0);278}279280/**281* Find a route in the table.282*/283static struct sroute *284sroute_get(const struct asn_oid *oid, u_int sub)285{286struct sroute key;287int i;288289if (oid->len - sub != 13)290return (NULL);291for (i = 0; i < 13; i++)292key.index[i] = oid->subs[sub + i];293return (RB_FIND(sroutes, &sroutes, &key));294}295296/**297* Find next route in the table. There is no such RB_ macro, so must298* dig into the innards of the RB stuff.299*/300static struct sroute *301sroute_getnext(struct asn_oid *oid, u_int sub)302{303u_int i;304int comp;305struct sroute key;306struct sroute *best;307struct sroute *s;308309/*310* We now, that the OID is at least the tableEntry OID. If it is,311* the user wants the first route.312*/313if (oid->len == sub)314return (RB_MIN(sroutes, &sroutes));315316/*317* This is also true for any index that consists of zeros and is318* shorter than the full index.319*/320if (oid->len < sub + 13) {321for (i = sub; i < oid->len; i++)322if (oid->subs[i] != 0)323break;324if (i == oid->len)325return (RB_MIN(sroutes, &sroutes));326327/*328* Now if the index is too short, we fill it with zeros and then329* subtract one from the index. We can do this, because we now,330* that there is at least one index element that is not zero.331*/332for (i = oid->len; i < sub + 13; i++)333oid->subs[i] = 0;334335for (i = sub + 13 - 1; i >= sub; i--) {336if (oid->subs[i] != 0) {337oid->subs[i]--;338break;339}340oid->subs[i] = ASN_MAXID;341}342oid->len = sub + 13;343}344345/* build the index */346for (i = sub; i < sub + 13; i++)347key.index[i - sub] = oid->subs[i];348349/* now find the element */350best = NULL;351s = RB_ROOT(&sroutes);352353while (s != NULL) {354comp = sroute_compare(&key, s);355if (comp >= 0) {356/* The current element is smaller than what we search.357* Forget about it and move to the right subtree. */358s = RB_RIGHT(s, link);359continue;360}361/* the current element is larger than what we search.362* forget about the right subtree (its even larger), but363* the current element may be what we need. */364if (best == NULL || sroute_compare(s, best) < 0)365/* this one's better */366best = s;367368s = RB_LEFT(s, link);369}370return (best);371}372373/*374* Table375*/376int377op_route_table(struct snmp_context *ctx __unused, struct snmp_value *value,378u_int sub, u_int iidx __unused, enum snmp_op op)379{380struct sroute *r;381382if (mib_fetch_route() == -1)383return (SNMP_ERR_GENERR);384385switch (op) {386387case SNMP_OP_GETNEXT:388if ((r = sroute_getnext(&value->var, sub)) == NULL)389return (SNMP_ERR_NOSUCHNAME);390sroute_index_append(&value->var, sub, r);391break;392393case SNMP_OP_GET:394if ((r = sroute_get(&value->var, sub)) == NULL)395return (SNMP_ERR_NOSUCHNAME);396break;397398case SNMP_OP_SET:399if ((r = sroute_get(&value->var, sub)) == NULL)400return (SNMP_ERR_NOSUCHNAME);401return (SNMP_ERR_NOT_WRITEABLE);402403case SNMP_OP_ROLLBACK:404case SNMP_OP_COMMIT:405abort();406407default:408abort();409}410411switch (value->var.subs[sub - 1]) {412413case LEAF_ipCidrRouteDest:414value->v.ipaddress[0] = r->index[0];415value->v.ipaddress[1] = r->index[1];416value->v.ipaddress[2] = r->index[2];417value->v.ipaddress[3] = r->index[3];418break;419420case LEAF_ipCidrRouteMask:421value->v.ipaddress[0] = r->index[4];422value->v.ipaddress[1] = r->index[5];423value->v.ipaddress[2] = r->index[6];424value->v.ipaddress[3] = r->index[7];425break;426427case LEAF_ipCidrRouteTos:428value->v.integer = r->index[8];429break;430431case LEAF_ipCidrRouteNextHop:432value->v.ipaddress[0] = r->index[9];433value->v.ipaddress[1] = r->index[10];434value->v.ipaddress[2] = r->index[11];435value->v.ipaddress[3] = r->index[12];436break;437438case LEAF_ipCidrRouteIfIndex:439value->v.integer = r->ifindex;440break;441442case LEAF_ipCidrRouteType:443value->v.integer = r->type;444break;445446case LEAF_ipCidrRouteProto:447value->v.integer = r->proto;448break;449450case LEAF_ipCidrRouteAge:451value->v.integer = 0;452break;453454case LEAF_ipCidrRouteInfo:455value->v.oid = oid_zeroDotZero;456break;457458case LEAF_ipCidrRouteNextHopAS:459value->v.integer = 0;460break;461462case LEAF_ipCidrRouteMetric1:463case LEAF_ipCidrRouteMetric2:464case LEAF_ipCidrRouteMetric3:465case LEAF_ipCidrRouteMetric4:466case LEAF_ipCidrRouteMetric5:467value->v.integer = -1;468break;469470case LEAF_ipCidrRouteStatus:471value->v.integer = 1;472break;473}474return (SNMP_ERR_NOERROR);475}476477/*478* scalars479*/480int481op_route(struct snmp_context *ctx __unused, struct snmp_value *value,482u_int sub, u_int iidx __unused, enum snmp_op op)483{484switch (op) {485486case SNMP_OP_GETNEXT:487abort();488489case SNMP_OP_GET:490break;491492case SNMP_OP_SET:493return (SNMP_ERR_NOT_WRITEABLE);494495case SNMP_OP_ROLLBACK:496case SNMP_OP_COMMIT:497abort();498}499500if (mib_fetch_route() == -1)501return (SNMP_ERR_GENERR);502503switch (value->var.subs[sub - 1]) {504505case LEAF_ipCidrRouteNumber:506value->v.uint32 = route_total;507break;508509}510return (SNMP_ERR_NOERROR);511}512513RB_GENERATE(sroutes, sroute, link, sroute_compare);514515516