/contrib/bsnmp/snmp_mibII/mibII_route.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 515 lines · 356 code · 78 blank · 81 comment · 76 complexity · fe20dc0da480f884b7f02a82be8f5bd1 MD5 · raw file

  1. /*
  2. * Copyright (c) 2001-2003
  3. * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
  4. * All rights reserved.
  5. *
  6. * Author: Harti Brandt <harti@freebsd.org>
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. *
  29. * $Begemot: bsnmp/snmp_mibII/mibII_route.c,v 1.9 2005/10/06 07:15:00 brandt_h Exp $
  30. *
  31. * Routing table
  32. */
  33. /*#include "support.h"*/
  34. #ifdef HAVE_SYS_TREE_H
  35. #include <sys/tree.h>
  36. #else
  37. #include "tree.h"
  38. #endif
  39. #include "mibII.h"
  40. #include "mibII_oid.h"
  41. struct sroute {
  42. RB_ENTRY(sroute) link;
  43. uint32_t ifindex;
  44. uint8_t index[13];
  45. uint8_t type;
  46. uint8_t proto;
  47. };
  48. RB_HEAD(sroutes, sroute) sroutes = RB_INITIALIZER(&sroutes);
  49. RB_PROTOTYPE(sroutes, sroute, link, sroute_compare);
  50. #define ROUTE_UPDATE_INTERVAL (100 * 60 * 10) /* 10 min */
  51. static uint64_t route_tick;
  52. static u_int route_total;
  53. /*
  54. * Compare two routes
  55. */
  56. static int
  57. sroute_compare(struct sroute *s1, struct sroute *s2)
  58. {
  59. return (memcmp(s1->index, s2->index, 13));
  60. }
  61. static void
  62. sroute_index_append(struct asn_oid *oid, u_int sub, const struct sroute *s)
  63. {
  64. int i;
  65. oid->len = sub + 13;
  66. for (i = 0; i < 13; i++)
  67. oid->subs[sub + i] = s->index[i];
  68. }
  69. #if 0
  70. static void
  71. sroute_print(const struct sroute *r)
  72. {
  73. u_int i;
  74. for (i = 0; i < 13 - 1; i++)
  75. printf("%u.", r->index[i]);
  76. printf("%u proto=%u type=%u", r->index[i], r->proto, r->type);
  77. }
  78. #endif
  79. /*
  80. * process routing message
  81. */
  82. void
  83. mib_sroute_process(struct rt_msghdr *rtm, struct sockaddr *gw,
  84. struct sockaddr *dst, struct sockaddr *mask)
  85. {
  86. struct sockaddr_in *in_dst, *in_gw;
  87. struct in_addr in_mask;
  88. struct mibif *ifp;
  89. struct sroute key;
  90. struct sroute *r, *r1;
  91. in_addr_t ha;
  92. if (dst == NULL || gw == NULL || dst->sa_family != AF_INET ||
  93. gw->sa_family != AF_INET)
  94. return;
  95. in_dst = (struct sockaddr_in *)(void *)dst;
  96. in_gw = (struct sockaddr_in *)(void *)gw;
  97. if (rtm->rtm_flags & RTF_HOST)
  98. in_mask.s_addr = 0xffffffff;
  99. else if (mask == NULL || mask->sa_len == 0)
  100. in_mask.s_addr = 0;
  101. else
  102. in_mask = ((struct sockaddr_in *)(void *)mask)->sin_addr;
  103. /* build the index */
  104. ha = ntohl(in_dst->sin_addr.s_addr);
  105. key.index[0] = (ha >> 24) & 0xff;
  106. key.index[1] = (ha >> 16) & 0xff;
  107. key.index[2] = (ha >> 8) & 0xff;
  108. key.index[3] = (ha >> 0) & 0xff;
  109. ha = ntohl(in_mask.s_addr);
  110. key.index[4] = (ha >> 24) & 0xff;
  111. key.index[5] = (ha >> 16) & 0xff;
  112. key.index[6] = (ha >> 8) & 0xff;
  113. key.index[7] = (ha >> 0) & 0xff;
  114. /* ToS */
  115. key.index[8] = 0;
  116. ha = ntohl(in_gw->sin_addr.s_addr);
  117. key.index[9] = (ha >> 24) & 0xff;
  118. key.index[10] = (ha >> 16) & 0xff;
  119. key.index[11] = (ha >> 8) & 0xff;
  120. key.index[12] = (ha >> 0) & 0xff;
  121. if (rtm->rtm_type == RTM_DELETE) {
  122. r = RB_FIND(sroutes, &sroutes, &key);
  123. if (r == 0) {
  124. #ifdef DEBUG_ROUTE
  125. syslog(LOG_WARNING, "%s: DELETE: %u.%u.%u.%u "
  126. "%u.%u.%u.%u %u %u.%u.%u.%u not found", __func__,
  127. key.index[0], key.index[1], key.index[2],
  128. key.index[3], key.index[4], key.index[5],
  129. key.index[6], key.index[7], key.index[8],
  130. key.index[9], key.index[10], key.index[11],
  131. key.index[12]);
  132. #endif
  133. return;
  134. }
  135. RB_REMOVE(sroutes, &sroutes, r);
  136. free(r);
  137. route_total--;
  138. #ifdef DEBUG_ROUTE
  139. printf("%s: DELETE: %u.%u.%u.%u "
  140. "%u.%u.%u.%u %u %u.%u.%u.%u\n", __func__,
  141. key.index[0], key.index[1], key.index[2],
  142. key.index[3], key.index[4], key.index[5],
  143. key.index[6], key.index[7], key.index[8],
  144. key.index[9], key.index[10], key.index[11],
  145. key.index[12]);
  146. #endif
  147. return;
  148. }
  149. /* GET or ADD */
  150. ifp = NULL;
  151. if ((ifp = mib_find_if_sys(rtm->rtm_index)) == NULL) {
  152. if (rtm->rtm_type == RTM_ADD) {
  153. /* make it a get so the kernel fills the index */
  154. mib_send_rtmsg(rtm, gw, dst, mask);
  155. return;
  156. }
  157. mib_iflist_bad = 1;
  158. }
  159. if ((r = malloc(sizeof(*r))) == NULL) {
  160. syslog(LOG_ERR, "%m");
  161. return;
  162. }
  163. memcpy(r->index, key.index, sizeof(r->index));
  164. r->ifindex = (ifp == NULL) ? 0 : ifp->index;
  165. r->type = (rtm->rtm_flags & RTF_REJECT) ? 2 : 4;
  166. /* cannot really know, what protocol it runs */
  167. r->proto = (rtm->rtm_flags & RTF_LOCAL) ? 2 :
  168. (rtm->rtm_flags & RTF_STATIC) ? 3 :
  169. (rtm->rtm_flags & RTF_DYNAMIC) ? 4 : 10;
  170. r1 = RB_INSERT(sroutes, &sroutes, r);
  171. if (r1 != NULL) {
  172. #ifdef DEBUG_ROUTE
  173. syslog(LOG_WARNING, "%s: %u.%u.%u.%u "
  174. "%u.%u.%u.%u %u %u.%u.%u.%u duplicate route", __func__,
  175. key.index[0], key.index[1], key.index[2],
  176. key.index[3], key.index[4], key.index[5],
  177. key.index[6], key.index[7], key.index[8],
  178. key.index[9], key.index[10], key.index[11],
  179. key.index[12]);
  180. #endif
  181. r1->ifindex = r->ifindex;
  182. r1->type = r->type;
  183. r1->proto = r->proto;
  184. free(r);
  185. return;
  186. }
  187. route_total++;
  188. #ifdef DEBUG_ROUTE
  189. printf("%s: ADD/GET: %u.%u.%u.%u "
  190. "%u.%u.%u.%u %u %u.%u.%u.%u\n", __func__,
  191. key.index[0], key.index[1], key.index[2],
  192. key.index[3], key.index[4], key.index[5],
  193. key.index[6], key.index[7], key.index[8],
  194. key.index[9], key.index[10], key.index[11],
  195. key.index[12]);
  196. #endif
  197. }
  198. int
  199. mib_fetch_route(void)
  200. {
  201. u_char *rtab, *next;
  202. size_t len;
  203. struct sroute *r, *r1;
  204. struct rt_msghdr *rtm;
  205. struct sockaddr *addrs[RTAX_MAX];
  206. if (route_tick != 0 && route_tick + ROUTE_UPDATE_INTERVAL > this_tick)
  207. return (0);
  208. /*
  209. * Remove all routes
  210. */
  211. r = RB_MIN(sroutes, &sroutes);
  212. while (r != NULL) {
  213. r1 = RB_NEXT(sroutes, &sroutes, r);
  214. RB_REMOVE(sroutes, &sroutes, r);
  215. free(r);
  216. r = r1;
  217. }
  218. route_total = 0;
  219. if ((rtab = mib_fetch_rtab(AF_INET, NET_RT_DUMP, 0, &len)) == NULL)
  220. return (-1);
  221. next = rtab;
  222. for (next = rtab; next < rtab + len; next += rtm->rtm_msglen) {
  223. rtm = (struct rt_msghdr *)(void *)next;
  224. if (rtm->rtm_type != RTM_GET ||
  225. !(rtm->rtm_flags & RTF_UP))
  226. continue;
  227. mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs);
  228. mib_sroute_process(rtm, addrs[RTAX_GATEWAY], addrs[RTAX_DST],
  229. addrs[RTAX_NETMASK]);
  230. }
  231. #if 0
  232. u_int n = 0;
  233. r = RB_MIN(sroutes, &sroutes);
  234. while (r != NULL) {
  235. printf("%u: ", n++);
  236. sroute_print(r);
  237. printf("\n");
  238. r = RB_NEXT(sroutes, &sroutes, r);
  239. }
  240. #endif
  241. free(rtab);
  242. route_tick = get_ticks();
  243. return (0);
  244. }
  245. /**
  246. * Find a route in the table.
  247. */
  248. static struct sroute *
  249. sroute_get(const struct asn_oid *oid, u_int sub)
  250. {
  251. struct sroute key;
  252. int i;
  253. if (oid->len - sub != 13)
  254. return (NULL);
  255. for (i = 0; i < 13; i++)
  256. key.index[i] = oid->subs[sub + i];
  257. return (RB_FIND(sroutes, &sroutes, &key));
  258. }
  259. /**
  260. * Find next route in the table. There is no such RB_ macro, so must
  261. * dig into the innards of the RB stuff.
  262. */
  263. static struct sroute *
  264. sroute_getnext(struct asn_oid *oid, u_int sub)
  265. {
  266. u_int i;
  267. int comp;
  268. struct sroute key;
  269. struct sroute *best;
  270. struct sroute *s;
  271. /*
  272. * We now, that the OID is at least the tableEntry OID. If it is,
  273. * the user wants the first route.
  274. */
  275. if (oid->len == sub)
  276. return (RB_MIN(sroutes, &sroutes));
  277. /*
  278. * This is also true for any index that consists of zeros and is
  279. * shorter than the full index.
  280. */
  281. if (oid->len < sub + 13) {
  282. for (i = sub; i < oid->len; i++)
  283. if (oid->subs[i] != 0)
  284. break;
  285. if (i == oid->len)
  286. return (RB_MIN(sroutes, &sroutes));
  287. /*
  288. * Now if the index is too short, we fill it with zeros and then
  289. * subtract one from the index. We can do this, because we now,
  290. * that there is at least one index element that is not zero.
  291. */
  292. for (i = oid->len; i < sub + 13; i++)
  293. oid->subs[i] = 0;
  294. for (i = sub + 13 - 1; i >= sub; i--) {
  295. if (oid->subs[i] != 0) {
  296. oid->subs[i]--;
  297. break;
  298. }
  299. oid->subs[i] = ASN_MAXID;
  300. }
  301. oid->len = sub + 13;
  302. }
  303. /* build the index */
  304. for (i = sub; i < sub + 13; i++)
  305. key.index[i - sub] = oid->subs[i];
  306. /* now find the element */
  307. best = NULL;
  308. s = RB_ROOT(&sroutes);
  309. while (s != NULL) {
  310. comp = sroute_compare(&key, s);
  311. if (comp >= 0) {
  312. /* The current element is smaller than what we search.
  313. * Forget about it and move to the right subtree. */
  314. s = RB_RIGHT(s, link);
  315. continue;
  316. }
  317. /* the current element is larger than what we search.
  318. * forget about the right subtree (its even larger), but
  319. * the current element may be what we need. */
  320. if (best == NULL || sroute_compare(s, best) < 0)
  321. /* this one's better */
  322. best = s;
  323. s = RB_LEFT(s, link);
  324. }
  325. return (best);
  326. }
  327. /*
  328. * Table
  329. */
  330. int
  331. op_route_table(struct snmp_context *ctx __unused, struct snmp_value *value,
  332. u_int sub, u_int iidx __unused, enum snmp_op op)
  333. {
  334. struct sroute *r;
  335. if (mib_fetch_route() == -1)
  336. return (SNMP_ERR_GENERR);
  337. switch (op) {
  338. case SNMP_OP_GETNEXT:
  339. if ((r = sroute_getnext(&value->var, sub)) == NULL)
  340. return (SNMP_ERR_NOSUCHNAME);
  341. sroute_index_append(&value->var, sub, r);
  342. break;
  343. case SNMP_OP_GET:
  344. if ((r = sroute_get(&value->var, sub)) == NULL)
  345. return (SNMP_ERR_NOSUCHNAME);
  346. break;
  347. case SNMP_OP_SET:
  348. if ((r = sroute_get(&value->var, sub)) == NULL)
  349. return (SNMP_ERR_NOSUCHNAME);
  350. return (SNMP_ERR_NOT_WRITEABLE);
  351. case SNMP_OP_ROLLBACK:
  352. case SNMP_OP_COMMIT:
  353. abort();
  354. default:
  355. abort();
  356. }
  357. switch (value->var.subs[sub - 1]) {
  358. case LEAF_ipCidrRouteDest:
  359. value->v.ipaddress[0] = r->index[0];
  360. value->v.ipaddress[1] = r->index[1];
  361. value->v.ipaddress[2] = r->index[2];
  362. value->v.ipaddress[3] = r->index[3];
  363. break;
  364. case LEAF_ipCidrRouteMask:
  365. value->v.ipaddress[0] = r->index[4];
  366. value->v.ipaddress[1] = r->index[5];
  367. value->v.ipaddress[2] = r->index[6];
  368. value->v.ipaddress[3] = r->index[7];
  369. break;
  370. case LEAF_ipCidrRouteTos:
  371. value->v.integer = r->index[8];
  372. break;
  373. case LEAF_ipCidrRouteNextHop:
  374. value->v.ipaddress[0] = r->index[9];
  375. value->v.ipaddress[1] = r->index[10];
  376. value->v.ipaddress[2] = r->index[11];
  377. value->v.ipaddress[3] = r->index[12];
  378. break;
  379. case LEAF_ipCidrRouteIfIndex:
  380. value->v.integer = r->ifindex;
  381. break;
  382. case LEAF_ipCidrRouteType:
  383. value->v.integer = r->type;
  384. break;
  385. case LEAF_ipCidrRouteProto:
  386. value->v.integer = r->proto;
  387. break;
  388. case LEAF_ipCidrRouteAge:
  389. value->v.integer = 0;
  390. break;
  391. case LEAF_ipCidrRouteInfo:
  392. value->v.oid = oid_zeroDotZero;
  393. break;
  394. case LEAF_ipCidrRouteNextHopAS:
  395. value->v.integer = 0;
  396. break;
  397. case LEAF_ipCidrRouteMetric1:
  398. case LEAF_ipCidrRouteMetric2:
  399. case LEAF_ipCidrRouteMetric3:
  400. case LEAF_ipCidrRouteMetric4:
  401. case LEAF_ipCidrRouteMetric5:
  402. value->v.integer = -1;
  403. break;
  404. case LEAF_ipCidrRouteStatus:
  405. value->v.integer = 1;
  406. break;
  407. }
  408. return (SNMP_ERR_NOERROR);
  409. }
  410. /*
  411. * scalars
  412. */
  413. int
  414. op_route(struct snmp_context *ctx __unused, struct snmp_value *value,
  415. u_int sub, u_int iidx __unused, enum snmp_op op)
  416. {
  417. switch (op) {
  418. case SNMP_OP_GETNEXT:
  419. abort();
  420. case SNMP_OP_GET:
  421. break;
  422. case SNMP_OP_SET:
  423. return (SNMP_ERR_NOT_WRITEABLE);
  424. case SNMP_OP_ROLLBACK:
  425. case SNMP_OP_COMMIT:
  426. abort();
  427. }
  428. if (mib_fetch_route() == -1)
  429. return (SNMP_ERR_GENERR);
  430. switch (value->var.subs[sub - 1]) {
  431. case LEAF_ipCidrRouteNumber:
  432. value->v.uint32 = route_total;
  433. break;
  434. }
  435. return (SNMP_ERR_NOERROR);
  436. }
  437. RB_GENERATE(sroutes, sroute, link, sroute_compare);