| /* |
| * Template MIB group implementation - at.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> |
| #include "mibII_common.h" /* for NETSNMP_KLOOKUP */ |
| |
| #if HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| #if HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| #if defined(IFNET_NEEDS_KERNEL) && !defined(_KERNEL) |
| #define _KERNEL 1 |
| #define _I_DEFINED_KERNEL |
| #endif |
| #include <sys/types.h> |
| #if TIME_WITH_SYS_TIME |
| # if defined (WIN32) || defined (cygwin) |
| # include <sys/timeb.h> |
| # else |
| # include <sys/time.h> |
| # endif |
| # include <time.h> |
| #else |
| # if HAVE_SYS_TIME_H |
| # include <sys/time.h> |
| # else |
| # include <time.h> |
| # endif |
| #endif |
| #if HAVE_SYS_SOCKET_H |
| #include <sys/socket.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_IF_ETHER_H |
| #include <netinet/if_ether.h> |
| #endif |
| #if HAVE_INET_MIB2_H |
| #include <inet/mib2.h> |
| #endif |
| #if HAVE_SYS_PARAM_H |
| #include <sys/param.h> |
| #endif |
| #if HAVE_SYS_SYSCTL_H |
| #include <sys/sysctl.h> |
| #endif |
| #if HAVE_NET_IF_DL_H |
| #ifndef dynix |
| #include <net/if_dl.h> |
| #else |
| #include <sys/net/if_dl.h> |
| #endif |
| #endif |
| #if HAVE_SYS_STREAM_H |
| #include <sys/stream.h> |
| #endif |
| #if HAVE_NET_ROUTE_H |
| #include <net/route.h> |
| #endif |
| #ifdef solaris2 |
| #include "kernel_sunos5.h" |
| #endif |
| #if HAVE_WINSOCK_H |
| #include <winsock.h> |
| #endif |
| |
| #ifdef hpux11 |
| #include <sys/mib.h> |
| #include <netinet/mib_kern.h> |
| #endif /* hpux11 */ |
| |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/net-snmp-agent-includes.h> |
| #include <net-snmp/agent/auto_nlist.h> |
| |
| #include "at.h" |
| #include "interfaces.h" |
| |
| #include <net-snmp/data_access/interface.h> |
| |
| #if defined(HAVE_SYS_SYSCTL_H) && !defined(NETSNMP_CAN_USE_SYSCTL) |
| # if defined(RTF_LLINFO) |
| # define NETSNMP_CAN_USE_SYSCTL 1 |
| # endif |
| #endif |
| |
| #ifdef cygwin |
| #include <windows.h> |
| #endif |
| |
| /********************* |
| * |
| * Kernel & interface information, |
| * and internal forward declarations |
| * |
| *********************/ |
| |
| #if !defined (WIN32) && !defined (cygwin) |
| #ifndef solaris2 |
| static void ARP_Scan_Init(void); |
| #ifdef ARP_SCAN_FOUR_ARGUMENTS |
| static int ARP_Scan_Next(in_addr_t *, char *, int *, u_long *, u_short *); |
| #else |
| static int ARP_Scan_Next(in_addr_t *, char *, int *, u_long *); |
| #endif |
| #endif |
| #endif |
| |
| /********************* |
| * |
| * Public interface functions |
| * |
| *********************/ |
| |
| /* |
| * define the structure we're going to ask the agent to register our |
| * information at |
| */ |
| struct variable1 at_variables[] = { |
| {ATIFINDEX, ASN_INTEGER, RONLY, var_atEntry, 1, {1}}, |
| {ATPHYSADDRESS, ASN_OCTET_STR, RONLY, var_atEntry, 1, {2}}, |
| {ATNETADDRESS, ASN_IPADDRESS, RONLY, var_atEntry, 1, {3}} |
| }; |
| |
| /* |
| * Define the OID pointer to the top of the mib tree that we're |
| * registering underneath |
| */ |
| oid at_variables_oid[] = { SNMP_OID_MIB2, 3, 1, 1 }; |
| |
| void |
| init_at(void) |
| { |
| /* |
| * register ourselves with the agent to handle our mib tree |
| */ |
| REGISTER_MIB("mibII/at", at_variables, variable1, at_variables_oid); |
| #ifdef solaris2 |
| init_kernel_sunos5(); |
| #endif |
| } |
| |
| #if !defined (WIN32) && !defined (cygwin) |
| #ifndef solaris2 |
| |
| /* |
| * var_atEntry(... |
| * 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_atEntry(struct variable *vp, |
| oid * name, |
| size_t * length, |
| int exact, size_t * var_len, WriteMethod ** write_method) |
| { |
| /* |
| * Address Translation table object identifier is of form: |
| * 1.3.6.1.2.1.3.1.1.1.interface.1.A.B.C.D, where A.B.C.D is IP address. |
| * Interface is at offset 10, |
| * IPADDR starts at offset 12. |
| * |
| * IP Net to Media table object identifier is of form: |
| * 1.3.6.1.2.1.4.22.1.1.1.interface.A.B.C.D, where A.B.C.D is IP address. |
| * Interface is at offset 10, |
| * IPADDR starts at offset 11. |
| */ |
| u_char *cp; |
| oid *op; |
| oid lowest[16]; |
| oid current[16]; |
| static char PhysAddr[MAX_MAC_ADDR_LEN], LowPhysAddr[MAX_MAC_ADDR_LEN]; |
| static int PhysAddrLen, LowPhysAddrLen; |
| in_addr_t Addr, LowAddr; |
| int foundone; |
| static in_addr_t addr_ret; |
| #ifdef ARP_SCAN_FOUR_ARGUMENTS |
| u_short ifIndex, lowIfIndex = 0; |
| #endif /* ARP_SCAN_FOUR_ARGUMENTS */ |
| u_long ifType, lowIfType = 0; |
| |
| int oid_length; |
| |
| /* |
| * fill in object part of name for current (less sizeof instance part) |
| */ |
| memcpy((char *) current, (char *) vp->name, |
| (int) vp->namelen * sizeof(oid)); |
| |
| if (current[6] == 3) { /* AT group oid */ |
| oid_length = 16; |
| } else { /* IP NetToMedia group oid */ |
| oid_length = 15; |
| } |
| |
| LowAddr = 0; /* Don't have one yet */ |
| foundone = 0; |
| ARP_Scan_Init(); |
| for (;;) { |
| #ifdef ARP_SCAN_FOUR_ARGUMENTS |
| if (ARP_Scan_Next(&Addr, PhysAddr, &PhysAddrLen, &ifType, &ifIndex) == 0) |
| break; |
| current[10] = ifIndex; |
| |
| if (current[6] == 3) { /* AT group oid */ |
| current[11] = 1; |
| op = current + 12; |
| } else { /* IP NetToMedia group oid */ |
| op = current + 11; |
| } |
| #else /* ARP_SCAN_FOUR_ARGUMENTS */ |
| if (ARP_Scan_Next(&Addr, PhysAddr, &PhysAddrLen, &ifType) == 0) |
| break; |
| current[10] = 1; |
| |
| if (current[6] == 3) { /* AT group oid */ |
| current[11] = 1; |
| op = current + 12; |
| } else { /* IP NetToMedia group oid */ |
| op = current + 11; |
| } |
| #endif /* ARP_SCAN_FOUR_ARGUMENTS */ |
| cp = (u_char *) & Addr; |
| *op++ = *cp++; |
| *op++ = *cp++; |
| *op++ = *cp++; |
| *op++ = *cp++; |
| |
| if (exact) { |
| if (snmp_oid_compare(current, oid_length, name, *length) == 0) { |
| memcpy((char *) lowest, (char *) current, |
| oid_length * sizeof(oid)); |
| LowAddr = Addr; |
| foundone = 1; |
| #ifdef ARP_SCAN_FOUR_ARGUMENTS |
| lowIfIndex = ifIndex; |
| #endif /* ARP_SCAN_FOUR_ARGUMENTS */ |
| memcpy(LowPhysAddr, PhysAddr, sizeof(PhysAddr)); |
| LowPhysAddrLen = PhysAddrLen; |
| lowIfType = ifType; |
| break; /* no need to search further */ |
| } |
| } else { |
| if ((snmp_oid_compare(current, oid_length, name, *length) > 0) |
| && ((foundone == 0) |
| || |
| (snmp_oid_compare |
| (current, oid_length, lowest, oid_length) < 0))) { |
| /* |
| * if new one is greater than input and closer to input than |
| * previous lowest, save this one as the "next" one. |
| */ |
| memcpy((char *) lowest, (char *) current, |
| oid_length * sizeof(oid)); |
| LowAddr = Addr; |
| foundone = 1; |
| #ifdef ARP_SCAN_FOUR_ARGUMENTS |
| lowIfIndex = ifIndex; |
| #endif /* ARP_SCAN_FOUR_ARGUMENTS */ |
| memcpy(LowPhysAddr, PhysAddr, sizeof(PhysAddr)); |
| LowPhysAddrLen = PhysAddrLen; |
| lowIfType = ifType; |
| } |
| } |
| } |
| if (foundone == 0) |
| return (NULL); |
| |
| memcpy((char *) name, (char *) lowest, oid_length * sizeof(oid)); |
| *length = oid_length; |
| *write_method = 0; |
| switch (vp->magic) { |
| case IPMEDIAIFINDEX: /* also ATIFINDEX */ |
| *var_len = sizeof long_return; |
| #ifdef ARP_SCAN_FOUR_ARGUMENTS |
| long_return = lowIfIndex; |
| #else /* ARP_SCAN_FOUR_ARGUMENTS */ |
| #if NETSNMP_NO_DUMMY_VALUES |
| return NULL; |
| #endif |
| long_return = 1; /* XXX */ |
| #endif /* ARP_SCAN_FOUR_ARGUMENTS */ |
| return (u_char *) & long_return; |
| case IPMEDIAPHYSADDRESS: /* also ATPHYSADDRESS */ |
| *var_len = LowPhysAddrLen; |
| return (u_char *) LowPhysAddr; |
| case IPMEDIANETADDRESS: /* also ATNETADDRESS */ |
| *var_len = sizeof(addr_ret); |
| addr_ret = LowAddr; |
| return (u_char *) & addr_ret; |
| case IPMEDIATYPE: |
| *var_len = sizeof long_return; |
| long_return = lowIfType; |
| return (u_char *) & long_return; |
| default: |
| DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_atEntry\n", |
| vp->magic)); |
| } |
| return NULL; |
| } |
| #else /* solaris2 */ |
| |
| typedef struct if_ip { |
| int ifIdx; |
| IpAddress ipAddr; |
| } if_ip_t; |
| |
| static int |
| AT_Cmp(void *addr, void *ep) |
| { |
| mib2_ipNetToMediaEntry_t *mp = (mib2_ipNetToMediaEntry_t *) ep; |
| int ret = -1; |
| oid index; |
| |
| #ifdef NETSNMP_INCLUDE_IFTABLE_REWRITES |
| mp->ipNetToMediaIfIndex.o_bytes[mp->ipNetToMediaIfIndex.o_length] = '\0'; |
| index = netsnmp_access_interface_index_find( |
| mp->ipNetToMediaIfIndex.o_bytes); |
| #else |
| index = Interface_Index_By_Name(mp->ipNetToMediaIfIndex.o_bytes, |
| mp->ipNetToMediaIfIndex.o_length); |
| #endif |
| DEBUGMSGTL(("mibII/at", "......... AT_Cmp %lx<>%lx %d<>%d (%.5s)\n", |
| mp->ipNetToMediaNetAddress, ((if_ip_t *) addr)->ipAddr, |
| ((if_ip_t *) addr)->ifIdx, index, |
| mp->ipNetToMediaIfIndex.o_bytes)); |
| if (mp->ipNetToMediaNetAddress != ((if_ip_t *) addr)->ipAddr) |
| ret = 1; |
| else if (((if_ip_t *) addr)->ifIdx != index) |
| ret = 1; |
| else |
| ret = 0; |
| DEBUGMSGTL(("mibII/at", "......... AT_Cmp returns %d\n", ret)); |
| return ret; |
| } |
| |
| u_char * |
| var_atEntry(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.3.1.1.1.interface.1.A.B.C.D, where A.B.C.D is IP address. |
| * Interface is at offset 10, |
| * IPADDR starts at offset 12. |
| */ |
| #define AT_MAX_NAME_LENGTH 16 |
| #define AT_IFINDEX_OFF 10 |
| u_char *cp; |
| oid *op; |
| oid lowest[AT_MAX_NAME_LENGTH]; |
| oid current[AT_MAX_NAME_LENGTH]; |
| if_ip_t NextAddr; |
| mib2_ipNetToMediaEntry_t entry; |
| static mib2_ipNetToMediaEntry_t Lowentry; |
| int Found = 0; |
| req_e req_type; |
| int offset, olength; |
| static in_addr_t addr_ret; |
| |
| /* |
| * fill in object part of name for current (less sizeof instance part) |
| */ |
| |
| DEBUGMSGTL(("mibII/at", "var_atEntry: ")); |
| DEBUGMSGOID(("mibII/at", vp->name, vp->namelen)); |
| DEBUGMSG(("mibII/at", " %d\n", exact)); |
| |
| memset(&Lowentry, 0, sizeof(Lowentry)); |
| memcpy((char *) current, (char *) vp->name, vp->namelen * sizeof(oid)); |
| lowest[0] = 1024; |
| for (NextAddr.ipAddr = (u_long) - 1, NextAddr.ifIdx = 255, req_type = |
| GET_FIRST;; |
| NextAddr.ipAddr = entry.ipNetToMediaNetAddress, NextAddr.ifIdx = |
| current[AT_IFINDEX_OFF], req_type = GET_NEXT) { |
| if (getMibstat |
| (MIB_IP_NET, &entry, sizeof(mib2_ipNetToMediaEntry_t), |
| req_type, &AT_Cmp, &NextAddr) != 0) |
| break; |
| #ifdef NETSNMP_INCLUDE_IFTABLE_REWRITES |
| entry.ipNetToMediaIfIndex.o_bytes[entry.ipNetToMediaIfIndex.o_length] = '\0'; |
| current[AT_IFINDEX_OFF] = netsnmp_access_interface_index_find( |
| entry.ipNetToMediaIfIndex.o_bytes); |
| #else |
| current[AT_IFINDEX_OFF] = |
| Interface_Index_By_Name(entry.ipNetToMediaIfIndex.o_bytes, |
| entry.ipNetToMediaIfIndex.o_length); |
| #endif |
| if (current[6] == 3) { /* AT group oid */ |
| current[AT_IFINDEX_OFF + 1] = 1; |
| offset = AT_IFINDEX_OFF + 2; |
| olength = AT_IFINDEX_OFF + 6; |
| } else { |
| offset = AT_IFINDEX_OFF + 1; |
| olength = AT_IFINDEX_OFF + 5; |
| } |
| COPY_IPADDR(cp, (u_char *) & entry.ipNetToMediaNetAddress, op, |
| current + offset); |
| if (exact) { |
| if (snmp_oid_compare(current, olength, name, *length) == 0) { |
| memcpy((char *) lowest, (char *) current, |
| olength * sizeof(oid)); |
| Lowentry = entry; |
| Found++; |
| break; /* no need to search further */ |
| } |
| } else { |
| if (snmp_oid_compare(current, olength, name, *length) > 0 |
| && snmp_oid_compare(current, olength, lowest, |
| *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, |
| olength * sizeof(oid)); |
| Lowentry = entry; |
| Found++; |
| } |
| } |
| } |
| DEBUGMSGTL(("mibII/at", "... Found = %d\n", Found)); |
| if (Found == 0) |
| return (NULL); |
| memcpy((char *) name, (char *) lowest, olength * sizeof(oid)); |
| *length = olength; |
| *write_method = 0; |
| switch (vp->magic) { |
| case IPMEDIAIFINDEX: |
| *var_len = sizeof long_return; |
| #ifdef NETSNMP_INCLUDE_IFTABLE_REWRITES |
| Lowentry.ipNetToMediaIfIndex.o_bytes[ |
| Lowentry.ipNetToMediaIfIndex.o_length] = '\0'; |
| long_return = netsnmp_access_interface_index_find( |
| Lowentry.ipNetToMediaIfIndex.o_bytes); |
| #else |
| long_return = Interface_Index_By_Name( |
| Lowentry.ipNetToMediaIfIndex.o_bytes, |
| Lowentry.ipNetToMediaIfIndex.o_length); |
| #endif |
| return (u_char *) & long_return; |
| case IPMEDIAPHYSADDRESS: |
| *var_len = Lowentry.ipNetToMediaPhysAddress.o_length; |
| return Lowentry.ipNetToMediaPhysAddress.o_bytes; |
| case IPMEDIANETADDRESS: |
| *var_len = sizeof(addr_ret); |
| addr_ret = Lowentry.ipNetToMediaNetAddress; |
| return (u_char *) &addr_ret; |
| case IPMEDIATYPE: |
| *var_len = sizeof long_return; |
| long_return = Lowentry.ipNetToMediaType; |
| return (u_char *) & long_return; |
| default: |
| DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_atEntry\n", |
| vp->magic)); |
| } |
| return NULL; |
| } |
| #endif /* solaris2 */ |
| |
| |
| /********************* |
| * |
| * Internal implementation functions |
| * |
| *********************/ |
| |
| #ifndef solaris2 |
| |
| static int arptab_size, arptab_current; |
| #if NETSNMP_CAN_USE_SYSCTL |
| static char *lim, *rtnext; |
| static char *at = 0; |
| #else |
| #ifdef STRUCT_ARPHD_HAS_AT_NEXT |
| static struct arphd *at = 0; |
| static struct arptab *at_ptr, at_entry; |
| static struct arpcom at_com; |
| #elif defined(hpux11) |
| static mib_ipNetToMediaEnt *at = (mib_ipNetToMediaEnt *) 0; |
| #else |
| |
| /* |
| * at used to be allocated every time we needed to look at the arp cache. |
| * This cause us to parse /proc/net/arp twice for each request and didn't |
| * allow us to filter things like we'd like to. So now we use it |
| * semi-statically. We initialize it to size 0 and if we need more room |
| * we realloc room for ARP_CACHE_INCR more entries in the table. |
| * We never release what we've taken . . . |
| */ |
| #define ARP_CACHE_INCR 1024 |
| static struct arptab *at = NULL; |
| static int arptab_curr_max_size = 0; |
| |
| #endif |
| #endif /* NETSNMP_CAN_USE_SYSCTL */ |
| |
| static void |
| ARP_Scan_Init(void) |
| { |
| #ifndef NETSNMP_CAN_USE_SYSCTL |
| #ifndef linux |
| #ifdef hpux11 |
| |
| int fd; |
| struct nmparms p; |
| int val; |
| unsigned int ulen; |
| int ret; |
| |
| if (at) |
| free(at); |
| at = (mib_ipNetToMediaEnt *) 0; |
| arptab_size = 0; |
| |
| if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) { |
| p.objid = ID_ipNetToMediaTableNum; |
| p.buffer = (void *) &val; |
| ulen = sizeof(int); |
| p.len = &ulen; |
| if ((ret = get_mib_info(fd, &p)) == 0) |
| arptab_size = val; |
| |
| if (arptab_size > 0) { |
| ulen = (unsigned) arptab_size *sizeof(mib_ipNetToMediaEnt); |
| at = (mib_ipNetToMediaEnt *) malloc(ulen); |
| memset(at, 0, ulen); |
| p.objid = ID_ipNetToMediaTable; |
| p.buffer = (void *) at; |
| p.len = &ulen; |
| if ((ret = get_mib_info(fd, &p)) < 0) |
| arptab_size = 0; |
| else |
| arptab_size = *p.len / sizeof(mib_ipNetToMediaEnt); |
| } |
| |
| close_mib(fd); |
| } |
| |
| arptab_current = 0; |
| |
| #else /* hpux11 */ |
| |
| if (!at) { |
| #ifdef ARPTAB_SIZE_SYMBOL |
| auto_nlist(ARPTAB_SIZE_SYMBOL, (char *) &arptab_size, |
| sizeof arptab_size); |
| #ifdef STRUCT_ARPHD_HAS_AT_NEXT |
| at = (struct arphd *) malloc(arptab_size * sizeof(struct arphd)); |
| #else |
| at = (struct arptab *) malloc(arptab_size * sizeof(struct arptab)); |
| #endif |
| #else |
| return; |
| #endif |
| } |
| #ifdef STRUCT_ARPHD_HAS_AT_NEXT |
| auto_nlist(ARPTAB_SYMBOL, (char *) at, |
| arptab_size * sizeof(struct arphd)); |
| at_ptr = at[0].at_next; |
| #else |
| auto_nlist(ARPTAB_SYMBOL, (char *) at, |
| arptab_size * sizeof(struct arptab)); |
| #endif |
| arptab_current = 0; |
| |
| #endif /* hpux11 */ |
| #else /* linux */ |
| |
| static time_t tm = 0; /* Time of last scan */ |
| FILE *in; |
| int i, j; |
| char line[128]; |
| int za, zb, zc, zd; |
| char ifname[21]; |
| char mac[3*MAX_MAC_ADDR_LEN+1]; |
| char *tok; |
| |
| arptab_current = 0; /* Anytime this is called we need to reset 'current' */ |
| |
| if (time(NULL) < tm + 1) { /*Our cool one second cache implementation :-) */ |
| return; |
| } |
| |
| in = fopen("/proc/net/arp", "r"); |
| if (!in) { |
| snmp_log(LOG_ERR, "snmpd: Cannot open /proc/net/arp\n"); |
| arptab_size = 0; |
| return; |
| } |
| |
| /* |
| * Get rid of the header line |
| */ |
| fgets(line, sizeof(line), in); |
| |
| i = 0; |
| while (fgets(line, sizeof(line), in)) { |
| u_long tmp_a; |
| int tmp_flags; |
| if (i >= arptab_curr_max_size) { |
| struct arptab *newtab = (struct arptab *) |
| realloc(at, (sizeof(struct arptab) * |
| (arptab_curr_max_size + ARP_CACHE_INCR))); |
| if (newtab == at) { |
| snmp_log(LOG_ERR, |
| "Error allocating more space for arpcache. " |
| "Cache will continue to be limited to %d entries", |
| arptab_curr_max_size); |
| break; |
| } else { |
| arptab_curr_max_size += ARP_CACHE_INCR; |
| at = newtab; |
| } |
| } |
| if (7 != |
| sscanf(line, |
| "%d.%d.%d.%d 0x%*x 0x%x %s %*[^ ] %20s\n", |
| &za, &zb, &zc, &zd, &tmp_flags, mac, ifname)) { |
| snmp_log(LOG_ERR, "Bad line in /proc/net/arp: %s", line); |
| continue; |
| } |
| /* |
| * Invalidated entries have their flag set to 0. |
| * * We want to ignore them |
| */ |
| if (tmp_flags == 0) { |
| continue; |
| } |
| ifname[sizeof(ifname)-1] = 0; /* make sure name is null terminated */ |
| at[i].at_flags = tmp_flags; |
| tmp_a = ((u_long) za << 24) | |
| ((u_long) zb << 16) | ((u_long) zc << 8) | ((u_long) zd); |
| at[i].at_iaddr.s_addr = htonl(tmp_a); |
| at[i].if_index = netsnmp_access_interface_index_find(ifname); |
| |
| for (j=0,tok=strtok(mac, ":"); tok != NULL; tok=strtok(NULL, ":"),j++) { |
| at[i].at_enaddr[j] = strtol(tok, NULL, 16); |
| } |
| at[i].at_enaddr_len = j; |
| i++; |
| } |
| arptab_size = i; |
| |
| fclose(in); |
| time(&tm); |
| #endif /* linux */ |
| #else /* NETSNMP_CAN_USE_SYSCTL */ |
| |
| int mib[6]; |
| size_t needed; |
| |
| mib[0] = CTL_NET; |
| mib[1] = PF_ROUTE; |
| mib[2] = 0; |
| mib[3] = AF_INET; |
| mib[4] = NET_RT_FLAGS; |
| #if defined RTF_LLINFO |
| mib[5] = RTF_LLINFO; |
| #else |
| mib[5] = 0; |
| #endif |
| |
| if (at) |
| free(at); |
| rtnext = lim = at = 0; |
| |
| if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) |
| snmp_log_perror("route-sysctl-estimate"); |
| else { |
| if ((at = malloc(needed ? needed : 1)) == NULL) |
| snmp_log_perror("malloc"); |
| else { |
| if (sysctl(mib, 6, at, &needed, NULL, 0) < 0) |
| snmp_log_perror("actual retrieval of routing table"); |
| else { |
| lim = at + needed; |
| rtnext = at; |
| } |
| } |
| } |
| |
| #endif /* NETSNMP_CAN_USE_SYSCTL */ |
| } |
| |
| #ifdef ARP_SCAN_FOUR_ARGUMENTS |
| static int |
| ARP_Scan_Next(in_addr_t * IPAddr, char *PhysAddr, int *PhysAddrLen, |
| u_long * ifType, u_short * ifIndex) |
| #else |
| static int |
| ARP_Scan_Next(in_addr_t * IPAddr, char *PhysAddr, int *PhysAddrLen, |
| u_long * ifType) |
| #endif |
| { |
| #ifndef NETSNMP_CAN_USE_SYSCTL |
| #ifdef linux |
| if (arptab_current < arptab_size) { |
| /* |
| * copy values |
| */ |
| *IPAddr = at[arptab_current].at_iaddr.s_addr; |
| *ifType = |
| (at[arptab_current]. |
| at_flags & ATF_PERM) ? 4 /*static */ : 3 /*dynamic */ ; |
| *ifIndex = at[arptab_current].if_index; |
| memcpy(PhysAddr, &at[arptab_current].at_enaddr, |
| sizeof(at[arptab_current].at_enaddr)); |
| *PhysAddrLen = at[arptab_current].at_enaddr_len; |
| |
| /* |
| * increment to point next entry |
| */ |
| arptab_current++; |
| /* |
| * return success |
| */ |
| return (1); |
| } |
| #elif defined(hpux11) |
| if (arptab_current < arptab_size) { |
| /* |
| * copy values |
| */ |
| *IPAddr = at[arptab_current].NetAddr; |
| memcpy(PhysAddr, at[arptab_current].PhysAddr.o_bytes, |
| at[arptab_current].PhysAddr.o_length); |
| *ifType = at[arptab_current].Type; |
| *ifIndex = at[arptab_current].IfIndex; |
| *PhysAddrLen = at[arptab_current].PhysAddr.o_length; |
| /* |
| * increment to point next entry |
| */ |
| arptab_current++; |
| /* |
| * return success |
| */ |
| return (1); |
| } |
| #elif !defined(ARP_SCAN_FOUR_ARGUMENTS) || defined(hpux) |
| register struct arptab *atab; |
| |
| while (arptab_current < arptab_size) { |
| #ifdef STRUCT_ARPHD_HAS_AT_NEXT |
| /* |
| * The arp table is an array of linked lists of arptab entries. |
| * Unused slots have pointers back to the array entry itself |
| */ |
| |
| if (at_ptr == (auto_nlist_value(ARPTAB_SYMBOL) + |
| arptab_current * sizeof(struct arphd))) { |
| /* |
| * Usused |
| */ |
| arptab_current++; |
| at_ptr = at[arptab_current].at_next; |
| continue; |
| } |
| |
| if (!NETSNMP_KLOOKUP(at_ptr, (char *) &at_entry, sizeof(struct arptab))) { |
| DEBUGMSGTL(("mibII/at:ARP_Scan_Next", "klookup failed\n")); |
| break; |
| } |
| |
| if (!NETSNMP_KLOOKUP(at_entry.at_ac, (char *) &at_com, sizeof(struct arpcom))) { |
| DEBUGMSGTL(("mibII/at:ARP_Scan_Next", "klookup failed\n")); |
| break; |
| } |
| |
| at_ptr = at_entry.at_next; |
| atab = &at_entry; |
| *ifIndex = at_com.ac_if.if_index; /* not strictly ARPHD */ |
| #else /* STRUCT_ARPHD_HAS_AT_NEXT */ |
| atab = &at[arptab_current++]; |
| #endif /* STRUCT_ARPHD_HAS_AT_NEXT */ |
| if (!(atab->at_flags & ATF_COM)) |
| continue; |
| *ifType = (atab->at_flags & ATF_PERM) ? 4 : 3; |
| *IPAddr = atab->at_iaddr.s_addr; |
| #if defined (sunV3) || defined(sparc) || defined(hpux) |
| memcpy(PhysAddr, (char *) &atab->at_enaddr, |
| sizeof(atab->at_enaddr)); |
| *PhysAddrLen = sizeof(atab->at_enaddr); |
| #endif |
| #if defined(mips) || defined(ibm032) |
| memcpy(PhysAddr, (char *) atab->at_enaddr, |
| sizeof(atab->at_enaddr)); |
| *PhysAddrLen = sizeof(atab->at_enaddr); |
| #endif |
| return (1); |
| } |
| #endif /* linux || hpux11 || !ARP_SCAN_FOUR_ARGUMENTS || hpux */ |
| |
| return 0; /* we need someone with an irix box to fix this section */ |
| |
| #else /* !NETSNMP_CAN_USE_SYSCTL */ |
| struct rt_msghdr *rtm; |
| struct sockaddr_inarp *sin; |
| struct sockaddr_dl *sdl; |
| |
| while (rtnext < lim) { |
| rtm = (struct rt_msghdr *) rtnext; |
| sin = (struct sockaddr_inarp *) (rtm + 1); |
| sdl = (struct sockaddr_dl *) (sin + 1); |
| rtnext += rtm->rtm_msglen; |
| if (sdl->sdl_alen) { |
| #ifdef irix6 |
| *IPAddr = sin->sarp_addr.s_addr; |
| #else |
| *IPAddr = sin->sin_addr.s_addr; |
| #endif |
| memcpy(PhysAddr, (char *) LLADDR(sdl), sdl->sdl_alen); |
| *PhysAddrLen = sdl->sdl_alen; |
| *ifIndex = sdl->sdl_index; |
| *ifType = 1; /* XXX */ |
| return (1); |
| } |
| } |
| return (0); /* "EOF" */ |
| #endif /* !NETSNMP_CAN_USE_SYSCTL */ |
| } |
| #endif /* solaris2 */ |
| |
| #else /* WIN32 cygwin */ |
| #include <iphlpapi.h> |
| |
| extern WriteMethod write_arp; |
| MIB_IPNETROW *arp_row = NULL; |
| int create_flag = 0; |
| |
| u_char * |
| var_atEntry(struct variable *vp, |
| oid * name, |
| size_t * length, |
| int exact, size_t * var_len, WriteMethod ** write_method) |
| { |
| /* |
| * Address Translation table object identifier is of form: |
| * 1.3.6.1.2.1.3.1.?.interface.1.A.B.C.D, where A.B.C.D is IP address. |
| * Interface is at offset 10, |
| * IPADDR starts at offset 12. |
| * |
| * IP Net to Media table object identifier is of form: |
| * 1.3.6.1.2.1.4.22.1.?.interface.A.B.C.D, where A.B.C.D is IP address. |
| * Interface is at offset 10, |
| * IPADDR starts at offset 11. |
| */ |
| u_char *cp; |
| oid *op; |
| oid lowest[16]; |
| oid current[16]; |
| int oid_length; |
| int lowState = -1; /* Don't have one yet */ |
| PMIB_IPNETTABLE pIpNetTable = NULL; |
| DWORD status = NO_ERROR; |
| DWORD dwActualSize = 0; |
| UINT i; |
| u_char dest_addr[4]; |
| void *result = NULL; |
| 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 (current[6] == 3) { /* AT group oid */ |
| oid_length = 16; |
| } else { /* IP NetToMedia group oid */ |
| oid_length = 15; |
| } |
| |
| status = GetIpNetTable(pIpNetTable, &dwActualSize, TRUE); |
| if (status == ERROR_INSUFFICIENT_BUFFER) { |
| pIpNetTable = malloc(dwActualSize); |
| if (pIpNetTable) |
| status = GetIpNetTable(pIpNetTable, &dwActualSize, TRUE); |
| } |
| |
| |
| if (status == NO_ERROR) { |
| for (i = 0; i < pIpNetTable->dwNumEntries; ++i) { |
| current[10] = pIpNetTable->table[i].dwIndex; |
| |
| |
| if (current[6] == 3) { /* AT group oid */ |
| current[11] = 1; |
| op = current + 12; |
| } else { /* IP NetToMedia group oid */ |
| op = current + 11; |
| } |
| cp = (u_char *) & pIpNetTable->table[i].dwAddr; |
| *op++ = *cp++; |
| *op++ = *cp++; |
| *op++ = *cp++; |
| *op++ = *cp++; |
| |
| if (exact) { |
| if (snmp_oid_compare(current, oid_length, name, *length) == |
| 0) { |
| memcpy((char *) lowest, (char *) current, |
| oid_length * sizeof(oid)); |
| lowState = 0; |
| break; /* no need to search further */ |
| } |
| } else { |
| if (snmp_oid_compare(current, oid_length, name, *length) > |
| 0) { |
| memcpy((char *) lowest, (char *) current, |
| oid_length * sizeof(oid)); |
| lowState = 0; |
| break; /* As the table is sorted, no need to search further */ |
| } |
| } |
| } |
| } |
| if (arp_row == NULL) { |
| /* |
| * Free allocated memory in case of SET request's FREE phase |
| */ |
| arp_row = (PMIB_IPNETROW) malloc(sizeof(MIB_IPNETROW)); |
| } |
| |
| if (lowState < 0 || status != NO_ERROR) { |
| /* |
| * for creation of new row, only ipNetToMediaTable case is considered |
| */ |
| if (*length == 15 || *length == 16) { |
| create_flag = 1; |
| *write_method = write_arp; |
| arp_row->dwIndex = name[10]; |
| |
| if (*length == 15) { /* ipNetToMediaTable */ |
| i = 11; |
| } else { /* at Table */ |
| |
| i = 12; |
| } |
| |
| dest_addr[0] = (u_char) name[i]; |
| dest_addr[1] = (u_char) name[i + 1]; |
| dest_addr[2] = (u_char) name[i + 2]; |
| dest_addr[3] = (u_char) name[i + 3]; |
| arp_row->dwAddr = *((DWORD *) dest_addr); |
| |
| arp_row->dwType = 4; /* Static */ |
| arp_row->dwPhysAddrLen = 0; |
| } |
| goto out; |
| } |
| |
| create_flag = 0; |
| memcpy((char *) name, (char *) lowest, oid_length * sizeof(oid)); |
| *length = oid_length; |
| *write_method = write_arp; |
| *arp_row = pIpNetTable->table[i]; |
| |
| switch (vp->magic) { |
| case IPMEDIAIFINDEX: /* also ATIFINDEX */ |
| *var_len = sizeof long_return; |
| long_return = pIpNetTable->table[i].dwIndex; |
| result = &long_return; |
| break; |
| case IPMEDIAPHYSADDRESS: /* also ATPHYSADDRESS */ |
| *var_len = pIpNetTable->table[i].dwPhysAddrLen; |
| memcpy(return_buf, pIpNetTable->table[i].bPhysAddr, *var_len); |
| result = return_buf; |
| break; |
| case IPMEDIANETADDRESS: /* also ATNETADDRESS */ |
| *var_len = sizeof(addr_ret); |
| addr_ret = pIpNetTable->table[i].dwAddr; |
| result = &addr_ret; |
| break; |
| case IPMEDIATYPE: |
| *var_len = sizeof long_return; |
| long_return = pIpNetTable->table[i].dwType; |
| result = &long_return; |
| break; |
| default: |
| DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_atEntry\n", |
| vp->magic)); |
| break; |
| } |
| out: |
| free(pIpNetTable); |
| return result; |
| } |
| |
| int |
| write_arp(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, u_char * statP, oid * name, size_t length) |
| { |
| int var, retval = SNMP_ERR_NOERROR; |
| static PMIB_IPNETROW oldarp_row = NULL; |
| MIB_IPNETROW temp_row; |
| DWORD status = NO_ERROR; |
| |
| /* |
| * IP Net to Media table object identifier is of form: |
| * 1.3.6.1.2.1.4.22.1.?.interface.A.B.C.D, where A.B.C.D is IP address. |
| * Interface is at offset 10, |
| * IPADDR starts at offset 11. |
| */ |
| |
| if (name[6] == 3) { /* AT group oid */ |
| if (length != 16) { |
| snmp_log(LOG_ERR, "length error\n"); |
| return SNMP_ERR_NOCREATION; |
| } |
| } else { /* IP NetToMedia group oid */ |
| if (length != 15) { |
| snmp_log(LOG_ERR, "length error\n"); |
| return SNMP_ERR_NOCREATION; |
| } |
| } |
| |
| |
| /* |
| * #define for ipNetToMediaTable entries are 1 less than corresponding sub-id in MIB |
| * * i.e. IPMEDIAIFINDEX defined as 0, but ipNetToMediaIfIndex registered as 1 |
| */ |
| var = name[9] - 1; |
| switch (action) { |
| case RESERVE1: |
| switch (var) { |
| case IPMEDIAIFINDEX: |
| if (var_val_type != ASN_INTEGER) { |
| snmp_log(LOG_ERR, "not integer\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| if ((*((int *) var_val)) < 0) { |
| snmp_log(LOG_ERR, "invalid media ifIndex"); |
| return SNMP_ERR_WRONGVALUE; |
| } |
| if (var_val_len > sizeof(int)) { |
| snmp_log(LOG_ERR, "bad length\n"); |
| return SNMP_ERR_WRONGLENGTH; |
| } |
| break; |
| case IPMEDIANETADDRESS: |
| if (var_val_type != ASN_IPADDRESS) { |
| snmp_log(LOG_ERR, "not IP Address\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| if ((*((int *) var_val)) < 0) { |
| snmp_log(LOG_ERR, "invalid media net address"); |
| return SNMP_ERR_WRONGVALUE; |
| } |
| if (var_val_len > sizeof(DWORD)) { |
| snmp_log(LOG_ERR, "bad length\n"); |
| return SNMP_ERR_WRONGLENGTH; |
| } |
| break; |
| case IPMEDIATYPE: |
| if (var_val_type != ASN_INTEGER) { |
| snmp_log(LOG_ERR, "not integer\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| if ((*((int *) var_val)) < 1 || (*((int *) var_val)) > 4) { |
| snmp_log(LOG_ERR, "invalid media type"); |
| return SNMP_ERR_WRONGVALUE; |
| } |
| if (var_val_len > sizeof(int)) { |
| snmp_log(LOG_ERR, "bad length\n"); |
| return SNMP_ERR_WRONGLENGTH; |
| } |
| break; |
| case IPMEDIAPHYSADDRESS: |
| if (var_val_type != ASN_OCTET_STR) { |
| snmp_log(LOG_ERR, "not octet str"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| if (var_val_len != 6) { |
| snmp_log(LOG_ERR, "not correct ipAddress length: %d", |
| var_val_len); |
| return SNMP_ERR_WRONGLENGTH; |
| } |
| break; |
| default: |
| DEBUGMSGTL(("snmpd", "unknown sub-id %d in write_rte\n", |
| var + 1)); |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| break; |
| case RESERVE2: |
| /* |
| * Save the old value, in case of UNDO |
| */ |
| if (oldarp_row == NULL) { |
| oldarp_row = (PMIB_IPNETROW) malloc(sizeof(MIB_IPNETROW)); |
| *oldarp_row = *arp_row; |
| } |
| break; |
| case ACTION: /* Perform the SET action (if reversible) */ |
| switch (var) { |
| |
| case IPMEDIAIFINDEX: |
| temp_row = *arp_row; |
| arp_row->dwIndex = *((int *) var_val); |
| /* |
| * In case of new entry, physical address is mandatory. |
| * * SetIpNetEntry will be done in COMMIT case |
| */ |
| if (!create_flag) { |
| if (SetIpNetEntry(arp_row) != NO_ERROR) { |
| arp_row->dwIndex = temp_row.dwIndex; |
| retval = SNMP_ERR_COMMITFAILED; |
| } |
| /* |
| * Don't know yet, whether change in ifIndex creates new row or not |
| */ |
| /* |
| * else{ |
| */ |
| /* |
| * temp_row.dwType = 2; |
| */ |
| /* |
| * if(SetIpNetEntry(&temp_row) != NO_ERROR) |
| */ |
| /* |
| * retval = SNMP_ERR_COMMITFAILED; |
| */ |
| /* |
| * } |
| */ |
| } |
| break; |
| case IPMEDIANETADDRESS: |
| temp_row = *arp_row; |
| arp_row->dwAddr = *((int *) var_val); |
| if (!create_flag) { |
| if (SetIpNetEntry(arp_row) != NO_ERROR) { |
| arp_row->dwAddr = oldarp_row->dwAddr; |
| retval = SNMP_ERR_COMMITFAILED; |
| } else { |
| temp_row.dwType = 2; |
| if (SetIpNetEntry(&temp_row) != NO_ERROR) { |
| snmp_log(LOG_ERR, |
| "Failed in ACTION, while deleting old row \n"); |
| retval = SNMP_ERR_COMMITFAILED; |
| } |
| } |
| } |
| break; |
| case IPMEDIATYPE: |
| arp_row->dwType = *((int *) var_val); |
| if (!create_flag) { |
| if (SetIpNetEntry(arp_row) != NO_ERROR) |
| retval = SNMP_ERR_COMMITFAILED; |
| } |
| break; |
| case IPMEDIAPHYSADDRESS: |
| memcpy(arp_row->bPhysAddr, var_val, var_val_len); |
| arp_row->dwPhysAddrLen = var_val_len; |
| if (!create_flag) { |
| if (SetIpNetEntry(arp_row) != NO_ERROR) |
| retval = SNMP_ERR_COMMITFAILED; |
| } |
| break; |
| default: |
| DEBUGMSGTL(("snmpd", "unknown sub-id %d in write_arp\n", |
| var + 1)); |
| retval = SNMP_ERR_NOTWRITABLE; |
| } |
| return retval; |
| case UNDO: |
| /* |
| * Reverse the SET action and free resources |
| */ |
| if (oldarp_row != NULL) { |
| /* |
| * UNDO the changes done for existing entry. |
| */ |
| if (!create_flag) { |
| if ((status = SetIpNetEntry(oldarp_row)) != NO_ERROR) { |
| snmp_log(LOG_ERR, "Error in case UNDO, status : %lu\n", |
| status); |
| retval = SNMP_ERR_UNDOFAILED; |
| } |
| } |
| |
| if (oldarp_row->dwAddr != arp_row->dwAddr) { |
| arp_row->dwType = 2; /*If row was added/created delete that row */ |
| |
| if ((status = SetIpNetEntry(arp_row)) != NO_ERROR) { |
| snmp_log(LOG_ERR, |
| "Error while deleting added row, status : %lu\n", |
| status); |
| retval = SNMP_ERR_UNDOFAILED; |
| } |
| } |
| free(oldarp_row); |
| oldarp_row = NULL; |
| free(arp_row); |
| arp_row = NULL; |
| return retval; |
| } |
| break; |
| case COMMIT: |
| /* |
| * if new entry and physical address specified, create new entry |
| */ |
| if (create_flag) { |
| if (arp_row->dwPhysAddrLen != 0) { |
| if ((status = CreateIpNetEntry(arp_row)) != NO_ERROR) { |
| snmp_log(LOG_ERR, |
| "Inside COMMIT: CreateIpNetEntry failed, status %lu\n", |
| status); |
| retval = SNMP_ERR_COMMITFAILED; |
| } |
| } else { |
| /* |
| * For new entry, physical address must be set. |
| */ |
| snmp_log(LOG_ERR, |
| "Can't create new entry without physical address\n"); |
| retval = SNMP_ERR_WRONGVALUE; |
| } |
| /* |
| * unset the create_flag, so that CreateIpNetEntry called only once |
| */ |
| create_flag = 0; |
| } |
| |
| case FREE: |
| /* |
| * Free any resources allocated |
| */ |
| free(oldarp_row); |
| oldarp_row = NULL; |
| free(arp_row); |
| arp_row = NULL; |
| break; |
| } |
| return retval; |
| } |
| #endif /* WIN32 cygwin */ |