File socket-activation-fix-rpcbind-service-to-use-separate-sockets of Package rpcbind

From: Jeff Mahoney <jeffm@suse.com>
Subject: socket-activation: Fix rpcbind.service to use separate sockets
References: bnc#757909

 systemd will, by default, pass a socket that provides both IPv4 and
 IPv6 services. RPC netconfig requires that sockets be either IPv4
 or IPv6.

 This patch fixes the rpcbind.socket unit file and adds a warning
 to rpcbind should the user encounter an issue.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---

 src/rpcbind.c          |   32 +++++++++++++++++++++++++++++++-
 systemd/rpcbind.socket |    9 +++++++--
 2 files changed, 38 insertions(+), 3 deletions(-)

Index: rpcbind-0.2.0_git201103171419/src/rpcbind.c
===================================================================
--- rpcbind-0.2.0_git201103171419.orig/src/rpcbind.c
+++ rpcbind-0.2.0_git201103171419/src/rpcbind.c
@@ -50,6 +50,7 @@
 #include <sys/file.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <netinet/in.h>
 #include <rpc/rpc.h>
 #include <rpc/rpc_com.h>
 #ifdef PORTMAP
@@ -263,6 +264,32 @@ main(int argc, char *argv[])
 }
 
 /*
+ * Normally systemd will open sockets in dual ipv4/ipv6 mode.
+ * That won't work with netconfig and we'll only match
+ * the ipv6 socket. Convert it to IPV6_V6ONLY and issue
+ * a warning for the user to fix their systemd config.
+ */
+static int
+handle_ipv6_socket(int fd)
+{
+	int opt;
+	socklen_t len = sizeof(opt);
+
+	if (getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, &len)) {
+		syslog(LOG_ERR, "failed to get ipv6 socket opts: %s",
+		       strerror(errno));
+		return 1;
+	}
+
+	if (opt) /* socket is already in V6ONLY mode */
+		return 0;
+
+	syslog(LOG_ERR, "systemd has passed an IPv4/IPv6 dual-mode socket.");
+	syslog(LOG_ERR, "Please fix your systemd config by specifying IPv4 and IPv6 sockets separately and using BindIPv6Only=ipv6-only.");
+	return 1;
+}
+
+/*
  * Adds the entry into the rpcbind database.
  * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
  * Returns 0 if succeeds, else fails
@@ -314,7 +341,7 @@ init_transport(struct netconfig *nconf)
 #ifdef SYSTEMD
 	n = sd_listen_fds(0);
 	if (n < 0) {
-		syslog(LOG_ERR, "failed to acquire systemd scokets: %s", strerror(-n));
+		syslog(LOG_ERR, "failed to acquire systemd sockets: %s", strerror(-n));
 		return 1;
 	}
 
@@ -348,6 +375,9 @@ init_transport(struct netconfig *nconf)
 			goto error;
 		}
 
+		if (sa.sa.sa_family == AF_INET6 && handle_ipv6_socket(fd))
+			goto error;
+
 		/* Copy the address */
 		taddr.addr.maxlen = taddr.addr.len = addrlen;
 		taddr.addr.buf = malloc(addrlen);
Index: rpcbind-0.2.0_git201103171419/systemd/rpcbind.socket
===================================================================
--- rpcbind-0.2.0_git201103171419.orig/systemd/rpcbind.socket
+++ rpcbind-0.2.0_git201103171419/systemd/rpcbind.socket
@@ -4,9 +4,14 @@ Wants=rpcbind.target
 Before=rpcbind.target
 
 [Socket]
-ListenStream=/var/run/rpcbind.sock
-ListenStream=111
-ListenDatagram=111
+ListenStream=/run/rpcbind.sock
+
+# RPC netconfig can't handle ipv6/ipv4 dual sockets
+BindIPv6Only=ipv6-only
+ListenStream=0.0.0.0:111
+ListenDatagram=0.0.0.0:111
+ListenStream=[::]:111
+ListenDatagram=[::]:111
 
 [Install]
 WantedBy=sockets.target
openSUSE Build Service is sponsored by