[Pkg-net-snmp-devel] [Patch] net-snmp 5.3.1-2: 24_pktinfo.patch breaks TCP

Jan Andres jandres at gmx.net
Fri Feb 9 22:15:06 CET 2007


Hi,

With 24_pktinfo.patch applied snmpd will never respond to TCP
requests, because the address -> security name mapping always fails.

I propose the patch attached as a replacement for 24_pktinfo.patch. It's
the version of the fix as diffed from the V5-3-patches branch of net-snmp,
and includes the fix for the TCP code.

Regards,
Jan

-- 
Jan Andres <jandres at gmx.net>
-------------- next part --------------
diff -ur net-snmp-5.3.1/snmplib/snmpTCPDomain.c net-snmp-5.3.1-fixed/snmplib/snmpTCPDomain.c
--- net-snmp-5.3.1/snmplib/snmpTCPDomain.c	2005-09-16 12:30:48.000000000 +0200
+++ net-snmp-5.3.1-fixed/snmplib/snmpTCPDomain.c	2007-02-09 20:52:29.112680146 +0100
@@ -44,6 +44,12 @@
 #include <net-snmp/library/snmpUDPDomain.h>
 #include <net-snmp/library/snmpTCPDomain.h>
 
+/* Copied from snmpUDPDomain.c */
+typedef struct netsnmp_udp_addr_pair_s {
+    struct sockaddr_in remote_addr;
+    struct in_addr local_addr;
+} netsnmp_udp_addr_pair;
+
 oid netsnmp_snmpTCPDomain[] = { TRANSPORT_DOMAIN_TCP_IP };
 static netsnmp_tdomain tcpDomain;
 
@@ -55,18 +61,23 @@
 static char *
 netsnmp_tcp_fmtaddr(netsnmp_transport *t, void *data, int len)
 {
-    struct sockaddr_in *to = NULL;
+    netsnmp_udp_addr_pair *addr_pair = NULL;
 
-    if (data != NULL && len == sizeof(struct sockaddr_in)) {
-        to = (struct sockaddr_in *) data;
-    } else if (t != NULL && t->data != NULL &&
-               t->data_length == sizeof(struct sockaddr_in)) {
-        to = (struct sockaddr_in *) t->data;
+    if (data != NULL && len == sizeof(netsnmp_udp_addr_pair)) {
+	addr_pair = (netsnmp_udp_addr_pair *) data;
+    } else if (t != NULL && t->data != NULL) {
+	addr_pair = (netsnmp_udp_addr_pair *) t->data;
     }
-    if (to == NULL) {
+
+    if (addr_pair == NULL) {
         return strdup("TCP: unknown");
     } else {
-        char tmp[64];
+        struct sockaddr_in *to = NULL;
+	char tmp[64];
+        to = (struct sockaddr_in *) &(addr_pair->remote_addr);
+        if (to == NULL) {
+            return strdup("TCP: unknown");
+        }
 
         sprintf(tmp, "TCP: [%s]:%hd",
                 inet_ntoa(to->sin_addr), ntohs(to->sin_port));
@@ -163,19 +174,21 @@
 netsnmp_tcp_accept(netsnmp_transport *t)
 {
     struct sockaddr *farend = NULL;
+    netsnmp_udp_addr_pair *addr_pair = NULL;
     int             newsock = -1, sockflags = 0;
     socklen_t       farendlen = sizeof(struct sockaddr_in);
     char           *str = NULL;
 
-    farend = (struct sockaddr *) malloc(sizeof(struct sockaddr_in));
+    addr_pair = (netsnmp_udp_addr_pair *)malloc(sizeof(netsnmp_udp_addr_pair));
 
-    if (farend == NULL) {
+    if (addr_pair == NULL) {
         /*
          * Indicate that the acceptance of this socket failed.  
          */
         DEBUGMSGTL(("netsnmp_tcp", "accept: malloc failed\n"));
         return -1;
     }
+    farend = (struct sockaddr_in *) &(addr_pair->remote_addr);
 
     if (t != NULL && t->sock >= 0) {
         newsock = accept(t->sock, farend, &farendlen);
@@ -191,8 +204,8 @@
             free(t->data);
         }
 
-        t->data = farend;
-        t->data_length = farendlen;
+        t->data = addr_pair;
+        t->data_length = sizeof(netsnmp_udp_addr_pair);
         str = netsnmp_tcp_fmtaddr(NULL, farend, farendlen);
         DEBUGMSGTL(("netsnmp_tcp", "accept succeeded (from %s)\n", str));
         free(str);
@@ -238,6 +251,7 @@
 netsnmp_tcp_transport(struct sockaddr_in *addr, int local)
 {
     netsnmp_transport *t = NULL;
+    netsnmp_udp_addr_pair *addr_pair = NULL;
     int rc = 0;
 
 
@@ -251,13 +265,14 @@
     }
     memset(t, 0, sizeof(netsnmp_transport));
 
-    t->data = malloc(sizeof(struct sockaddr_in));
-    if (t->data == NULL) {
+    addr_pair = (netsnmp_udp_addr_pair *)malloc(sizeof(netsnmp_udp_addr_pair));
+    if (addr_pair == NULL) {
         netsnmp_transport_free(t);
         return NULL;
     }
-    t->data_length = sizeof(struct sockaddr_in);
-    memcpy(t->data, addr, sizeof(struct sockaddr_in));
+    t->data = addr_pair;
+    t->data_length = sizeof(netsnmp_udp_addr_pair);
+    memcpy(&(addr_pair->remote_addr), addr, sizeof(struct sockaddr_in));
 
     t->domain = netsnmp_snmpTCPDomain;
     t->domain_length =
diff -ur net-snmp-5.3.1/snmplib/snmpUDPDomain.c net-snmp-5.3.1-fixed/snmplib/snmpUDPDomain.c
--- net-snmp-5.3.1/snmplib/snmpUDPDomain.c	2005-11-05 23:01:42.000000000 +0100
+++ net-snmp-5.3.1-fixed/snmplib/snmpUDPDomain.c	2007-02-09 20:53:10.626567462 +0100
@@ -64,6 +64,11 @@
 
 static netsnmp_tdomain udpDomain;
 
+typedef struct netsnmp_udp_addr_pair_s {
+    struct sockaddr_in remote_addr;
+    struct in_addr local_addr;
+} netsnmp_udp_addr_pair;
+
 /*
  * not static, since snmpUDPIPv6Domain needs it, but not public, either.
  * (ie don't put it in a public header.)
@@ -78,17 +83,23 @@
 static char *
 netsnmp_udp_fmtaddr(netsnmp_transport *t, void *data, int len)
 {
-    struct sockaddr_in *to = NULL;
+    netsnmp_udp_addr_pair *addr_pair = NULL;
 
-    if (data != NULL && len == sizeof(struct sockaddr_in)) {
-        to = (struct sockaddr_in *) data;
+    if (data != NULL && len == sizeof(netsnmp_udp_addr_pair)) {
+	addr_pair = (netsnmp_udp_addr_pair *) data;
     } else if (t != NULL && t->data != NULL) {
-        to = (struct sockaddr_in *) t->data;
+	addr_pair = (netsnmp_udp_addr_pair *) t->data;
     }
-    if (to == NULL) {
+
+    if (addr_pair == NULL) {
         return strdup("UDP: unknown");
     } else {
+        struct sockaddr_in *to = NULL;
 	char tmp[64];
+        to = (struct sockaddr_in *) &(addr_pair->remote_addr);
+        if (to == NULL) {
+            return strdup("UDP: unknown");
+        }
 
         sprintf(tmp, "UDP: [%s]:%hu",
                 inet_ntoa(to->sin_addr), ntohs(to->sin_port));
@@ -98,6 +109,77 @@
 
 
 
+#ifdef IP_PKTINFO
+
+# 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)
+{
+    int r;
+    struct iovec iov[1];
+    char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
+    struct cmsghdr *cmsgptr;
+    struct msghdr msg;
+
+    iov[0].iov_base = buf;
+    iov[0].iov_len = len;
+
+    memset(&msg, 0, sizeof msg);
+    msg.msg_name = from;
+    msg.msg_namelen = *fromlen;
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = &cmsg;
+    msg.msg_controllen = sizeof(cmsg);
+
+    r = recvmsg(s, &msg, 0);
+
+    if (r == -1) {
+        return -1;
+    }
+    
+    DEBUGMSGTL(("netsnmp_udp", "got source addr: %s\n", inet_ntoa(((struct sockaddr_in *)from)->sin_addr)));
+    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)));
+        }
+    }
+    return r;
+}
+
+static int netsnmp_udp_sendto(int fd, struct in_addr *srcip, 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);
+}
+#endif /* IP_PKTINFO */
+
 /*
  * You can write something into opaque that will subsequently get passed back 
  * to your send function if you like.  For instance, you might want to
@@ -110,27 +192,33 @@
 {
     int             rc = -1;
     socklen_t       fromlen = sizeof(struct sockaddr);
+    netsnmp_udp_addr_pair *addr_pair = NULL;
     struct sockaddr *from;
 
     if (t != NULL && t->sock >= 0) {
-        from = (struct sockaddr *) malloc(sizeof(struct sockaddr_in));
-        if (from == NULL) {
+        addr_pair = (netsnmp_udp_addr_pair *) malloc(sizeof(netsnmp_udp_addr_pair));
+        if (addr_pair == NULL) {
             *opaque = NULL;
             *olength = 0;
             return -1;
         } else {
-            memset(from, 0, fromlen);
+            memset(addr_pair, 0, sizeof(netsnmp_udp_addr_pair));
+            from = (struct sockaddr *) &(addr_pair->remote_addr);
         }
 
 	while (rc < 0) {
-	    rc = recvfrom(t->sock, buf, size, 0, from, &fromlen);
+#if defined IP_PKTINFO
+            rc = netsnmp_udp_recvfrom(t->sock, buf, size, from, &fromlen, &(addr_pair->local_addr));
+#else
+            rc = recvfrom(t->sock, buf, size, 0, from, &fromlen);
+#endif /* IP_PKTINFO */
 	    if (rc < 0 && errno != EINTR) {
 		break;
 	    }
 	}
 
         if (rc >= 0) {
-            char *str = netsnmp_udp_fmtaddr(NULL, from, fromlen);
+            char *str = netsnmp_udp_fmtaddr(NULL, addr_pair, sizeof(netsnmp_udp_addr_pair));
             DEBUGMSGTL(("netsnmp_udp",
 			"recvfrom fd %d got %d bytes (from %s)\n",
 			t->sock, rc, str));
@@ -139,8 +227,8 @@
             DEBUGMSGTL(("netsnmp_udp", "recvfrom fd %d err %d (\"%s\")\n",
                         t->sock, errno, strerror(errno)));
         }
-        *opaque = (void *)from;
-        *olength = sizeof(struct sockaddr_in);
+        *opaque = (void *)addr_pair;
+        *olength = sizeof(netsnmp_udp_addr_pair);
     }
     return rc;
 }
@@ -152,24 +240,31 @@
 		 void **opaque, int *olength)
 {
     int rc = -1;
+    netsnmp_udp_addr_pair *addr_pair = NULL;
     struct sockaddr *to = NULL;
 
     if (opaque != NULL && *opaque != NULL &&
-        *olength == sizeof(struct sockaddr_in)) {
-        to = (struct sockaddr *) (*opaque);
+        *olength == sizeof(netsnmp_udp_addr_pair)) {
+        addr_pair = (netsnmp_udp_addr_pair *) (*opaque);
     } else if (t != NULL && t->data != NULL &&
-               t->data_length == sizeof(struct sockaddr_in)) {
-        to = (struct sockaddr *) (t->data);
+                t->data_length == sizeof(netsnmp_udp_addr_pair)) {
+        addr_pair = (netsnmp_udp_addr_pair *) (t->data);
     }
 
+    to = (struct sockaddr *) &(addr_pair->remote_addr);
+
     if (to != NULL && t != NULL && t->sock >= 0) {
-        char *str = netsnmp_udp_fmtaddr(NULL, (void *) to,
-					sizeof(struct sockaddr_in));
+        char *str = netsnmp_udp_fmtaddr(NULL, (void *) addr_pair,
+                                        sizeof(netsnmp_udp_addr_pair));
         DEBUGMSGTL(("netsnmp_udp", "send %d bytes from %p to %s on fd %d\n",
                     size, buf, str, t->sock));
         free(str);
 	while (rc < 0) {
-	    rc = sendto(t->sock, buf, size, 0, to, sizeof(struct sockaddr));
+#if defined IP_PKTINFO
+            rc = netsnmp_udp_sendto(t->sock, addr_pair ? &(addr_pair->local_addr) : NULL, to, buf, size);
+#else
+            rc = sendto(t->sock, buf, size, 0, to, sizeof(struct sockaddr));
+#endif /* IP_PKTINFO */
 	    if (rc < 0 && errno != EINTR) {
                 DEBUGMSGTL(("netsnmp_udp", "sendto error, rc %d (errno %d)\n",
                             rc, errno));
@@ -486,18 +581,26 @@
     int             rc = 0;
     char           *str = NULL;
     char           *client_socket = NULL;
+    netsnmp_udp_addr_pair *addr_pair = NULL;
 
     if (addr == NULL || addr->sin_family != AF_INET) {
         return NULL;
     }
 
+    addr_pair = (struct	udp_addr_pair *) malloc(sizeof(netsnmp_udp_addr_pair));
+    if (addr_pair == NULL) {
+        return NULL;
+    }
+    memset(addr_pair, 0, sizeof(netsnmp_udp_addr_pair));
+    memcpy(&(addr_pair->remote_addr), addr, sizeof(struct sockaddr_in));
+
     t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
     if (t == NULL) {
         return NULL;
     }
 
-    str = netsnmp_udp_fmtaddr(NULL, (void *)addr, 
-				 sizeof(struct sockaddr_in));
+    str = netsnmp_udp_fmtaddr(NULL, (void *)addr_pair, 
+                                 sizeof(netsnmp_udp_addr_pair));
     DEBUGMSGTL(("netsnmp_udp", "open %s %s:%d\n", local ? "local" : "remote",
                 str,addr->sin_port));
     free(str);
@@ -532,6 +635,18 @@
         t->local[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
         t->local_length = 6;
 
+#ifdef  IP_PKTINFO
+        { 
+            int sockopt = 1;
+            int sockoptlen = sizeof(int);
+            if (setsockopt(t->sock, SOL_IP, IP_PKTINFO, &sockopt, sizeof sockopt) == -1) {
+                DEBUGMSGTL(("netsnmp_udp", "couldn't set IP_PKTINFO: %s\n",
+                    strerror(errno)));
+                return NULL;
+            }
+            DEBUGMSGTL(("netsnmp_udp", "set IP_PKTINFO\n"));
+        }
+#endif
         rc = bind(t->sock, (struct sockaddr *) addr,
                   sizeof(struct sockaddr));
         if (rc != 0) {
@@ -561,7 +676,7 @@
          * transport-specific data pointer for later use by netsnmp_udp_send.
          */
 
-        t->data = malloc(sizeof(struct sockaddr_in));
+        t->data = malloc(sizeof(netsnmp_udp_addr_pair));
         t->remote = malloc(6);
         if (t->data == NULL || t->remote == NULL) {
             netsnmp_transport_free(t);
@@ -571,8 +686,8 @@
         t->remote[4] = (htons(addr->sin_port) & 0xff00) >> 8;
         t->remote[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
         t->remote_length = 6;
-        memcpy(t->data, addr, sizeof(struct sockaddr_in));
-        t->data_length = sizeof(struct sockaddr_in);
+        memcpy(t->data, addr_pair, sizeof(netsnmp_udp_addr_pair));
+        t->data_length = sizeof(netsnmp_udp_addr_pair);
     }
 
     /*
@@ -993,7 +1108,8 @@
                        char **contextName)
 {
     com2SecEntry   *c;
-    struct sockaddr_in *from = (struct sockaddr_in *) opaque;
+    netsnmp_udp_addr_pair *addr_pair = (netsnmp_udp_addr_pair *) opaque;
+    struct sockaddr_in *from = (struct sockaddr_in *) &(addr_pair->remote_addr);
     char           *ztcommunity = NULL;
 
     if (secName != NULL) {
@@ -1015,7 +1131,7 @@
      * name.  
      */
 
-    if (opaque == NULL || olength != sizeof(struct sockaddr_in) ||
+    if (opaque == NULL || olength != sizeof(netsnmp_udp_addr_pair) ||
         from->sin_family != AF_INET) {
         DEBUGMSGTL(("netsnmp_udp_getSecName",
 		    "no IPv4 source address in PDU?\n"));


More information about the Pkg-net-snmp-devel mailing list