From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp11.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id COzlG3P+hGIVqwAAbAwnHQ (envelope-from ) for ; Wed, 18 May 2022 16:10:59 +0200 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp11.migadu.com with LMTPS id OJHeG3P+hGLrsgAA9RJhRA (envelope-from ) for ; Wed, 18 May 2022 16:10:59 +0200 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 8C75D132A1 for ; Wed, 18 May 2022 16:10:58 +0200 (CEST) Received: from localhost ([::1]:54832 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nrKO9-0006Ph-8s for larch@yhetil.org; Wed, 18 May 2022 10:10:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46954) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nrKLL-0003Lx-0X for bug-guix@gnu.org; Wed, 18 May 2022 10:08:03 -0400 Received: from debbugs.gnu.org ([209.51.188.43]:39187) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nrKLK-0000kB-OA for bug-guix@gnu.org; Wed, 18 May 2022 10:08:02 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nrKLK-0003u6-JN for bug-guix@gnu.org; Wed, 18 May 2022 10:08:02 -0400 X-Loop: help-debbugs@gnu.org Subject: bug#55335: [PATCH Shepherd 3/3] Interpret AF_INET6 endpoints as IPv6-only. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= Original-Sender: "Debbugs-submit" Resent-CC: bug-guix@gnu.org Resent-Date: Wed, 18 May 2022 14:08:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 55335 X-GNU-PR-Package: guix X-GNU-PR-Keywords: To: 55335@debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= Received: via spool by 55335-submit@debbugs.gnu.org id=B55335.165288283414931 (code B ref 55335); Wed, 18 May 2022 14:08:02 +0000 Received: (at 55335) by debbugs.gnu.org; 18 May 2022 14:07:14 +0000 Received: from localhost ([127.0.0.1]:33080 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nrKKX-0003se-K0 for submit@debbugs.gnu.org; Wed, 18 May 2022 10:07:14 -0400 Received: from eggs.gnu.org ([209.51.188.92]:53362) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nrKKP-0003rO-DI for 55335@debbugs.gnu.org; Wed, 18 May 2022 10:07:07 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:58652) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nrKKK-0000dy-7P; Wed, 18 May 2022 10:07:00 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:References:In-Reply-To:Date:Subject:To: From; bh=5jIG4E8LPC++EfiAKatlUMPRyiIKO0S1bhQGpEgZMlQ=; b=F+xCvk7BabhMiZukejj/ 3XLnjVPHlcBfmXohpAl6wQruekCp55cyEI6uE4iVlbmBCQ7SG42hnFfrDlQ7qq2hlzMnPbIAZfqeA X2kQGoVB8vYO+TnfEnYCzw9qEPM4gproysC4Vde5uOfOua0HKK2+uB9DMV9v0hAO9bFXLcSw5Z+4D bGihridVgQAlpU2pJhe+IrR7DFEpvXqGtIQ6cWnt0pMEqxQ3UzOyiZ/vMuNH6hWEz/57y5jFyZ4EX 810fx0esB+yqem9xqzzIhTP7zxl0ok3wGLWLIt63CRkc109NVBalAN4+HUEpmPbOprXtI1zgIy8n4 HRS6+Zzv/0zM0Q==; Received: from 91-160-117-201.subs.proxad.net ([91.160.117.201]:56764 helo=gnu.org) by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nrKKJ-0003x7-QX; Wed, 18 May 2022 10:07:00 -0400 From: Ludovic =?UTF-8?Q?Court=C3=A8s?= Date: Wed, 18 May 2022 16:06:45 +0200 Message-Id: <20220518140645.17144-4-ludo@gnu.org> X-Mailer: git-send-email 2.36.0 In-Reply-To: <20220518140645.17144-1-ludo@gnu.org> References: <87zgjkfbcl.fsf_-_@gnu.org> <20220518140645.17144-1-ludo@gnu.org> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-guix@gnu.org List-Id: Bug reports for GNU Guix List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-guix-bounces+larch=yhetil.org@gnu.org Sender: "bug-Guix" X-Migadu-Flow: FLOW_IN X-Migadu-To: larch@yhetil.org X-Migadu-Country: US ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1652883059; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding:resent-cc: resent-from:resent-sender:resent-message-id:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=T++moctejtj7dd+JOgUY7FVmptXOXHleJx0ytHCkNGA=; b=HNIm02R18fdbmZGz9UmU0m2Ldvxveb3uOczs95sorCqyf7tkv2VywTYKbQFQeqOh0amV9i iVDF4xFO4EAxu750xMDzEYhJ4QVbZnfJCzxU4hdV21etxR59OpP6Bq1Q/FtJ3CpAw9AFoT yaDPkfae3t5YZF8Z7mz7irZquM5IcAspZO9NGQMJSHLxj6m1EL7xQRExn9A1JY/R+KIY0p yt1Z3x1O0sA/M0xw1MDqQEaNP77Ji/olu09Q589SVkwDe/wYMjQjRJwFGnrVAvG55926Nj HvFUJZhlN6TlxMHA7ZEeyH93Jp/gf/O+0SG8V1QqndB/epImTK4co8eh1miBxg== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1652883059; a=rsa-sha256; cv=none; b=OuHFkaniF1pAZvhl4GubjgQ+yrdTU44RKttzaM12/X8DbWnFNpVeq0bz0xHRVHcA9sMZXO 45atgsrP82gNMyIvBulKa4TIzk22IfXlTrUfIaemsmDeTrs6YsYzzbN60bNm/K9iSB/F/7 Zi8FfJqN1SkTt7yvXUhXrAGMmKUdy8L4RqdVdivTIB/krkJrdFNn5RXlAJkHCv0FAUGbU5 c2JPOBDGGxeqDUXsZk50oq5RFJTQVWWh5e/QLPOIOvoOg5YcHvG9PHR7DFrsY8I1zkJHxU 3T8YRea8fmsiiMRVFCauQdpS0rt+yAKmOY7XZ5HmNCqgB7tS0yAIh/0hC/KeNQ== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("body hash did not verify") header.d=gnu.org header.s=fencepost-gnu-org header.b=F+xCvk7B; dmarc=pass (policy=none) header.from=gnu.org; spf=pass (aspmx1.migadu.com: domain of "bug-guix-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="bug-guix-bounces+larch=yhetil.org@gnu.org" X-Migadu-Spam-Score: -2.95 Authentication-Results: aspmx1.migadu.com; dkim=fail ("body hash did not verify") header.d=gnu.org header.s=fencepost-gnu-org header.b=F+xCvk7B; dmarc=pass (policy=none) header.from=gnu.org; spf=pass (aspmx1.migadu.com: domain of "bug-guix-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="bug-guix-bounces+larch=yhetil.org@gnu.org" X-Migadu-Queue-Id: 8C75D132A1 X-Spam-Score: -2.95 X-Migadu-Scanner: scn1.migadu.com X-TUID: EQUobZgBtpy2 * configure.ac: Check the values of IPPROTO_IPV6 and IPV6_V6ONLY. * modules/shepherd/system.scm.in (ipv6-only): New procedure. * modules/shepherd/service.scm (endpoint->listening-socket): Call it if ADDRESS is AF_INET6. (define-as-needed): New macro. (IN6ADDR_LOOPBACK, IN6ADDR_ANY): New variables. * tests/inetd.sh: Add 'test-inetd6' and 'test-inetd-v6-only' services. Test them. --- NEWS | 11 +++++++ configure.ac | 12 +++++++ doc/shepherd.texi | 14 ++++++++ modules/shepherd/service.scm | 19 +++++++++++ modules/shepherd/system.scm.in | 11 +++++++ tests/inetd.sh | 58 ++++++++++++++++++++++++++++++++++ 6 files changed, 125 insertions(+) diff --git a/NEWS b/NEWS index 4ce7a48..3798b31 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,17 @@ For compatibility with 0.9.0, if the second argument to list of endpoints. This behavior will be preserved for at least the whole 0.9.x series. +** ‘AF_INET6’ endpoints are now interpreted as IPv6-only + +In 0.9.0, using an ‘AF_INET6’ endpoint for ‘make-systemd-constructor’ would +usually have the effect of making the service available on both IPv6 and IPv4. +This is due to the default behavior of Linux, which is to bind IPv6 addresses +as IPv4 as well (the default behavior can be changed by running +‘sysctl net.ipv6.bindv6only 1’). + +‘AF_INET6’ endpoints are now interpreted as IPv6-only. Thus, if a service is +to be made available both as IPv6 and IPv4, two endpoints must be used. + ** ‘shepherd’ reports whether a service is transient ** ‘herd status’ shows whether a service is transient ** Fix possible file descriptor leak in ‘make-inetd-constructor’ diff --git a/configure.ac b/configure.ac index bf91560..b745813 100644 --- a/configure.ac +++ b/configure.ac @@ -141,6 +141,18 @@ AC_SUBST([SIG_BLOCK]) AC_SUBST([SIG_UNBLOCK]) AC_SUBST([SIG_SETMASK]) +dnl Check for constants not exported by Guile as of 3.0.8. +AC_MSG_CHECKING([ constants]) +AC_COMPUTE_INT([IPPROTO_IPV6], [IPPROTO_IPV6], [ + #include + #include ]) +AC_COMPUTE_INT([IPV6_V6ONLY], [IPV6_V6ONLY], [ + #include + #include ]) +AC_MSG_RESULT([done]) +AC_SUBST([IPPROTO_IPV6]) +AC_SUBST([IPV6_V6ONLY]) + AC_MSG_CHECKING([whether to build crash handler]) case "$host_os" in linux-gnu*) build_crash_handler=yes;; diff --git a/doc/shepherd.texi b/doc/shepherd.texi index 9efc48e..841b854 100644 --- a/doc/shepherd.texi +++ b/doc/shepherd.texi @@ -1093,6 +1093,20 @@ Return a new endpoint called @var{name} of @var{address}, an address as return by @code{make-socket-address}, with the given @var{style} and @var{backlog}. +When @var{address} is of type @code{AF_INET6}, the endpoint is +@emph{IPv6-only}. Thus, if you want a service available both on IPv4 +and IPv6, you need two endpoints. For example, below is a list of +endpoints to listen on port 4444 on all the network interfaces, both in +IPv4 and IPv6 (``0.0.0.0'' for IPv4 and ``::0'' for IPv6): + +@lisp +(list (endpoint (make-socket-address AF_INET INADDR_ANY 4444)) + (endpoint (make-socket-address AF_INET6 IN6ADDR_ANY 4444))) +@end lisp + +This is the list you would pass to @code{make-inetd-constructor} or +@code{make-systemd-constructor}---see below. + When @var{address} is of type @code{AF_UNIX}, @var{socket-owner} and @var{socket-group} are strings or integers that specify its ownership and that of its parent directory; @var{socket-directory-permissions} specifies the diff --git a/modules/shepherd/service.scm b/modules/shepherd/service.scm index e93466a..6df550c 100644 --- a/modules/shepherd/service.scm +++ b/modules/shepherd/service.scm @@ -1251,6 +1251,10 @@ as argument, where SIGNAL defaults to `SIGTERM'." return by @code{make-socket-address}, with the given @var{style} and @var{backlog}. +When @var{address} is of type @code{AF_INET6}, the endpoint is +@emph{IPv6-only}. Thus, if you want a service available both on IPv4 and +IPv6, you need two endpoints. + When @var{address} is of type @code{AF_UNIX}, @var{socket-owner} and @var{socket-group} are strings or integers that specify its ownership and that of its parent directory; @var{socket-directory-permissions} specifies the @@ -1273,6 +1277,11 @@ permissions for its parent directory." group (group:gid (getgrnam group))))) (setsockopt sock SOL_SOCKET SO_REUSEADDR 1) + (when (= AF_INET6 (sockaddr:fam address)) + ;; Interpret AF_INET6 endpoints as IPv6-only. This is contrary to + ;; the Linux defaults where listening on an IPv6 address also listens + ;; on its IPv4 counterpart. + (ipv6-only sock)) (when (= AF_UNIX (sockaddr:fam address)) (mkdir-p (dirname (sockaddr:path address)) permissions) (chown (dirname (sockaddr:path address)) owner group) @@ -1309,6 +1318,16 @@ thrown an previously-opened sockets are closed." (apply throw args))))) (loop tail (cons sock result))))))) +(define-syntax-rule (define-as-needed name value) + (unless (defined? 'name) + (module-define! (current-module) 'name value) + (module-export! (current-module) '(name)))) + +;; These values are not defined as of Guile 3.0.8. Provide them as a +;; convenience. +(define-as-needed IN6ADDR_LOOPBACK 1) +(define-as-needed IN6ADDR_ANY 0) + ;;; ;;; Inetd-style services. diff --git a/modules/shepherd/system.scm.in b/modules/shepherd/system.scm.in index 2562764..0978c18 100644 --- a/modules/shepherd/system.scm.in +++ b/modules/shepherd/system.scm.in @@ -32,6 +32,7 @@ prctl PR_SET_CHILD_SUBREAPER getpgid + ipv6-only SFD_CLOEXEC signalfd consume-signalfd-siginfo @@ -141,6 +142,16 @@ ctrlaltdel(8) and see kernel/reboot.c in Linux." (list err)) result))))) +(define (ipv6-only port) + "Make PORT, a file port backed by a socket, IPv6-only (using the IPV6_V6ONLY +socket option) and return PORT. + +This is useful when willing to make a listening socket that operates on IPv6 +only (by default, Linux binds AF_INET6 addresses on IPv4 as well)." + ;; As of Guile 3.0.8, IPPROTO_IPV6 and IPV6_V6ONLY are not exported. + (setsockopt port @IPPROTO_IPV6@ @IPV6_V6ONLY@ 1) + port) + (define (allocate-sigset) (bytevector->pointer (make-bytevector @SIZEOF_SIGSET_T@))) diff --git a/tests/inetd.sh b/tests/inetd.sh index 83037bf..c05d6fe 100644 --- a/tests/inetd.sh +++ b/tests/inetd.sh @@ -48,6 +48,28 @@ cat > "$conf" < + #:provides '(test-inetd6) + #:start (make-inetd-constructor %command + (list + (endpoint (make-socket-address + AF_INET + INADDR_LOOPBACK + $PORT)) + (endpoint (make-socket-address + AF_INET6 + IN6ADDR_LOOPBACK + $PORT)))) + #:stop (make-inetd-destructor)) + (make + #:provides '(test-inetd-v6-only) + #:start (make-inetd-constructor %command + (list + (endpoint (make-socket-address + AF_INET6 + IN6ADDR_LOOPBACK + $PORT)))) + #:stop (make-inetd-destructor)) (make #:provides '(test-inetd-unix) #:start (make-inetd-constructor %command @@ -81,6 +103,7 @@ test $($herd status | grep '\+' | wc -l) -eq 2 converse_with_echo_server () { guile -c "(use-modules (ice-9 match) (ice-9 rdelim)) + (define IN6ADDR_LOOPBACK 1) (define address $1) (define sock (socket (sockaddr:fam address) SOCK_STREAM 0)) (connect sock address) @@ -98,10 +121,45 @@ do "(make-socket-address AF_INET INADDR_LOOPBACK $PORT)" done +# Unavailable on IPv6. +! converse_with_echo_server \ + "(make-socket-address AF_INET6 IN6ADDR_LOOPBACK $PORT)" + $herd stop test-inetd ! converse_with_echo_server \ "(make-socket-address AF_INET INADDR_LOOPBACK $PORT)" +if guile -c '(socket AF_INET6 SOCK_STREAM 0)'; then + # Test IPv6 support. + $herd start test-inetd6 + + converse_with_echo_server \ + "(make-socket-address AF_INET6 IN6ADDR_LOOPBACK $PORT)" + converse_with_echo_server \ + "(make-socket-address AF_INET INADDR_LOOPBACK $PORT)" + + $herd stop test-inetd6 + + ! converse_with_echo_server \ + "(make-socket-address AF_INET6 IN6ADDR_LOOPBACK $PORT)" + ! converse_with_echo_server \ + "(make-socket-address AF_INET INADDR_LOOPBACK $PORT)" + + $herd start test-inetd-v6-only + + converse_with_echo_server \ + "(make-socket-address AF_INET6 IN6ADDR_LOOPBACK $PORT)" + ! converse_with_echo_server \ + "(make-socket-address AF_INET INADDR_LOOPBACK $PORT)" + + $herd stop test-inetd-v6-only + + ! converse_with_echo_server \ + "(make-socket-address AF_INET6 IN6ADDR_LOOPBACK $PORT)" + ! converse_with_echo_server \ + "(make-socket-address AF_INET INADDR_LOOPBACK $PORT)" +fi + # Now test inetd on a Unix-domain socket. $herd start test-inetd-unix -- 2.36.0