Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 20db51d70e6b59a061db97ce9b89c771 > files > 44

net-snmp-5.3.2.2-14.el5.src.rpm

521175: [5.1] snmp communication using a broadcast address is unavailable.

Source: upstream SVN rev. 17855 and 17908.

UDP responses are sent with source IP address which was destination of
appropriate requests (implemented in SVN rev. 15215). But if the destination
of a request is broadcast IP address, the request was sent with the broadcast
address as source. sendmsg() on Linux does not support this and returns error
 -> response is not sent. In order to send responses from the same interface,
interface index of the appropriate interface must be used.

diff -up net-snmp-5.3.2.2/snmplib/snmpUDPDomain.c.broadcast-response net-snmp-5.3.2.2/snmplib/snmpUDPDomain.c
--- net-snmp-5.3.2.2/snmplib/snmpUDPDomain.c.broadcast-response	2009-11-30 17:21:28.000000000 +0100
+++ net-snmp-5.3.2.2/snmplib/snmpUDPDomain.c	2009-11-30 17:22:26.000000000 +0100
@@ -70,6 +70,7 @@ static netsnmp_tdomain udpDomain;
 typedef struct netsnmp_udp_addr_pair_s {
     struct sockaddr_in remote_addr;
     struct in_addr local_addr;
+    int if_index;
 } netsnmp_udp_addr_pair;
 
 /*
@@ -121,7 +122,7 @@ netsnmp_udp_fmtaddr(netsnmp_transport *t
 
 # define netsnmp_dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))
 
-static int netsnmp_udp_recvfrom(int s, char *buf, int len, struct sockaddr *from, int *fromlen, struct in_addr *dstip)
+static int netsnmp_udp_recvfrom(int s, char *buf, int len, struct sockaddr *from, int *fromlen, struct in_addr *dstip, int *if_index)
 {
     int r;
     struct iovec iov[1];
@@ -150,41 +151,54 @@ static int netsnmp_udp_recvfrom(int s, c
     for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
         if (cmsgptr->cmsg_level == SOL_IP && cmsgptr->cmsg_type == IP_PKTINFO) {
             memcpy((void *) dstip, netsnmp_dstaddr(cmsgptr), sizeof(struct in_addr));
-            DEBUGMSGTL(("netsnmp_udp", "got destination (local) addr %s\n",
-                    inet_ntoa(*dstip)));
+            *if_index = (((struct in_pktinfo *)(CMSG_DATA(cmsgptr)))->ipi_ifindex);
+            DEBUGMSGTL(("netsnmp_udp", "got destination (local) addr %s, iface %d\n",
+                    inet_ntoa(*dstip), *if_index));
         }
     }
     return r;
 }
 
-static int netsnmp_udp_sendto(int fd, struct in_addr *srcip, struct sockaddr *remote,
-			char *data, int len)
+static int netsnmp_udp_sendto(int fd, struct in_addr *srcip, int if_index,
+        struct sockaddr *remote, char *data, int len)
 {
     struct iovec iov = { data, len };
     struct {
         struct cmsghdr cm;
         struct in_pktinfo ipi;
-    } cmsg = {
-        .cm = {
-            .cmsg_len	= sizeof(struct cmsghdr) + sizeof(struct in_pktinfo),
-            .cmsg_level	= SOL_IP,
-            .cmsg_type	= IP_PKTINFO,
-        },
-        .ipi = {
-            .ipi_ifindex	= 0,
-            .ipi_spec_dst	= srcip ? srcip->s_addr : 0,
-        },
-    };
-    struct msghdr m = {
-        .msg_name	= remote,
-        .msg_namelen	= sizeof(struct sockaddr_in),
-        .msg_iov	= &iov,
-        .msg_iovlen	= 1,
-        .msg_control	= &cmsg,
-        .msg_controllen	= sizeof(cmsg),
-        .msg_flags	= 0,
-    };
-    return sendmsg(fd, &m, MSG_NOSIGNAL|MSG_DONTWAIT);
+    } cmsg;
+    struct msghdr m;
+    int ret;
+
+    memset(&cmsg, 0, sizeof(cmsg));
+    cmsg.cm.cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
+    cmsg.cm.cmsg_level = SOL_IP;
+    cmsg.cm.cmsg_type = IP_PKTINFO;
+    cmsg.ipi.ipi_ifindex = if_index;
+    cmsg.ipi.ipi_spec_dst.s_addr = (srcip ? srcip->s_addr : INADDR_ANY);
+
+    m.msg_name		= remote;
+    m.msg_namelen	= sizeof(struct sockaddr_in);
+    m.msg_iov		= &iov;
+    m.msg_iovlen	= 1;
+    m.msg_control	= &cmsg;
+    m.msg_controllen= sizeof(cmsg);
+    m.msg_flags		= 0;
+
+    DEBUGMSGTL(("netsnmp_udp", "sending from %s iface %d\n",
+            (srcip ? inet_ntoa(*srcip) : "NULL"), if_index));
+    errno = 0;
+    ret = sendmsg(fd, &m, MSG_NOSIGNAL|MSG_DONTWAIT);
+    if (ret < 0 && errno == EINVAL && srcip) {
+        /* The error might be caused by broadcast srcip (i.e. we're responding
+         * to broadcast request) - sendmsg does not like it. Try to resend it
+         * with global address. */
+        cmsg.ipi.ipi_spec_dst.s_addr = INADDR_ANY;
+        DEBUGMSGTL(("netsnmp_udp",
+                "netsnmp_udp_sendto: re-sending the message\n"));
+        ret = sendmsg(fd, &m, MSG_NOSIGNAL|MSG_DONTWAIT);
+    }
+    return ret;
 }
 #endif /* IP_PKTINFO */
 
@@ -216,7 +230,8 @@ netsnmp_udp_recv(netsnmp_transport *t, v
 
 	while (rc < 0) {
 #if defined IP_PKTINFO
-            rc = netsnmp_udp_recvfrom(t->sock, buf, size, from, &fromlen, &(addr_pair->local_addr));
+            rc = netsnmp_udp_recvfrom(t->sock, buf, size, from, &fromlen,
+            		&(addr_pair->local_addr), &(addr_pair->if_index));
 #else
             rc = recvfrom(t->sock, buf, size, 0, from, &fromlen);
 #endif /* IP_PKTINFO */
@@ -269,7 +284,10 @@ netsnmp_udp_send(netsnmp_transport *t, v
         free(str);
 	while (rc < 0) {
 #if defined IP_PKTINFO
-            rc = netsnmp_udp_sendto(t->sock, addr_pair ? &(addr_pair->local_addr) : NULL, to, buf, size);
+            rc = netsnmp_udp_sendto(t->sock,
+            		addr_pair ? &(addr_pair->local_addr) : NULL,
+            		addr_pair ? addr_pair->if_index : 0,
+            		to, buf, size);
 #else
             rc = sendto(t->sock, buf, size, 0, to, sizeof(struct sockaddr));
 #endif /* IP_PKTINFO */
diff -up net-snmp-5.3.2.2/snmplib/snmpTCPDomain.c.broadcast-response net-snmp-5.3.2.2/snmplib/snmpTCPDomain.c
--- net-snmp-5.3.2.2/snmplib/snmpTCPDomain.c.broadcast-response	2009-12-14 14:42:30.000000000 +0100
+++ net-snmp-5.3.2.2/snmplib/snmpTCPDomain.c	2009-12-14 14:42:49.000000000 +0100
@@ -48,6 +48,7 @@
 typedef struct netsnmp_udp_addr_pair_s {
     struct sockaddr_in remote_addr;
     struct in_addr local_addr;
+    int if_index;
 } netsnmp_udp_addr_pair;
 
 oid netsnmp_snmpTCPDomain[] = { TRANSPORT_DOMAIN_TCP_IP };