/* * snmp_var_route.c - return a pointer to the named variable. * * */ /*********************************************************** 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. ******************************************************************/ /* * 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 system({CTL_NET,PF_ROUTE,...) by Simon Leinen * (simon@switch.ch) 1997 */ #include #if !defined(CAN_USE_SYSCTL) #define GATEWAY /* MultiNet is always configured this way! */ #include #include #if HAVE_SYS_PARAM_H #include #endif #if HAVE_SYS_SOCKET_H #include #endif #if TIME_WITH_SYS_TIME # ifdef WIN32 # include # else # include # endif # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #if HAVE_SYS_SELECT_H #include #endif #if HAVE_NETINET_IN_H #include #endif #if HAVE_ARPA_INET_H #include #endif #if HAVE_SYSLOG_H #include #endif #if HAVE_MACHINE_PARAM_H #include #endif #if HAVE_SYS_MBUF_H #include #endif #if HAVE_NET_IF_H #include #endif #ifdef HAVE_NET_IF_VAR_H #include #endif #if HAVE_SYS_HASHING_H #include #endif #if HAVE_NETINET_IN_VAR_H #include #endif #define KERNEL /* to get routehash and RTHASHSIZ */ #if HAVE_SYS_STREAM_H #include #endif #if HAVE_NET_ROUTE_H #include #endif #undef KERNEL #ifdef RTENTRY_4_4 #ifndef STRUCT_RTENTRY_HAS_RT_UNIT #define rt_unit rt_refcnt /* Reuse this field for device # */ #endif #ifndef STRUCT_RTENTRY_HAS_RT_DST #define rt_dst rt_nodes->rn_key #endif #else /* RTENTRY_4_3 */ #ifndef STRUCT_RTENTRY_HAS_RT_DST #define rt_dst rt_nodes->rn_key #endif #ifndef STRUCT_RTENTRY_HAS_RT_HASH #define rt_hash rt_pad1 #endif #ifndef STRUCT_RTENTRY_HAS_RT_REFCNT #ifndef hpux10 #define rt_refcnt rt_pad2 #endif #endif #ifndef STRUCT_RTENTRY_HAS_RT_USE #define rt_use rt_pad3 #endif #ifndef STRUCT_RTENTRY_HAS_RT_UNIT #define rt_unit rt_refcnt /* Reuse this field for device # */ #endif #endif #ifndef NULL #define NULL 0 #endif #if HAVE_KVM_OPENFILES #include #endif #if HAVE_KVM_H #include #endif #if HAVE_STRING_H #include #else #include #endif #if HAVE_STDLIB_H #include #endif #if HAVE_INET_MIB2_H #include #endif #if HAVE_SYS_SYSCTL_H #include #endif #if HAVE_NET_IF_DL_H #ifndef dynix #include #else #include #endif #endif #if HAVE_WINSOCK_H #include #endif #if HAVE_NLIST_H #include #endif #if solaris2 #include "kernel_sunos5.h" #endif #ifdef HAVE_SYS_SYSCTL_H # ifdef CTL_NET # ifdef PF_ROUTE # ifdef NET_RT_DUMP # define USE_SYSCTL_ROUTE_DUMP # endif # endif # endif #endif #if HAVE_DMALLOC_H #include #endif #ifdef cygwin #define WIN32 #include #endif #define CACHE_TIME (120) /* Seconds */ #include #include #include #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 #include #endif /* hpux */ extern WriteMethod write_rte; #ifndef WIN32 #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; #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 */ *write_method = write_rte; *var_len = sizeof(long_return); switch (vp->magic) { case IPROUTEDEST: 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 NO_DUMMY_VALUES return NULL; #endif long_return = -1; return (u_char *) & long_return; case IPROUTEMETRIC3: #if NO_DUMMY_VALUES return NULL; #endif long_return = -1; return (u_char *) & long_return; case IPROUTEMETRIC4: #if NO_DUMMY_VALUES return NULL; #endif long_return = -1; return (u_char *) & long_return; case IPROUTEMETRIC5: #if NO_DUMMY_VALUES return NULL; #endif long_return = -1; return (u_char *) & long_return; case IPROUTENEXTHOP: 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 NO_DUMMY_VALUES return NULL; #endif long_return = 0; return (u_char *) & long_return; case IPROUTEMASK: if (rtp->rtm_flags & RTF_HOST) { long_return = 0x00000001; return (u_char *) & long_return; } 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 */ static void Route_Scan_Reload(void); #ifdef hpux11 static int rtsize = 0; static mib_ipRouteEnt *rt = (mib_ipRouteEnt *) 0; #else /* hpux11 */ static RTENTRY **rthead = 0; static int rtsize = 0, rtallocate = 0; #endif /* hpux11 */ #if !(defined(linux) || defined(solaris2) || defined(hpux11)) #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) { klookup((u_long) dst, (char *) &klgetsatmp.sin, sizeof klgetsatmp.sin); if (klgetsatmp.sin.sin_len > sizeof(klgetsatmp.sin)) klookup((u_long) dst, (char *) &klgetsatmp.sin, klgetsatmp.sin.sin_len); 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; #if NEED_KLGETSA struct sockaddr_in *sa; #endif #if !defined(linux) && !defined(hpux11) struct ifnet rt_ifnet; struct in_ifaddr rt_ifnetaddr; #endif /** ** this optimisation fails, if there is only a single route avail. ** it is a very special case, but better leave it out ... **/ #if 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; } *write_method = write_rte; *var_len = sizeof(long_return); switch (vp->magic) { case IPROUTEDEST: #if NEED_KLGETSA sa = klgetsa((struct sockaddr_in *) rthead[RtIndex]->rt_dst); return (u_char *) & (sa->sin_addr.s_addr); #elif defined(hpux11) long_return = rt[RtIndex].Dest; return (u_char *) & long_return; #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(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(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(NO_DUMMY_VALUES) return NULL; #endif long_return = -1; return (u_char *) & long_return; case IPROUTEMETRIC5: #if NO_DUMMY_VALUES return NULL; #endif long_return = -1; return (u_char *) & long_return; case IPROUTENEXTHOP: #if NEED_KLGETSA sa = klgetsa((struct sockaddr_in *) rthead[RtIndex]->rt_gateway); return (u_char *) & (sa->sin_addr.s_addr); #elif defined(hpux11) long_return = rt[RtIndex].NextHop; return (u_char *) & long_return; #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(NO_DUMMY_VALUES) return NULL; #endif long_return = 0; return (u_char *) & long_return; case IPROUTEMASK: #if NEED_KLGETSA /* * XXX - Almost certainly not right * but I don't have a suitable system to test this on */ #if NO_DUMMY_VALUES return NULL; #endif long_return = 0; #elif defined(hpux11) long_return = rt[RtIndex].Mask; return (u_char *) & long_return; #else /* !NEED_KLGETSA && !hpux11 */ if (((struct sockaddr_in *) &rthead[RtIndex]->rt_dst)->sin_addr. s_addr == 0) long_return = 0; /* Default route */ else { #ifndef linux klookup((unsigned long) rthead[RtIndex]->rt_ifp, (char *) &rt_ifnet, sizeof(rt_ifnet)); klookup((unsigned long) rt_ifnet.if_addrlist, (char *) &rt_ifnetaddr, sizeof(rt_ifnetaddr)); long_return = 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 *) & long_return; 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; /* * 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 :-( */ 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; *write_method = write_rte; *var_len = sizeof(long_return); switch (vp->magic) { case IPROUTEDEST: long_return = Lowentry.ipRouteDest; return (u_char *) & long_return; case IPROUTEIFINDEX: long_return = Interface_Index_By_Name(Lowentry.ipRouteIfIndex.o_bytes, Lowentry.ipRouteIfIndex.o_length); 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: long_return = Lowentry.ipRouteNextHop; return (u_char *) & long_return; 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: long_return = Lowentry.ipRouteMask; return (u_char *) & long_return; 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) #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 (!klookup ((unsigned long) pt, (char *) &node, sizeof(struct radix_node))) { DEBUGMSGTL(("mibII/var_route", "Fail\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 */ klookup((unsigned long) pt, (char *) &rt, sizeof(RTENTRY)); if (rt.rt_ifp != 0) { klookup((unsigned long) rt.rt_ifp, (char *) &ifnet, sizeof(ifnet)); #if STRUCT_IFNET_HAS_IF_XNAME #if defined(netbsd1) || defined(openbsd2) strncpy(name, ifnet.if_xname, sizeof name); #else klookup((unsigned long) ifnet.if_xname, name, sizeof name); #endif name[sizeof(name) - 1] = '\0'; #else klookup((unsigned long) ifnet.if_name, name, sizeof name); 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 (klookup ((unsigned long) 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... */ klookup(m, (char *) &mb, sizeof(mb)); m = mb.rt_next; rt = &mb; if (rt->rt_ifp != 0) { klookup(rt->rt_ifp, (char *) &ifnet, sizeof(ifnet)); klookup(ifnet.if_name, name, 16); 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... */ klookup((unsigned long) m, (char *) &mb, sizeof(mb)); m = mb.m_next; rt = mtod(&mb, RTENTRY *); if (rt->rt_ifp != 0) { klookup((unsigned long) rt->rt_ifp, (char *) &ifnet, sizeof(ifnet)); klookup((unsigned long) ifnet.if_name, name, 16); 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], temp[16]; static int Time_Of_Last_Reload = 0; struct timeval now; /* * allow 20 seconds in cache: */ gettimeofday(&now, (struct timezone *) 0); if (Time_Of_Last_Reload + 20 > 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; strncpy(name, rt->rt_dev, sizeof(name)); name[ sizeof(name)-1 ] = 0; /* * linux says ``lo'', but the interface is stored as ``lo0'': */ if (!strcmp(name, "lo")) strcat(name, "0"); rt->rt_flags = flags, rt->rt_refcnt = refcnt; rt->rt_use = use, rt->rt_metric = metric; 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 = (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) { mib_ipRouteEnt * const *r1 = (mib_ipRouteEnt * const *) v1; mib_ipRouteEnt * const *r2 = (mib_ipRouteEnt * const *) 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 */ #include #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; /** ** this optimisation fails, if there is only a single route avail. ** it is a very special case, but better leave it out ... **/ #if 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: *write_method = write_rte; long_return = pIpRtrTable->table[RtIndex].dwForwardDest; return (u_char *) & long_return; 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: *write_method = write_rte; long_return = pIpRtrTable->table[RtIndex].dwForwardNextHop; return (u_char *) & long_return; 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; long_return = pIpRtrTable->table[RtIndex].dwForwardMask; return (u_char *) & long_return; 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 */ #else /* CAN_USE_SYSCTL */ #include #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif #include #if HAVE_SYS_STREAM_H #include #endif #include #include #define CACHE_TIME (120) /* Seconds */ #include #include #include "ip.h" #include "kernel.h" #include "interfaces.h" #include "struct.h" #include "util_funcs.h" 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]; #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; } *write_method = write_rte; *var_len = sizeof long_return; switch (vp->magic) { case IPROUTEDEST: long_return = rt->dest.s_addr; return (u_char *) & long_return; 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: if (rt->gateway.s_addr == 0 && rt->ifa.s_addr == 0) long_return = 0; else if (rt->gateway.s_addr == 0) long_return = rt->ifa.s_addr; else long_return = rt->gateway.s_addr; return (u_char *) & long_return; 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 NO_DUMMY_VALUES return NULL; #endif long_return = 0; return (u_char *) & long_return; case IPROUTEMASK: long_return = rt->netmask.s_addr; return (u_char *) & long_return; 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 /* 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 /* * returns the length of a socket structure */ size_t snmp_socket_length(int family) { size_t length; switch (family) { #ifndef cygwin #ifndef WIN32 #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 */