diff options
Diffstat (limited to 'agent/mibgroup/ip-mib/data_access/ipaddress_linux.c')
-rw-r--r-- | agent/mibgroup/ip-mib/data_access/ipaddress_linux.c | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/agent/mibgroup/ip-mib/data_access/ipaddress_linux.c b/agent/mibgroup/ip-mib/data_access/ipaddress_linux.c new file mode 100644 index 0000000..dea1a52 --- /dev/null +++ b/agent/mibgroup/ip-mib/data_access/ipaddress_linux.c @@ -0,0 +1,342 @@ +/* + * Interface MIB architecture support + * + * $Id: ipaddress_linux.c 18009 2010-01-21 14:55:34Z jsafranek $ + */ +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-includes.h> +#include "mibII/mibII_common.h" + +#include <net-snmp/agent/net-snmp-agent-includes.h> +#include <net-snmp/data_access/ipaddress.h> +#include <net-snmp/data_access/interface.h> + +#include "ip-mib/ipAddressTable/ipAddressTable_constants.h" + +#include <errno.h> +#include <sys/ioctl.h> + +#if defined (NETSNMP_ENABLE_IPV6) +#include <linux/types.h> +#include <asm/types.h> +#include <linux/rtnetlink.h> +#endif + +#include "ipaddress_ioctl.h" + +int _load_v6(netsnmp_container *container, int idx_offset); + +/* + * initialize arch specific storage + * + * @retval 0: success + * @retval <0: error + */ +int +netsnmp_arch_ipaddress_entry_init(netsnmp_ipaddress_entry *entry) +{ + /* + * init ipv4 stuff + */ + if (NULL == netsnmp_ioctl_ipaddress_entry_init(entry)) + return -1; + + /* + * init ipv6 stuff + * so far, we can just share the ipv4 stuff, so nothing to do + */ + + return 0; +} + +/* + * cleanup arch specific storage + */ +void +netsnmp_arch_ipaddress_entry_cleanup(netsnmp_ipaddress_entry *entry) +{ + /* + * cleanup ipv4 stuff + */ + netsnmp_ioctl_ipaddress_entry_cleanup(entry); + + /* + * cleanup ipv6 stuff + * so far, we can just share the ipv4 stuff, so nothing to do + */ +} + +/* + * copy arch specific storage + */ +int +netsnmp_arch_ipaddress_entry_copy(netsnmp_ipaddress_entry *lhs, + netsnmp_ipaddress_entry *rhs) +{ + int rc; + + /* + * copy ipv4 stuff + */ + rc = netsnmp_ioctl_ipaddress_entry_copy(lhs, rhs); + if (rc) + return rc; + + /* + * copy ipv6 stuff + * so far, we can just share the ipv4 stuff, so nothing to do + */ + + return rc; +} + +/* + * create a new entry + */ +int +netsnmp_arch_ipaddress_create(netsnmp_ipaddress_entry *entry) +{ + if (NULL == entry) + return -1; + + if (4 != entry->ia_address_len) { + DEBUGMSGT(("access:ipaddress:create", "only ipv4 supported\n")); + return -2; + } + + return _netsnmp_ioctl_ipaddress_set_v4(entry); +} + +/* + * create a new entry + */ +int +netsnmp_arch_ipaddress_delete(netsnmp_ipaddress_entry *entry) +{ + if (NULL == entry) + return -1; + + if (4 != entry->ia_address_len) { + DEBUGMSGT(("access:ipaddress:create", "only ipv4 supported\n")); + return -2; + } + + return _netsnmp_ioctl_ipaddress_delete_v4(entry); +} + +/** + * + * @retval 0 no errors + * @retval !0 errors + */ +int +netsnmp_arch_ipaddress_container_load(netsnmp_container *container, + u_int load_flags) +{ + int rc = 0, idx_offset = 0; + + if (0 == (load_flags & NETSNMP_ACCESS_IPADDRESS_LOAD_IPV6_ONLY)) { + rc = _netsnmp_ioctl_ipaddress_container_load_v4(container, idx_offset); + if(rc < 0) { + u_int flags = NETSNMP_ACCESS_IPADDRESS_FREE_KEEP_CONTAINER; + netsnmp_access_ipaddress_container_free(container, flags); + } + } + +#if defined (NETSNMP_ENABLE_IPV6) + + if (0 == (load_flags & NETSNMP_ACCESS_IPADDRESS_LOAD_IPV4_ONLY)) { + if (rc < 0) + rc = 0; + + idx_offset = rc; + + /* + * load ipv6, ignoring errors if file not found + */ + rc = _load_v6(container, idx_offset); + if (-2 == rc) + rc = 0; + else if(rc < 0) { + u_int flags = NETSNMP_ACCESS_IPADDRESS_FREE_KEEP_CONTAINER; + netsnmp_access_ipaddress_container_free(container, flags); + } + } +#endif + + /* + * return no errors (0) if we found any interfaces + */ + if(rc > 0) + rc = 0; + + return rc; +} + +#if defined (NETSNMP_ENABLE_IPV6) +/** + */ +int +_load_v6(netsnmp_container *container, int idx_offset) +{ + FILE *in; + char line[80], addr[40]; + char if_name[IFNAMSIZ+1];/* +1 for '\0' because of the ugly sscanf below */ + u_char *buf; + int if_index, pfx_len, scope, flags, rc = 0; + size_t in_len, out_len; + netsnmp_ipaddress_entry *entry; + _ioctl_extras *extras; + static int log_open_err = 1; + + netsnmp_assert(NULL != container); + +#define PROCFILE "/proc/net/if_inet6" + if (!(in = fopen(PROCFILE, "r"))) { + if (1 == log_open_err) { + snmp_log(LOG_ERR,"could not open " PROCFILE "\n"); + log_open_err = 0; + } + return -2; + } + /* + * if we hadn't been able to open file and turned of err logging, + * turn it back on now that we opened the file. + */ + if (0 == log_open_err) + log_open_err = 1; + + /* + * address index prefix_len scope status if_name + */ + while (fgets(line, sizeof(line), in)) { + /* + * fe800000000000000200e8fffe5b5c93 05 40 20 80 eth0 + * A D P S F I + * A: address + * D: device number + * P: prefix len + * S: scope (see include/net/ipv6.h, net/ipv6/addrconf.c) + * F: flags (see include/linux/rtnetlink.h, net/ipv6/addrconf.c) + * I: interface + */ + rc = sscanf(line, "%39s %08x %08x %04x %02x %" SNMP_MACRO_VAL_TO_STR(IFNAMSIZ) "s\n", + addr, &if_index, &pfx_len, &scope, &flags, if_name); + if( 6 != rc ) { + snmp_log(LOG_ERR, PROCFILE " data format error (%d!=6), line ==|%s|\n", + rc, line); + continue; + } + DEBUGMSGTL(("access:ipaddress:container", + "addr %s, index %d, pfx %d, scope %d, flags 0x%X, name %s\n", + addr, if_index, pfx_len, scope, flags, if_name)); + /* + */ + entry = netsnmp_access_ipaddress_entry_create(); + if(NULL == entry) { + rc = -3; + break; + } + + in_len = entry->ia_address_len = sizeof(entry->ia_address); + netsnmp_assert(16 == in_len); + out_len = 0; + buf = entry->ia_address; + if(1 != netsnmp_hex_to_binary(&buf, &in_len, + &out_len, 0, addr, ":")) { + snmp_log(LOG_ERR,"error parsing '%s', skipping\n", + entry->ia_address); + netsnmp_access_ipaddress_entry_free(entry); + continue; + } + netsnmp_assert(16 == out_len); + entry->ia_address_len = out_len; + + entry->ns_ia_index = ++idx_offset; + + /* + * save if name + */ + extras = netsnmp_ioctl_ipaddress_extras_get(entry); + memcpy(extras->name, if_name, sizeof(extras->name)); + extras->flags = flags; + + /* + * yyy-rks: optimization: create a socket outside the loop and use + * netsnmp_access_interface_ioctl_ifindex_get() here, since + * netsnmp_access_interface_index_find will open/close a socket + * every time it is called. + */ + entry->if_index = netsnmp_access_interface_index_find(if_name); + + /* + #define IPADDRESSSTATUSTC_PREFERRED 1 + #define IPADDRESSSTATUSTC_DEPRECATED 2 + #define IPADDRESSSTATUSTC_INVALID 3 + #define IPADDRESSSTATUSTC_INACCESSIBLE 4 + #define IPADDRESSSTATUSTC_UNKNOWN 5 + #define IPADDRESSSTATUSTC_TENTATIVE 6 + #define IPADDRESSSTATUSTC_DUPLICATE 7 + */ + if(flags & IFA_F_PERMANENT) + entry->ia_status = IPADDRESSSTATUSTC_PREFERRED; /* ?? */ + else if(flags & IFA_F_DEPRECATED) + entry->ia_status = IPADDRESSSTATUSTC_DEPRECATED; + else if(flags & IFA_F_TENTATIVE) + entry->ia_status = IPADDRESSSTATUSTC_TENTATIVE; + else { + entry->ia_status = IPADDRESSSTATUSTC_UNKNOWN; + DEBUGMSGTL(("access:ipaddress:ipv6", + "unknown flags 0x%x\n", flags)); + } + + /* + * if it's not multi, it must be uni. + * (an ipv6 address is never broadcast) + */ + if (IN6_IS_ADDR_MULTICAST(entry->ia_address)) + entry->ia_type = IPADDRESSTYPE_ANYCAST; + else + entry->ia_type = IPADDRESSTYPE_UNICAST; + + + entry->ia_prefix_len = pfx_len; + + /* + * can we figure out if an address is from DHCP? + * use manual until then... + * + *#define IPADDRESSORIGINTC_OTHER 1 + *#define IPADDRESSORIGINTC_MANUAL 2 + *#define IPADDRESSORIGINTC_DHCP 4 + *#define IPADDRESSORIGINTC_LINKLAYER 5 + *#define IPADDRESSORIGINTC_RANDOM 6 + * + * are 'local' address assigned by link layer?? + */ + if (IN6_IS_ADDR_LINKLOCAL(entry->ia_address) || + IN6_IS_ADDR_SITELOCAL(entry->ia_address)) + entry->ia_origin = IPADDRESSORIGINTC_LINKLAYER; + else + entry->ia_origin = IPADDRESSORIGINTC_MANUAL; + + /* xxx-rks: what can we do with scope? */ + + /* + * add entry to container + */ + if (CONTAINER_INSERT(container, entry) < 0) { + DEBUGMSGTL(("access:ipaddress:container","error with ipaddress_entry: insert into container failed.\n")); + netsnmp_access_ipaddress_entry_free(entry); + continue; + } + } + + fclose(in); + + if(rc<0) + return rc; + + return idx_offset; +} +#endif |