1122394Sharti/* 2122394Sharti * Copyright (c) 2001-2003 3122394Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4122394Sharti * All rights reserved. 5122394Sharti * 6122394Sharti * Author: Harti Brandt <harti@freebsd.org> 7310903Sngie * 8133211Sharti * Redistribution and use in source and binary forms, with or without 9133211Sharti * modification, are permitted provided that the following conditions 10133211Sharti * are met: 11133211Sharti * 1. Redistributions of source code must retain the above copyright 12133211Sharti * notice, this list of conditions and the following disclaimer. 13122394Sharti * 2. Redistributions in binary form must reproduce the above copyright 14122394Sharti * notice, this list of conditions and the following disclaimer in the 15122394Sharti * documentation and/or other materials provided with the distribution. 16310903Sngie * 17133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20133211Sharti * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27133211Sharti * SUCH DAMAGE. 28122394Sharti * 29156066Sharti * $Begemot: bsnmp/snmp_mibII/mibII_route.c,v 1.9 2005/10/06 07:15:00 brandt_h Exp $ 30122394Sharti * 31122394Sharti * Routing table 32122394Sharti */ 33156066Sharti 34156066Sharti#ifdef HAVE_SYS_TREE_H 35150920Sharti#include <sys/tree.h> 36156066Sharti#else 37156066Sharti#include "tree.h" 38156066Sharti#endif 39156066Sharti 40122394Sharti#include "mibII.h" 41122394Sharti#include "mibII_oid.h" 42122394Sharti 43122394Shartistruct sroute { 44150920Sharti RB_ENTRY(sroute) link; 45150920Sharti uint32_t ifindex; 46150920Sharti uint8_t index[13]; 47150920Sharti uint8_t type; 48150920Sharti uint8_t proto; 49122394Sharti}; 50150920ShartiRB_HEAD(sroutes, sroute) sroutes = RB_INITIALIZER(&sroutes); 51122394Sharti 52150920ShartiRB_PROTOTYPE(sroutes, sroute, link, sroute_compare); 53150920Sharti 54150920Sharti#define ROUTE_UPDATE_INTERVAL (100 * 60 * 10) /* 10 min */ 55146525Shartistatic uint64_t route_tick; 56122394Shartistatic u_int route_total; 57122394Sharti 58150920Sharti/* 59150920Sharti * Compare two routes 60150920Sharti */ 61122394Shartistatic int 62150920Shartisroute_compare(struct sroute *s1, struct sroute *s2) 63122394Sharti{ 64150920Sharti 65150920Sharti return (memcmp(s1->index, s2->index, 13)); 66150920Sharti} 67150920Sharti 68150920Shartistatic void 69150920Shartisroute_index_append(struct asn_oid *oid, u_int sub, const struct sroute *s) 70150920Sharti{ 71150920Sharti int i; 72150920Sharti 73150920Sharti oid->len = sub + 13; 74150920Sharti for (i = 0; i < 13; i++) 75150920Sharti oid->subs[sub + i] = s->index[i]; 76150920Sharti} 77150920Sharti 78150920Sharti#if 0 79150920Shartistatic void 80150920Shartisroute_print(const struct sroute *r) 81150920Sharti{ 82150920Sharti u_int i; 83150920Sharti 84150920Sharti for (i = 0; i < 13 - 1; i++) 85150920Sharti printf("%u.", r->index[i]); 86150920Sharti printf("%u proto=%u type=%u", r->index[i], r->proto, r->type); 87150920Sharti} 88150920Sharti#endif 89150920Sharti 90150920Sharti/* 91150920Sharti * process routing message 92150920Sharti */ 93150920Shartivoid 94150920Shartimib_sroute_process(struct rt_msghdr *rtm, struct sockaddr *gw, 95150920Sharti struct sockaddr *dst, struct sockaddr *mask) 96150920Sharti{ 97150920Sharti struct sockaddr_in *in_dst, *in_gw; 98150920Sharti struct in_addr in_mask; 99150920Sharti struct mibif *ifp; 100150920Sharti struct sroute key; 101150920Sharti struct sroute *r, *r1; 102150920Sharti in_addr_t ha; 103150920Sharti 104150920Sharti if (dst == NULL || gw == NULL || dst->sa_family != AF_INET || 105150920Sharti gw->sa_family != AF_INET) 106150920Sharti return; 107150920Sharti 108150920Sharti in_dst = (struct sockaddr_in *)(void *)dst; 109150920Sharti in_gw = (struct sockaddr_in *)(void *)gw; 110150920Sharti 111150920Sharti if (rtm->rtm_flags & RTF_HOST) 112150920Sharti in_mask.s_addr = 0xffffffff; 113150920Sharti else if (mask == NULL || mask->sa_len == 0) 114150920Sharti in_mask.s_addr = 0; 115150920Sharti else 116150920Sharti in_mask = ((struct sockaddr_in *)(void *)mask)->sin_addr; 117150920Sharti 118150920Sharti /* build the index */ 119150920Sharti ha = ntohl(in_dst->sin_addr.s_addr); 120150920Sharti key.index[0] = (ha >> 24) & 0xff; 121150920Sharti key.index[1] = (ha >> 16) & 0xff; 122150920Sharti key.index[2] = (ha >> 8) & 0xff; 123150920Sharti key.index[3] = (ha >> 0) & 0xff; 124150920Sharti 125150920Sharti ha = ntohl(in_mask.s_addr); 126150920Sharti key.index[4] = (ha >> 24) & 0xff; 127150920Sharti key.index[5] = (ha >> 16) & 0xff; 128150920Sharti key.index[6] = (ha >> 8) & 0xff; 129150920Sharti key.index[7] = (ha >> 0) & 0xff; 130150920Sharti 131150920Sharti /* ToS */ 132150920Sharti key.index[8] = 0; 133150920Sharti 134150920Sharti ha = ntohl(in_gw->sin_addr.s_addr); 135150920Sharti key.index[9] = (ha >> 24) & 0xff; 136150920Sharti key.index[10] = (ha >> 16) & 0xff; 137150920Sharti key.index[11] = (ha >> 8) & 0xff; 138150920Sharti key.index[12] = (ha >> 0) & 0xff; 139150920Sharti 140150920Sharti if (rtm->rtm_type == RTM_DELETE) { 141150920Sharti r = RB_FIND(sroutes, &sroutes, &key); 142150920Sharti if (r == 0) { 143150920Sharti#ifdef DEBUG_ROUTE 144150920Sharti syslog(LOG_WARNING, "%s: DELETE: %u.%u.%u.%u " 145150920Sharti "%u.%u.%u.%u %u %u.%u.%u.%u not found", __func__, 146150920Sharti key.index[0], key.index[1], key.index[2], 147150920Sharti key.index[3], key.index[4], key.index[5], 148150920Sharti key.index[6], key.index[7], key.index[8], 149150920Sharti key.index[9], key.index[10], key.index[11], 150150920Sharti key.index[12]); 151150920Sharti#endif 152150920Sharti return; 153150920Sharti } 154150920Sharti RB_REMOVE(sroutes, &sroutes, r); 155150920Sharti free(r); 156150920Sharti route_total--; 157150920Sharti#ifdef DEBUG_ROUTE 158150920Sharti printf("%s: DELETE: %u.%u.%u.%u " 159150920Sharti "%u.%u.%u.%u %u %u.%u.%u.%u\n", __func__, 160150920Sharti key.index[0], key.index[1], key.index[2], 161150920Sharti key.index[3], key.index[4], key.index[5], 162150920Sharti key.index[6], key.index[7], key.index[8], 163150920Sharti key.index[9], key.index[10], key.index[11], 164150920Sharti key.index[12]); 165150920Sharti#endif 166150920Sharti return; 167150920Sharti } 168150920Sharti 169150920Sharti /* GET or ADD */ 170150920Sharti ifp = NULL; 171150920Sharti if ((ifp = mib_find_if_sys(rtm->rtm_index)) == NULL) { 172150920Sharti if (rtm->rtm_type == RTM_ADD) { 173150920Sharti /* make it a get so the kernel fills the index */ 174150920Sharti mib_send_rtmsg(rtm, gw, dst, mask); 175150920Sharti return; 176150920Sharti } 177150920Sharti mib_iflist_bad = 1; 178150920Sharti } 179150920Sharti 180150920Sharti if ((r = malloc(sizeof(*r))) == NULL) { 181150920Sharti syslog(LOG_ERR, "%m"); 182150920Sharti return; 183150920Sharti } 184150920Sharti 185150920Sharti memcpy(r->index, key.index, sizeof(r->index)); 186150920Sharti r->ifindex = (ifp == NULL) ? 0 : ifp->index; 187150920Sharti 188186119Sqingli r->type = (rtm->rtm_flags & RTF_REJECT) ? 2 : 4; 189150920Sharti 190150920Sharti /* cannot really know, what protocol it runs */ 191150920Sharti r->proto = (rtm->rtm_flags & RTF_LOCAL) ? 2 : 192150920Sharti (rtm->rtm_flags & RTF_STATIC) ? 3 : 193150920Sharti (rtm->rtm_flags & RTF_DYNAMIC) ? 4 : 10; 194150920Sharti 195150920Sharti r1 = RB_INSERT(sroutes, &sroutes, r); 196150920Sharti if (r1 != NULL) { 197150920Sharti#ifdef DEBUG_ROUTE 198150920Sharti syslog(LOG_WARNING, "%s: %u.%u.%u.%u " 199150920Sharti "%u.%u.%u.%u %u %u.%u.%u.%u duplicate route", __func__, 200150920Sharti key.index[0], key.index[1], key.index[2], 201150920Sharti key.index[3], key.index[4], key.index[5], 202150920Sharti key.index[6], key.index[7], key.index[8], 203150920Sharti key.index[9], key.index[10], key.index[11], 204150920Sharti key.index[12]); 205150920Sharti#endif 206150920Sharti r1->ifindex = r->ifindex; 207150920Sharti r1->type = r->type; 208150920Sharti r1->proto = r->proto; 209150920Sharti free(r); 210150920Sharti return; 211150920Sharti } 212150920Sharti 213150920Sharti route_total++; 214150920Sharti#ifdef DEBUG_ROUTE 215150920Sharti printf("%s: ADD/GET: %u.%u.%u.%u " 216150920Sharti "%u.%u.%u.%u %u %u.%u.%u.%u\n", __func__, 217150920Sharti key.index[0], key.index[1], key.index[2], 218150920Sharti key.index[3], key.index[4], key.index[5], 219150920Sharti key.index[6], key.index[7], key.index[8], 220150920Sharti key.index[9], key.index[10], key.index[11], 221150920Sharti key.index[12]); 222150920Sharti#endif 223150920Sharti} 224150920Sharti 225150920Shartiint 226150920Shartimib_fetch_route(void) 227150920Sharti{ 228122394Sharti u_char *rtab, *next; 229122394Sharti size_t len; 230150920Sharti struct sroute *r, *r1; 231122394Sharti struct rt_msghdr *rtm; 232122394Sharti struct sockaddr *addrs[RTAX_MAX]; 233122394Sharti 234150920Sharti if (route_tick != 0 && route_tick + ROUTE_UPDATE_INTERVAL > this_tick) 235150920Sharti return (0); 236150920Sharti 237150920Sharti /* 238150920Sharti * Remove all routes 239150920Sharti */ 240150920Sharti r = RB_MIN(sroutes, &sroutes); 241150920Sharti while (r != NULL) { 242150920Sharti r1 = RB_NEXT(sroutes, &sroutes, r); 243150920Sharti RB_REMOVE(sroutes, &sroutes, r); 244122394Sharti free(r); 245150920Sharti r = r1; 246122394Sharti } 247122394Sharti route_total = 0; 248122394Sharti 249122394Sharti if ((rtab = mib_fetch_rtab(AF_INET, NET_RT_DUMP, 0, &len)) == NULL) 250122394Sharti return (-1); 251122394Sharti 252122394Sharti next = rtab; 253122394Sharti for (next = rtab; next < rtab + len; next += rtm->rtm_msglen) { 254122394Sharti rtm = (struct rt_msghdr *)(void *)next; 255122394Sharti if (rtm->rtm_type != RTM_GET || 256122394Sharti !(rtm->rtm_flags & RTF_UP)) 257122394Sharti continue; 258122394Sharti mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs); 259122394Sharti 260310903Sngie 261150920Sharti mib_sroute_process(rtm, addrs[RTAX_GATEWAY], addrs[RTAX_DST], 262150920Sharti addrs[RTAX_NETMASK]); 263150920Sharti } 264122394Sharti 265150920Sharti#if 0 266150920Sharti u_int n = 0; 267150920Sharti r = RB_MIN(sroutes, &sroutes); 268150920Sharti while (r != NULL) { 269150920Sharti printf("%u: ", n++); 270150920Sharti sroute_print(r); 271150920Sharti printf("\n"); 272150920Sharti r = RB_NEXT(sroutes, &sroutes, r); 273150920Sharti } 274150920Sharti#endif 275150920Sharti free(rtab); 276150920Sharti route_tick = get_ticks(); 277122394Sharti 278150920Sharti return (0); 279150920Sharti} 280122394Sharti 281150920Sharti/** 282150920Sharti * Find a route in the table. 283150920Sharti */ 284150920Shartistatic struct sroute * 285150920Shartisroute_get(const struct asn_oid *oid, u_int sub) 286150920Sharti{ 287150920Sharti struct sroute key; 288150920Sharti int i; 289122394Sharti 290150920Sharti if (oid->len - sub != 13) 291150920Sharti return (NULL); 292150920Sharti for (i = 0; i < 13; i++) 293150920Sharti key.index[i] = oid->subs[sub + i]; 294150920Sharti return (RB_FIND(sroutes, &sroutes, &key)); 295150920Sharti} 296122394Sharti 297150920Sharti/** 298150920Sharti * Find next route in the table. There is no such RB_ macro, so must 299150920Sharti * dig into the innards of the RB stuff. 300150920Sharti */ 301150920Shartistatic struct sroute * 302150920Shartisroute_getnext(struct asn_oid *oid, u_int sub) 303150920Sharti{ 304150920Sharti u_int i; 305150920Sharti int comp; 306150920Sharti struct sroute key; 307150920Sharti struct sroute *best; 308150920Sharti struct sroute *s; 309122394Sharti 310150920Sharti /* 311150920Sharti * We now, that the OID is at least the tableEntry OID. If it is, 312150920Sharti * the user wants the first route. 313150920Sharti */ 314150920Sharti if (oid->len == sub) 315150920Sharti return (RB_MIN(sroutes, &sroutes)); 316122394Sharti 317150920Sharti /* 318150920Sharti * This is also true for any index that consists of zeros and is 319150920Sharti * shorter than the full index. 320150920Sharti */ 321150920Sharti if (oid->len < sub + 13) { 322150920Sharti for (i = sub; i < oid->len; i++) 323150920Sharti if (oid->subs[i] != 0) 324150920Sharti break; 325150920Sharti if (i == oid->len) 326150920Sharti return (RB_MIN(sroutes, &sroutes)); 327122394Sharti 328150920Sharti /* 329150920Sharti * Now if the index is too short, we fill it with zeros and then 330150920Sharti * subtract one from the index. We can do this, because we now, 331150920Sharti * that there is at least one index element that is not zero. 332150920Sharti */ 333150920Sharti for (i = oid->len; i < sub + 13; i++) 334150920Sharti oid->subs[i] = 0; 335122394Sharti 336150920Sharti for (i = sub + 13 - 1; i >= sub; i--) { 337150920Sharti if (oid->subs[i] != 0) { 338150920Sharti oid->subs[i]--; 339150920Sharti break; 340150920Sharti } 341150920Sharti oid->subs[i] = ASN_MAXID; 342150920Sharti } 343150920Sharti oid->len = sub + 13; 344150920Sharti } 345122394Sharti 346150920Sharti /* build the index */ 347150920Sharti for (i = sub; i < sub + 13; i++) 348150920Sharti key.index[i - sub] = oid->subs[i]; 349122394Sharti 350150920Sharti /* now find the element */ 351150920Sharti best = NULL; 352150920Sharti s = RB_ROOT(&sroutes); 353122394Sharti 354150920Sharti while (s != NULL) { 355150920Sharti comp = sroute_compare(&key, s); 356150920Sharti if (comp >= 0) { 357150920Sharti /* The current element is smaller than what we search. 358150920Sharti * Forget about it and move to the right subtree. */ 359150920Sharti s = RB_RIGHT(s, link); 360150920Sharti continue; 361150920Sharti } 362150920Sharti /* the current element is larger than what we search. 363150920Sharti * forget about the right subtree (its even larger), but 364150920Sharti * the current element may be what we need. */ 365150920Sharti if (best == NULL || sroute_compare(s, best) < 0) 366150920Sharti /* this one's better */ 367150920Sharti best = s; 368122394Sharti 369150920Sharti s = RB_LEFT(s, link); 370150920Sharti } 371150920Sharti return (best); 372122394Sharti} 373122394Sharti 374122394Sharti/* 375122394Sharti * Table 376122394Sharti */ 377122394Shartiint 378122394Shartiop_route_table(struct snmp_context *ctx __unused, struct snmp_value *value, 379122394Sharti u_int sub, u_int iidx __unused, enum snmp_op op) 380122394Sharti{ 381150920Sharti struct sroute *r; 382122394Sharti 383150920Sharti if (mib_fetch_route() == -1) 384150920Sharti return (SNMP_ERR_GENERR); 385122394Sharti 386122394Sharti switch (op) { 387122394Sharti 388122394Sharti case SNMP_OP_GETNEXT: 389150920Sharti if ((r = sroute_getnext(&value->var, sub)) == NULL) 390122394Sharti return (SNMP_ERR_NOSUCHNAME); 391150920Sharti sroute_index_append(&value->var, sub, r); 392122394Sharti break; 393122394Sharti 394122394Sharti case SNMP_OP_GET: 395150920Sharti if ((r = sroute_get(&value->var, sub)) == NULL) 396122394Sharti return (SNMP_ERR_NOSUCHNAME); 397122394Sharti break; 398122394Sharti 399122394Sharti case SNMP_OP_SET: 400150920Sharti if ((r = sroute_get(&value->var, sub)) == NULL) 401150920Sharti return (SNMP_ERR_NOSUCHNAME); 402122394Sharti return (SNMP_ERR_NOT_WRITEABLE); 403122394Sharti 404122394Sharti case SNMP_OP_ROLLBACK: 405122394Sharti case SNMP_OP_COMMIT: 406122394Sharti abort(); 407122394Sharti 408122394Sharti default: 409122394Sharti abort(); 410122394Sharti } 411122394Sharti 412122394Sharti switch (value->var.subs[sub - 1]) { 413122394Sharti 414122394Sharti case LEAF_ipCidrRouteDest: 415150920Sharti value->v.ipaddress[0] = r->index[0]; 416150920Sharti value->v.ipaddress[1] = r->index[1]; 417150920Sharti value->v.ipaddress[2] = r->index[2]; 418150920Sharti value->v.ipaddress[3] = r->index[3]; 419122394Sharti break; 420122394Sharti 421122394Sharti case LEAF_ipCidrRouteMask: 422150920Sharti value->v.ipaddress[0] = r->index[4]; 423150920Sharti value->v.ipaddress[1] = r->index[5]; 424150920Sharti value->v.ipaddress[2] = r->index[6]; 425150920Sharti value->v.ipaddress[3] = r->index[7]; 426122394Sharti break; 427122394Sharti 428122394Sharti case LEAF_ipCidrRouteTos: 429150920Sharti value->v.integer = r->index[8]; 430122394Sharti break; 431122394Sharti 432122394Sharti case LEAF_ipCidrRouteNextHop: 433150920Sharti value->v.ipaddress[0] = r->index[9]; 434150920Sharti value->v.ipaddress[1] = r->index[10]; 435150920Sharti value->v.ipaddress[2] = r->index[11]; 436150920Sharti value->v.ipaddress[3] = r->index[12]; 437122394Sharti break; 438122394Sharti 439122394Sharti case LEAF_ipCidrRouteIfIndex: 440122394Sharti value->v.integer = r->ifindex; 441122394Sharti break; 442122394Sharti 443122394Sharti case LEAF_ipCidrRouteType: 444122394Sharti value->v.integer = r->type; 445122394Sharti break; 446122394Sharti 447122394Sharti case LEAF_ipCidrRouteProto: 448122394Sharti value->v.integer = r->proto; 449122394Sharti break; 450122394Sharti 451122394Sharti case LEAF_ipCidrRouteAge: 452122394Sharti value->v.integer = 0; 453122394Sharti break; 454122394Sharti 455122394Sharti case LEAF_ipCidrRouteInfo: 456122394Sharti value->v.oid = oid_zeroDotZero; 457122394Sharti break; 458122394Sharti 459122394Sharti case LEAF_ipCidrRouteNextHopAS: 460122394Sharti value->v.integer = 0; 461122394Sharti break; 462122394Sharti 463122394Sharti case LEAF_ipCidrRouteMetric1: 464122394Sharti case LEAF_ipCidrRouteMetric2: 465122394Sharti case LEAF_ipCidrRouteMetric3: 466122394Sharti case LEAF_ipCidrRouteMetric4: 467122394Sharti case LEAF_ipCidrRouteMetric5: 468122394Sharti value->v.integer = -1; 469122394Sharti break; 470122394Sharti 471122394Sharti case LEAF_ipCidrRouteStatus: 472122394Sharti value->v.integer = 1; 473122394Sharti break; 474122394Sharti } 475122394Sharti return (SNMP_ERR_NOERROR); 476122394Sharti} 477122394Sharti 478122394Sharti/* 479122394Sharti * scalars 480122394Sharti */ 481122394Shartiint 482122394Shartiop_route(struct snmp_context *ctx __unused, struct snmp_value *value, 483122394Sharti u_int sub, u_int iidx __unused, enum snmp_op op) 484122394Sharti{ 485122394Sharti switch (op) { 486122394Sharti 487122394Sharti case SNMP_OP_GETNEXT: 488122394Sharti abort(); 489122394Sharti 490122394Sharti case SNMP_OP_GET: 491122394Sharti break; 492122394Sharti 493122394Sharti case SNMP_OP_SET: 494122394Sharti return (SNMP_ERR_NOT_WRITEABLE); 495122394Sharti 496122394Sharti case SNMP_OP_ROLLBACK: 497122394Sharti case SNMP_OP_COMMIT: 498122394Sharti abort(); 499122394Sharti } 500122394Sharti 501150920Sharti if (mib_fetch_route() == -1) 502150920Sharti return (SNMP_ERR_GENERR); 503122394Sharti 504122394Sharti switch (value->var.subs[sub - 1]) { 505122394Sharti 506122394Sharti case LEAF_ipCidrRouteNumber: 507122394Sharti value->v.uint32 = route_total; 508122394Sharti break; 509122394Sharti 510122394Sharti } 511122394Sharti return (SNMP_ERR_NOERROR); 512122394Sharti} 513150920Sharti 514150920ShartiRB_GENERATE(sroutes, sroute, link, sroute_compare); 515