Hi.

Here is what tcpdump sees when polling multihomed linux host with address 10.1.1.16 on eth interface and address 10.20.0.1 on dummy (loopback) interface:

22:21:45.418354 10.10.194.15.57311 > 10.20.0.1.snmp: C=public GetRequest(28) .1.3.6.1.2.1.1.1.0 (DF) 22:21:45.419425 10.1.1.16.snmp > 10.10.194.15.57311: C=public GetResponse(39) .1.3.6.1.2.1.1.1.0="Linux" (DF)

This is not very convinient when using stateful firewall somewhere between that two hosts or on monitoring station, as responce has no relation to request from point of view of linux iptables connection tracking.

I attach the patch which corrects this behaviour for linux (Based on thread http://groups.google.com/group/linux.kernel/browse_thread/thread/c3cdcfc8da4335b1/e5df1c1bf1fa7aea?lnk=st&q=linux+sendto+recvfrom+DSTADDR&rnum=1).
Hope it is useful.
--
Best,
Vladislav Bogdanov
diff -urNp net-snmp-5.3.1.orig/README net-snmp-5.3.1/README
--- net-snmp-5.3.1.orig/README  2006-07-14 00:55:27.000000000 +0300
+++ net-snmp-5.3.1/README       2006-09-06 00:17:16.000000000 +0300
@@ -343,6 +343,7 @@ THANKS
     Andrew Rucker Jones <[EMAIL PROTECTED]>
     Dai.H. <[EMAIL PROTECTED]>
     Thomas Anders <[EMAIL PROTECTED]>
+    Vladislav Bogdanov <[EMAIL PROTECTED]>
 
   We've probably forgotten people on this list.  Let us know if you've
   contributed code and we've left you out.
diff -urNp net-snmp-5.3.1.orig/snmplib/snmpUDPDomain.c 
net-snmp-5.3.1/snmplib/snmpUDPDomain.c
--- net-snmp-5.3.1.orig/snmplib/snmpUDPDomain.c 2005-11-06 00:01:42.000000000 
+0200
+++ net-snmp-5.3.1/snmplib/snmpUDPDomain.c      2006-09-06 00:13:59.000000000 
+0300
@@ -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 @@ void _netsnmp_udp_sockopt_set(int fd, in
 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 @@ netsnmp_udp_fmtaddr(netsnmp_transport *t
 
 
 
+#if defined IP_PKTINFO
+
+# define 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, 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 @@ netsnmp_udp_recv(netsnmp_transport *t, v
 {
     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 @@ netsnmp_udp_recv(netsnmp_transport *t, v
             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 @@ netsnmp_udp_send(netsnmp_transport *t, v
                 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 @@ netsnmp_udp_transport(struct sockaddr_in
     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 @@ netsnmp_udp_transport(struct sockaddr_in
         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 +679,7 @@ netsnmp_udp_transport(struct sockaddr_in
          * 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 +689,8 @@ netsnmp_udp_transport(struct sockaddr_in
         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 +1111,8 @@ netsnmp_udp_getSecName(void *opaque, int
                        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 +1134,7 @@ netsnmp_udp_getSecName(void *opaque, int
      * 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"));
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Net-snmp-coders mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders

Reply via email to