Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 9 Sep 2012 09:46:49 +0000 (UTC)
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r240271 - head/contrib/bsnmp/snmpd
Message-ID:  <201209090946.q899kncP045285@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: glebius
Date: Sun Sep  9 09:46:48 2012
New Revision: 240271
URL: http://svn.freebsd.org/changeset/base/240271

Log:
  For UDP transport set IP_RECVDSTADDR sockopt on the socket, and provide
  IP_SENDSRCADDR control with datagram message we reply with. This makes
  bsnmpd reply from exactly same address that request was sent to, thus
  successfully bypassing stateful firewalls or other kinds of strict checking.
  
  PR:		bin/171279

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

Modified: head/contrib/bsnmp/snmpd/main.c
==============================================================================
--- head/contrib/bsnmp/snmpd/main.c	Sun Sep  9 08:40:44 2012	(r240270)
+++ head/contrib/bsnmp/snmpd/main.c	Sun Sep  9 09:46:48 2012	(r240271)
@@ -1106,10 +1106,11 @@ recv_stream(struct port_input *pi)
  * Each receive should return one datagram.
  */
 static int
-recv_dgram(struct port_input *pi)
+recv_dgram(struct port_input *pi, struct in_addr *laddr)
 {
 	u_char embuf[1000];
-	char cbuf[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX))];
+	char cbuf[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) +
+	    CMSG_SPACE(sizeof(struct in_addr))];
 	struct msghdr msg;
 	struct iovec iov[1];
 	ssize_t len;
@@ -1159,6 +1160,9 @@ recv_dgram(struct port_input *pi)
 
 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
 	    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));
 		if (cmsg->cmsg_level == SOL_SOCKET &&
 		    cmsg->cmsg_type == SCM_CREDS)
 			cred = (struct sockcred *)CMSG_DATA(cmsg);
@@ -1187,12 +1191,27 @@ snmpd_input(struct port_input *pi, struc
 #ifdef USE_TCPWRAPPERS
 	char client[16];
 #endif
+	struct msghdr msg;
+	struct iovec iov[1];
+	char cbuf[CMSG_SPACE(sizeof(struct in_addr))];
+	struct cmsghdr *cmsgp;
 
 	/* get input depending on the transport */
 	if (pi->stream) {
+		msg.msg_control = NULL;
+		msg.msg_controllen = 0;
+
 		ret = recv_stream(pi);
 	} else {
-		ret = recv_dgram(pi);
+		memset(cbuf, 0, CMSG_SPACE(sizeof(struct in_addr)));
+		msg.msg_control = cbuf;
+		msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
+		cmsgp = CMSG_FIRSTHDR(&msg);
+		cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+		cmsgp->cmsg_level = IPPROTO_IP;
+		cmsgp->cmsg_type = IP_SENDSRCADDR;
+		
+		ret = recv_dgram(pi, (struct in_addr *)CMSG_DATA(cmsgp));
 	}
 
 	if (ret == -1)
@@ -1337,11 +1356,19 @@ snmpd_input(struct port_input *pi, struc
 	    sndbuf, &sndlen, "SNMP", ierr, vi, NULL);
 
 	if (ferr == SNMPD_INPUT_OK) {
-		slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen);
+		msg.msg_name = pi->peer;
+		msg.msg_namelen = pi->peerlen;
+		msg.msg_iov = iov;
+		msg.msg_iovlen = 1;
+		msg.msg_flags = 0;
+		iov[0].iov_base = sndbuf;
+		iov[0].iov_len = sndlen;
+
+		slen = sendmsg(pi->fd, &msg, 0);
 		if (slen == -1)
-			syslog(LOG_ERR, "sendto: %m");
+			syslog(LOG_ERR, "sendmsg: %m");
 		else if ((size_t)slen != sndlen)
-			syslog(LOG_ERR, "sendto: short write %zu/%zu",
+			syslog(LOG_ERR, "sendmsg: short write %zu/%zu",
 			    sndlen, (size_t)slen);
 	}
 	snmp_pdu_free(&pdu);

Modified: head/contrib/bsnmp/snmpd/trans_udp.c
==============================================================================
--- head/contrib/bsnmp/snmpd/trans_udp.c	Sun Sep  9 08:40:44 2012	(r240270)
+++ head/contrib/bsnmp/snmpd/trans_udp.c	Sun Sep  9 09:46:48 2012	(r240271)
@@ -103,11 +103,19 @@ udp_init_port(struct tport *tp)
 	struct udp_port *p = (struct udp_port *)tp;
 	struct sockaddr_in addr;
 	u_int32_t ip;
+	const int on = 1;
 
 	if ((p->input.fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
 		syslog(LOG_ERR, "creating UDP socket: %m");
 		return (SNMP_ERR_RES_UNAVAIL);
 	}
+	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);
+	}
 	ip = (p->addr[0] << 24) | (p->addr[1] << 16) | (p->addr[2] << 8) |
 	    p->addr[3];
 	memset(&addr, 0, sizeof(addr));



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201209090946.q899kncP045285>