From 6fab2f80c95959b17adb2f81656e9abf003e1717 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 21 Jul 2011 01:40:50 +0000 Subject: [PATCH] 3135. [port] FreeBSD: workaround broken IPV6_USE_MIN_MTU processing. See http://www.freebsd.org/cgi/query-pr.cgi?pr=158307 [RT #24950] --- CHANGES | 4 ++++ lib/isc/unix/socket.c | 44 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 7f3dc8f11a..a5e65a2562 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +3135. [port] FreeBSD: workaround broken IPV6_USE_MIN_MTU processing. + See http://www.freebsd.org/cgi/query-pr.cgi?pr=158307 + [RT #24950] + 3134. [bug] Improve the accuracy of dnssec-signzone's signing statistics. [RT #16030] diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index 9d47f72403..90be778a4b 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: socket.c,v 1.338 2011/03/11 06:11:26 marka Exp $ */ +/* $Id: socket.c,v 1.339 2011/07/21 01:40:50 marka Exp $ */ /*! \file */ @@ -1364,6 +1364,9 @@ build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, #if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO) if ((sock->type == isc_sockettype_udp) && ((dev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0)) { +#if defined(IPV6_USE_MIN_MTU) + int use_min_mtu = 1; /* -1, 0, 1 */ +#endif struct cmsghdr *cmsgp; struct in6_pktinfo *pktinfop; @@ -1382,6 +1385,22 @@ build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, cmsgp->cmsg_len = cmsg_len(sizeof(struct in6_pktinfo)); pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp); memcpy(pktinfop, &dev->pktinfo, sizeof(struct in6_pktinfo)); +#if defined(IPV6_USE_MIN_MTU) + /* + * Set IPV6_USE_MIN_MTU as a per packet option as FreeBSD + * ignores setsockopt(IPV6_USE_MIN_MTU) when IPV6_PKTINFO + * is used. + */ + cmsgp = (struct cmsghdr *)(sock->sendcmsgbuf + + msg->msg_controllen); + msg->msg_controllen += cmsg_space(sizeof(use_min_mtu)); + INSIST(msg->msg_controllen <= sock->sendcmsgbuflen); + + cmsgp->cmsg_level = IPPROTO_IPV6; + cmsgp->cmsg_type = IPV6_USE_MIN_MTU; + cmsgp->cmsg_len = cmsg_len(sizeof(use_min_mtu)); + memcpy(CMSG_DATA(cmsgp), &use_min_mtu, sizeof(use_min_mtu)); +#endif } #endif /* USE_CMSG && ISC_PLATFORM_HAVEIPV6 */ #else /* ISC_NET_BSD44MSGHDR */ @@ -2053,6 +2072,13 @@ allocate_socket(isc__socketmgr_t *manager, isc_sockettype_t type, cmsgbuflen = 0; #if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO) cmsgbuflen += cmsg_space(sizeof(struct in6_pktinfo)); +#if defined(IPV6_USE_MIN_MTU) + /* + * Provide space for working around FreeBSD's broken IPV6_USE_MIN_MTU + * support. + */ + cmsgbuflen += cmsg_space(sizeof(int)); +#endif #endif sock->sendcmsgbuflen = cmsgbuflen; if (sock->sendcmsgbuflen != 0U) { @@ -2402,10 +2428,18 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock) { #endif /* ISC_PLATFORM_HAVEIN6PKTINFO */ #ifdef IPV6_USE_MIN_MTU /* RFC 3542, not too common yet*/ /* use minimum MTU */ - if (sock->pf == AF_INET6) { - (void)setsockopt(sock->fd, IPPROTO_IPV6, - IPV6_USE_MIN_MTU, - (void *)&on, sizeof(on)); + if (sock->pf == AF_INET6 && + setsockopt(sock->fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU, + (void *)&on, sizeof(on)) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IPV6_USE_MIN_MTU) " + "%s: %s", sock->fd, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); } #endif #if defined(IPV6_MTU)