net-snmp/Fix-for-Internet-Address-Table.patch

406 lines
15 KiB
Diff

From 12cb1f471833a7e145bdf7cb4d471d0bd74d73f0 Mon Sep 17 00:00:00 2001
From: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
Date: Mon, 20 Oct 2008 16:08:06 +0900
Subject: [PATCH] Fix for Internet Address Table
From net-snmp patch tracker:
[ 1692817 ] ipAddressTable fixes
http://sourceforge.net/tracker/index.php?func=detail&aid=1692817&group_id=12694&atid=312694
[ 1712645 ] meaningful log message on duplicate IP address
http://sourceforge.net/tracker/index.php?func=detail&aid=1712645&group_id=12694&atid=312694
[ 1810660 ] Fix broadcast addresses in ipAddressTable on 64 bit
linux
http://sourceforge.net/tracker/index.php?func=detail&aid=1810660&group_id=12694&atid=312694
Signed-off-by: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
---
.../mibgroup/ip-mib/data_access/ipaddress_ioctl.c | 63 +++++++++-
.../mibgroup/ip-mib/data_access/ipaddress_ioctl.h | 13 ++
.../mibgroup/ip-mib/data_access/ipaddress_linux.c | 121 ++++++++++++++++++--
.../ip-mib/ipAddressTable/ipAddressTable.c | 5 +-
include/net-snmp/library/container.h | 2 +-
snmplib/container.c | 2 +-
6 files changed, 189 insertions(+), 17 deletions(-)
diff --git a/agent/mibgroup/ip-mib/data_access/ipaddress_ioctl.c b/agent/mibgroup/ip-mib/data_access/ipaddress_ioctl.c
index d5e78f0..085653d 100644
--- a/agent/mibgroup/ip-mib/data_access/ipaddress_ioctl.c
+++ b/agent/mibgroup/ip-mib/data_access/ipaddress_ioctl.c
@@ -135,7 +135,9 @@ _netsnmp_ioctl_ipaddress_container_load_v4(netsnmp_container *container,
struct ifreq *ifrp;
struct sockaddr save_addr;
struct sockaddr_in * si;
- netsnmp_ipaddress_entry *entry;
+ netsnmp_ipaddress_entry *entry, *bcastentry;
+ struct address_flag_info addr_info;
+ in_addr_t ipval;
_ioctl_extras *extras;
if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
@@ -184,6 +186,7 @@ _netsnmp_ioctl_ipaddress_container_load_v4(netsnmp_container *container,
netsnmp_assert(AF_INET == ifrp->ifr_addr.sa_family);
si = (struct sockaddr_in *) &ifrp->ifr_addr;
entry->ia_address_len = sizeof(si->sin_addr.s_addr);
+ ipval = si->sin_addr.s_addr;
memcpy(entry->ia_address, &si->sin_addr.s_addr,
entry->ia_address_len);
@@ -220,6 +223,26 @@ _netsnmp_ioctl_ipaddress_container_load_v4(netsnmp_container *container,
}
/*
+ * get broadcast
+ */
+ memset(&addr_info, 0, sizeof(struct address_flag_info));
+#if defined (NETSNMP_ENABLE_IPV6)
+ addr_info = netsnmp_access_other_info_get(entry->if_index, AF_INET);
+ if(addr_info.bcastflg) {
+ bcastentry = netsnmp_access_ipaddress_entry_create();
+ if(NULL == entry) {
+ rc = -3;
+ break;
+ }
+ bcastentry->if_index = entry->if_index;
+ bcastentry->ns_ia_index = ++idx_offset;
+ bcastentry->ia_address_len = sizeof(addr_info.inp->s_addr);
+ memcpy(bcastentry->ia_address, &addr_info.inp->s_addr,
+ bcastentry->ia_address_len);
+ }
+#endif
+
+ /*
* get netmask
*/
ifrp->ifr_addr = save_addr;
@@ -232,7 +255,10 @@ _netsnmp_ioctl_ipaddress_container_load_v4(netsnmp_container *container,
netsnmp_assert(AF_INET == ifrp->ifr_addr.sa_family);
si = (struct sockaddr_in *) &ifrp->ifr_addr;
entry->ia_prefix_len =
- netsnmp_ipaddress_ipv4_prefix_len(si->sin_addr.s_addr);
+ netsnmp_ipaddress_ipv4_prefix_len(ntohl(si->sin_addr.s_addr));
+ if(addr_info.bcastflg)
+ bcastentry->ia_prefix_len = entry->ia_prefix_len;
+
/*
* get flags
@@ -246,7 +272,12 @@ _netsnmp_ioctl_ipaddress_container_load_v4(netsnmp_container *container,
}
extras->flags = ifrp->ifr_flags;
- entry->ia_type = IPADDRESSTYPE_UNICAST; /* assume unicast? */
+ if(addr_info.bcastflg)
+ bcastentry->ia_type = IPADDRESSTYPE_BROADCAST;
+ if(addr_info.anycastflg)
+ entry->ia_type = IPADDRESSTYPE_ANYCAST;
+ else
+ entry->ia_type = IPADDRESSTYPE_UNICAST;
/** entry->ia_prefix_oid ? */
@@ -256,12 +287,23 @@ _netsnmp_ioctl_ipaddress_container_load_v4(netsnmp_container *container,
* always preferred(1).
*/
entry->ia_status = IPADDRESSSTATUSTC_PREFERRED;
+ if(addr_info.bcastflg)
+ bcastentry->ia_status = IPADDRESSSTATUSTC_PREFERRED;
/*
* can we figure out if an address is from DHCP?
* use manual until then...
*/
- entry->ia_origin = IPADDRESSORIGINTC_MANUAL;
+ if(IS_APIPA(ipval)) {
+ entry->ia_origin = IPADDRESSORIGINTC_RANDOM;
+ if(addr_info.bcastflg)
+ bcastentry->ia_origin = IPADDRESSORIGINTC_RANDOM;
+ }
+ else {
+ entry->ia_origin = IPADDRESSORIGINTC_MANUAL;
+ if(addr_info.bcastflg)
+ bcastentry->ia_origin = IPADDRESSORIGINTC_MANUAL;
+ }
DEBUGIF("access:ipaddress:container") {
DEBUGMSGT_NC(("access:ipaddress:container",
@@ -279,12 +321,21 @@ _netsnmp_ioctl_ipaddress_container_load_v4(netsnmp_container *container,
/*
* add entry to container
*/
- if (CONTAINER_INSERT(container, entry) < 0)
- {
+ if(addr_info.bcastflg){
+ if (CONTAINER_INSERT(container, bcastentry) < 0) {
+ DEBUGMSGTL(("access:ipaddress:container","error with ipaddress_entry: insert broadcast entry into container failed.\n"));
+ netsnmp_access_ipaddress_entry_free(bcastentry);
+ netsnmp_access_ipaddress_entry_free(entry);
+ continue;
+ }
+ }
+
+ 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;
}
+
}
/*
diff --git a/agent/mibgroup/ip-mib/data_access/ipaddress_ioctl.h b/agent/mibgroup/ip-mib/data_access/ipaddress_ioctl.h
index a7a0ea2..fc9774f 100644
--- a/agent/mibgroup/ip-mib/data_access/ipaddress_ioctl.h
+++ b/agent/mibgroup/ip-mib/data_access/ipaddress_ioctl.h
@@ -2,6 +2,17 @@
extern "C" {
#endif
+/*
+ * struct for netlink extras
+ */
+struct address_flag_info {
+ int bcastflg;
+ int anycastflg;
+ struct in_addr *inp;
+};
+
+#define IS_APIPA(a) (((in_addr_t)(a << 16)) == 0xFEA90000)
+
int
_netsnmp_ioctl_ipaddress_container_load_v4(netsnmp_container *container,
int idx_offset);
@@ -13,6 +24,8 @@ _netsnmp_ioctl_ipaddress_remove_v4(netsnmp_ipaddress_entry * entry);
int
netsnmp_access_ipaddress_ioctl_get_interface_count(int sd, struct ifconf * ifc);
+struct address_flag_info
+netsnmp_access_other_info_get(int index, int family);
/*
* struct ioctl for arch_data
diff --git a/agent/mibgroup/ip-mib/data_access/ipaddress_linux.c b/agent/mibgroup/ip-mib/data_access/ipaddress_linux.c
index 8cb06a2..ac37578 100644
--- a/agent/mibgroup/ip-mib/data_access/ipaddress_linux.c
+++ b/agent/mibgroup/ip-mib/data_access/ipaddress_linux.c
@@ -19,6 +19,7 @@
#if defined (NETSNMP_ENABLE_IPV6)
#include <linux/types.h>
#include <asm/types.h>
+#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#endif
@@ -188,6 +189,7 @@ _load_v6(netsnmp_container *container, int idx_offset)
netsnmp_ipaddress_entry *entry;
_ioctl_extras *extras;
static int log_open_err = 1;
+ struct address_flag_info addr_info;
netsnmp_assert(NULL != container);
@@ -268,6 +270,10 @@ _load_v6(netsnmp_container *container, int idx_offset)
* every time it is called.
*/
entry->if_index = netsnmp_access_interface_index_find(if_name);
+ memset(&addr_info, 0, sizeof(struct address_flag_info));
+#if defined (NETSNMP_ENABLE_IPV6)
+ addr_info = netsnmp_access_other_info_get(entry->if_index, AF_INET6);
+#endif
/*
#define IPADDRESSSTATUSTC_PREFERRED 1
@@ -278,7 +284,7 @@ _load_v6(netsnmp_container *container, int idx_offset)
#define IPADDRESSSTATUSTC_TENTATIVE 6
#define IPADDRESSSTATUSTC_DUPLICATE 7
*/
- if(flags & IFA_F_PERMANENT)
+ if((flags & IFA_F_PERMANENT) || (!flags) || (flags & IFA_F_TEMPORARY))
entry->ia_status = IPADDRESSSTATUSTC_PREFERRED; /* ?? */
else if(flags & IFA_F_DEPRECATED)
entry->ia_status = IPADDRESSSTATUSTC_DEPRECATED;
@@ -294,7 +300,7 @@ _load_v6(netsnmp_container *container, int idx_offset)
* if it's not multi, it must be uni.
* (an ipv6 address is never broadcast)
*/
- if (IN6_IS_ADDR_MULTICAST(entry->ia_address))
+ if(addr_info.anycastflg)
entry->ia_type = IPADDRESSTYPE_ANYCAST;
else
entry->ia_type = IPADDRESSTYPE_UNICAST;
@@ -314,18 +320,28 @@ _load_v6(netsnmp_container *container, int idx_offset)
*
* 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;
+ if (!flags)
+ entry->ia_origin = IPADDRESSORIGINTC_LINKLAYER;
+ else if (flags & IFA_F_TEMPORARY)
+ entry->ia_origin = IPADDRESSORIGINTC_RANDOM;
+ else if (IN6_IS_ADDR_LINKLOCAL(entry->ia_address))
+ entry->ia_origin = IPADDRESSORIGINTC_LINKLAYER;
+ else
+ entry->ia_origin = IPADDRESSORIGINTC_MANUAL;
+
+ if(entry->ia_origin == IPADDRESSORIGINTC_LINKLAYER)
+ entry->ia_storagetype = STORAGETYPE_PERMANENT;
/* xxx-rks: what can we do with scope? */
/*
* add entry to container
*/
- CONTAINER_INSERT(container, entry);
+ 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);
@@ -335,4 +351,93 @@ _load_v6(netsnmp_container *container, int idx_offset)
return idx_offset;
}
+
+struct address_flag_info
+netsnmp_access_other_info_get(int index, int family)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifaddrmsg r;
+ char buf[1024];
+ } req;
+ struct address_flag_info addr;
+ struct rtattr *rta;
+ int status;
+ char buf[16384];
+ struct nlmsghdr *nlmp;
+ struct ifaddrmsg *rtmp;
+ struct rtattr *rtatp;
+ int rtattrlen;
+ int sd;
+
+ memset(&addr, 0, sizeof(struct address_flag_info));
+ sd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if(sd < 0) {
+ snmp_log(LOG_ERR, "could not open netlink socket\n");
+ return addr;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
+ req.n.nlmsg_type = RTM_GETADDR;
+ req.r.ifa_family = family;
+ rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len));
+ if(family == AF_INET)
+ rta->rta_len = RTA_LENGTH(4);
+ else
+ rta->rta_len = RTA_LENGTH(16);
+
+ status = send(sd, &req, req.n.nlmsg_len, 0);
+ if (status < 0) {
+ snmp_log(LOG_ERR, "could not send netlink request\n");
+ return addr;
+ }
+
+ status = recv(sd, buf, sizeof(buf), 0);
+ if (status < 0) {
+ snmp_log (LOG_ERR, "could not recieve netlink request\n");
+ return addr;
+ }
+
+ if(status == 0) {
+ snmp_log (LOG_ERR, "nothing to read\n");
+ return addr;
+ }
+
+ for(nlmp = (struct nlmsghdr *)buf; status > sizeof(*nlmp);) {
+ int len = nlmp->nlmsg_len;
+ int req_len = len - sizeof(*nlmp);
+
+ if (req_len < 0 || len > status) {
+ snmp_log (LOG_ERR, "invalid netlink message\n");
+ return addr;
+ }
+
+ if (!NLMSG_OK(nlmp, status)) {
+ snmp_log (LOG_ERR, "invalid NLMSG message\n");
+ return addr;
+ }
+ rtmp = (struct ifaddrmsg *)NLMSG_DATA(nlmp);
+ rtatp = (struct rtattr *)IFA_RTA(rtmp);
+ rtattrlen = IFA_PAYLOAD(nlmp);
+ if(index == rtmp->ifa_index){
+ for (; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen)) {
+ if(rtatp->rta_type == IFA_BROADCAST){
+ addr.inp = (struct in_addr *)RTA_DATA(rtatp);
+ addr.bcastflg = 1;
+ }
+ if(rtatp->rta_type == IFA_ANYCAST){
+ addr.inp = (struct in_addr *)RTA_DATA(rtatp);
+ addr.anycastflg = 1;
+ }
+ }
+ }
+ status -= NLMSG_ALIGN(len);
+ nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len));
+ }
+ close(sd);
+ return addr;
+}
#endif
+
diff --git a/agent/mibgroup/ip-mib/ipAddressTable/ipAddressTable.c b/agent/mibgroup/ip-mib/ipAddressTable/ipAddressTable.c
index e695ab3..8bb3cbc 100644
--- a/agent/mibgroup/ip-mib/ipAddressTable/ipAddressTable.c
+++ b/agent/mibgroup/ip-mib/ipAddressTable/ipAddressTable.c
@@ -942,7 +942,10 @@ ipAddressRowStatus_get(ipAddressTable_rowreq_ctx * rowreq_ctx,
netsnmp_assert(NULL != ipAddressRowStatus_val_ptr);
/** WARNING: this code might not work for netsnmp_ipaddress_entry */
- (*ipAddressRowStatus_val_ptr) = rowreq_ctx->ipAddressRowStatus;
+ if(rowreq_ctx->data->if_index)
+ (*ipAddressRowStatus_val_ptr) = rowreq_ctx->ipAddressRowStatus;
+ else
+ (*ipAddressRowStatus_val_ptr) = ROWSTATUS_NOTREADY;
return MFD_SUCCESS;
} /* ipAddressRowStatus_get */
diff --git a/include/net-snmp/library/container.h b/include/net-snmp/library/container.h
index f88fa21..22684aa 100644
--- a/include/net-snmp/library/container.h
+++ b/include/net-snmp/library/container.h
@@ -358,7 +358,7 @@ extern "C" {
if(x) {
int rc = x->insert(x,k);
if(rc)
- snmp_log(LOG_ERR,"error on subcontainer '%s' insert (%d)\n",
+ snmp_log(LOG_DEBUG,"error on subcontainer '%s' insert (%d)\n",
x->container_name ? x->container_name : "", rc);
else {
rc = CONTAINER_INSERT_HELPER(x->next, k);
diff --git a/snmplib/container.c b/snmplib/container.c
index e34e922..1255f0a 100644
--- a/snmplib/container.c
+++ b/snmplib/container.c
@@ -275,7 +275,7 @@ int CONTAINER_INSERT_HELPER(netsnmp_container* x, const void* k)
if(x) {
int rc = x->insert(x,k);
if(rc)
- snmp_log(LOG_ERR,"error on subcontainer '%s' insert (%d)\n",
+ snmp_log(LOG_DEBUG,"error on subcontainer '%s' insert (%d)\n",
x->container_name ? x->container_name : "", rc);
else {
rc = CONTAINER_INSERT_HELPER(x->next, k);
--
1.6.0.2