| /* |
| * Interface MIB architecture support |
| * |
| * $Id$ |
| */ |
| #include <net-snmp/net-snmp-config.h> |
| #include <net-snmp/net-snmp-features.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 "ip-mib/ipAddressPrefixTable/ipAddressPrefixTable_constants.h" |
| #include "mibgroup/util_funcs.h" |
| |
| #include <errno.h> |
| #include <sys/ioctl.h> |
| #include <arpa/inet.h> |
| |
| netsnmp_feature_require(prefix_info) |
| netsnmp_feature_require(find_prefix_info) |
| |
| netsnmp_feature_child_of(ipaddress_arch_entry_copy, ipaddress_common) |
| |
| #ifdef NETSNMP_FEATURE_REQUIRE_IPADDRESS_ARCH_ENTRY_COPY |
| netsnmp_feature_require(ipaddress_ioctl_entry_copy) |
| #endif /* NETSNMP_FEATURE_REQUIRE_IPADDRESS_ARCH_ENTRY_COPY */ |
| |
| #include "ipaddress_ioctl.h" |
| #ifdef SUPPORT_PREFIX_FLAGS |
| extern prefix_cbx *prefix_head_list; |
| #endif |
| |
| #define ROUNDUP(a) \ |
| ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) |
| |
| /* |
| * 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 |
| */ |
| } |
| |
| #ifndef NETSNMP_FEATURE_REMOVE_IPADDRESS_ARCH_ENTRY_COPY |
| /* |
| * copy arch specific storage |
| */ |
| int |
| netsnmp_arch_ipaddress_entry_copy(netsnmp_ipaddress_entry *lhs, |
| netsnmp_ipaddress_entry *rhs) |
| { |
| int rc; |
| |
| rc = 0; |
| |
| /* |
| * 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; |
| } |
| #endif /* NETSNMP_FEATURE_REMOVE_IPADDRESS_ARCH_ENTRY_COPY */ |
| |
| /* |
| * create a new entry |
| */ |
| int |
| netsnmp_arch_ipaddress_create(netsnmp_ipaddress_entry *entry) |
| { |
| if (NULL == entry) |
| return -1; |
| |
| if (4 == entry->ia_address_len) { |
| return -1; |
| } else if (16 == entry->ia_address_len) { |
| return -1; |
| } else { |
| DEBUGMSGT(("access:ipaddress:create", "wrong length of IP address\n")); |
| return -2; |
| } |
| } |
| |
| /* |
| * create a new entry |
| */ |
| int |
| netsnmp_arch_ipaddress_delete(netsnmp_ipaddress_entry *entry) |
| { |
| if (NULL == entry) |
| return -1; |
| |
| if (4 == entry->ia_address_len) { |
| return -2; |
| } else if (16 == entry->ia_address_len) { |
| return -3; |
| } else { |
| DEBUGMSGT(("access:ipaddress:create", "only ipv4 supported\n")); |
| return -2; |
| } |
| } |
| |
| /** |
| * |
| * @retval 0 no errors |
| * @retval !0 errors |
| */ |
| int |
| netsnmp_arch_ipaddress_container_load(netsnmp_container *container, |
| u_int load_flags) |
| { |
| netsnmp_ipaddress_entry *entry = NULL; |
| u_char *if_list = NULL, *cp; |
| size_t if_list_size = 0; |
| int sysctl_oid[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; |
| struct ifa_msghdr *ifa; |
| struct sockaddr *a; |
| int amask; |
| int rc = 0; |
| int idx_offset = 0; |
| |
| DEBUGMSGTL(("access:ipaddress:container:sysctl", |
| "load (flags %u)\n", load_flags)); |
| |
| if (NULL == container) { |
| snmp_log(LOG_ERR, "no container specified/found for interface\n"); |
| return -1; |
| } |
| |
| if (sysctl(sysctl_oid, sizeof(sysctl_oid)/sizeof(int), 0, |
| &if_list_size, 0, 0) == -1) { |
| snmp_log(LOG_ERR, "could not get interface info (size)\n"); |
| return -2; |
| } |
| |
| if_list = (u_char*)malloc(if_list_size); |
| if (if_list == NULL) { |
| snmp_log(LOG_ERR, "could not allocate memory for interface info " |
| "(%zu bytes)\n", if_list_size); |
| return -3; |
| } else { |
| DEBUGMSGTL(("access:ipaddress:container:sysctl", |
| "allocated %zu bytes for if_list\n", if_list_size)); |
| } |
| |
| if (sysctl(sysctl_oid, sizeof(sysctl_oid)/sizeof(int), if_list, |
| &if_list_size, 0, 0) == -1) { |
| snmp_log(LOG_ERR, "could not get interface info\n"); |
| free(if_list); |
| return -2; |
| } |
| |
| /* pass 2: walk addresses */ |
| for (cp = if_list; cp < if_list + if_list_size; cp += ifa->ifam_msglen) { |
| ifa = (struct ifa_msghdr *) cp; |
| int rtax; |
| |
| if (ifa->ifam_type != RTM_NEWADDR) |
| continue; |
| |
| DEBUGMSGTL(("access:ipaddress:container:sysctl", |
| "received 0x%x in RTM_NEWADDR for ifindex %u\n", |
| ifa->ifam_addrs, ifa->ifam_index)); |
| |
| entry = netsnmp_access_ipaddress_entry_create(); |
| if (entry == NULL) { |
| rc = -3; |
| break; |
| } |
| |
| a = (struct sockaddr *) (ifa + 1); |
| entry->ia_status = IPADDRESSSTATUSTC_UNKNOWN; |
| entry->ia_origin = IPADDRESSORIGINTC_OTHER; |
| entry->ia_address_len = 0; |
| for (amask = ifa->ifam_addrs, rtax = 0; amask != 0; amask >>= 1, rtax++) { |
| if ((amask & 1) != 0) { |
| entry->ns_ia_index = ++idx_offset; |
| entry->if_index = ifa->ifam_index; |
| DEBUGMSGTL(("access:ipaddress:container:sysctl", |
| "%d: a=%p, sa_len=%d, sa_family=0x%x\n", |
| (int)entry->if_index, a, a->sa_len, a->sa_family)); |
| |
| if (a->sa_family == AF_INET || a->sa_family == 0) { |
| struct sockaddr_in *a4 = (struct sockaddr_in *)a; |
| char str[128]; |
| DEBUGMSGTL(("access:ipaddress:container:sysctl", |
| "IPv4 addr %s\n", inet_ntop(AF_INET, &a4->sin_addr.s_addr, str, 128))); |
| if (rtax == RTAX_IFA) { |
| entry->ia_address_len = 4; |
| memcpy(entry->ia_address, &a4->sin_addr.s_addr, entry->ia_address_len); |
| } |
| else if (rtax == RTAX_NETMASK) |
| entry->ia_prefix_len = netsnmp_ipaddress_ipv4_prefix_len(a4->sin_addr.s_addr); |
| } |
| else if (a->sa_family == AF_INET6) { |
| struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)a; |
| char str[128]; |
| DEBUGMSGTL(("access:ipaddress:container:sysctl", |
| "IPv6 addr %s\n", inet_ntop(AF_INET6, &a6->sin6_addr.s6_addr, str, 128))); |
| if (rtax == RTAX_IFA) { |
| entry->ia_address_len = 16; |
| memcpy(entry->ia_address, &a6->sin6_addr, entry->ia_address_len); |
| } |
| else if (rtax == RTAX_NETMASK) { |
| entry->ia_prefix_len = netsnmp_ipaddress_ipv6_prefix_len(a6->sin6_addr); |
| DEBUGMSGTL(("access:ipaddress:container:sysctl", |
| "prefix_len=%d\n", entry->ia_prefix_len)); |
| } |
| } |
| a = (struct sockaddr *) ( ((char *) a) + ROUNDUP(a->sa_len) ); |
| } |
| } |
| if (entry->ia_address_len == 0) { |
| DEBUGMSGTL(("access:ipaddress:container:sysctl", |
| "entry skipped\n")); |
| netsnmp_access_ipaddress_entry_free(entry); |
| } |
| else 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; |
| } |
| } |
| |
| if (if_list != NULL) |
| free(if_list); |
| |
| return 0; |
| } |