Author: glebius
Date: Tue Jan 17 03:52:57 2017
New Revision: 312331
URL: https://svnweb.freebsd.org/changeset/base/312331

Log:
  Fix regression from r310655, which broke operation of bsnmpd if it is bound
  to a non-wildcard address.  As documented in ip(4), doing sendmsg(2) with
  IP_SENDSRCADDR on a socket that is bound to non-wildcard address is
  completely different to using this control message on a wildcard one.
  
  A fix is to add a bool to mark whether we did setsockopt(IP_RECVDSTADDR)
  on the socket, and use IP_SENDSRCADDR control message only if we did.
  
  While here, garbage collect absolutely useless udp_recv() function that
  establishes some structures on stack to never use them later.

Modified:
  head/contrib/bsnmp/snmpd/trans_udp.c
  head/contrib/bsnmp/snmpd/trans_udp.h

Modified: head/contrib/bsnmp/snmpd/trans_udp.c
==============================================================================
--- head/contrib/bsnmp/snmpd/trans_udp.c        Tue Jan 17 03:44:45 2017        
(r312330)
+++ head/contrib/bsnmp/snmpd/trans_udp.c        Tue Jan 17 03:52:57 2017        
(r312331)
@@ -34,6 +34,7 @@
 #include <sys/queue.h>
 #include <sys/ucred.h>
 
+#include <stdbool.h>
 #include <stdlib.h>
 #include <syslog.h>
 #include <string.h>
@@ -119,13 +120,15 @@ udp_init_port(struct tport *tp)
        addr.sin_port = htons(p->port);
        addr.sin_family = AF_INET;
        addr.sin_len = sizeof(addr);
-       if (addr.sin_addr.s_addr == INADDR_ANY &&
-           setsockopt(p->input.fd, IPPROTO_IP, IP_RECVDSTADDR, &on,
-           sizeof(on)) == -1) {
-               syslog(LOG_ERR, "setsockopt(IP_RECVDSTADDR): %m");
-               close(p->input.fd);
-               p->input.fd = -1;
-               return (SNMP_ERR_GENERR);
+       if (addr.sin_addr.s_addr == INADDR_ANY) {
+               if (setsockopt(p->input.fd, IPPROTO_IP, IP_RECVDSTADDR, &on,
+                   sizeof(on)) == -1) {
+                       syslog(LOG_ERR, "setsockopt(IP_RECVDSTADDR): %m");
+                       close(p->input.fd);
+                       p->input.fd = -1;
+                       return (SNMP_ERR_GENERR);
+               }
+               p->recvdstaddr = true;
        }
        if (bind(p->input.fd, (struct sockaddr *)&addr, sizeof(addr))) {
                if (errno == EADDRNOTAVAIL) {
@@ -218,7 +221,6 @@ udp_send(struct tport *tp, const u_char 
 {
        struct udp_port *p = (struct udp_port *)tp;
        struct cmsghdr *cmsg;
-       struct in_addr *src_addr;
        struct msghdr msg;
        char cbuf[CMSG_SPACE(sizeof(struct in_addr))];
        struct iovec iov;
@@ -231,15 +233,20 @@ udp_send(struct tport *tp, const u_char 
        msg.msg_iovlen = 1;
        msg.msg_name = __DECONST(void *, addr);
        msg.msg_namelen = addrlen;
-       msg.msg_control = cbuf;
-       msg.msg_controllen = sizeof(cbuf);
 
-       cmsg = CMSG_FIRSTHDR(&msg);
-       cmsg->cmsg_level = IPPROTO_IP;
-       cmsg->cmsg_type = IP_SENDSRCADDR;
-       cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
-       src_addr = (struct in_addr *)(void*)CMSG_DATA(cmsg);
-       memcpy(src_addr, &p->recv_addr, sizeof(struct in_addr));
+       if (p->recvdstaddr) {
+               msg.msg_control = cbuf;
+               msg.msg_controllen = sizeof(cbuf);
+
+               cmsg = CMSG_FIRSTHDR(&msg);
+               cmsg->cmsg_level = IPPROTO_IP;
+               cmsg->cmsg_type = IP_SENDSRCADDR;
+               cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+               memcpy(CMSG_DATA(cmsg), &p->dstaddr, sizeof(struct in_addr));
+       } else {
+               msg.msg_control = NULL;
+               msg.msg_controllen = 0;
+       }
 
        return (sendmsg(p->input.fd, &msg, 0));
 }
@@ -260,11 +267,12 @@ check_priv_dgram(struct port_input *pi, 
  * Each receive should return one datagram.
  */
 static ssize_t
-recv_dgram(struct port_input *pi, struct in_addr *laddr)
+udp_recv(struct tport *tp, struct port_input *pi)
 {
        u_char embuf[1000];
        char cbuf[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) +
            CMSG_SPACE(sizeof(struct in_addr))];
+       struct udp_port *p = (struct udp_port *)tp;
        struct msghdr msg;
        struct iovec iov[1];
        ssize_t len;
@@ -316,7 +324,8 @@ recv_dgram(struct port_input *pi, struct
            cmsg = CMSG_NXTHDR(&msg, cmsg)) {
                if (cmsg->cmsg_level == IPPROTO_IP &&
                    cmsg->cmsg_type == IP_RECVDSTADDR)
-                       memcpy(laddr, CMSG_DATA(cmsg), sizeof(struct in_addr));
+                       memcpy(&p->dstaddr, CMSG_DATA(cmsg),
+                           sizeof(struct in_addr));
                if (cmsg->cmsg_level == SOL_SOCKET &&
                    cmsg->cmsg_type == SCM_CREDS)
                        cred = (struct sockcred *)CMSG_DATA(cmsg);
@@ -329,42 +338,6 @@ recv_dgram(struct port_input *pi, struct
 }
 
 /*
- * Receive something
- */
-static ssize_t
-udp_recv(struct tport *tp, struct port_input *pi)
-{
-       struct udp_port *p = (struct udp_port *)tp;
-       struct cmsghdr *cmsgp;
-       struct in_addr *laddr;
-       struct msghdr msg;
-       char cbuf[CMSG_SPACE(sizeof(struct in_addr))];
-       ssize_t ret;
-
-       memset(cbuf, 0, sizeof(cbuf));
-
-       msg.msg_control = cbuf;
-       msg.msg_controllen = sizeof(cbuf);
-
-       cmsgp = CMSG_FIRSTHDR(&msg);
-       cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
-       cmsgp->cmsg_level = IPPROTO_IP;
-       cmsgp->cmsg_type = IP_SENDSRCADDR;
-       laddr = (struct in_addr *)CMSG_DATA(cmsgp);
-
-       ret = recv_dgram(pi, laddr);
-
-       memcpy(&p->recv_addr, laddr, sizeof(struct in_addr));
-
-       if (laddr->s_addr == INADDR_ANY) {
-               msg.msg_control = NULL;
-               msg.msg_controllen = 0;
-       }
-
-       return (ret);
-}
-
-/*
  * Port table
  */
 int

Modified: head/contrib/bsnmp/snmpd/trans_udp.h
==============================================================================
--- head/contrib/bsnmp/snmpd/trans_udp.h        Tue Jan 17 03:44:45 2017        
(r312330)
+++ head/contrib/bsnmp/snmpd/trans_udp.h        Tue Jan 17 03:52:57 2017        
(r312331)
@@ -39,7 +39,9 @@ struct udp_port {
        struct port_input input;        /* common input stuff */
 
        struct sockaddr_in ret;         /* the return address */
-       struct in_addr recv_addr;       /* the address the request was sent to 
*/
+
+       bool            recvdstaddr;    /* IP_RECVDSTADDR is on */
+       struct in_addr  dstaddr;        /* address the request was sent to */
 };
 
 /* argument for open call */
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to