| /* |
| * 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 <net-snmp/net-snmp-config.h> |
| |
| #if defined(IFNET_NEEDS_KERNEL) && !defined(_KERNEL) |
| #define _KERNEL 1 |
| #define _I_DEFINED_KERNEL |
| #endif |
| #if HAVE_SYS_PARAM_H |
| #include <sys/param.h> |
| #endif |
| #if HAVE_UNISTD_H |
| #ifdef irix6 |
| #define _STANDALONE 1 |
| #endif |
| #include <unistd.h> |
| #endif |
| #if HAVE_SYS_SOCKET_H |
| #include <sys/socket.h> |
| #endif |
| |
| #if HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| #include <sys/types.h> |
| #if HAVE_WINSOCK_H |
| #include <winsock.h> |
| #endif |
| #if HAVE_SYS_SYSCTL_H |
| #ifdef _I_DEFINED_KERNEL |
| #undef _KERNEL |
| #endif |
| #include <sys/sysctl.h> |
| #ifdef _I_DEFINED_KERNEL |
| #define _KERNEL 1 |
| #endif |
| #endif |
| #if HAVE_SYS_SYSMP_H |
| #include <sys/sysmp.h> |
| #endif |
| #if HAVE_SYS_TCPIPSTATS_H |
| #include <sys/tcpipstats.h> |
| #endif |
| #if HAVE_NETINET_IN_H |
| #include <netinet/in.h> |
| #endif |
| #if HAVE_NET_IF_H |
| #include <net/if.h> |
| #endif |
| #if HAVE_NET_IF_VAR_H |
| #include <net/if_var.h> |
| #endif |
| #ifdef _I_DEFINED_KERNEL |
| #undef _KERNEL |
| #endif |
| #if HAVE_NETINET_IN_SYSTM_H |
| #include <netinet/in_systm.h> |
| #endif |
| #if HAVE_SYS_HASHING_H |
| #include <sys/hashing.h> |
| #endif |
| #if HAVE_NETINET_IN_VAR_H |
| #include <netinet/in_var.h> |
| #endif |
| #if HAVE_NETINET_IP_H |
| #include <netinet/ip.h> |
| #endif |
| #if HAVE_NETINET_IP_VAR_H |
| #include <netinet/ip_var.h> |
| #endif |
| #if HAVE_INET_MIB2_H |
| #include <inet/mib2.h> |
| #endif |
| #if HAVE_SYS_STREAM_H |
| #include <sys/stream.h> |
| #endif |
| #if HAVE_NET_ROUTE_H |
| #include <net/route.h> |
| #endif |
| #if HAVE_SYSLOG_H |
| #include <syslog.h> |
| #endif |
| #if HAVE_SYS_IOCTL_H |
| #include <sys/ioctl.h> |
| #endif |
| |
| #if defined(MIB_IPCOUNTER_SYMBOL) || defined(hpux11) |
| #include <sys/mib.h> |
| #include <netinet/mib_kern.h> |
| #endif /* MIB_IPCOUNTER_SYMBOL || hpux11 */ |
| |
| #ifdef solaris2 |
| #include "kernel_sunos5.h" |
| #else |
| #include "kernel.h" |
| #endif |
| |
| #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 "interfaces.h" |
| #include "sysORTable.h" |
| |
| #ifdef cygwin |
| #include <windows.h> |
| #endif |
| |
| /********************* |
| * |
| * 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 STRUCT_IFNET_HAS_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 = 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; |
| close(fd); |
| } |
| |
| /* |
| * 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 */ |
| |
| #else /* WIN32 cygwin */ |
| #include <iphlpapi.h> |
| 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 */ |