File 0001-rpcinfo-change-order-of-version-to-be-tried-to-4-3-2.patch of Package libtirpc.7906
From 42eb0d9ead5b15d9f2ac4b565c11a39ae19a1291 Mon Sep 17 00:00:00 2001
From: Thomas Blume <Thomas.Blume@suse.com>
Date: Wed, 14 Mar 2018 09:51:51 -0400
Subject: [PATCH 1/3] rpcinfo: change order of version to be tried to 4, 3, 2
When specifying TCP as transport on rpcinfo getport command (-T tcp),
the initial RPC getport packet is still sent as a UDP packet.
This is due to rpc protocol version 2 is tried first and
function getpmaphandle() states:
/*
* Try UDP only - there are some portmappers out
* there that use UDP only.
*/
Even on systems with newer rpc versions, this will hang when
the UDP port is blocked. That is a quite artifical limitation,
because UDP only portmappert should be really rare by now.
The attached code changes the order of versions to be tried
to 4, then 3 and use version 2 only as fallback.
Reviewed-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Thomas Blume <Thomas.Blume@suse.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
(cherry picked from commit 5e7b57bc20bd9cadfffd6de52c3331a926ebdf92)
---
src/rpcb_clnt.c | 148 ++++++++++++++++++++++++++++++--------------------------
1 file changed, 80 insertions(+), 68 deletions(-)
diff --git a/src/rpcb_clnt.c b/src/rpcb_clnt.c
index 78b1534..a94fc73 100644
--- a/src/rpcb_clnt.c
+++ b/src/rpcb_clnt.c
@@ -729,14 +729,83 @@ __rpcbind_is_up()
}
#endif
+#ifdef PORTMAP
+static struct netbuf *
+__try_protocol_version_2(program, version, nconf, host, tp)
+ rpcprog_t program;
+ rpcvers_t version;
+ const struct netconfig *nconf;
+ const char *host;
+ struct timeval *tp;
+{
+ u_short port = 0;
+ struct netbuf remote;
+ struct pmap pmapparms;
+ CLIENT *client = NULL;
+ enum clnt_stat clnt_st;
+ struct netbuf *pmapaddress;
+ RPCB parms;
+
+ if (strcmp(nconf->nc_proto, NC_UDP) != 0
+ && strcmp(nconf->nc_proto, NC_TCP) != 0)
+ return (NULL);
+
+ client = getpmaphandle(nconf, host, &parms.r_addr);
+ if (client == NULL)
+ return (NULL);
+
+ /*
+ * Set retry timeout.
+ */
+ CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
+
+ pmapparms.pm_prog = program;
+ pmapparms.pm_vers = version;
+ pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ?
+ IPPROTO_UDP : IPPROTO_TCP;
+ pmapparms.pm_port = 0; /* not needed */
+ clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
+ (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms,
+ (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port,
+ *tp);
+ if (clnt_st != RPC_SUCCESS) {
+ rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ return (NULL);
+ } else if (port == 0) {
+ pmapaddress = NULL;
+ rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+ return (NULL);
+ }
+ port = htons(port);
+ CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
+ if (((pmapaddress = (struct netbuf *)
+ malloc(sizeof (struct netbuf))) == NULL) ||
+ ((pmapaddress->buf = (char *)
+ malloc(remote.len)) == NULL)) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ if (pmapaddress) {
+ free(pmapaddress);
+ pmapaddress = NULL;
+ }
+ return (NULL);
+ }
+ memcpy(pmapaddress->buf, remote.buf, remote.len);
+ memcpy(&((char *)pmapaddress->buf)[sizeof (short)],
+ (char *)(void *)&port, sizeof (short));
+ pmapaddress->len = pmapaddress->maxlen = remote.len;
+
+ return pmapaddress;
+}
+#endif
+
/*
* An internal function which optimizes rpcb_getaddr function. It also
* returns the client handle that it uses to contact the remote rpcbind.
*
* The algorithm used: If the transports is TCP or UDP, it first tries
- * version 2 (portmap), 4 and then 3 (svr4). This order should be
- * changed in the next OS release to 4, 2 and 3. We are assuming that by
- * that time, version 4 would be available on many machines on the network.
+ * version 4 (srv4), then 3 and then fall back to version 2 (portmap).
* With this algorithm, we get performance as well as a plan for
* obsoleting version 2.
*
@@ -781,71 +850,6 @@ __rpcb_findaddr_timed(program, version, nconf, host, clpp, tp)
*/
if (tp == NULL)
tp = &tottimeout;
-
-#ifdef PORTMAP
- /* Try version 2 for TCP or UDP */
- if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
- u_short port = 0;
- struct netbuf remote;
- struct pmap pmapparms;
-
- if (strcmp(nconf->nc_proto, NC_UDP) != 0
- && strcmp(nconf->nc_proto, NC_TCP) != 0)
- goto try_rpcbind;
-
- client = getpmaphandle(nconf, host, &parms.r_addr);
- if (client == NULL)
- return (NULL);
-
- /*
- * Set retry timeout.
- */
- CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
-
- pmapparms.pm_prog = program;
- pmapparms.pm_vers = version;
- pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ?
- IPPROTO_UDP : IPPROTO_TCP;
- pmapparms.pm_port = 0; /* not needed */
- clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
- (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms,
- (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port,
- *tp);
- if (clnt_st != RPC_SUCCESS) {
- if ((clnt_st == RPC_PROGVERSMISMATCH) ||
- (clnt_st == RPC_PROGUNAVAIL))
- goto try_rpcbind;
- rpc_createerr.cf_stat = RPC_PMAPFAILURE;
- clnt_geterr(client, &rpc_createerr.cf_error);
- goto error;
- } else if (port == 0) {
- address = NULL;
- rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
- goto error;
- }
- port = htons(port);
- CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
- if (((address = (struct netbuf *)
- malloc(sizeof (struct netbuf))) == NULL) ||
- ((address->buf = (char *)
- malloc(remote.len)) == NULL)) {
- rpc_createerr.cf_stat = RPC_SYSTEMERROR;
- clnt_geterr(client, &rpc_createerr.cf_error);
- if (address) {
- free(address);
- address = NULL;
- }
- goto error;
- }
- memcpy(address->buf, remote.buf, remote.len);
- memcpy(&((char *)address->buf)[sizeof (short)],
- (char *)(void *)&port, sizeof (short));
- address->len = address->maxlen = remote.len;
- goto done;
- }
-
-try_rpcbind:
-#endif /* PORTMAP */
parms.r_prog = program;
parms.r_vers = version;
@@ -923,6 +927,14 @@ try_rpcbind:
}
}
+#ifdef PORTMAP /* Try version 2 for TCP or UDP */
+ if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
+ address = __try_protocol_version_2(program, 2, nconf, host, tp);
+ if (address == NULL)
+ goto error;
+ }
+#endif /* PORTMAP */
+
if ((address == NULL) || (address->len == 0)) {
rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
clnt_geterr(client, &rpc_createerr.cf_error);
--
2.16.4