diff --git a/agent/mibgroup/mibII/ipAddr.c b/agent/mibgroup/mibII/ipAddr.c index 2b9d3d1..ffed5cd 100644 --- a/agent/mibgroup/mibII/ipAddr.c +++ b/agent/mibgroup/mibII/ipAddr.c @@ -495,14 +495,16 @@ Address_Scan_Next(Index, Retin_ifaddr) } #elif defined(linux) +#include static struct ifreq *ifr; static int ifr_counter; static void Address_Scan_Init(void) { - int num_interfaces = 0; + int i; int fd; + int lastlen = 0; /* get info about all interfaces */ @@ -510,28 +512,45 @@ Address_Scan_Init(void) SNMP_FREE(ifc.ifc_buf); ifr_counter = 0; - do - { if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { DEBUGMSGTL(("snmpd", "socket open failure in Address_Scan_Init\n")); return; } - num_interfaces += 16; - ifc.ifc_len = sizeof(struct ifreq) * num_interfaces; - ifc.ifc_buf = (char*) realloc(ifc.ifc_buf, ifc.ifc_len); - - if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) - { - ifr=NULL; - close(fd); - return; - } - close(fd); + /* + * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF + * on some platforms; see W. R. Stevens, ``Unix Network Programming + * Volume I'', p.435... + */ + + for (i = 8;; i *= 2) { + ifc.ifc_len = sizeof(struct ifreq) * i; + ifc.ifc_req = calloc(i, sizeof(struct ifreq)); + + if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { + if (errno != EINVAL || lastlen != 0) { + /* + * Something has gone genuinely wrong... + */ + snmp_log(LOG_ERR, "bad rc from ioctl, errno %d", errno); + SNMP_FREE(ifc.ifc_buf); + close(fd); + return; + } + } else { + if (ifc.ifc_len == lastlen) { + /* + * The length is the same as the last time; we're done... + */ + break; + } + lastlen = ifc.ifc_len; + } + free(ifc.ifc_buf); /* no SNMP_FREE, getting ready to reassign */ } - while (ifc.ifc_len >= (sizeof(struct ifreq) * num_interfaces)); - + + close(fd); ifr = ifc.ifc_req; } diff --git a/agent/mibgroup/mibII/ipAddr.c.ipAddress-faster-load b/agent/mibgroup/mibII/ipAddr.c.ipAddress-faster-load new file mode 100644 index 0000000..2b9d3d1 --- /dev/null +++ b/agent/mibgroup/mibII/ipAddr.c.ipAddress-faster-load @@ -0,0 +1,1078 @@ +/* + * IP MIB group implementation - ip.c + * + */ + +/* 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: + */ +/* + * 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. + */ + +#include +#include + +#if defined(NETSNMP_IFNET_NEEDS_KERNEL) && !defined(_KERNEL) +#define _KERNEL 1 +#define _I_DEFINED_KERNEL +#endif +#if HAVE_SYS_PARAM_H +#include +#endif +#if HAVE_UNISTD_H +#ifdef irix6 +#define _STANDALONE 1 +#endif +#include +#endif +#if HAVE_SYS_SOCKET_H +#include +#endif + +#if HAVE_STRING_H +#include +#else +#include +#endif +#include +#if HAVE_SYS_SYSCTL_H +#ifdef _I_DEFINED_KERNEL +#undef _KERNEL +#endif +#include +#ifdef _I_DEFINED_KERNEL +#define _KERNEL 1 +#endif +#endif +#if HAVE_SYS_SYSMP_H +#include +#endif +#if HAVE_SYS_TCPIPSTATS_H +#include +#endif +#if HAVE_NETINET_IN_H +#include +#endif +#if HAVE_NET_IF_H +#include +#endif +#if HAVE_NET_IF_VAR_H +#include +#endif +#ifdef _I_DEFINED_KERNEL +#undef _KERNEL +#endif +#if HAVE_NETINET_IN_SYSTM_H +#include +#endif +#if HAVE_SYS_HASHING_H +#include +#endif +#if HAVE_NETINET_IN_VAR_H +#include +#endif +#if HAVE_NETINET_IP_H +#include +#endif +#if HAVE_NETINET_IP_VAR_H +#include +#endif +#if HAVE_INET_MIB2_H +#include +#endif +#if HAVE_SYS_STREAM_H +#include +#endif +#if HAVE_NET_ROUTE_H +#include +#endif +#if HAVE_SYSLOG_H +#include +#endif +#if HAVE_SYS_IOCTL_H +#include +#endif + +#if defined(MIB_IPCOUNTER_SYMBOL) || defined(hpux11) +#include +#include +#endif /* MIB_IPCOUNTER_SYMBOL || hpux11 */ + +#ifdef solaris2 +#include "kernel_sunos5.h" +#else +#include "kernel.h" +#endif + +#include +#include +#include +#include + +#include "ip.h" +#include "ipAddr.h" +#include "interfaces.h" + +#if defined(cygwin) || defined(mingw32) +#include +#include +#endif + +netsnmp_feature_require(interface_legacy) + + /********************* + * + * Kernel & interface information, + * and internal forward declarations + * + *********************/ + + /********************* + * + * Initialisation & common implementation functions + * + *********************/ + + /********************* + * + * System specific implementation functions + * + *********************/ + +#if !defined (WIN32) && !defined (cygwin) + +#if !defined(NETSNMP_CAN_USE_SYSCTL) || !defined(IPCTL_STATS) +#ifndef solaris2 + +#if defined(freebsd2) || defined(hpux11) || defined(linux) +static void Address_Scan_Init(void); +#ifdef freebsd2 +static int Address_Scan_Next(short *, struct in_ifaddr *); +#else +#ifdef linux +static struct ifconf ifc; +static int Address_Scan_Next(short *, struct ifnet *); +#else +static int Address_Scan_Next(short *, mib_ipAdEnt *); +#endif +#endif +#endif + +/* + * var_ipAddrEntry(... + * 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 + * + */ + +u_char * +var_ipAddrEntry(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.20.1.?.A.B.C.D, where A.B.C.D is IP address. + * IPADDR starts at offset 10. + */ + oid lowest[14]; + oid current[14], *op; + u_char *cp; + int lowinterface = 0; +#ifndef freebsd2 + short interface; +#endif +#ifdef hpux11 + static mib_ipAdEnt in_ifaddr, lowin_ifaddr; +#else +#if !defined(linux) && !defined(sunV3) + static struct in_ifaddr in_ifaddr, lowin_ifaddr; +#else + static struct ifnet lowin_ifnet; +#endif + static struct ifnet ifnet; +#endif /* hpux11 */ + static in_addr_t addr_ret; + + /* + * fill in object part of name for current (less sizeof instance part) + */ + + memcpy((char *) current, (char *) vp->name, + (int) vp->namelen * sizeof(oid)); + +#if !defined(freebsd2) && !defined(hpux11) && !defined(linux) + Interface_Scan_Init(); +#else + Address_Scan_Init(); +#endif + for (;;) { + +#if !defined(freebsd2) && !defined(hpux11) && !defined(linux) + if (Interface_Scan_Next(&interface, NULL, &ifnet, &in_ifaddr) == 0) + break; +#ifdef HAVE_STRUCT_IFNET_IF_ADDRLIST + if (ifnet.if_addrlist == 0) + continue; /* No address found for interface */ +#endif +#else /* !freebsd2 && !hpux11 */ +#if defined(linux) + if (Address_Scan_Next(&interface, &ifnet) == 0) + break; +#else + if (Address_Scan_Next(&interface, &in_ifaddr) == 0) + break; +#endif +#endif /* !freebsd2 && !hpux11 && !linux */ + +#ifdef hpux11 + cp = (u_char *) & in_ifaddr.Addr; +#elif defined(linux) || defined(sunV3) + cp = (u_char *) & (((struct sockaddr_in *) &(ifnet.if_addr))-> + sin_addr.s_addr); +#else + cp = (u_char *) & (((struct sockaddr_in *) &(in_ifaddr.ia_addr))-> + sin_addr.s_addr); +#endif + + op = current + 10; + *op++ = *cp++; + *op++ = *cp++; + *op++ = *cp++; + *op++ = *cp++; + if (exact) { + if (snmp_oid_compare(current, 14, name, *length) == 0) { + memcpy((char *) lowest, (char *) current, + 14 * sizeof(oid)); + lowinterface = interface; +#if defined(linux) || defined(sunV3) + lowin_ifnet = ifnet; +#else + lowin_ifaddr = in_ifaddr; +#endif + break; /* no need to search further */ + } + } else { + if ((snmp_oid_compare(current, 14, name, *length) > 0) && + (!lowinterface + || (snmp_oid_compare(current, 14, lowest, 14) < 0))) { + /* + * if new one is greater than input and closer to input than + * previous lowest, save this one as the "next" one. + */ + lowinterface = interface; +#if defined(linux) || defined(sunV3) + lowin_ifnet = ifnet; +#else + lowin_ifaddr = in_ifaddr; +#endif + memcpy((char *) lowest, (char *) current, + 14 * sizeof(oid)); + } + } + } + +#if defined(linux) + SNMP_FREE(ifc.ifc_buf); +#endif + + if (!lowinterface) + return (NULL); + memcpy((char *) name, (char *) lowest, 14 * sizeof(oid)); + *length = 14; + *write_method = (WriteMethod*)0; + *var_len = sizeof(long_return); + switch (vp->magic) { + case IPADADDR: + *var_len = sizeof(addr_ret); +#ifdef hpux11 + addr_ret = lowin_ifaddr.Addr; + return (u_char *) & addr_ret; +#elif defined(linux) || defined(sunV3) + return (u_char *) & ((struct sockaddr_in *) &lowin_ifnet.if_addr)-> + sin_addr.s_addr; +#else + return (u_char *) & ((struct sockaddr_in *) &lowin_ifaddr. + ia_addr)->sin_addr.s_addr; +#endif + case IPADIFINDEX: + long_return = lowinterface; + return (u_char *) & long_return; + case IPADNETMASK: + *var_len = sizeof(addr_ret); +#ifdef hpux11 + addr_ret = lowin_ifaddr.NetMask; + return (u_char *) & addr_ret; +#elif defined(linux) + return (u_char *) & ((struct sockaddr_in *) &lowin_ifnet. + ia_subnetmask)->sin_addr.s_addr; +#elif !defined(sunV3) + addr_ret = lowin_ifaddr.ia_subnetmask; + return (u_char *) & addr_ret; +#endif + case IPADBCASTADDR: +#ifdef hpux11 + long_return = lowin_ifaddr.BcastAddr & 1; +#elif defined(linux) || defined(sunV3) + *var_len = sizeof(long_return); + long_return = + ntohl(((struct sockaddr_in *) &lowin_ifnet.ifu_broadaddr)-> + sin_addr.s_addr) & 1; +#elif defined(netbsd1) + long_return = + ((struct sockaddr_in *) &lowin_ifaddr.ia_broadaddr)->sin_addr. + s_addr & 1; +#else + long_return = + ntohl(((struct sockaddr_in *) &lowin_ifaddr.ia_broadaddr)-> + sin_addr.s_addr) & 1; +#endif + return (u_char *) & long_return; + case IPADREASMMAX: +#ifdef hpux11 + long_return = lowin_ifaddr.ReasmMaxSize; + return (u_char *) & long_return; +#elif defined(NETSNMP_NO_DUMMY_VALUES) + return NULL; +#else + long_return = -1; + return (u_char *) & long_return; +#endif + default: + DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipAddrEntry\n", + vp->magic)); + } + return NULL; +} + +#ifdef freebsd2 +static struct in_ifaddr *in_ifaddraddr = NULL; + +static void +Address_Scan_Init(void) +{ + int rc = auto_nlist(IFADDR_SYMBOL, (char *) &in_ifaddraddr, + sizeof(in_ifaddraddr)); + if (0 == rc) + in_ifaddraddr = NULL; +} + +/* + * NB: Index is the number of the corresponding interface, not of the address + */ +static int +Address_Scan_Next(Index, Retin_ifaddr) + short *Index; + struct in_ifaddr *Retin_ifaddr; +{ + struct in_ifaddr in_ifaddr; + struct ifnet ifnet, *ifnetaddr; /* NOTA: same name as another one */ + short iindex = 1; + + while (in_ifaddraddr) { + /* + * Get the "in_ifaddr" structure + */ + if (!NETSNMP_KLOOKUP(in_ifaddraddr, (char *) &in_ifaddr, sizeof in_ifaddr)) { + DEBUGMSGTL(("mibII/ip:Address_Scan_Next", "klookup failed\n")); + return 0; + } + + in_ifaddraddr = in_ifaddr.ia_next; + + if (Retin_ifaddr) + *Retin_ifaddr = in_ifaddr; + + /* + * Now, more difficult, find the index of the interface to which + * this address belongs + */ + + auto_nlist(IFNET_SYMBOL, (char *) &ifnetaddr, sizeof(ifnetaddr)); + while (ifnetaddr && ifnetaddr != in_ifaddr.ia_ifp) { + if (!NETSNMP_KLOOKUP(ifnetaddr, (char *) &ifnet, sizeof ifnet)) { + DEBUGMSGTL(("mibII/ip:Address_Scan_Next", "klookup failed\n")); + return 0; + } + ifnetaddr = ifnet.if_next; + iindex++; + } + + /* + * XXX - might not find it? + */ + + if (Index) + *Index = iindex; + + return (1); /* DONE */ + } + return (0); /* EOF */ +} + +#elif defined(hpux11) + +static int iptab_size, iptab_current; +static mib_ipAdEnt *ip = (mib_ipAdEnt *) 0; + +static void +Address_Scan_Init(void) +{ + int fd; + struct nmparms p; + int val; + unsigned int ulen; + int ret; + + if (ip) + free(ip); + ip = (mib_ipAdEnt *) 0; + iptab_size = 0; + + if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) { + p.objid = ID_ipAddrNumEnt; + p.buffer = (void *) &val; + ulen = sizeof(int); + p.len = &ulen; + if ((ret = get_mib_info(fd, &p)) == 0) + iptab_size = val; + + if (iptab_size > 0) { + ulen = (unsigned) iptab_size *sizeof(mib_ipAdEnt); + ip = (mib_ipAdEnt *) malloc(ulen); + p.objid = ID_ipAddrTable; + p.buffer = (void *) ip; + p.len = &ulen; + if ((ret = get_mib_info(fd, &p)) < 0) + iptab_size = 0; + } + + close_mib(fd); + } + + iptab_current = 0; +} + +/* + * NB: Index is the number of the corresponding interface, not of the address + */ +static int +Address_Scan_Next(Index, Retin_ifaddr) + short *Index; + mib_ipAdEnt *Retin_ifaddr; +{ + if (iptab_current < iptab_size) { + /* + * copy values + */ + *Index = ip[iptab_current].IfIndex; + *Retin_ifaddr = ip[iptab_current]; + /* + * increment to point to next entry + */ + iptab_current++; + /* + * return success + */ + return (1); + } + + /* + * return done + */ + return (0); +} + +#elif defined(linux) +static struct ifreq *ifr; +static int ifr_counter; + +static void +Address_Scan_Init(void) +{ + int num_interfaces = 0; + int fd; + + /* get info about all interfaces */ + + ifc.ifc_len = 0; + SNMP_FREE(ifc.ifc_buf); + ifr_counter = 0; + + do + { + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + DEBUGMSGTL(("snmpd", "socket open failure in Address_Scan_Init\n")); + return; + } + num_interfaces += 16; + + ifc.ifc_len = sizeof(struct ifreq) * num_interfaces; + ifc.ifc_buf = (char*) realloc(ifc.ifc_buf, ifc.ifc_len); + + if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) + { + ifr=NULL; + close(fd); + return; + } + close(fd); + } + while (ifc.ifc_len >= (sizeof(struct ifreq) * num_interfaces)); + + ifr = ifc.ifc_req; +} + +/* + * NB: Index is the number of the corresponding interface, not of the address + */ +static int +Address_Scan_Next(short *Index, struct ifnet *Retifnet) +{ + struct ifnet ifnet_store; + int fd; + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + DEBUGMSGTL(("snmpd", "socket open failure in Address_Scan_Next\n")); + return(0); + } + + while (ifr) { + + ifnet_store.if_addr = ifr->ifr_addr; + + if (Retifnet) + { + Retifnet->if_addr = ifr->ifr_addr; + + if (ioctl(fd, SIOCGIFBRDADDR, ifr) < 0) + { + memset((char *) &Retifnet->ifu_broadaddr, 0, sizeof(Retifnet->ifu_broadaddr)); + } + else + Retifnet->ifu_broadaddr = ifr->ifr_broadaddr; + + ifr->ifr_addr = Retifnet->if_addr; + if (ioctl(fd, SIOCGIFNETMASK, ifr) < 0) + { + memset((char *) &Retifnet->ia_subnetmask, 0, sizeof(Retifnet->ia_subnetmask)); + } + else + Retifnet->ia_subnetmask = ifr->ifr_netmask; + + } + + if (Index) + { + ifr->ifr_addr = ifnet_store.if_addr; + *Index = netsnmp_access_interface_index_find(ifr->ifr_name); + } + + ifr++; + ifr_counter+=sizeof(struct ifreq); + if (ifr_counter >= ifc.ifc_len) + { + ifr = NULL; /* beyond the end */ + } + + close(fd); + return (1); /* DONE */ + } + close(fd); + return (0); /* EOF */ +} + +#endif /* freebsd,hpux11,linux */ + +#else /* solaris2 */ + + +static int +IP_Cmp(void *addr, void *ep) +{ + if (((mib2_ipAddrEntry_t *) ep)->ipAdEntAddr == *(IpAddress *) addr) + return (0); + else + return (1); +} + +u_char * +var_ipAddrEntry(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.20.1.?.A.B.C.D, where A.B.C.D is IP address. + * IPADDR starts at offset 10. + */ +#define IP_ADDRNAME_LENGTH 14 +#define IP_ADDRINDEX_OFF 10 + oid lowest[IP_ADDRNAME_LENGTH]; + oid current[IP_ADDRNAME_LENGTH], *op; + u_char *cp; + IpAddress NextAddr; + mib2_ipAddrEntry_t entry; + static mib2_ipAddrEntry_t Lowentry; + int Found = 0; + req_e req_type; + static in_addr_t addr_ret; + + /* + * fill in object part of name for current (less sizeof instance part) + */ + + DEBUGMSGTL(("mibII/ip", "var_ipAddrEntry: ")); + DEBUGMSGOID(("mibII/ip", name, *length)); + DEBUGMSG(("mibII/ip", " %d\n", exact)); + + memset(&Lowentry, 0, sizeof(Lowentry)); + memcpy((char *) current, (char *) vp->name, + (int) vp->namelen * sizeof(oid)); + if (*length == IP_ADDRNAME_LENGTH) /* Assume that the input name is the lowest */ + memcpy((char *) lowest, (char *) name, + IP_ADDRNAME_LENGTH * sizeof(oid)); + else + lowest[0] = 0xff; + for (NextAddr = (u_long) - 1, req_type = GET_FIRST;; + NextAddr = entry.ipAdEntAddr, req_type = GET_NEXT) { + if (getMibstat + (MIB_IP_ADDR, &entry, sizeof(mib2_ipAddrEntry_t), req_type, + &IP_Cmp, &NextAddr) != 0) + break; + COPY_IPADDR(cp, (u_char *) & entry.ipAdEntAddr, op, + current + IP_ADDRINDEX_OFF); + if (exact) { + if (snmp_oid_compare + (current, IP_ADDRNAME_LENGTH, name, *length) == 0) { + memcpy((char *) lowest, (char *) current, + IP_ADDRNAME_LENGTH * sizeof(oid)); + Lowentry = entry; + Found++; + break; /* no need to search further */ + } + } else { + if ((snmp_oid_compare + (current, IP_ADDRNAME_LENGTH, name, *length) > 0) + && (((NextAddr == (u_long) - 1)) + || + (snmp_oid_compare + (current, IP_ADDRNAME_LENGTH, lowest, + IP_ADDRNAME_LENGTH) < 0) + || + (snmp_oid_compare + (name, *length, lowest, IP_ADDRNAME_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. + */ + Lowentry = entry; + Found++; + memcpy((char *) lowest, (char *) current, + IP_ADDRNAME_LENGTH * sizeof(oid)); + } + } + } + DEBUGMSGTL(("mibII/ip", "... Found = %d\n", Found)); + if (Found == 0) + return (NULL); + memcpy((char *) name, (char *) lowest, + IP_ADDRNAME_LENGTH * sizeof(oid)); + *length = IP_ADDRNAME_LENGTH; + *write_method = 0; + *var_len = sizeof(long_return); + switch (vp->magic) { + case IPADADDR: + *var_len = sizeof(addr_ret); + addr_ret = Lowentry.ipAdEntAddr; + return (u_char *) & addr_ret; + case IPADIFINDEX: +#ifdef NETSNMP_INCLUDE_IFTABLE_REWRITES + Lowentry.ipAdEntIfIndex.o_bytes[Lowentry.ipAdEntIfIndex.o_length] = '\0'; + long_return = + netsnmp_access_interface_index_find(Lowentry. + ipAdEntIfIndex.o_bytes); +#else + long_return = + Interface_Index_By_Name(Lowentry.ipAdEntIfIndex.o_bytes, + Lowentry.ipAdEntIfIndex.o_length); +#endif + return (u_char *) & long_return; + case IPADNETMASK: + *var_len = sizeof(addr_ret); + addr_ret = Lowentry.ipAdEntNetMask; + return (u_char *) & addr_ret; + case IPADBCASTADDR: + long_return = Lowentry.ipAdEntBcastAddr; + return (u_char *) & long_return; + case IPADREASMMAX: + long_return = Lowentry.ipAdEntReasmMaxSize; + return (u_char *) & long_return; + default: + DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipAddrEntry\n", + vp->magic)); + } + return NULL; +} + +#endif /* solaris2 */ + + + + /********************* + * + * Internal implementation functions + * + *********************/ + + +#else /* NETSNMP_CAN_USE_SYSCTL && IPCTL_STATS */ + +/* + * Ideally, this would be combined with the code in interfaces.c. + * Even separate, it's still better than what went before. + */ +struct iflist { + int flags; + int index; + struct in_addr addr; + struct in_addr mask; + struct in_addr bcast; +}; +static struct iflist *ifs; +static int nifs; + +static void +get_iflist(void) +{ + int naddrs, bit; + static int mib[6] + = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, 0 }; + char *cp, *ifbuf; + size_t len; + struct rt_msghdr *rtm; + struct if_msghdr *ifm; + struct ifa_msghdr *ifam; + struct sockaddr *sa; + int flags; + + naddrs = 0; + if (ifs) + free(ifs); + ifs = 0; + nifs = 0; + len = 0; + if (sysctl(mib, 6, 0, &len, 0, 0) < 0) + return; + + ifbuf = malloc(len); + if (ifbuf == 0) + return; + if (sysctl(mib, 6, ifbuf, &len, 0, 0) < 0) { + syslog(LOG_WARNING, "sysctl net-route-iflist: %m"); + free(ifbuf); + return; + } + + loop: + cp = ifbuf; + while (cp < &ifbuf[len]) { + int gotaddr; + + gotaddr = 0; + rtm = (struct rt_msghdr *) cp; + if (rtm->rtm_version != RTM_VERSION || rtm->rtm_type != RTM_IFINFO) { + free(ifs); + ifs = 0; + nifs = 0; + free(ifbuf); + return; + } + ifm = (struct if_msghdr *) rtm; + flags = ifm->ifm_flags; + cp += ifm->ifm_msglen; + rtm = (struct rt_msghdr *) cp; + while (cp < &ifbuf[len] && rtm->rtm_type == RTM_NEWADDR) { + ifam = (struct ifa_msghdr *) rtm; + cp += sizeof(*ifam); + /* + * from route.c + */ +#define ROUND(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + for (bit = 1; bit && cp < &ifbuf[len]; bit <<= 1) { + if (!(ifam->ifam_addrs & bit)) + continue; + sa = (struct sockaddr *) cp; + cp += ROUND(sa->sa_len); + + /* + * Netmasks are returned as bit + * strings of type AF_UNSPEC. The + * others are pretty ok. + */ + if (bit == RTA_IFA) { +#define satosin(sa) ((struct sockaddr_in *)(sa)) + if (ifs) { + ifs[naddrs].addr = satosin(sa)->sin_addr; + ifs[naddrs].index = ifam->ifam_index; + ifs[naddrs].flags = flags; + } + gotaddr = 1; + } else if (bit == RTA_NETMASK) { + if (ifs) + ifs[naddrs].mask = satosin(sa)->sin_addr; + } else if (bit == RTA_BRD) { + if (ifs) + ifs[naddrs].bcast = satosin(sa)->sin_addr; + } + } + if (gotaddr) + naddrs++; + cp = (char *) rtm + rtm->rtm_msglen; + rtm = (struct rt_msghdr *) cp; + } + } + if (ifs) { + nifs = naddrs; + free(ifbuf); + return; + } + ifs = malloc(naddrs * sizeof(*ifs)); + if (ifs == 0) { + free(ifbuf); + return; + } + naddrs = 0; + goto loop; +} + +u_char * +var_ipAddrEntry(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.20.1.?.A.B.C.D, where A.B.C.D is IP address. + * IPADDR starts at offset 10. + */ + oid lowest[14]; + oid current[14], *op; + u_char *cp; + int lowinterface = -1; + int i; + static in_addr_t addr_ret; + + /* + * fill in object part of name for current (less sizeof instance part) + */ + memcpy(current, vp->name, (int) vp->namelen * sizeof(oid)); + + /* + * Get interface table from kernel. + */ + get_iflist(); + + for (i = 0; i < nifs; i++) { + op = ¤t[10]; + cp = (u_char *) & ifs[i].addr; + *op++ = *cp++; + *op++ = *cp++; + *op++ = *cp++; + *op++ = *cp++; + if (exact) { + if (snmp_oid_compare(current, 14, name, *length) == 0) { + memcpy(lowest, current, 14 * sizeof(oid)); + lowinterface = i; + break; /* no need to search further */ + } + } else { + if ((snmp_oid_compare(current, 14, name, *length) > 0) && + (lowinterface < 0 + || (snmp_oid_compare(current, 14, lowest, 14) < 0))) { + /* + * if new one is greater than input + * and closer to input than previous + * lowest, save this one as the "next" + * one. + */ + lowinterface = i; + memcpy(lowest, current, 14 * sizeof(oid)); + } + } + } + + if (lowinterface < 0) + return NULL; + i = lowinterface; + memcpy(name, lowest, 14 * sizeof(oid)); + *length = 14; + *write_method = 0; + *var_len = sizeof(long_return); + switch (vp->magic) { + case IPADADDR: + *var_len = sizeof(addr_ret); + addr_ret = ifs[i].addr.s_addr; + return (u_char *) & addr_ret; + + case IPADIFINDEX: + long_return = ifs[i].index; + return (u_char *) & long_return; + + case IPADNETMASK: + *var_len = sizeof(addr_ret); + addr_ret = ifs[i].mask.s_addr; + return (u_char *) & addr_ret; + + case IPADBCASTADDR: + long_return = ntohl(ifs[i].bcast.s_addr) & 1; + return (u_char *) & long_return; + + case IPADREASMMAX: +#if NETSNMP_NO_DUMMY_VALUES + return NULL; +#else + long_return = -1; + return (u_char *) & long_return; +#endif + + default: + DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipAddrEntry\n", + vp->magic)); + } + return NULL; +} + +#endif /* NETSNMP_CAN_USE_SYSCTL && IPCTL_STATS */ + +#elif defined(HAVE_IPHLPAPI_H) /* WIN32 cygwin */ +#include +u_char * +var_ipAddrEntry(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.20.1.?.A.B.C.D, where A.B.C.D is IP address. + * IPADDR starts at offset 10. + */ + oid lowest[14]; + oid current[14], *op; + u_char *cp; + int lowinterface = -1; + int i; + PMIB_IPADDRTABLE pIpAddrTable = NULL; + DWORD status = NO_ERROR; + DWORD statusRetry = NO_ERROR; + DWORD dwActualSize = 0; + void *result = NULL; + static in_addr_t addr_ret; + + /* + * fill in object part of name for current (less sizeof instance part) + */ + memcpy(current, vp->name, (int) vp->namelen * sizeof(oid)); + + /* + * Get interface table from kernel. + */ + status = GetIpAddrTable(pIpAddrTable, &dwActualSize, TRUE); + if (status == ERROR_INSUFFICIENT_BUFFER) { + pIpAddrTable = (PMIB_IPADDRTABLE) malloc(dwActualSize); + if (pIpAddrTable != NULL) { + statusRetry = + GetIpAddrTable(pIpAddrTable, &dwActualSize, TRUE); + } + } + + if (statusRetry == NO_ERROR || status == NO_ERROR) { + + for (i = 0; i < (int) pIpAddrTable->dwNumEntries; ++i) { + op = ¤t[10]; + cp = (u_char *) & pIpAddrTable->table[i].dwAddr; + *op++ = *cp++; + *op++ = *cp++; + *op++ = *cp++; + *op++ = *cp++; + if (exact) { + if (snmp_oid_compare(current, 14, name, *length) == 0) { + memcpy(lowest, current, 14 * sizeof(oid)); + lowinterface = i; + break; /* no need to search further */ + } + } else { + if (snmp_oid_compare(current, 14, name, *length) > 0) { + lowinterface = i; + memcpy(lowest, current, 14 * sizeof(oid)); + break; /* Since the table is sorted, no need to search further */ + } + } + } + } + + if (lowinterface < 0) + goto out; + + i = lowinterface; + memcpy(name, lowest, 14 * sizeof(oid)); + *length = 14; + *write_method = 0; + switch (vp->magic) { + case IPADADDR: + *var_len = sizeof(addr_ret); + addr_ret = pIpAddrTable->table[i].dwAddr; + result = &addr_ret; + break; + + case IPADIFINDEX: + *var_len = sizeof(long_return); + long_return = pIpAddrTable->table[i].dwIndex; + result = &long_return; + break; + + case IPADNETMASK: + *var_len = sizeof(addr_ret); + addr_ret = pIpAddrTable->table[i].dwMask; + result = &addr_ret; + break; + + case IPADBCASTADDR: + *var_len = sizeof(long_return); + long_return = pIpAddrTable->table[i].dwBCastAddr; + result = &long_return; + break; + + case IPADREASMMAX: + *var_len = sizeof(long_return); + long_return = pIpAddrTable->table[i].dwReasmSize; + result = &long_return; + break; + + default: + DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_ipAddrEntry\n", + vp->magic)); + break; + } + +out: + free(pIpAddrTable); + return result; +} +#endif /* WIN32 cygwin */