| /* |
| * 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 "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" |
| |
| #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 = 0; |
| static int rtsize = 0, rtallocate = 0; |
| |
| static void Route_Scan_Reload(void); |
| |
| RTENTRY **netsnmp_get_routes(size_t *size) { |
| Route_Scan_Reload(); |
| if (size) |
| *size = rtsize; |
| return rthead; |
| } |
| #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 int saveNameLen = 0, 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; |
| 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 !STRUCT_IFNET_HAS_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 STRUCT_IFNET_HAS_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 |
| 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 |
| 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 int Time_Of_Last_Reload = 0; |
| struct timeval now; |
| |
| gettimeofday(&now, (struct timezone *) 0); |
| 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 */ |
| 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 |
| 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 int Time_Of_Last_Reload = 0; |
| struct timeval now; |
| int hashsize; |
| |
| gettimeofday(&now, (struct timezone *) 0); |
| 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 int Time_Of_Last_Reload = 0; |
| struct timeval now; |
| |
| gettimeofday(&now, (struct timezone *) 0); |
| 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"))) { |
| snmp_log(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, flags, metric; |
| unsigned 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 %u %d %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 */ |
| |
| #else /* 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; |
| 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 long Time_Of_Last_Reload = 0; |
| u_char dest_addr[4]; |
| MIB_IPFORWARDROW temp_row; |
| 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)); |
| } |
| gettimeofday(&now, (struct timezone *) 0); |
| 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) { |
| 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]; |
| 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 */ |