]> granicus.if.org Git - libtirpc/commit
rpcb_getaddr: Always do PMAP_GETPORT first for NC_INET transports
authorChuck Lever <chuck.lever@oracle.com>
Mon, 30 Nov 2009 13:54:02 +0000 (08:54 -0500)
committerSteve Dickson <steved@redhat.com>
Mon, 30 Nov 2009 13:54:02 +0000 (08:54 -0500)
commit4c3d6a16b6d1407846192f96d9fd1010c7c3f9a9
treeb2d02546823d2c5bf2fac15269a9a97f0557a00b
parent71148877b92ca33d46117dae3f1f8b098e06a5a3
rpcb_getaddr: Always do PMAP_GETPORT first for NC_INET transports

For PF_INET transports, use PMAP_GETPORT.  This is what network
captures show that Solaris user space does, what the Linux mount.nfs
command does, and what the Linux kernel rpcbind client does.  It's
more efficient when querying legacy hosts, of which there are still
many.

An additional benefit of this change is that since libtirpc uses
only UDP for PMAP_GETPORT requests, and it now tries PMAP_GETPORT
first, the creation of a TCP socket in a very common case is now
avoided.  This reduces the consumption of ephemeral ports that
can be left in TIME_WAIT after a request.

It appears that the order in which __rpcb_findaddr_timed() tries the
rpcbind protocol versions was changed in the FreeBSD port of libtirpc.
The documenting comment that appears before __rpcb_findaddr_timed()
was never updated.  This patch restores the original behavior, which
is "try v2 first if the remote is a PF_INET; then try v4, then v3."

The FreeBSD change introduced two bugs: one serious, the other
harmless but wasteful.

The PORTMAP logic overwrites the pointer in "client" instead of
invoking CLNT_DESTROY().  Since the portmap code was originally
executed first, it had no need to invoke CLNT_DESTROY().

This orphans the RPC client previously created for the v3/v4 query.
If a connection-oriented socket was used during the v3/v4 query,
this socket is left connected to the remote portmapper, resulting in
an inadvertant denial of service attack on the remote.

For short-lived programs, this bug is hidden, because a program
exit causes all sockets to be closed automatically.  Long-running
programs leave these sockets connected indefinitely.

The harmless bug is that even though a portmapper replies to a v4
RPCB_GETADDR request with "version 4 not supported; use only version
2", libtirpc tries again with a v3 RPCB_GETADDR anyway.  Though
harmless, this is obviously a wasted round trip.  Perform these
requests in the original order (v2, then v4, then v3), then the
original code makes sense, and the extra v3 round trip is avoided.

Reverting the FreeBSD change fixes both problems.

Reported-by: Jens-Uwe Mozdzen <jmozdzen@nde.ag>.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
src/rpcb_clnt.c