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
This commit is contained in:
parent
64dd8b7554
commit
f2ddd22eac
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=240271
@ -1106,10 +1106,11 @@ recv_stream(struct port_input *pi)
|
|||||||
* Each receive should return one datagram.
|
* Each receive should return one datagram.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
recv_dgram(struct port_input *pi)
|
recv_dgram(struct port_input *pi, struct in_addr *laddr)
|
||||||
{
|
{
|
||||||
u_char embuf[1000];
|
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 msghdr msg;
|
||||||
struct iovec iov[1];
|
struct iovec iov[1];
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
@ -1159,6 +1160,9 @@ recv_dgram(struct port_input *pi)
|
|||||||
|
|
||||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||||
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
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 &&
|
if (cmsg->cmsg_level == SOL_SOCKET &&
|
||||||
cmsg->cmsg_type == SCM_CREDS)
|
cmsg->cmsg_type == SCM_CREDS)
|
||||||
cred = (struct sockcred *)CMSG_DATA(cmsg);
|
cred = (struct sockcred *)CMSG_DATA(cmsg);
|
||||||
@ -1187,12 +1191,27 @@ snmpd_input(struct port_input *pi, struct tport *tport)
|
|||||||
#ifdef USE_TCPWRAPPERS
|
#ifdef USE_TCPWRAPPERS
|
||||||
char client[16];
|
char client[16];
|
||||||
#endif
|
#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 */
|
/* get input depending on the transport */
|
||||||
if (pi->stream) {
|
if (pi->stream) {
|
||||||
|
msg.msg_control = NULL;
|
||||||
|
msg.msg_controllen = 0;
|
||||||
|
|
||||||
ret = recv_stream(pi);
|
ret = recv_stream(pi);
|
||||||
} else {
|
} 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)
|
if (ret == -1)
|
||||||
@ -1337,11 +1356,19 @@ snmpd_input(struct port_input *pi, struct tport *tport)
|
|||||||
sndbuf, &sndlen, "SNMP", ierr, vi, NULL);
|
sndbuf, &sndlen, "SNMP", ierr, vi, NULL);
|
||||||
|
|
||||||
if (ferr == SNMPD_INPUT_OK) {
|
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)
|
if (slen == -1)
|
||||||
syslog(LOG_ERR, "sendto: %m");
|
syslog(LOG_ERR, "sendmsg: %m");
|
||||||
else if ((size_t)slen != sndlen)
|
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);
|
sndlen, (size_t)slen);
|
||||||
}
|
}
|
||||||
snmp_pdu_free(&pdu);
|
snmp_pdu_free(&pdu);
|
||||||
|
@ -103,11 +103,19 @@ udp_init_port(struct tport *tp)
|
|||||||
struct udp_port *p = (struct udp_port *)tp;
|
struct udp_port *p = (struct udp_port *)tp;
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
u_int32_t ip;
|
u_int32_t ip;
|
||||||
|
const int on = 1;
|
||||||
|
|
||||||
if ((p->input.fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
|
if ((p->input.fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||||
syslog(LOG_ERR, "creating UDP socket: %m");
|
syslog(LOG_ERR, "creating UDP socket: %m");
|
||||||
return (SNMP_ERR_RES_UNAVAIL);
|
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) |
|
ip = (p->addr[0] << 24) | (p->addr[1] << 16) | (p->addr[2] << 8) |
|
||||||
p->addr[3];
|
p->addr[3];
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
Loading…
Reference in New Issue
Block a user