Fix bsnmpd sending/receiving with multi-homed configurations or INADDR_ANY used
as the listening address in snmpd_input(..) Stash the IPv4 address of the receiver via the recv(..) callback and use it in the send(..) callback for the transport by specifying IP_SENDSRCADDR for the control message type. Add sendmsg logic to the UDP transport's send(..) callback and use the respective send(..) callback for the transport instead of calling sendto in snmpd_input(..). MFC after: 3 weeks Obtained from: Isilon OneFS (^/onefs/branches/BR_8_0_0_DEV@r507595) Submitted by: Thor Steingrimsson <thor.steingrimsson@isilon.com> Sponsored by: Dell EMC Isilon
This commit is contained in:
parent
80601634ab
commit
8684890cca
@ -1040,10 +1040,8 @@ snmpd_input(struct port_input *pi, struct tport *tport)
|
||||
#ifdef USE_TCPWRAPPERS
|
||||
char client[16];
|
||||
#endif
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
|
||||
ret = tport->transport->vtab->recv(pi);
|
||||
ret = tport->transport->vtab->recv(tport, pi);
|
||||
if (ret == -1)
|
||||
return (-1);
|
||||
|
||||
@ -1186,21 +1184,15 @@ snmpd_input(struct port_input *pi, struct tport *tport)
|
||||
sndbuf, &sndlen, "SNMP", ierr, vi, NULL);
|
||||
|
||||
if (ferr == SNMPD_INPUT_OK) {
|
||||
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);
|
||||
slen = tport->transport->vtab->send(tport, sndbuf, sndlen,
|
||||
pi->peer, pi->peerlen);
|
||||
if (slen == -1)
|
||||
syslog(LOG_ERR, "sendmsg: %m");
|
||||
syslog(LOG_ERR, "send*: %m");
|
||||
else if ((size_t)slen != sndlen)
|
||||
syslog(LOG_ERR, "sendmsg: short write %zu/%zu",
|
||||
sndlen, (size_t)slen);
|
||||
syslog(LOG_ERR, "send*: short write %zu/%zu", sndlen,
|
||||
(size_t)slen);
|
||||
}
|
||||
|
||||
snmp_pdu_free(&pdu);
|
||||
free(sndbuf);
|
||||
snmp_input_consume(pi);
|
||||
|
@ -193,7 +193,7 @@ struct transport_def {
|
||||
|
||||
ssize_t (*send)(struct tport *, const u_char *, size_t,
|
||||
const struct sockaddr *, size_t);
|
||||
ssize_t (*recv)(struct port_input *);
|
||||
ssize_t (*recv)(struct tport *, struct port_input *);
|
||||
};
|
||||
struct transport {
|
||||
struct asn_oid index; /* transport table index */
|
||||
|
@ -59,7 +59,7 @@ static void lsock_close_port(struct tport *);
|
||||
static int lsock_init_port(struct tport *);
|
||||
static ssize_t lsock_send(struct tport *, const u_char *, size_t,
|
||||
const struct sockaddr *, size_t);
|
||||
static ssize_t lsock_recv(struct port_input *);
|
||||
static ssize_t lsock_recv(struct tport *, struct port_input *);
|
||||
|
||||
/* exported */
|
||||
const struct transport_def lsock_trans = {
|
||||
@ -444,7 +444,7 @@ check_priv_stream(struct port_input *pi)
|
||||
* Receive something
|
||||
*/
|
||||
static ssize_t
|
||||
lsock_recv(struct port_input *pi)
|
||||
lsock_recv(struct tport *tp __unused, struct port_input *pi)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
|
@ -55,7 +55,7 @@ static void udp_close_port(struct tport *);
|
||||
static int udp_init_port(struct tport *);
|
||||
static ssize_t udp_send(struct tport *, const u_char *, size_t,
|
||||
const struct sockaddr *, size_t);
|
||||
static ssize_t udp_recv(struct port_input *);
|
||||
static ssize_t udp_recv(struct tport *, struct port_input *);
|
||||
|
||||
/* exported */
|
||||
const struct transport_def udp_trans = {
|
||||
@ -217,8 +217,30 @@ udp_send(struct tport *tp, const u_char *buf, size_t len,
|
||||
const struct sockaddr *addr, size_t addrlen)
|
||||
{
|
||||
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;
|
||||
|
||||
return (sendto(p->input.fd, buf, len, 0, addr, addrlen));
|
||||
iov.iov_base = __DECONST(void*, buf);
|
||||
iov.iov_len = len;
|
||||
|
||||
msg.msg_iov = &iov;
|
||||
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));
|
||||
|
||||
return (sendmsg(p->input.fd, &msg, 0));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -309,8 +331,9 @@ recv_dgram(struct port_input *pi, struct in_addr *laddr)
|
||||
* Receive something
|
||||
*/
|
||||
static ssize_t
|
||||
udp_recv(struct port_input *pi)
|
||||
udp_recv(struct tport *tp, struct port_input *pi)
|
||||
{
|
||||
struct udp_port *p = (struct udp_port *)tp;
|
||||
struct in_addr *laddr;
|
||||
struct msghdr msg;
|
||||
char cbuf[CMSG_SPACE(sizeof(struct in_addr))];
|
||||
@ -330,6 +353,8 @@ udp_recv(struct port_input *pi)
|
||||
|
||||
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;
|
||||
|
@ -39,6 +39,7 @@ 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 */
|
||||
};
|
||||
|
||||
/* argument for open call */
|
||||
|
Loading…
Reference in New Issue
Block a user