| /* |
| * Interface MIB architecture support |
| * |
| * $Id$ |
| */ |
| #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 |