[PATCH] Patch for bug 11714: Listening for network interface changes doesn't work

Ralph Boehme rb at sernet.de
Thu Feb 4 17:20:20 UTC 2016


Hi!

<https://bugzilla.samba.org/show_bug.cgi?id=11714>

winbindd is watching for network interface address changes by virtue
of our addrchange_send/recv() API that uses netlink to query the
kernel for this information.

Log:

[2016/02/04 11:43:31.723123, 10, pid=17692, effective(0, 0), real(0,0)] ../source3/lib/addrchange.c:154(addrchange_done)
  tdgram_recvfrom_recv returned Operation not supported
[2016/02/04 11:43:31.723176, 10, pid=17692, effective(0, 0), real(0,0), class=winbind] ../source3/winbindd/winbindd.c:1486(winbindd_addr_changed)
  addrchange_recv failed: NT_STATUS_NOT_SUPPORTED, stop listening

strace shows a failing ioctl(fd, FIONREAD, ...) returning
EOPNOTSUPP. We use the ioctl to determine the amount of pending data
so we can allocate an appropriate buffer.

This is a regression introduced in 0d161e42d9aeb155eae2b04eccec497b21de8029.

What can we do?

We could use MSG_PEEK, but that's not portable and we'd have to call
recvmsg() twice every time the fd is reported readable.

As a band aid, allocate a laaaarge buffer and watch out for MSG_TRUNC
after receiving.

We could also revert 0d161e42d9aeb155eae2b04eccec497b21de8029 and fix
the issue that change was trying to address differently.

Review&comments welcome.

Thanks!
-Ralph

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de,mailto:kontakt@sernet.de
-------------- next part --------------
From bb4c47b7ebc96c81d3091500f6bd0f467b7a7e10 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 4 Feb 2016 15:26:05 +0100
Subject: [PATCH 1/2] lib/tsocket: use recvmsg() instead of recvfrom()

recvmsg() returns msg_flags which will be used in a subsequent commit.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11714

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 lib/tsocket/tsocket_bsd.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c
index ac0617d..9b339da 100644
--- a/lib/tsocket/tsocket_bsd.c
+++ b/lib/tsocket/tsocket_bsd.c
@@ -891,6 +891,8 @@ static void tdgram_bsd_recvfrom_handler(void *private_data)
 	ssize_t ret;
 	int err;
 	bool retry;
+	struct iovec iov;
+	struct msghdr msg;
 
 	ret = tsocket_bsd_pending(bsds->fd);
 	if (state->first_try && ret == 0) {
@@ -931,8 +933,19 @@ static void tdgram_bsd_recvfrom_handler(void *private_data)
 	bsda->u.sa.sa_len = bsda->sa_socklen;
 #endif
 
-	ret = recvfrom(bsds->fd, state->buf, state->len, 0,
-		       &bsda->u.sa, &bsda->sa_socklen);
+	iov = (struct iovec) {
+		.iov_base = state->buf,
+		.iov_len = state->len
+	};
+
+	msg = (struct msghdr) {
+		.msg_name = &bsda->u.sa,
+		.msg_namelen = bsda->sa_socklen,
+		.msg_iov = &iov,
+		.msg_iovlen = 1
+	};
+
+	ret = recvmsg(bsds->fd, &msg, 0);
 	err = tsocket_bsd_error_from_errno(ret, errno, &retry);
 	if (retry) {
 		/* retry later */
@@ -942,6 +955,8 @@ static void tdgram_bsd_recvfrom_handler(void *private_data)
 		return;
 	}
 
+	bsda->sa_socklen = msg.msg_namelen;
+
 	/*
 	 * Some systems (FreeBSD, see bug #7115) return too much
 	 * bytes in tsocket_bsd_pending()/ioctl(fd, FIONREAD, ...),
-- 
2.5.0


From 28dfca513b9cc28107438edb1b616ef393b89b45 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 4 Feb 2016 15:35:06 +0100
Subject: [PATCH 2/2] lib/tsocket: workaround sockets not supporting FIONREAD

Some sockets, notably netlink sockets, don't support querying pending
bytes with ioctl(fd, FIONREAD, ...) and return EOPNOTSUPP.

What can we do?

We could use MSG_PEEK, but that's not portable and we'd have to call
recvmsg() twice every time the fd is reported readable.

As a band aid, allocate a laaaarge buffer and watch out for MSG_TRUNC
after receiving.

The buffer is reallocated to the actual size at the end anyway and then
passed to the caller.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11714

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 lib/tsocket/tsocket_bsd.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c
index 9b339da..146afeb 100644
--- a/lib/tsocket/tsocket_bsd.c
+++ b/lib/tsocket/tsocket_bsd.c
@@ -140,6 +140,16 @@ static ssize_t tsocket_bsd_pending(int fd)
 
 	ret = ioctl(fd, FIONREAD, &value);
 	if (ret == -1) {
+		if (errno == EOPNOTSUPP) {
+			/*
+			 * Damn! Some sockets, notably netlink sockets, don't
+			 * support this. Allocate a large buffer, hoping for the
+			 * best. In case the received messages is truncated,
+			 * we'll return an error.
+			 */
+			errno = 0;
+			return 64 * 1024;
+		}
 		return ret;
 	}
 
@@ -946,6 +956,18 @@ static void tdgram_bsd_recvfrom_handler(void *private_data)
 	};
 
 	ret = recvmsg(bsds->fd, &msg, 0);
+
+	if (msg.msg_flags & MSG_TRUNC) {
+		/*
+		 * It didn't work out to peak at the pending bytes in
+		 * tsocket_bsd_pending() and we used some default size that
+		 * apperently wasn't big enough. We can't recover from this so
+		 * error out.
+		 */
+		errno = EINVAL;
+		ret = -1;
+	}
+
 	err = tsocket_bsd_error_from_errno(ret, errno, &retry);
 	if (retry) {
 		/* retry later */
-- 
2.5.0



More information about the samba-technical mailing list