File libtirpc-rpc_broadcast_misformed_replies.patch of Package libtirpc.370

commit 17619288497d76ade1671f0adbda682548d026d5
Author: Olaf Kirch <okir@suse.de>
Date:   Thu Nov 13 10:24:39 2008 +0100

    rpc_broadcast: handle misformed rpcbind replies
    
    Some rpcbind implementations seem to return IPv6 uaddrs
    in response to an IPv4 broadcast (which is probably due
    to their using a single v6 socket to handle both v6 and
    v4 requests).
    
    We can either discard these replies, or fix them up silently.
    Here's a patch that implements the latter.
    
    Signed-off-by: Olaf Kirch <okir@suse.de>

diff --git a/src/clnt_bcast.c b/src/clnt_bcast.c
index 899eb76..55efc9d 100644
--- a/src/clnt_bcast.c
+++ b/src/clnt_bcast.c
@@ -227,6 +227,39 @@ __rpc_broadenable(int af, int s, struct broadif *bip)
 	return 0;
 }
 
+/*
+ * Some rpcbind implementations use an IPv6 socket to serve both 
+ * IPv4 and IPv6 messages, but neglect to check for the caller's
+ * address family when sending broadcast replies. These rpcbind
+ * implementations return an IPv6 address in reply to an IPv4
+ * broadcast. We can either ignore them, or try to patch them up.
+ */
+static struct netbuf *
+__ipv6v4_fixup(struct sockaddr_storage *ss, const char *uaddr)
+{
+	struct sockaddr_in sin;
+	struct netbuf *np;
+
+	/* ss is the remote rpcbind server's address */
+	if (ss->ss_family != AF_INET)
+		return NULL;
+	memcpy(&sin, ss, sizeof(sin));
+
+	np = __rpc_uaddr2taddr_af(AF_INET6, uaddr);
+	if (np == NULL)
+		return NULL;
+
+	/* Overwrite the port with that of the service we
+	 * wanted to talk to. */
+	sin.sin_port = ((struct sockaddr_in6 *) np)->sin6_port;
+
+	/* We know netbuf holds a sockaddr_in6, so it can easily
+	 * hold a sockaddr_in as well. */
+	memcpy(np->buf, &sin, sizeof(sin));
+	np->len = sizeof(sin);
+
+	return np;
+}
 
 enum clnt_stat
 rpc_broadcast_exp(prog, vers, proc, xargs, argsp, xresults, resultsp,
@@ -607,6 +640,13 @@ rpc_broadcast_exp(prog, vers, proc, xargs, argsp, xresults, resultsp,
 #endif
 						np = uaddr2taddr(
 						    fdlist[i].nconf, uaddrp);
+						/* Some misguided rpcbind implemenations
+						 * seem to return an IPv6 uaddr in IPv4
+						 * responses. */
+						if (np == NULL)
+							np = __ipv6v4_fixup(
+								&fdlist[i].raddr,
+								uaddrp);
 						if (np != NULL) {
 							done = (*eachresult)(resultsp,
 							    np, fdlist[i].nconf);