summaryrefslogtreecommitdiff
path: root/agent/mibgroup/mibII/var_route.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/mibgroup/mibII/var_route.c')
-rw-r--r--agent/mibgroup/mibII/var_route.c2122
1 files changed, 2122 insertions, 0 deletions
diff --git a/agent/mibgroup/mibII/var_route.c b/agent/mibgroup/mibII/var_route.c
new file mode 100644
index 0000000..52fcd86
--- /dev/null
+++ b/agent/mibgroup/mibII/var_route.c
@@ -0,0 +1,2122 @@
+/*
+ * snmp_var_route.c - return a pointer to the named variable.
+ *
+ *
+ */
+/* Portions of this file are subject to the following copyright(s). See
+ * the Net-SNMP's COPYING file for more details and other copyrights
+ * that may apply:
+ */
+/***********************************************************
+ Copyright 1988, 1989 by Carnegie Mellon University
+ Copyright 1989 TGV, Incorporated
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of CMU and TGV not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CMU AND TGV DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL CMU OR TGV BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+******************************************************************/
+/*
+ * Portions of this file are copyrighted by:
+ * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms specified in the COPYING file
+ * distributed with the Net-SNMP package.
+ */
+
+/*
+ * additions, fixes and enhancements for Linux by Erik Schoenfelder
+ * (schoenfr@ibr.cs.tu-bs.de) 1994/1995.
+ * Linux additions taken from CMU to UCD stack by Jennifer Bray of Origin
+ * (jbray@origin-at.co.uk) 1997
+ * Support for sysctl({CTL_NET,PF_ROUTE,...) by Simon Leinen
+ * (simon@switch.ch) 1997
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+
+#include "route_headers.h"
+#define CACHE_TIME (120) /* Seconds */
+
+#if !defined(NETSNMP_CAN_USE_SYSCTL)
+
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include <net-snmp/agent/auto_nlist.h>
+#include <net-snmp/data_access/interface.h>
+
+#include "ip.h"
+#include "kernel.h"
+#include "interfaces.h"
+#include "struct.h"
+
+netsnmp_feature_child_of(get_routes, libnetsnmpmibs)
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifdef hpux11
+#include <sys/mib.h>
+#include <netinet/mib_kern.h>
+#endif /* hpux */
+
+extern WriteMethod write_rte;
+
+#if !defined (WIN32) && !defined (cygwin)
+
+#ifdef USE_SYSCTL_ROUTE_DUMP
+
+static void Route_Scan_Reload(void);
+
+static unsigned char *all_routes = 0;
+static unsigned char *all_routes_end;
+static size_t all_routes_size;
+
+extern const struct sockaddr *get_address(const void *, int, int);
+extern const struct in_addr *get_in_address(const void *, int, int);
+
+/*
+ * var_ipRouteEntry(...
+ * Arguments:
+ * vp IN - pointer to variable entry that points here
+ * name IN/OUT - IN/name requested, OUT/name found
+ * length IN/OUT - length of IN/OUT oid's
+ * exact IN - TRUE if an exact match was requested
+ * var_len OUT - length of variable or 0 if function returned
+ * write_method out - pointer to function to set variable, otherwise 0
+ */
+u_char *
+var_ipRouteEntry(struct variable *vp,
+ oid * name,
+ size_t * length,
+ int exact, size_t * var_len, WriteMethod ** write_method)
+{
+ /*
+ * object identifier is of form:
+ * 1.3.6.1.2.1.4.21.1.1.A.B.C.D, where A.B.C.D is IP address.
+ * IPADDR starts at offset 10.
+ */
+ struct rt_msghdr *rtp, *saveRtp = 0;
+ register int Save_Valid, result;
+ static int saveNameLen = 0, saveExact = 0;
+ static oid saveName[MAX_OID_LEN], Current[MAX_OID_LEN];
+ u_char *cp;
+ u_char *ap;
+ oid *op;
+ static in_addr_t addr_ret;
+
+ *write_method = NULL; /* write_rte; XXX: SET support not really implemented */
+
+#if 0
+ /**
+ ** this optimisation fails, if there is only a single route avail.
+ ** it is a very special case, but better leave it out ...
+ **/
+#if 0
+ if (rtsize <= 1)
+ Save_Valid = 0;
+ else
+#endif /* 0 */
+ /*
+ * OPTIMIZATION:
+ *
+ * If the name was the same as the last name, with the possible
+ * exception of the [9]th token, then don't read the routing table
+ *
+ */
+
+ if ((saveNameLen == *length) && (saveExact == exact)) {
+ register int temp = name[9];
+ name[9] = 0;
+ Save_Valid =
+ (snmp_oid_compare(name, *length, saveName, saveNameLen) == 0);
+ name[9] = temp;
+ } else
+ Save_Valid = 0;
+
+ if (Save_Valid && saveRtp) {
+ register int temp = name[9]; /* Fix up 'lowest' found entry */
+ memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
+ name[9] = temp;
+ *length = 14;
+ rtp = saveRtp;
+ } else {
+#endif /* 0 */
+ /*
+ * fill in object part of name for current (less sizeof instance part)
+ */
+
+ memcpy((char *) Current, (char *) vp->name,
+ (int) (vp->namelen) * sizeof(oid));
+
+#if 0
+ /*
+ * Only reload if this is the start of a wildcard
+ */
+ if (*length < 14) {
+ Route_Scan_Reload();
+ }
+#else
+ Route_Scan_Reload();
+#endif
+ for (ap = all_routes; ap < all_routes_end; ap += rtp->rtm_msglen) {
+ rtp = (struct rt_msghdr *) ap;
+ if (rtp->rtm_type == 0)
+ break;
+ if (rtp->rtm_version != RTM_VERSION) {
+ snmp_log(LOG_ERR,
+ "routing socket message version mismatch (%d instead of %d)\n",
+ rtp->rtm_version, RTM_VERSION);
+ break;
+ }
+ if (rtp->rtm_type != RTM_GET) {
+ snmp_log(LOG_ERR,
+ "routing socket returned message other than GET (%d)\n",
+ rtp->rtm_type);
+ continue;
+ }
+ if (!(rtp->rtm_addrs & RTA_DST))
+ continue;
+ cp = (u_char *) get_in_address((struct sockaddr *) (rtp + 1),
+ rtp->rtm_addrs, RTA_DST);
+ if (cp == NULL)
+ return NULL;
+
+ op = Current + 10;
+ *op++ = *cp++;
+ *op++ = *cp++;
+ *op++ = *cp++;
+ *op++ = *cp++;
+
+ result = snmp_oid_compare(name, *length, Current, 14);
+ if ((exact && (result == 0)) || (!exact && (result < 0)))
+ break;
+ }
+ if (ap >= all_routes_end || rtp->rtm_type == 0)
+ return 0;
+ /*
+ * Save in the 'cache'
+ */
+ memcpy((char *) saveName, (char *) name,
+ SNMP_MIN(*length, MAX_OID_LEN) * sizeof(oid));
+ saveName[9] = '\0';
+ saveNameLen = *length;
+ saveExact = exact;
+ saveRtp = rtp;
+ /*
+ * Return the name
+ */
+ memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
+ *length = 14;
+#if 0
+ }
+#endif /* 0 */
+
+ *var_len = sizeof(long_return);
+
+ switch (vp->magic) {
+ case IPROUTEDEST:
+ *var_len = sizeof(addr_ret);
+ return (u_char *) get_in_address((struct sockaddr *) (rtp + 1),
+ rtp->rtm_addrs, RTA_DST);
+ case IPROUTEIFINDEX:
+ long_return = (u_long) rtp->rtm_index;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC1:
+ long_return = (rtp->rtm_flags & RTF_UP) ? 1 : 0;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC2:
+#if NETSNMP_NO_DUMMY_VALUES
+ return NULL;
+#endif
+ long_return = -1;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC3:
+#if NETSNMP_NO_DUMMY_VALUES
+ return NULL;
+#endif
+ long_return = -1;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC4:
+#if NETSNMP_NO_DUMMY_VALUES
+ return NULL;
+#endif
+ long_return = -1;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC5:
+#if NETSNMP_NO_DUMMY_VALUES
+ return NULL;
+#endif
+ long_return = -1;
+ return (u_char *) & long_return;
+ case IPROUTENEXTHOP:
+ *var_len = sizeof(addr_ret);
+ return (u_char *) get_in_address((struct sockaddr *) (rtp + 1),
+ rtp->rtm_addrs, RTA_GATEWAY);
+ case IPROUTETYPE:
+ if (rtp->rtm_flags & RTF_UP) {
+ if (rtp->rtm_flags & RTF_GATEWAY) {
+ long_return = 4; /* indirect(4) */
+ } else {
+ long_return = 3; /* direct(3) */
+ }
+ } else {
+ long_return = 2; /* invalid(2) */
+ }
+ return (u_char *) & long_return;
+ case IPROUTEPROTO:
+ long_return = (rtp->rtm_flags & RTF_DYNAMIC)
+ ? 10 : (rtp->rtm_flags & RTF_STATIC)
+ ? 2 : (rtp->rtm_flags & RTF_DYNAMIC) ? 4 : 1;
+ return (u_char *) & long_return;
+ case IPROUTEAGE:
+#if NETSNMP_NO_DUMMY_VALUES
+ return NULL;
+#endif
+ long_return = 0;
+ return (u_char *) & long_return;
+ case IPROUTEMASK:
+ *var_len = sizeof(addr_ret);
+ if (rtp->rtm_flags & RTF_HOST) {
+ addr_ret = 0x00000001;
+ return (u_char *) & addr_ret;
+ } else {
+ return (u_char *) get_in_address((struct sockaddr *) (rtp + 1),
+ rtp->rtm_addrs, RTA_NETMASK);
+ }
+ case IPROUTEINFO:
+ *var_len = nullOidLen;
+ return (u_char *) nullOid;
+ default:
+ DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
+ vp->magic));
+ }
+ return NULL;
+}
+
+#else /* not USE_SYSCTL_ROUTE_DUMP */
+
+#ifdef hpux11
+static int rtsize = 0;
+static mib_ipRouteEnt *rt = (mib_ipRouteEnt *) 0;
+static void Route_Scan_Reload(void);
+#elif !defined(solaris2)
+static RTENTRY **rthead = NULL;
+static int rtsize = 0, rtallocate = 0;
+
+static void Route_Scan_Reload(void);
+
+#ifndef NETSNMP_FEATURE_REMOVE_GET_ROUTES
+RTENTRY **netsnmp_get_routes(size_t *size) {
+ Route_Scan_Reload();
+ if (size)
+ *size = rtsize;
+ return rthead;
+}
+#endif /* NETSNMP_FEATURE_REMOVE_GET_ROUTES */
+#endif /* hpux11 */
+
+#if !(defined(linux) || defined(solaris2) || defined(hpux11)) && defined(RTHOST_SYMBOL) && defined(RTNET_SYMBOL)
+#define NUM_ROUTE_SYMBOLS 2
+static char *route_symbols[] = {
+ RTHOST_SYMBOL,
+ RTNET_SYMBOL
+};
+#endif
+#endif
+
+#ifdef USE_SYSCTL_ROUTE_DUMP
+
+void
+init_var_route(void)
+{
+#ifdef solaris2
+ init_kernel_sunos5();
+#endif
+}
+
+static void
+Route_Scan_Reload(void)
+{
+ size_t size = 0;
+ int name[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 };
+
+ if (sysctl(name, sizeof(name) / sizeof(int), 0, &size, 0, 0) == -1) {
+ snmp_log(LOG_ERR, "sysctl(CTL_NET,PF_ROUTE,0,0,NET_RT_DUMP,0)\n");
+ } else {
+ if (all_routes == 0 || all_routes_size < size) {
+ if (all_routes != 0) {
+ free(all_routes);
+ all_routes = 0;
+ }
+ if ((all_routes = malloc(size)) == 0) {
+ snmp_log(LOG_ERR,
+ "out of memory allocating route table\n");
+ }
+ all_routes_size = size;
+ } else {
+ size = all_routes_size;
+ }
+ if (sysctl(name, sizeof(name) / sizeof(int),
+ all_routes, &size, 0, 0) == -1) {
+ snmp_log(LOG_ERR,
+ "sysctl(CTL_NET,PF_ROUTE,0,0,NET_RT_DUMP,0)\n");
+ }
+ all_routes_end = all_routes + size;
+ }
+}
+
+#else /* not USE_SYSCTL_ROUTE_DUMP */
+
+void
+init_var_route(void)
+{
+#ifdef RTTABLES_SYMBOL
+ auto_nlist(RTTABLES_SYMBOL, 0, 0);
+#endif
+#ifdef RTHASHSIZE_SYMBOL
+ auto_nlist(RTHASHSIZE_SYMBOL, 0, 0);
+#endif
+#ifdef RTHOST_SYMBOL
+ auto_nlist(RTHOST_SYMBOL, 0, 0);
+#endif
+#ifdef RTNET_SYMBOL
+ auto_nlist(RTNET_SYMBOL, 0, 0);
+#endif
+}
+
+#ifndef solaris2
+
+#if NEED_KLGETSA
+static union {
+ struct sockaddr_in sin;
+ u_short data[128];
+} klgetsatmp;
+
+struct sockaddr_in *
+klgetsa(struct sockaddr_in *dst)
+{
+ if (!NETSNMP_KLOOKUP(dst, (char *) &klgetsatmp.sin, sizeof klgetsatmp.sin)) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return NULL;
+ }
+ if (klgetsatmp.sin.sin_len > sizeof(klgetsatmp.sin)) {
+ if (!NETSNMP_KLOOKUP(dst, (char *) &klgetsatmp.sin, klgetsatmp.sin.sin_len)) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return NULL;
+ }
+ }
+ return (&klgetsatmp.sin);
+}
+#endif
+
+u_char *
+var_ipRouteEntry(struct variable * vp,
+ oid * name,
+ size_t * length,
+ int exact, size_t * var_len, WriteMethod ** write_method)
+{
+ /*
+ * object identifier is of form:
+ * 1.3.6.1.2.1.4.21.1.1.A.B.C.D, where A.B.C.D is IP address.
+ * IPADDR starts at offset 10.
+ */
+ register int Save_Valid, result, RtIndex;
+ static size_t saveNameLen = 0;
+ static int saveExact = 0, saveRtIndex = 0;
+ static oid saveName[MAX_OID_LEN], Current[MAX_OID_LEN];
+ u_char *cp;
+ oid *op;
+ static in_addr_t addr_ret;
+#if NEED_KLGETSA
+ struct sockaddr_in *sa;
+#endif
+#if !defined(linux) && !defined(hpux11)
+ struct ifnet rt_ifnet;
+ struct in_ifaddr rt_ifnetaddr;
+#endif
+
+ *write_method = NULL; /* write_rte; XXX: SET support not really implemented */
+
+ /**
+ ** this optimisation fails, if there is only a single route avail.
+ ** it is a very special case, but better leave it out ...
+ **/
+#if NETSNMP_NO_DUMMY_VALUES
+ saveNameLen = 0;
+#endif
+ if (rtsize <= 1)
+ Save_Valid = 0;
+ else
+ /*
+ * OPTIMIZATION:
+ *
+ * If the name was the same as the last name, with the possible
+ * exception of the [9]th token, then don't read the routing table
+ *
+ */
+
+ if ((saveNameLen == *length) && (saveExact == exact)) {
+ register int temp = name[9];
+ name[9] = 0;
+ Save_Valid =
+ (snmp_oid_compare(name, *length, saveName, saveNameLen) == 0);
+ name[9] = temp;
+ } else
+ Save_Valid = 0;
+
+ if (Save_Valid) {
+ register int temp = name[9]; /* Fix up 'lowest' found entry */
+ memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
+ name[9] = temp;
+ *length = 14;
+ RtIndex = saveRtIndex;
+ } else {
+ /*
+ * fill in object part of name for current (less sizeof instance part)
+ */
+
+ memcpy((char *) Current, (char *) vp->name,
+ (int) (vp->namelen) * sizeof(oid));
+
+#if 0
+ /*
+ * Only reload if this is the start of a wildcard
+ */
+ if (*length < 14) {
+ Route_Scan_Reload();
+ }
+#else
+ Route_Scan_Reload();
+#endif
+ for (RtIndex = 0; RtIndex < rtsize; RtIndex++) {
+#if NEED_KLGETSA
+ sa = klgetsa((struct sockaddr_in *) rthead[RtIndex]->rt_dst);
+ cp = (u_char *) & (sa->sin_addr.s_addr);
+#elif defined(hpux11)
+ cp = (u_char *) & rt[RtIndex].Dest;
+#else
+ cp = (u_char *) &
+ (((struct sockaddr_in *) &(rthead[RtIndex]->rt_dst))->
+ sin_addr.s_addr);
+#endif
+ op = Current + 10;
+ *op++ = *cp++;
+ *op++ = *cp++;
+ *op++ = *cp++;
+ *op++ = *cp++;
+
+ result = snmp_oid_compare(name, *length, Current, 14);
+ if ((exact && (result == 0)) || (!exact && (result < 0)))
+ break;
+ }
+ if (RtIndex >= rtsize)
+ return (NULL);
+ /*
+ * Save in the 'cache'
+ */
+ memcpy((char *) saveName, (char *) name,
+ SNMP_MIN(*length, MAX_OID_LEN) * sizeof(oid));
+ saveName[9] = 0;
+ saveNameLen = *length;
+ saveExact = exact;
+ saveRtIndex = RtIndex;
+ /*
+ * Return the name
+ */
+ memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
+ *length = 14;
+ }
+
+ *var_len = sizeof(long_return);
+
+ switch (vp->magic) {
+ case IPROUTEDEST:
+ *var_len = sizeof(addr_ret);
+#if NEED_KLGETSA
+ sa = klgetsa((struct sockaddr_in *) rthead[RtIndex]->rt_dst);
+ return (u_char *) & (sa->sin_addr.s_addr);
+#elif defined(hpux11)
+ addr_ret = rt[RtIndex].Dest;
+ return (u_char *) & addr_ret;
+#else
+ return (u_char *) & ((struct sockaddr_in *) &rthead[RtIndex]->
+ rt_dst)->sin_addr.s_addr;
+#endif
+ case IPROUTEIFINDEX:
+#ifdef hpux11
+ long_return = rt[RtIndex].IfIndex;
+#else
+ long_return = (u_long) rthead[RtIndex]->rt_unit;
+#endif
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC1:
+#ifdef hpux11
+ long_return = rt[RtIndex].Metric1;
+#else
+ long_return = (rthead[RtIndex]->rt_flags & RTF_GATEWAY) ? 1 : 0;
+#endif
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC2:
+#ifdef hpux11
+ long_return = rt[RtIndex].Metric2;
+ return (u_char *) & long_return;
+#elif defined(NETSNMP_NO_DUMMY_VALUES)
+ return NULL;
+#endif
+ long_return = -1;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC3:
+#ifdef hpux11
+ long_return = rt[RtIndex].Metric3;
+ return (u_char *) & long_return;
+#elif defined(NETSNMP_NO_DUMMY_VALUES)
+ return NULL;
+#endif
+ long_return = -1;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC4:
+#ifdef hpux11
+ long_return = rt[RtIndex].Metric4;
+ return (u_char *) & long_return;
+#elif defined(NETSNMP_NO_DUMMY_VALUES)
+ return NULL;
+#endif
+ long_return = -1;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC5:
+#if NETSNMP_NO_DUMMY_VALUES
+ return NULL;
+#endif
+ long_return = -1;
+ return (u_char *) & long_return;
+ case IPROUTENEXTHOP:
+ *var_len = sizeof(addr_ret);
+#if NEED_KLGETSA
+ sa = klgetsa((struct sockaddr_in *) rthead[RtIndex]->rt_gateway);
+ return (u_char *) & (sa->sin_addr.s_addr);
+#elif defined(hpux11)
+ addr_ret = rt[RtIndex].NextHop;
+ return (u_char *) & addr_ret;
+#else
+ return (u_char *) & ((struct sockaddr_in *) &rthead[RtIndex]->
+ rt_gateway)->sin_addr.s_addr;
+#endif /* *bsd */
+ case IPROUTETYPE:
+#ifdef hpux11
+ long_return = rt[RtIndex].Type;
+#else
+ if (rthead[RtIndex]->rt_flags & RTF_UP) {
+ if (rthead[RtIndex]->rt_flags & RTF_GATEWAY) {
+ long_return = 4; /* indirect(4) */
+ } else {
+ long_return = 3; /* direct(3) */
+ }
+ } else {
+ long_return = 2; /* invalid(2) */
+ }
+#endif
+ return (u_char *) & long_return;
+ case IPROUTEPROTO:
+#ifdef hpux11
+ long_return = rt[RtIndex].Proto;
+#else
+ long_return = (rthead[RtIndex]->rt_flags & RTF_DYNAMIC) ? 4 : 2;
+#endif
+ return (u_char *) & long_return;
+ case IPROUTEAGE:
+#ifdef hpux11
+ long_return = rt[RtIndex].Age;
+ return (u_char *) & long_return;
+#elif defined(NETSNMP_NO_DUMMY_VALUES)
+ return NULL;
+#endif
+ long_return = 0;
+ return (u_char *) & long_return;
+ case IPROUTEMASK:
+ *var_len = sizeof(addr_ret);
+#if NEED_KLGETSA
+ /*
+ * XXX - Almost certainly not right
+ * but I don't have a suitable system to test this on
+ */
+#if NETSNMP_NO_DUMMY_VALUES
+ return NULL;
+#endif
+ addr_ret = 0;
+#elif defined(hpux11)
+ addr_ret = rt[RtIndex].Mask;
+ return (u_char *) & addr_ret;
+#else /* !NEED_KLGETSA && !hpux11 */
+ if (((struct sockaddr_in *) &rthead[RtIndex]->rt_dst)->sin_addr.
+ s_addr == 0)
+ addr_ret = 0; /* Default route */
+ else {
+#ifndef linux
+ if (!NETSNMP_KLOOKUP(rthead[RtIndex]->rt_ifp,
+ (char *) &rt_ifnet, sizeof(rt_ifnet))) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return NULL;
+ }
+ if (!NETSNMP_KLOOKUP(rt_ifnet.if_addrlist,
+ (char *) &rt_ifnetaddr, sizeof(rt_ifnetaddr))) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return NULL;
+ }
+
+ addr_ret = rt_ifnetaddr.ia_subnetmask;
+#else /* linux */
+ cp = (u_char *) &
+ (((struct sockaddr_in *) &(rthead[RtIndex]->rt_dst))->
+ sin_addr.s_addr);
+ return (u_char *) &
+ (((struct sockaddr_in *) &(rthead[RtIndex]->rt_genmask))->
+ sin_addr.s_addr);
+#endif /* linux */
+ }
+#endif /* NEED_KLGETSA */
+ return (u_char *) & addr_ret;
+ case IPROUTEINFO:
+ *var_len = nullOidLen;
+ return (u_char *) nullOid;
+ default:
+ DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
+ vp->magic));
+ }
+ return NULL;
+}
+
+#else /* solaris2 */
+
+static int
+IP_Cmp_Route(void *addr, void *ep)
+{
+ mib2_ipRouteEntry_t *Ep = ep, *Addr = addr;
+
+ if ((Ep->ipRouteDest == Addr->ipRouteDest) &&
+ (Ep->ipRouteNextHop == Addr->ipRouteNextHop) &&
+ (Ep->ipRouteType == Addr->ipRouteType) &&
+ (Ep->ipRouteProto == Addr->ipRouteProto) &&
+ (Ep->ipRouteMask == Addr->ipRouteMask) &&
+ (Ep->ipRouteInfo.re_max_frag == Addr->ipRouteInfo.re_max_frag) &&
+ (Ep->ipRouteInfo.re_rtt == Addr->ipRouteInfo.re_rtt) &&
+ (Ep->ipRouteInfo.re_ref == Addr->ipRouteInfo.re_ref) &&
+ (Ep->ipRouteInfo.re_frag_flag == Addr->ipRouteInfo.re_frag_flag) &&
+ (Ep->ipRouteInfo.re_src_addr == Addr->ipRouteInfo.re_src_addr) &&
+ (Ep->ipRouteInfo.re_ire_type == Addr->ipRouteInfo.re_ire_type) &&
+ (Ep->ipRouteInfo.re_obpkt == Addr->ipRouteInfo.re_obpkt) &&
+ (Ep->ipRouteInfo.re_ibpkt == Addr->ipRouteInfo.re_ibpkt)
+ )
+ return (0);
+ else
+ return (1); /* Not found */
+}
+
+u_char *
+var_ipRouteEntry(struct variable * vp,
+ oid * name,
+ size_t * length,
+ int exact, size_t * var_len, WriteMethod ** write_method)
+{
+ /*
+ * object identifier is of form:
+ * 1.3.6.1.2.1.4.21.1.1.A.B.C.D, where A.B.C.D is IP address.
+ * IPADDR starts at offset 10.
+ */
+#define IP_ROUTENAME_LENGTH 14
+#define IP_ROUTEADDR_OFF 10
+ oid current[IP_ROUTENAME_LENGTH],
+ lowest[IP_ROUTENAME_LENGTH];
+ u_char *cp;
+ oid *op;
+ mib2_ipRouteEntry_t Lowentry, Nextentry, entry;
+ int Found = 0;
+ req_e req_type;
+ static in_addr_t addr_ret;
+
+ *write_method = NULL; /* write_rte; XXX: SET support not really implemented */
+
+ /*
+ * fill in object part of name for current (less sizeof instance part)
+ */
+
+ memcpy((char *) current, (char *) vp->name, vp->namelen * sizeof(oid));
+ if (*length == IP_ROUTENAME_LENGTH) /* Assume that the input name is the lowest */
+ memcpy((char *) lowest, (char *) name,
+ IP_ROUTENAME_LENGTH * sizeof(oid));
+ else {
+ name[IP_ROUTEADDR_OFF] = (oid) - 1; /* Grhhh: to prevent accidental comparison :-( */
+ lowest[0] = 0xff;
+ }
+ for (Nextentry.ipRouteDest = (u_long) - 2, req_type = GET_FIRST;;
+ Nextentry = entry, req_type = GET_NEXT) {
+ if (getMibstat(MIB_IP_ROUTE, &entry, sizeof(mib2_ipRouteEntry_t),
+ req_type, &IP_Cmp_Route, &Nextentry) != 0)
+ break;
+#ifdef HAVE_DEFINED_IRE_CACHE
+ if(entry.ipRouteInfo.re_ire_type&IRE_CACHE)
+ continue;
+#endif /* HAVE_DEFINED_IRE_CACHE */
+ COPY_IPADDR(cp, (u_char *) & entry.ipRouteDest, op,
+ current + IP_ROUTEADDR_OFF);
+ if (exact) {
+ if (snmp_oid_compare
+ (current, IP_ROUTENAME_LENGTH, name, *length) == 0) {
+ memcpy((char *) lowest, (char *) current,
+ IP_ROUTENAME_LENGTH * sizeof(oid));
+ Lowentry = entry;
+ Found++;
+ break; /* no need to search further */
+ }
+ } else {
+ if ((snmp_oid_compare
+ (current, IP_ROUTENAME_LENGTH, name, *length) > 0)
+ && ((Nextentry.ipRouteDest == (u_long) - 2)
+ ||
+ (snmp_oid_compare
+ (current, IP_ROUTENAME_LENGTH, lowest,
+ IP_ROUTENAME_LENGTH) < 0)
+ ||
+ (snmp_oid_compare
+ (name, IP_ROUTENAME_LENGTH, lowest,
+ IP_ROUTENAME_LENGTH) == 0))) {
+
+ /*
+ * if new one is greater than input and closer to input than
+ * * previous lowest, and is not equal to it, save this one as the "next" one.
+ */
+ memcpy((char *) lowest, (char *) current,
+ IP_ROUTENAME_LENGTH * sizeof(oid));
+ Lowentry = entry;
+ Found++;
+ }
+ }
+ }
+ if (Found == 0)
+ return (NULL);
+ memcpy((char *) name, (char *) lowest,
+ IP_ROUTENAME_LENGTH * sizeof(oid));
+ *length = IP_ROUTENAME_LENGTH;
+ *var_len = sizeof(long_return);
+
+ switch (vp->magic) {
+ case IPROUTEDEST:
+ *var_len = sizeof(addr_ret);
+ addr_ret = Lowentry.ipRouteDest;
+ return (u_char *) & addr_ret;
+ case IPROUTEIFINDEX:
+#ifdef NETSNMP_INCLUDE_IFTABLE_REWRITES
+ Lowentry.ipRouteIfIndex.o_bytes[Lowentry.ipRouteIfIndex.o_length] = '\0';
+ long_return =
+ netsnmp_access_interface_index_find(
+ Lowentry.ipRouteIfIndex.o_bytes);
+#else
+ long_return =
+ Interface_Index_By_Name(Lowentry.ipRouteIfIndex.o_bytes,
+ Lowentry.ipRouteIfIndex.o_length);
+#endif
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC1:
+ long_return = Lowentry.ipRouteMetric1;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC2:
+ long_return = Lowentry.ipRouteMetric2;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC3:
+ long_return = Lowentry.ipRouteMetric3;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC4:
+ long_return = Lowentry.ipRouteMetric4;
+ return (u_char *) & long_return;
+ case IPROUTENEXTHOP:
+ *var_len = sizeof(addr_ret);
+ addr_ret = Lowentry.ipRouteNextHop;
+ return (u_char *) & addr_ret;
+ case IPROUTETYPE:
+ long_return = Lowentry.ipRouteType;
+ return (u_char *) & long_return;
+ case IPROUTEPROTO:
+ long_return = Lowentry.ipRouteProto;
+ if (long_return == -1)
+ long_return = 1;
+ return (u_char *) & long_return;
+ case IPROUTEAGE:
+ long_return = Lowentry.ipRouteAge;
+ return (u_char *) & long_return;
+ case IPROUTEMASK:
+ *var_len = sizeof(addr_ret);
+ addr_ret = Lowentry.ipRouteMask;
+ return (u_char *) & addr_ret;
+ default:
+ DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
+ vp->magic));
+ };
+ return NULL;
+}
+
+#endif /* solaris2 - var_IProute */
+
+#ifndef solaris2
+static int qsort_compare(const void *, const void *);
+#endif
+
+#if defined(RTENTRY_4_4) || defined(RTENTRY_RT_NEXT) || defined (hpux11)
+
+#if defined(RTENTRY_4_4) && !defined(hpux11)
+void
+load_rtentries(struct radix_node *pt)
+{
+ struct radix_node node;
+ RTENTRY rt;
+ struct ifnet ifnet;
+ char name[16], temp[16];
+#if !HAVE_STRUCT_IFNET_IF_XNAME
+ register char *cp;
+#endif
+
+ if (!NETSNMP_KLOOKUP(pt, (char *) &node, sizeof(struct radix_node))) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return;
+ }
+ if (node.rn_b >= 0) {
+ load_rtentries(node.rn_r);
+ load_rtentries(node.rn_l);
+ } else {
+ if (node.rn_flags & RNF_ROOT) {
+ /*
+ * root node
+ */
+ if (node.rn_dupedkey)
+ load_rtentries(node.rn_dupedkey);
+ return;
+ }
+ /*
+ * get the route
+ */
+ if (!NETSNMP_KLOOKUP(pt, (char *) &rt, sizeof(RTENTRY))) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return;
+ }
+
+ if (rt.rt_ifp != 0) {
+ if (!NETSNMP_KLOOKUP(rt.rt_ifp, (char *) &ifnet, sizeof(ifnet))) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return;
+ }
+#if HAVE_STRUCT_IFNET_IF_XNAME
+#if defined(netbsd1) || defined(openbsd2)
+ strlcpy(name, ifnet.if_xname, sizeof(name));
+#else
+ if (!NETSNMP_KLOOKUP(ifnet.if_xname, name, sizeof name)) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return;
+ }
+#endif
+ name[sizeof(name) - 1] = '\0';
+#else
+#ifdef NETSNMP_FEATURE_CHECKIN
+ /* this exists here just so we don't copy ifdef logic elsewhere */
+ netsnmp_feature_require(string_append_int);
+#endif
+ if (!NETSNMP_KLOOKUP(ifnet.if_name, name, sizeof name)) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return;
+ }
+ name[sizeof(name) - 1] = '\0';
+ cp = (char *) strchr(name, '\0');
+ string_append_int(cp, ifnet.if_unit);
+#endif
+#ifdef NETSNMP_FEATURE_CHECKIN
+ netsnmp_feature_require(interface_legacy)
+#endif /* NETSNMP_FEATURE_CHECKIN */
+ Interface_Scan_Init();
+ rt.rt_unit = 0;
+ while (Interface_Scan_Next
+ ((short *) &(rt.rt_unit), temp, NULL, NULL) != 0) {
+ if (strcmp(name, temp) == 0)
+ break;
+ }
+ }
+#if CHECK_RT_FLAGS
+ if (((rt.rt_flags & RTF_CLONING) != RTF_CLONING)
+ && ((rt.rt_flags & RTF_LLINFO) != RTF_LLINFO)) {
+#endif
+ /*
+ * check for space and malloc
+ */
+ if (rtsize >= rtallocate) {
+ rthead =
+ (RTENTRY **) realloc((char *) rthead,
+ 2 * rtallocate *
+ sizeof(RTENTRY *));
+ memset((char *) &rthead[rtallocate], (0),
+ rtallocate * sizeof(RTENTRY *));
+
+ rtallocate *= 2;
+ }
+ if (!rthead[rtsize])
+ rthead[rtsize] = (RTENTRY *) malloc(sizeof(RTENTRY));
+ /*
+ * Add this to the database
+ */
+ memcpy((char *) rthead[rtsize], (char *) &rt, sizeof(RTENTRY));
+ rtsize++;
+#if CHECK_RT_FLAGS
+ }
+#endif
+
+ if (node.rn_dupedkey)
+ load_rtentries(node.rn_dupedkey);
+ }
+}
+#endif /* RTENTRY_4_4 && !hpux11 */
+
+static void
+Route_Scan_Reload(void)
+{
+#ifdef hpux11
+
+ int fd;
+ struct nmparms p;
+ int val;
+ unsigned int ulen;
+ int ret;
+
+ if (rt)
+ free(rt);
+ rt = (mib_ipRouteEnt *) 0;
+ rtsize = 0;
+
+ if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) {
+ p.objid = ID_ipRouteNumEnt;
+ p.buffer = (void *) &val;
+ ulen = sizeof(int);
+ p.len = &ulen;
+ if ((ret = get_mib_info(fd, &p)) == 0)
+ rtsize = val;
+
+ if (rtsize > 0) {
+ ulen = (unsigned) rtsize *sizeof(mib_ipRouteEnt);
+ rt = (mib_ipRouteEnt *) malloc(ulen);
+ p.objid = ID_ipRouteTable;
+ p.buffer = (void *) rt;
+ p.len = &ulen;
+ if ((ret = get_mib_info(fd, &p)) < 0)
+ rtsize = 0;
+ }
+
+ close_mib(fd);
+ }
+
+ /*
+ * Sort it!
+ */
+ qsort((char *) rt, rtsize, sizeof(rt[0]),
+#ifdef __STDC__
+ (int (*)(const void *, const void *)) qsort_compare
+#else
+ qsort_compare
+#endif
+ );
+
+#else /* hpux11 */
+#if defined(RTENTRY_4_4)
+ struct radix_node_head head, *rt_table[AF_MAX + 1];
+ int i;
+#else
+ RTENTRY **routehash, mb;
+ register RTENTRY *m;
+ RTENTRY *rt;
+ struct ifnet ifnet;
+ int i, table;
+ register char *cp;
+ char name[16], temp[16];
+ int hashsize;
+#endif
+ static time_t Time_Of_Last_Reload;
+ struct timeval now;
+
+ netsnmp_get_monotonic_clock(&now);
+ if (Time_Of_Last_Reload + CACHE_TIME > now.tv_sec)
+ return;
+ Time_Of_Last_Reload = now.tv_sec;
+
+ /*
+ * * Makes sure we have SOME space allocated for new routing entries
+ */
+ if (!rthead) {
+ rthead = (RTENTRY **) malloc(100 * sizeof(RTENTRY *));
+ if (!rthead) {
+ snmp_log(LOG_ERR, "route table malloc fail\n");
+ return;
+ }
+ memset((char *) rthead, (0), 100 * sizeof(RTENTRY *));
+ rtallocate = 100;
+ }
+
+ /*
+ * reset the routing table size to zero -- was a CMU memory leak
+ */
+ rtsize = 0;
+
+#ifdef RTENTRY_4_4
+ /*
+ * rtentry is a BSD 4.4 compat
+ */
+
+#if !defined(AF_UNSPEC)
+#define AF_UNSPEC AF_INET
+#endif
+
+ auto_nlist(RTTABLES_SYMBOL, (char *) rt_table, sizeof(rt_table));
+ for (i = 0; i <= AF_MAX; i++) {
+ if (rt_table[i] == 0)
+ continue;
+ if (NETSNMP_KLOOKUP(rt_table[i], (char *) &head, sizeof(head))) {
+ load_rtentries(head.rnh_treetop);
+ }
+ }
+
+#else /* rtentry is a BSD 4.3 compat */
+#ifdef NETSNMP_FEATURE_CHECKIN
+ /* this exists here just so we don't copy ifdef logic elsewhere */
+ netsnmp_feature_require(string_append_int);
+ netsnmp_feature_require(interface_legacy)
+#endif
+ for (table = 0; table < NUM_ROUTE_SYMBOLS; table++) {
+ auto_nlist(RTHASHSIZE_SYMBOL, (char *) &hashsize,
+ sizeof(hashsize));
+ routehash = (RTENTRY **) malloc(hashsize * sizeof(struct mbuf *));
+ auto_nlist(route_symbols[table], (char *) routehash,
+ hashsize * sizeof(struct mbuf *));
+ for (i = 0; i < hashsize; i++) {
+ if (routehash[i] == 0)
+ continue;
+ m = routehash[i];
+ while (m) {
+ /*
+ * Dig the route out of the kernel...
+ */
+ if (!NETSNMP_KLOOKUP(m, (char *) &mb, sizeof(mb))) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return;
+ }
+ m = mb.rt_next;
+
+ rt = &mb;
+ if (rt->rt_ifp != 0) {
+ if (!NETSNMP_KLOOKUP(rt->rt_ifp, (char *) &ifnet, sizeof(ifnet))) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return;
+ }
+ if (!NETSNMP_KLOOKUP(ifnet.if_name, name, 16)) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return;
+ }
+ name[15] = '\0';
+ cp = (char *) strchr(name, '\0');
+ string_append_int(cp, ifnet.if_unit);
+
+ Interface_Scan_Init();
+ while (Interface_Scan_Next
+ ((short *) &rt->rt_unit, temp, NULL,
+ NULL) != 0) {
+ if (strcmp(name, temp) == 0)
+ break;
+ }
+ }
+ /*
+ * Allocate a block to hold it and add it to the database
+ */
+ if (rtsize >= rtallocate) {
+ rthead =
+ (RTENTRY **) realloc((char *) rthead,
+ 2 * rtallocate *
+ sizeof(RTENTRY *));
+ memset((char *) &rthead[rtallocate], (0),
+ rtallocate * sizeof(RTENTRY *));
+
+ rtallocate *= 2;
+ }
+ if (!rthead[rtsize])
+ rthead[rtsize] = (RTENTRY *) malloc(sizeof(RTENTRY));
+ /*
+ * Add this to the database
+ */
+ memcpy((char *) rthead[rtsize], (char *) rt,
+ sizeof(RTENTRY));
+ rtsize++;
+ }
+ }
+ free(routehash);
+ }
+#endif
+ /*
+ * Sort it!
+ */
+ qsort((char *) rthead, rtsize, sizeof(rthead[0]),
+#ifdef __STDC__
+ (int (*)(const void *, const void *)) qsort_compare
+#else
+ qsort_compare
+#endif
+ );
+#endif /* hpux11 */
+}
+
+#else
+
+#if HAVE_SYS_MBUF_H
+netsnmp_feature_require(string_append_int)
+netsnmp_feature_require(interface_legacy)
+static void
+Route_Scan_Reload(void)
+{
+ struct mbuf **routehash, mb;
+ register struct mbuf *m;
+ struct ifnet ifnet;
+ RTENTRY *rt;
+ int i, table;
+ register char *cp;
+ char name[16], temp[16];
+ static time_t Time_Of_Last_Reload;
+ struct timeval now;
+ int hashsize;
+
+ netsnmp_get_monotonic_clock(&now);
+ if (Time_Of_Last_Reload + CACHE_TIME > now.tv_sec)
+ return;
+ Time_Of_Last_Reload = now.tv_sec;
+
+ /*
+ * Makes sure we have SOME space allocated for new routing entries
+ */
+ if (!rthead) {
+ rthead = (RTENTRY **) malloc(100 * sizeof(RTENTRY *));
+ if (!rthead) {
+ snmp_log(LOG_ERR, "route table malloc fail\n");
+ return;
+ }
+ memset((char *) rthead, (0), 100 * sizeof(RTENTRY *));
+ rtallocate = 100;
+ }
+
+ /*
+ * reset the routing table size to zero -- was a CMU memory leak
+ */
+ rtsize = 0;
+
+ for (table = 0; table < NUM_ROUTE_SYMBOLS; table++) {
+#ifdef sunV3
+ hashsize = RTHASHSIZ;
+#else
+ auto_nlist(RTHASHSIZE_SYMBOL, (char *) &hashsize,
+ sizeof(hashsize));
+#endif
+ routehash =
+ (struct mbuf **) malloc(hashsize * sizeof(struct mbuf *));
+ auto_nlist(route_symbols[table], (char *) routehash,
+ hashsize * sizeof(struct mbuf *));
+ for (i = 0; i < hashsize; i++) {
+ if (routehash[i] == 0)
+ continue;
+ m = routehash[i];
+ while (m) {
+ /*
+ * Dig the route out of the kernel...
+ */
+ if (!NETSNMP_KLOOKUP(m, (char *) &mb, sizeof(mb))) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return;
+ }
+ m = mb.m_next;
+ rt = mtod(&mb, RTENTRY *);
+
+ if (rt->rt_ifp != 0) {
+
+ if (!NETSNMP_KLOOKUP(rt->rt_ifp, (char *) &ifnet, sizeof(ifnet))) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return;
+ }
+ if (!NETSNMP_KLOOKUP(ifnet.if_name, name, 16)) {
+ DEBUGMSGTL(("mibII/var_route", "klookup failed\n"));
+ return;
+ }
+ name[15] = '\0';
+ cp = (char *) strchr(name, '\0');
+ string_append_int(cp, ifnet.if_unit);
+ if (strcmp(name, "lo0") == 0)
+ continue;
+
+ Interface_Scan_Init();
+ while (Interface_Scan_Next
+ ((short *) &rt->rt_unit, temp, NULL,
+ NULL) != 0) {
+ if (strcmp(name, temp) == 0)
+ break;
+ }
+ }
+ /*
+ * Allocate a block to hold it and add it to the database
+ */
+ if (rtsize >= rtallocate) {
+ rthead =
+ (RTENTRY **) realloc((char *) rthead,
+ 2 * rtallocate *
+ sizeof(RTENTRY *));
+ memset((char *) &rthead[rtallocate], (0),
+ rtallocate * sizeof(RTENTRY *));
+
+ rtallocate *= 2;
+ }
+ if (!rthead[rtsize])
+ rthead[rtsize] = (RTENTRY *) malloc(sizeof(RTENTRY));
+ /*
+ * * Add this to the database
+ */
+ memcpy((char *) rthead[rtsize], (char *) rt,
+ sizeof(RTENTRY));
+ rtsize++;
+ }
+ }
+ free(routehash);
+ }
+ /*
+ * Sort it!
+ */
+ qsort((char *) rthead, rtsize, sizeof(rthead[0]), qsort_compare);
+}
+#else
+#ifdef linux
+static void
+Route_Scan_Reload(void)
+{
+ FILE *in;
+ char line[256];
+ struct rtentry *rt;
+ char name[16];
+ static time_t Time_Of_Last_Reload;
+ struct timeval now;
+
+ netsnmp_get_monotonic_clock(&now);
+ if (Time_Of_Last_Reload + CACHE_TIME > now.tv_sec)
+ return;
+ Time_Of_Last_Reload = now.tv_sec;
+
+ /*
+ * Makes sure we have SOME space allocated for new routing entries
+ */
+ if (!rthead) {
+ rthead = (struct rtentry **) calloc(100, sizeof(struct rtentry *));
+ if (!rthead) {
+ snmp_log(LOG_ERR, "route table malloc fail\n");
+ return;
+ }
+ rtallocate = 100;
+ }
+
+ /*
+ * fetch routes from the proc file-system:
+ */
+
+ rtsize = 0;
+
+ if (!(in = fopen("/proc/net/route", "r"))) {
+ NETSNMP_LOGONCE((LOG_ERR, "cannot open /proc/net/route - burps\n"));
+ return;
+ }
+
+ while (fgets(line, sizeof(line), in)) {
+ struct rtentry rtent;
+ char rtent_name[32];
+ int refcnt, metric;
+ unsigned flags, use;
+
+ rt = &rtent;
+ memset((char *) rt, (0), sizeof(*rt));
+ rt->rt_dev = rtent_name;
+
+ /*
+ * as with 1.99.14:
+ * Iface Dest GW Flags RefCnt Use Metric Mask MTU Win IRTT
+ * eth0 0A0A0A0A 00000000 05 0 0 0 FFFFFFFF 1500 0 0
+ */
+ if (8 != sscanf(line, "%s %x %x %x %d %u %d %x %*d %*d %*d\n",
+ rt->rt_dev,
+ &(((struct sockaddr_in *) &(rtent.rt_dst))->sin_addr.s_addr),
+ &(((struct sockaddr_in *) &(rtent.rt_gateway))->sin_addr.s_addr),
+ /*
+ * XXX: fix type of the args
+ */
+ &flags, &refcnt, &use, &metric,
+ &(((struct sockaddr_in *) &(rtent.rt_genmask))->sin_addr.s_addr)))
+ continue;
+
+ strlcpy(name, rt->rt_dev, sizeof(name));
+
+ rt->rt_flags = flags, rt->rt_refcnt = refcnt;
+ rt->rt_use = use, rt->rt_metric = metric;
+
+ rt->rt_unit = netsnmp_access_interface_index_find(name);
+
+ /*
+ * Allocate a block to hold it and add it to the database
+ */
+ if (rtsize >= rtallocate) {
+ rthead = (struct rtentry **) realloc((char *) rthead,
+ 2 * rtallocate *
+ sizeof(struct rtentry *));
+ memset(&rthead[rtallocate], 0,
+ rtallocate * sizeof(struct rtentry *));
+ rtallocate *= 2;
+ }
+ if (!rthead[rtsize])
+ rthead[rtsize] =
+ (struct rtentry *) malloc(sizeof(struct rtentry));
+ /*
+ * Add this to the database
+ */
+ memcpy((char *) rthead[rtsize], (char *) rt,
+ sizeof(struct rtentry));
+ rtsize++;
+ }
+
+ fclose(in);
+
+ /*
+ * Sort it!
+ */
+ qsort((char *) rthead, rtsize, sizeof(rthead[0]), qsort_compare);
+}
+#endif
+#endif
+#endif
+
+
+#ifndef solaris2
+/*
+ * Create a host table
+ */
+#ifdef hpux11
+static int
+qsort_compare(const void *v1, const void *v2)
+{
+ const mib_ipRouteEnt *r1 = (const mib_ipRouteEnt *) v1;
+ const mib_ipRouteEnt *r2 = (const mib_ipRouteEnt *) v2;
+ /*
+ * Do the comparison
+ */
+ if (r1->Dest == r2->Dest)
+ return (0);
+ if (r1->Dest > r2->Dest)
+ return (1);
+ return (-1);
+}
+#else
+static int
+qsort_compare(const void *v1, const void *v2)
+{
+ RTENTRY * const *r1 = (RTENTRY * const *) v1;
+ RTENTRY * const *r2 = (RTENTRY * const *) v2;
+#if NEED_KLGETSA
+ register u_long dst1 =
+ ntohl(klgetsa((const struct sockaddr_in *) (*r1)->rt_dst)->
+ sin_addr.s_addr);
+ register u_long dst2 =
+ ntohl(klgetsa((const struct sockaddr_in *) (*r2)->rt_dst)->
+ sin_addr.s_addr);
+#else
+ register u_long dst1 =
+ ntohl(((const struct sockaddr_in *) &((*r1)->rt_dst))->sin_addr.
+ s_addr);
+ register u_long dst2 =
+ ntohl(((const struct sockaddr_in *) &((*r2)->rt_dst))->sin_addr.
+ s_addr);
+#endif /* NEED_KLGETSA */
+
+ /*
+ * Do the comparison
+ */
+ if (dst1 == dst2)
+ return (0);
+ if (dst1 > dst2)
+ return (1);
+ return (-1);
+}
+#endif /* hpux11 */
+#endif /* not USE_SYSCTL_ROUTE_DUMP */
+
+#endif /* solaris2 */
+
+#elif defined(HAVE_IPHLPAPI_H) /* WIN32 cygwin */
+#include <iphlpapi.h>
+#ifndef MIB_IPPROTO_NETMGMT
+#define MIB_IPPROTO_NETMGMT 3
+#endif
+
+PMIB_IPFORWARDROW route_row;
+int create_flag;
+void
+init_var_route(void)
+{
+}
+
+u_char *
+var_ipRouteEntry(struct variable *vp,
+ oid * name,
+ size_t * length,
+ int exact, size_t * var_len, WriteMethod ** write_method)
+{
+ /*
+ * object identifier is of form:
+ * 1.3.6.1.2.1.4.21.1.?.A.B.C.D, where A.B.C.D is IP address.
+ * IPADDR starts at offset 10.
+ */
+ register int Save_Valid, result, RtIndex = 0;
+ static int saveNameLen = 0, saveExact = 0, saveRtIndex =
+ 0, rtsize = 0;
+ static oid saveName[MAX_OID_LEN], Current[MAX_OID_LEN];
+ u_char *cp;
+ oid *op;
+ DWORD status = NO_ERROR;
+ DWORD dwActualSize = 0;
+ static PMIB_IPFORWARDTABLE pIpRtrTable = NULL;
+ struct timeval now;
+ static time_t Time_Of_Last_Reload;
+ static in_addr_t addr_ret;
+
+
+ /**
+ ** this optimisation fails, if there is only a single route avail.
+ ** it is a very special case, but better leave it out ...
+ **/
+#if NETSNMP_NO_DUMMY_VALUES
+ saveNameLen = 0;
+#endif
+ if (route_row == NULL) {
+ /*
+ * Free allocated memory in case of SET request's FREE phase
+ */
+ route_row = (PMIB_IPFORWARDROW) malloc(sizeof(MIB_IPFORWARDROW));
+ }
+ netsnmp_get_monotonic_clock(&now);
+ if ((rtsize <= 1) || (Time_Of_Last_Reload + 5 <= now.tv_sec))
+ Save_Valid = 0;
+ else
+ /*
+ * OPTIMIZATION:
+ *
+ * If the name was the same as the last name, with the possible
+ * exception of the [9]th token, then don't read the routing table
+ *
+ */
+
+ if ((saveNameLen == (int) *length) && (saveExact == exact)) {
+ register int temp = name[9];
+ name[9] = 0;
+ Save_Valid =
+ (snmp_oid_compare(name, *length, saveName, saveNameLen) == 0);
+ name[9] = temp;
+ } else
+ Save_Valid = 0;
+
+ if (Save_Valid) {
+ register int temp = name[9]; /* Fix up 'lowest' found entry */
+ memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
+ name[9] = temp;
+ *length = 14;
+ RtIndex = saveRtIndex;
+ } else {
+ /*
+ * fill in object part of name for current(less sizeof instance part)
+ */
+
+ memcpy((char *) Current, (char *) vp->name,
+ (int) (vp->namelen) * sizeof(oid));
+
+
+ if ((Time_Of_Last_Reload + 5 <= now.tv_sec)
+ || (pIpRtrTable == NULL)) {
+ if (pIpRtrTable != NULL)
+ free(pIpRtrTable);
+ Time_Of_Last_Reload = now.tv_sec;
+ /*
+ * query for buffer size needed
+ */
+ status = GetIpForwardTable(pIpRtrTable, &dwActualSize, TRUE);
+ if (status == ERROR_INSUFFICIENT_BUFFER) {
+ pIpRtrTable = (PMIB_IPFORWARDTABLE) malloc(dwActualSize);
+ if (pIpRtrTable != NULL) {
+ /*
+ * Get the sorted IP Route Table
+ */
+ status =
+ GetIpForwardTable(pIpRtrTable, &dwActualSize,
+ TRUE);
+ }
+ }
+ }
+ if (status == NO_ERROR) {
+ rtsize = pIpRtrTable->dwNumEntries;
+ for (RtIndex = 0; RtIndex < rtsize; RtIndex++) {
+ cp = (u_char *) & pIpRtrTable->table[RtIndex].
+ dwForwardDest;
+ op = Current + 10;
+ *op++ = *cp++;
+ *op++ = *cp++;
+ *op++ = *cp++;
+ *op++ = *cp++;
+
+ result = snmp_oid_compare(name, *length, Current, 14);
+ if ((exact && (result == 0)) || (!exact && (result < 0)))
+ break;
+ }
+ }
+ if (RtIndex >= rtsize) {
+ /*
+ * for creation of new row, only ipNetToMediaTable case is considered
+ */
+ if (*length == 14) {
+ u_char dest_addr[4];
+ MIB_IPFORWARDROW temp_row;
+
+ create_flag = 1;
+ *write_method = write_rte;
+ dest_addr[0] = (u_char) name[10];
+ dest_addr[1] = (u_char) name[11];
+ dest_addr[2] = (u_char) name[12];
+ dest_addr[3] = (u_char) name[13];
+ memset(&temp_row, 0, sizeof(temp_row));
+ temp_row.dwForwardDest = *((DWORD *) dest_addr);
+ temp_row.dwForwardPolicy = 0;
+ temp_row.dwForwardProto = MIB_IPPROTO_NETMGMT;
+ *route_row = temp_row;
+ }
+ free(pIpRtrTable);
+ pIpRtrTable = NULL;
+ rtsize = 0;
+ return (NULL);
+ }
+ create_flag = 0;
+ /*
+ * Save in the 'cache'
+ */
+ memcpy((char *) saveName, (char *) name,
+ SNMP_MIN(*length, MAX_OID_LEN) * sizeof(oid));
+ saveName[9] = 0;
+ saveNameLen = *length;
+ saveExact = exact;
+ saveRtIndex = RtIndex;
+
+ /*
+ * Return the name
+ */
+ memcpy((char *) name, (char *) Current, 14 * sizeof(oid));
+ *length = 14;
+ }
+ *var_len = sizeof(long_return);
+ *route_row = pIpRtrTable->table[RtIndex];
+
+ switch (vp->magic) {
+ case IPROUTEDEST:
+ *var_len = sizeof(addr_ret);
+ *write_method = write_rte;
+ addr_ret = pIpRtrTable->table[RtIndex].dwForwardDest;
+ return (u_char *) & addr_ret;
+ case IPROUTEIFINDEX:
+ *write_method = write_rte;
+ long_return = pIpRtrTable->table[RtIndex].dwForwardIfIndex;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC1:
+ *write_method = write_rte;
+ long_return = pIpRtrTable->table[RtIndex].dwForwardMetric1;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC2:
+ *write_method = write_rte;
+ long_return = pIpRtrTable->table[RtIndex].dwForwardMetric2;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC3:
+ *write_method = write_rte;
+ long_return = pIpRtrTable->table[RtIndex].dwForwardMetric3;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC4:
+ *write_method = write_rte;
+ long_return = pIpRtrTable->table[RtIndex].dwForwardMetric4;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC5:
+ *write_method = write_rte;
+ long_return = pIpRtrTable->table[RtIndex].dwForwardMetric5;
+ return (u_char *) & long_return;
+ case IPROUTENEXTHOP:
+ *var_len = sizeof(addr_ret);
+ *write_method = write_rte;
+ addr_ret = pIpRtrTable->table[RtIndex].dwForwardNextHop;
+ return (u_char *) & addr_ret;
+ case IPROUTETYPE:
+ *write_method = write_rte;
+ long_return = pIpRtrTable->table[RtIndex].dwForwardType;
+ return (u_char *) & long_return;
+ case IPROUTEPROTO:
+ long_return = pIpRtrTable->table[RtIndex].dwForwardProto;
+ return (u_char *) & long_return;
+ case IPROUTEAGE:
+ *write_method = write_rte;
+ long_return = pIpRtrTable->table[RtIndex].dwForwardAge;
+ return (u_char *) & long_return;
+ case IPROUTEMASK:
+ *write_method = write_rte;
+ *var_len = sizeof(addr_ret);
+ addr_ret = pIpRtrTable->table[RtIndex].dwForwardMask;
+ return (u_char *) & addr_ret;
+ case IPROUTEINFO:
+ *var_len = nullOidLen;
+ return (u_char *) nullOid;
+ default:
+ DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
+ vp->magic));
+ }
+ return NULL;
+}
+
+#endif /* WIN32 cygwin */
+
+#else /* NETSNMP_CAN_USE_SYSCTL */
+
+static
+TAILQ_HEAD(, snmprt)
+ rthead;
+ static char *rtbuf;
+ static size_t rtbuflen;
+ static time_t lasttime;
+
+ struct snmprt {
+ TAILQ_ENTRY(snmprt) link;
+ struct rt_msghdr *hdr;
+ struct in_addr dest;
+ struct in_addr gateway;
+ struct in_addr netmask;
+ int index;
+ struct in_addr ifa;
+ };
+
+ static void
+ rtmsg(struct rt_msghdr *rtm)
+{
+ struct snmprt *rt;
+ struct sockaddr *sa;
+ int bit, gotdest, gotmask;
+
+ rt = malloc(sizeof *rt);
+ if (rt == 0)
+ return;
+ rt->hdr = rtm;
+ rt->ifa.s_addr = 0;
+ rt->dest = rt->gateway = rt->netmask = rt->ifa;
+ rt->index = rtm->rtm_index;
+
+ gotdest = gotmask = 0;
+ sa = (struct sockaddr *) (rtm + 1);
+ for (bit = 1; ((char *) sa < (char *) rtm + rtm->rtm_msglen) && bit;
+ bit <<= 1) {
+ if ((rtm->rtm_addrs & bit) == 0)
+ continue;
+ switch (bit) {
+ case RTA_DST:
+#define satosin(sa) ((struct sockaddr_in *)(sa))
+ rt->dest = satosin(sa)->sin_addr;
+ gotdest = 1;
+ break;
+ case RTA_GATEWAY:
+ if (sa->sa_family == AF_INET)
+ rt->gateway = satosin(sa)->sin_addr;
+ break;
+ case RTA_NETMASK:
+ if (sa->sa_len >= offsetof(struct sockaddr_in, sin_addr))
+ rt->netmask = satosin(sa)->sin_addr;
+ gotmask = 1;
+ break;
+ case RTA_IFA:
+ if (sa->sa_family == AF_INET)
+ rt->ifa = satosin(sa)->sin_addr;
+ break;
+ }
+ /*
+ * from rtsock.c
+ */
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+ sa = (struct sockaddr *) ((char *) sa + ROUNDUP(sa->sa_len));
+ }
+ if (!gotdest) {
+ /*
+ * XXX can't happen if code above is correct
+ */
+ snmp_log(LOG_ERR, "route no dest?\n");
+ free(rt);
+ } else {
+ /*
+ * If no mask provided, it was a host route.
+ */
+ if (!gotmask)
+ rt->netmask.s_addr = ~0;
+ TAILQ_INSERT_TAIL(&rthead, rt, link);
+ }
+}
+
+static int
+suck_krt(int force)
+{
+ time_t now;
+ struct snmprt *rt, *next;
+ size_t len;
+ static int name[6] =
+ { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0 };
+ char *cp;
+ struct rt_msghdr *rtm;
+
+ time(&now);
+ if (now < (lasttime + CACHE_TIME) && !force)
+ return 0;
+ lasttime = now;
+
+ for (rt = rthead.tqh_first; rt; rt = next) {
+ next = rt->link.tqe_next;
+ free(rt);
+ }
+ TAILQ_INIT(&rthead);
+
+ if (sysctl(name, 6, 0, &len, 0, 0) < 0) {
+ syslog(LOG_WARNING, "sysctl net-route-dump: %m");
+ return -1;
+ }
+
+ if (len > rtbuflen) {
+ char *newbuf;
+ newbuf = realloc(rtbuf, len);
+ if (newbuf == 0)
+ return -1;
+ rtbuf = newbuf;
+ rtbuflen = len;
+ }
+
+ if (sysctl(name, 6, rtbuf, &len, 0, 0) < 0) {
+ syslog(LOG_WARNING, "sysctl net-route-dump: %m");
+ return -1;
+ }
+
+ cp = rtbuf;
+ while (cp < rtbuf + len) {
+ rtm = (struct rt_msghdr *) cp;
+ /*
+ * NB:
+ * You might want to exclude routes with RTF_WASCLONED
+ * set. This keeps the cloned host routes (and thus also
+ * ARP entries) out of the routing table. Thus, it also
+ * presents management stations with an incomplete view.
+ * I believe that it should be possible for a management
+ * station to examine (and perhaps delete) such routes.
+ */
+ if (rtm->rtm_version == RTM_VERSION && rtm->rtm_type == RTM_GET)
+ rtmsg(rtm);
+ cp += rtm->rtm_msglen;
+ }
+ return 0;
+}
+
+u_char *
+var_ipRouteEntry(struct variable * vp,
+ oid * name,
+ size_t * length,
+ int exact, size_t * var_len, WriteMethod ** write_method)
+{
+ /*
+ * object identifier is of form:
+ * 1.3.6.1.2.1.4.21.1.1.A.B.C.D, where A.B.C.D is IP address.
+ * IPADDR starts at offset 10.
+ */
+ int Save_Valid, result;
+ u_char *cp;
+ oid *op;
+ struct snmprt *rt;
+ static struct snmprt *savert;
+ static int saveNameLen, saveExact;
+ static oid saveName[14], Current[14];
+ static in_addr_t addr_ret;
+
+ *write_method = NULL; /* write_rte; XXX: SET support not really implemented */
+
+#if 0
+ /*
+ * OPTIMIZATION:
+ *
+ * If the name was the same as the last name, with the possible
+ * exception of the [9]th token, then don't read the routing table
+ *
+ */
+
+ if ((saveNameLen == *length) && (saveExact == exact)) {
+ int temp = name[9];
+ name[9] = 0;
+ Save_Valid =
+ !snmp_oid_compare(name, *length, saveName, saveNameLen);
+ name[9] = temp;
+ } else {
+ Save_Valid = 0;
+ }
+#else
+ Save_Valid = 0;
+#endif
+
+ if (Save_Valid) {
+ int temp = name[9];
+ memcpy(name, Current, 14 * sizeof(oid));
+ name[9] = temp;
+ *length = 14;
+ rt = savert;
+ } else {
+ /*
+ * fill in object part of name for current
+ * (less sizeof instance part)
+ */
+
+ memcpy(Current, vp->name, SNMP_MIN(sizeof(Current), (int)(vp->namelen) * sizeof(oid)));
+
+ suck_krt(0);
+
+ for (rt = rthead.tqh_first; rt; rt = rt->link.tqe_next) {
+ op = Current + 10;
+ cp = (u_char *) & rt->dest;
+ *op++ = *cp++;
+ *op++ = *cp++;
+ *op++ = *cp++;
+ *op++ = *cp++;
+ result = snmp_oid_compare(name, *length, Current, 14);
+ if ((exact && (result == 0))
+ || (!exact && (result < 0)))
+ break;
+ }
+ if (rt == NULL)
+ return NULL;
+
+ /*
+ * Save in the 'cache'
+ */
+ memcpy(saveName, name, SNMP_MIN(sizeof(saveName), *length * sizeof(oid)));
+ saveName[9] = 0;
+ saveNameLen = *length;
+ saveExact = exact;
+ savert = rt;
+
+ /*
+ * Return the name
+ */
+ memcpy(name, Current, 14 * sizeof(oid));
+ *length = 14;
+ }
+
+ *var_len = sizeof(long_return);
+
+ switch (vp->magic) {
+ case IPROUTEDEST:
+ addr_ret = rt->dest.s_addr;
+ *var_len = sizeof(addr_ret);
+ return (u_char *) & addr_ret;
+
+ case IPROUTEIFINDEX:
+ long_return = rt->index;
+ return (u_char *) & long_return;
+
+ case IPROUTEMETRIC1:
+ long_return = (rt->hdr->rtm_flags & RTF_GATEWAY) ? 1 : 0;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC2:
+ long_return = rt->hdr->rtm_rmx.rmx_rtt;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC3:
+ long_return = rt->hdr->rtm_rmx.rmx_rttvar;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC4:
+ long_return = rt->hdr->rtm_rmx.rmx_ssthresh;
+ return (u_char *) & long_return;
+ case IPROUTEMETRIC5:
+ long_return = rt->hdr->rtm_rmx.rmx_mtu;
+ return (u_char *) & long_return;
+
+ case IPROUTENEXTHOP:
+ *var_len = sizeof(addr_ret);
+ if (rt->gateway.s_addr == 0 && rt->ifa.s_addr == 0)
+ addr_ret = 0;
+ else if (rt->gateway.s_addr == 0)
+ addr_ret = rt->ifa.s_addr;
+ else
+ addr_ret = rt->gateway.s_addr;
+ return (u_char *) & addr_ret;
+
+ case IPROUTETYPE:
+ if (rt->hdr->rtm_flags & RTF_UP) {
+ if (rt->hdr->rtm_flags & RTF_GATEWAY) {
+ long_return = 4; /* indirect(4) */
+ } else {
+ long_return = 3; /* direct(3) */
+ }
+ } else {
+ long_return = 2; /* invalid(2) */
+ }
+ return (u_char *) & long_return;
+
+ case IPROUTEPROTO:
+ long_return = (rt->hdr->rtm_flags & RTF_DYNAMIC) ? 4 : 2;
+ return (u_char *) & long_return;
+
+ case IPROUTEAGE:
+#if NETSNMP_NO_DUMMY_VALUES
+ return NULL;
+#endif
+ long_return = 0;
+ return (u_char *) & long_return;
+
+ case IPROUTEMASK:
+ addr_ret = rt->netmask.s_addr;
+ *var_len = sizeof(addr_ret);
+ return (u_char *) & addr_ret;
+
+ case IPROUTEINFO:
+ *var_len = nullOidLen;
+ return (u_char *) nullOid;
+ default:
+ DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipRouteEntry\n",
+ vp->magic));
+ }
+ return NULL;
+}
+
+void
+init_var_route(void)
+{
+ ;
+}
+
+#endif /* NETSNMP_CAN_USE_SYSCTL */
+
+#if defined(HAVE_SYS_SYSCTL_H) && !defined(linux)
+/*
+ * get_address()
+ *
+ * Traverse the address structures after a routing socket message and
+ * extract a specific one.
+ *
+ * Some of this is peculiar to IRIX 6.2, which doesn't have sa_len in
+ * the sockaddr structure yet. With sa_len, skipping an address entry
+ * would be much easier.
+ */
+#include <sys/un.h>
+
+/*
+ * returns the length of a socket structure
+ */
+
+size_t
+snmp_socket_length(int family)
+{
+ size_t length;
+
+ switch (family) {
+#ifndef cygwin
+#if !defined (WIN32) && !defined (cygwin)
+#ifdef AF_UNIX
+ case AF_UNIX:
+ length = sizeof(struct sockaddr_un);
+ break;
+#endif /* AF_UNIX */
+#endif
+#endif
+
+#ifndef aix3
+#ifdef AF_LINK
+ case AF_LINK:
+#ifdef _MAX_SA_LEN
+ length = _MAX_SA_LEN;
+#elif SOCK_MAXADDRLEN
+ length = SOCK_MAXADDRLEN;
+#else
+ length = sizeof(struct sockaddr_dl);
+#endif
+ break;
+#endif /* AF_LINK */
+#endif
+
+ case AF_INET:
+ length = sizeof(struct sockaddr_in);
+ break;
+ default:
+ length = sizeof(struct sockaddr);
+ break;
+ }
+
+ return length;
+}
+
+const struct sockaddr *
+get_address(const void *_ap, int addresses, int wanted)
+{
+ const struct sockaddr *ap = (const struct sockaddr *) _ap;
+ int iindex;
+ int bitmask;
+
+ for (iindex = 0, bitmask = 1;
+ iindex < RTAX_MAX; ++iindex, bitmask <<= 1) {
+ if (bitmask == wanted) {
+ if (bitmask & addresses) {
+ return ap;
+ } else {
+ return 0;
+ }
+ } else if (bitmask & addresses) {
+ unsigned length =
+ (unsigned) snmp_socket_length(ap->sa_family);
+ while (length % sizeof(long) != 0)
+ ++length;
+ ap = (const struct sockaddr *) ((const char *) ap + length);
+ }
+ }
+ return 0;
+}
+
+/*
+ * get_in_address()
+ *
+ * Convenience function for the special case of get_address where an
+ * AF_INET address is desired, and we're only interested in the in_addr
+ * part.
+ */
+const struct in_addr *
+get_in_address(const void *ap, int addresses, int wanted)
+{
+ const struct sockaddr_in *a;
+
+ a = (const struct sockaddr_in *) get_address(ap, addresses, wanted);
+ if (a == NULL)
+ return NULL;
+
+ if (a->sin_family != AF_INET) {
+ DEBUGMSGTL(("snmpd",
+ "unknown socket family %d [AF_INET expected] in var_ipRouteEntry.\n",
+ a->sin_family));
+ }
+ return &a->sin_addr;
+}
+#endif /* HAVE_SYS_SYSCTL_H */