git: 8c81694af438 - stable/14 - linux: ignore setsockopt(IPV6_RECVERR)

From: Warner Losh <imp_at_FreeBSD.org>
Date: Sat, 27 Apr 2024 13:03:17 UTC
The branch stable/14 has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=8c81694af438fee9071f826efcc9f1633c50ab3d

commit 8c81694af438fee9071f826efcc9f1633c50ab3d
Author:     Lexi Winter <lexi@le-Fay.ORG>
AuthorDate: 2024-04-22 21:58:11 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-04-27 12:59:46 +0000

    linux: ignore setsockopt(IPV6_RECVERR)
    
    Under Linux, the socket options IP_RECVERR and IPV6_RECVERR are used to
    receive socket errors via a dedicated 'error queue' which can be
    retrieved via recvmsg().  FreeBSD does not support this functionality.
    
    For IPv4, the sysctl compat.linux.ignore_ip_recverr can be set to 1 to
    silently ignore attempts to set IP_RECVERR and return success to the
    application, which is wrong, but is required for (among other things)
    a functional DNS client in recent versions of glibc.
    
    Add support for ignoring IPV6_RECVERR, controlled by the same sysctl.
    This fixes DNS in Linux when using IPv6 resolvers.
    
    Reviewed by: imp, Jose Luis Duran
    Pull Request: https://github.com/freebsd/freebsd-src/pull/1118
    
    (cherry picked from commit ca63710d3668cf6f3cb4faf065d8b4eeffa028ad)
---
 sys/compat/linux/linux_socket.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c
index a5ed5c5c62db..705a64de8ede 100644
--- a/sys/compat/linux/linux_socket.c
+++ b/sys/compat/linux/linux_socket.c
@@ -501,6 +501,11 @@ linux_to_bsd_ip6_sockopt(int opt)
 		    "unsupported IPv6 socket option IPV6_RECVFRAGSIZE (%d)",
 		    opt);
 		return (-2);
+	case LINUX_IPV6_RECVERR:
+		LINUX_RATELIMIT_MSG_OPT1(
+		    "unsupported IPv6 socket option IPV6_RECVERR (%d), you can not get extended reliability info in linux programs",
+		    opt);
+		return (-2);
 
 	/* unknown sockopts */
 	default:
@@ -2110,6 +2115,14 @@ linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
 		name = linux_to_bsd_ip_sockopt(args->optname);
 		break;
 	case IPPROTO_IPV6:
+		if (args->optname == LINUX_IPV6_RECVERR &&
+		    linux_ignore_ip_recverr) {
+			/*
+			 * XXX: This is a hack to unbreak DNS resolution
+			 *	with glibc 2.30 and above.
+			 */
+			return (0);
+		}
 		name = linux_to_bsd_ip6_sockopt(args->optname);
 		break;
 	case IPPROTO_TCP: