net-snmp/agent/mibgroup/mibII/var_route.c

2126 lines
64 KiB
C

/*
* 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"
#include "util_funcs.h"
#if defined(cygwin) || defined(mingw32)
#include <winerror.h>
#endif
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 */
#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;
/*
* 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 */
if(entry.ipRouteInfo.re_ire_type & IRE_BROADCAST)
continue;
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 */