From: "Ludovic Courtès" <ludo@gnu.org>
To: 55335@debbugs.gnu.org
Cc: "Ludovic Courtès" <ludo@gnu.org>
Subject: bug#55335: [PATCH Shepherd 3/3] Interpret AF_INET6 endpoints as IPv6-only.
Date: Wed, 18 May 2022 16:06:45 +0200 [thread overview]
Message-ID: <20220518140645.17144-4-ludo@gnu.org> (raw)
In-Reply-To: <20220518140645.17144-1-ludo@gnu.org>
* 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([<netinet/in.h> constants])
+AC_COMPUTE_INT([IPPROTO_IPV6], [IPPROTO_IPV6], [
+ #include <sys/socket.h>
+ #include <netinet/in.h>])
+AC_COMPUTE_INT([IPV6_V6ONLY], [IPV6_V6ONLY], [
+ #include <sys/socket.h>
+ #include <netinet/in.h>])
+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)
+
\f
;;;
;;; 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" <<EOF
INADDR_LOOPBACK
$PORT))))
#:stop (make-inetd-destructor))
+ (make <service>
+ #: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 <service>
+ #: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 <service>
#: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
next prev parent reply other threads:[~2022-05-18 14:10 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-05-09 10:39 bug#55335: openssh-service no longer listens on IPv6 Christopher Baines
2022-05-13 12:21 ` Christopher Baines
2022-05-13 14:23 ` bug#55335: [PATCH] services: Allow shepherd to listen for IPv6 connections to openssh Christopher Baines
2022-05-13 15:23 ` Jack Hill
2022-05-13 15:25 ` Jack Hill
2022-05-14 8:42 ` bug#55335: openssh-service no longer listens on IPv6 Ludovic Courtès
2022-05-14 14:16 ` Ludovic Courtès
2022-05-18 14:06 ` bug#55335: [PATCH Shepherd 0/3] Endpoints for inetd services + IPv6-only endpoints Ludovic Courtès
2022-05-18 14:06 ` bug#55335: [PATCH Shepherd 1/3] service: 'make-inetd-constructor' accepts a list of endpoints Ludovic Courtès
2022-05-18 14:06 ` bug#55335: [PATCH Shepherd 2/3] tests: Update inetd tests to pass " Ludovic Courtès
2022-05-18 14:06 ` Ludovic Courtès [this message]
2022-05-18 14:28 ` bug#55335: openssh-service no longer listens on IPv6 Ludovic Courtès
2022-05-22 20:08 ` Ludovic Courtès
2022-05-22 22:35 ` Jack Hill
2022-05-23 13:30 ` Ludovic Courtès
2022-05-23 15:29 ` Simon Streit
2022-05-14 15:49 ` Ludovic Courtès
2022-05-14 19:09 ` Jack Hill
2022-05-17 21:33 ` Christopher Baines
2022-05-18 9:30 ` Ludovic Courtès
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://guix.gnu.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220518140645.17144-4-ludo@gnu.org \
--to=ludo@gnu.org \
--cc=55335@debbugs.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/guix.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).