]> git.decadent.org.uk Git - nfs-utils.git/blob - support/nfs/getport.c
f5ba4ef7c585e24c8e5730ae8ce9f43936823102
[nfs-utils.git] / support / nfs / getport.c
1 /*
2  * Provide a variety of APIs that query an rpcbind daemon to
3  * discover RPC service ports and allowed protocol version
4  * numbers.
5  *
6  * Copyright (C) 2008 Oracle Corporation.  All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public
19  * License along with this program; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 021110-1307, USA.
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <errno.h>
34
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <netdb.h>
38 #include <arpa/inet.h>
39
40 #include <rpc/rpc.h>
41 #include <rpc/pmap_prot.h>
42
43 #ifdef HAVE_LIBTIRPC
44 #include <netconfig.h>
45 #include <rpc/rpcb_prot.h>
46 #endif
47
48 #include "nfsrpc.h"
49
50 /*
51  * Try a local socket first to access the local rpcbind daemon
52  *
53  * Rpcbind's local socket service does not seem to be working.
54  * Disable this logic for now.
55  */
56 #ifdef HAVE_LIBTIRPC
57 #undef NFS_GP_LOCAL
58 #else   /* !HAVE_LIBTIRPC */
59 #undef NFS_GP_LOCAL
60 #endif  /* !HAVE_LIBTIRPC */
61
62 #ifdef HAVE_LIBTIRPC
63 static const rpcvers_t default_rpcb_version = RPCBVERS_4;
64 #else   /* !HAVE_LIBTIRPC */
65 static const rpcvers_t default_rpcb_version = PMAPVERS;
66 #endif  /* !HAVE_LIBTIRPC */
67
68 /*
69  * Historical: Map TCP connect timeouts to timeout
70  * error code used by UDP.
71  */
72 static void
73 nfs_gp_map_tcp_errorcodes(const unsigned short protocol)
74 {
75         if (protocol != IPPROTO_TCP)
76                 return;
77
78         switch (rpc_createerr.cf_error.re_errno) {
79         case ETIMEDOUT:
80                 rpc_createerr.cf_stat = RPC_TIMEDOUT;
81                 break;
82         case ECONNREFUSED:
83                 rpc_createerr.cf_stat = RPC_CANTRECV;
84                 break;
85         }
86 }
87
88 /*
89  * There's no easy way to tell how the local system's networking
90  * and rpcbind is configured (ie. whether we want to use IPv6 or
91  * IPv4 loopback to contact RPC services on the local host).  We
92  * punt and simply try to look up "localhost".
93  *
94  * Returns TRUE on success.
95  */
96 static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen)
97 {
98         struct addrinfo *gai_results;
99         int ret = 0;
100
101         if (getaddrinfo("localhost", NULL, NULL, &gai_results))
102                 return 0;
103
104         if (*salen >= gai_results->ai_addrlen) {
105                 memcpy(sap, gai_results->ai_addr,
106                                 gai_results->ai_addrlen);
107                 *salen = gai_results->ai_addrlen;
108                 ret = 1;
109         }
110
111         freeaddrinfo(gai_results);
112         return ret;
113 }
114
115 /*
116  * Plant port number in @sap.  @port is already in network byte order.
117  */
118 static void nfs_gp_set_port(struct sockaddr *sap, const in_port_t port)
119 {
120         struct sockaddr_in *sin = (struct sockaddr_in *)sap;
121         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
122
123         switch (sap->sa_family) {
124         case AF_INET:
125                 sin->sin_port = port;
126                 break;
127         case AF_INET6:
128                 sin6->sin6_port = port;
129                 break;
130         }
131 }
132
133 /*
134  * Look up a network service in /etc/services and return the
135  * network-order port number of that service.
136  */
137 static in_port_t nfs_gp_getservbyname(const char *service,
138                                       const unsigned short protocol)
139 {
140         const struct addrinfo gai_hint = {
141                 .ai_family      = AF_INET,
142                 .ai_protocol    = protocol,
143                 .ai_flags       = AI_PASSIVE,
144         };
145         struct addrinfo *gai_results;
146         const struct sockaddr_in *sin;
147         in_port_t port;
148
149         if (getaddrinfo(NULL, service, &gai_hint, &gai_results) != 0)
150                 return 0;
151
152         sin = (const struct sockaddr_in *)gai_results->ai_addr;
153         port = sin->sin_port;
154         
155         freeaddrinfo(gai_results);
156         return port;
157 }
158
159 /*
160  * Discover the port number that should be used to contact an
161  * rpcbind service.  This will detect if the port has a local
162  * value that may have been set in /etc/services.
163  *
164  * Returns network byte-order port number of rpcbind service
165  * on this system.
166  */
167 static in_port_t nfs_gp_get_rpcb_port(const unsigned short protocol)
168 {
169         static const char *rpcb_netnametbl[] = {
170                 "rpcbind",
171                 "portmapper",
172                 "sunrpc",
173                 NULL,
174         };
175         unsigned int i;
176
177         for (i = 0; rpcb_netnametbl[i] != NULL; i++) {
178                 in_port_t port;
179
180                 port = nfs_gp_getservbyname(rpcb_netnametbl[i], protocol);
181                 if (port != 0)
182                         return port;
183         }
184
185         return (in_port_t)htons((uint16_t)PMAPPORT);
186 }
187
188 /*
189  * Set up an RPC client for communicating with an rpcbind daemon at
190  * @sap over @transport with protocol version @version.
191  *
192  * Returns a pointer to a prepared RPC client if successful, and
193  * @timeout is initialized; caller must destroy a non-NULL returned RPC
194  * client.  Otherwise returns NULL, and rpc_createerr.cf_stat is set to
195  * reflect the error.
196  */
197 static CLIENT *nfs_gp_get_rpcbclient(struct sockaddr *sap,
198                                      const socklen_t salen,
199                                      const unsigned short transport,
200                                      const rpcvers_t version,
201                                      struct timeval *timeout)
202 {
203         static const char *rpcb_pgmtbl[] = {
204                 "rpcbind",
205                 "portmap",
206                 "portmapper",
207                 "sunrpc",
208                 NULL,
209         };
210         rpcprog_t rpcb_prog = nfs_getrpcbyname(RPCBPROG, rpcb_pgmtbl);
211         CLIENT *clnt;
212
213         nfs_gp_set_port(sap, nfs_gp_get_rpcb_port(transport));
214         clnt = nfs_get_rpcclient(sap, salen, transport, rpcb_prog,
215                                                         version, timeout);
216         nfs_gp_map_tcp_errorcodes(transport);
217         return clnt;
218 }
219
220 /*
221  * One of the arguments passed when querying remote rpcbind services
222  * via rpcbind v3 or v4 is a netid string.  This replaces the pm_prot
223  * field used in legacy PMAP_GETPORT calls.
224  *
225  * RFC 1833 says netids are not standard but rather defined on the local
226  * host.  There are, however, standard definitions for nc_protofmly and
227  * nc_proto that can be used to derive a netid string on the local host,
228  * based on the contents of /etc/netconfig.
229  *
230  * Walk through the local netconfig database and grab the netid of the
231  * first entry that matches @family and @protocol and whose netid string
232  * fits in the provided buffer.
233  *
234  * Returns a '\0'-terminated string if successful; otherwise NULL.
235  * rpc_createerr.cf_stat is set to reflect the error.
236  */
237 #ifdef HAVE_LIBTIRPC
238
239 static char *nfs_gp_get_netid(const sa_family_t family,
240                               const unsigned short protocol)
241 {
242         char *nc_protofmly, *nc_proto, *nc_netid;
243         struct netconfig *nconf;
244         struct protoent *proto;
245         void *handle;
246
247         switch (family) {
248         case AF_LOCAL:
249         case AF_INET:
250                 nc_protofmly = NC_INET;
251                 break;
252         case AF_INET6:
253                 nc_protofmly = NC_INET6;
254                 break;
255         default:
256                 goto out;
257         }
258
259         proto = getprotobynumber(protocol);
260         if (proto == NULL)
261                 goto out;
262         nc_proto = proto->p_name;
263
264         handle = setnetconfig();
265         while ((nconf = getnetconfig(handle)) != NULL) {
266
267                 if (nconf->nc_protofmly != NULL &&
268                     strcmp(nconf->nc_protofmly, nc_protofmly) != 0)
269                         continue;
270                 if (nconf->nc_proto != NULL &&
271                     strcmp(nconf->nc_proto, nc_proto) != 0)
272                         continue;
273
274                 nc_netid = strdup(nconf->nc_netid);
275                 endnetconfig(handle);
276                 return nc_netid;
277         }
278         endnetconfig(handle);
279
280 out:
281         rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
282         return NULL;
283 }
284
285 #endif  /* HAVE_LIBTIRPC */
286
287 /*
288  * Extract a port number from a universal address, and terminate the
289  * string in @addrstr just after the address part.
290  *
291  * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
292  * is returned.
293  */
294 static int nfs_gp_universal_porthelper(char *addrstr)
295 {
296         char *p, *endptr;
297         unsigned long portlo, porthi;
298         int port = -1;
299
300         p = strrchr(addrstr, '.');
301         if (p == NULL)
302                 goto out;
303         portlo = strtoul(p + 1, &endptr, 10);
304         if (*endptr != '\0' || portlo > 255)
305                 goto out;
306         *p = '\0';
307
308         p = strrchr(addrstr, '.');
309         if (p == NULL)
310                 goto out;
311         porthi = strtoul(p + 1, &endptr, 10);
312         if (*endptr != '\0' || porthi > 255)
313                 goto out;
314         *p = '\0';
315         port = (porthi << 8) | portlo;
316
317 out:
318         return port;
319 }
320
321 /**
322  * nfs_universal2port - extract port number from a "universal address"
323  * @uaddr: '\0'-terminated C string containing a universal address
324  *
325  * Universal addresses (defined in RFC 1833) are used when calling an
326  * rpcbind daemon via protocol versions 3 or 4..
327  *
328  * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
329  * is returned.
330  */
331 int nfs_universal2port(const char *uaddr)
332 {
333         char *addrstr;
334         int port = -1;
335
336         addrstr = strdup(uaddr);
337         if (addrstr != NULL) {
338                 port = nfs_gp_universal_porthelper(addrstr);
339                 free(addrstr);
340         }
341         return port;
342 }
343
344 /**
345  * nfs_sockaddr2universal - convert a sockaddr to a "universal address"
346  * @sap: pointer to a socket address
347  *
348  * Universal addresses (defined in RFC 1833) are used when calling an
349  * rpcbind daemon via protocol versions 3 or 4..
350  *
351  * Returns a '\0'-terminated string if successful; caller must free
352  * the returned string.  Otherwise NULL is returned and
353  * rpc_createerr.cf_stat is set to reflect the error.
354  *
355  * inet_ntop(3) is used here, since getnameinfo(3) is not available
356  * in some earlier glibc releases, and we don't require support for
357  * scope IDs for universal addresses.
358  */
359 char *nfs_sockaddr2universal(const struct sockaddr *sap)
360 {
361         const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
362         const struct sockaddr_un *sun = (const struct sockaddr_un *)sap;
363         const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
364         char buf[INET6_ADDRSTRLEN + 8 /* for port information */];
365         uint16_t port;
366         size_t count;
367         char *result;
368         int len;
369
370         switch (sap->sa_family) {
371         case AF_LOCAL:
372                 return strndup(sun->sun_path, sizeof(sun->sun_path));
373         case AF_INET:
374                 if (inet_ntop(AF_INET, (const void *)&sin->sin_addr.s_addr,
375                                         buf, (socklen_t)sizeof(buf)) == NULL)
376                         goto out_err;
377                 port = ntohs(sin->sin_port);
378                 break;
379         case AF_INET6:
380                 if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
381                                         buf, (socklen_t)sizeof(buf)) == NULL)
382                         goto out_err;
383                 port = ntohs(sin6->sin6_port);
384                 break;
385         default:
386                 goto out_err;
387         }
388
389         count = sizeof(buf) - strlen(buf);
390         len = snprintf(buf + strlen(buf), count, ".%u.%u",
391                         (unsigned)(port >> 8), (unsigned)(port & 0xff));
392         /* before glibc 2.0.6, snprintf(3) could return -1 */
393         if (len < 0 || (size_t)len > count)
394                 goto out_err;
395
396         result = strdup(buf);
397         if (result != NULL)
398                 return result;
399
400 out_err:
401         rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
402         return NULL;
403 }
404
405 /*
406  * Send a NULL request to the indicated RPC service.
407  *
408  * Returns 1 if the service responded; otherwise 0;
409  */
410 static int nfs_gp_ping(CLIENT *client, struct timeval timeout)
411 {
412         enum clnt_stat status;
413
414         status = CLNT_CALL(client, NULLPROC,
415                            (xdrproc_t)xdr_void, NULL,
416                            (xdrproc_t)xdr_void, NULL,
417                            timeout);
418
419         return (int)(status == RPC_SUCCESS);
420 }
421
422 #ifdef HAVE_LIBTIRPC
423
424 /*
425  * Initialize the rpcb argument for a GETADDR request.
426  *
427  * Returns 1 if successful, and caller must free strings pointed
428  * to by r_netid and r_addr; otherwise 0.
429  */
430 static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap,
431                                   const rpcprog_t program,
432                                   const rpcvers_t version,
433                                   const unsigned short protocol,
434                                   struct rpcb *parms)
435 {
436         char *netid, *addr;
437
438         netid = nfs_gp_get_netid(sap->sa_family, protocol);
439         if (netid == NULL)
440                 return 0;
441
442         addr = nfs_sockaddr2universal(sap);
443         if (addr == NULL) {
444                 free(netid);
445                 return 0;
446         }
447
448         memset(parms, 0, sizeof(*parms));
449         parms->r_prog   = program;
450         parms->r_vers   = version;
451         parms->r_netid  = netid;
452         parms->r_addr   = addr;
453         parms->r_owner  = "";
454
455         return 1;
456 }
457
458 static void nfs_gp_free_rpcb_parms(struct rpcb *parms)
459 {
460         free(parms->r_netid);
461         free(parms->r_addr);
462 }
463
464 /*
465  * Try rpcbind GETADDR via version 4.  If that fails, try same
466  * request via version 3.
467  *
468  * Returns non-zero port number on success; otherwise returns
469  * zero.  rpccreateerr is set to reflect the nature of the error.
470  */
471 static unsigned short nfs_gp_rpcb_getaddr(CLIENT *client,
472                                           struct rpcb *parms,
473                                           struct timeval timeout)
474 {
475         rpcvers_t rpcb_version;
476         struct rpc_err rpcerr;
477         int port = 0;
478
479         for (rpcb_version = RPCBVERS_4;
480              rpcb_version >= RPCBVERS_3;
481              rpcb_version--) {
482                 enum clnt_stat status;
483                 char *uaddr = NULL;
484
485                 CLNT_CONTROL(client, CLSET_VERS, (void *)&rpcb_version);
486                 status = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR,
487                                    (xdrproc_t)xdr_rpcb, (void *)parms,
488                                    (xdrproc_t)xdr_wrapstring, (void *)&uaddr,
489                                    timeout);
490
491                 switch (status) {
492                 case RPC_SUCCESS:
493                         if ((uaddr == NULL) || (uaddr[0] == '\0')) {
494                                 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
495                                 return 0;
496                         }
497
498                         port = nfs_universal2port(uaddr);
499                         xdr_free((xdrproc_t)xdr_wrapstring, (char *)&uaddr);
500                         if (port == -1) {
501                                 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
502                                 return 0;
503                         }
504                         return (unsigned short)port;
505                 case RPC_PROGVERSMISMATCH:
506                         clnt_geterr(client, &rpcerr);
507                         if (rpcerr.re_vers.low > RPCBVERS4)
508                                 return 0;
509                         continue;
510                 case RPC_PROCUNAVAIL:
511                 case RPC_PROGUNAVAIL:
512                         continue;
513                 default:
514                         /* Most likely RPC_TIMEDOUT or RPC_CANTRECV */
515                         rpc_createerr.cf_stat = status;
516                         clnt_geterr(client, &rpc_createerr.cf_error);
517                         return 0;
518                 }
519
520         }
521
522         if (port == 0) {
523                 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
524                 clnt_geterr(client, &rpc_createerr.cf_error);
525         }
526         return port;
527 }
528
529 #endif  /* HAVE_LIBTIRPC */
530
531 /*
532  * Try GETPORT request via rpcbind version 2.
533  *
534  * Returns non-zero port number on success; otherwise returns
535  * zero.  rpccreateerr is set to reflect the nature of the error.
536  */
537 static unsigned long nfs_gp_pmap_getport(CLIENT *client,
538                                          struct pmap *parms,
539                                          struct timeval timeout)
540 {
541         enum clnt_stat status;
542         unsigned long port;
543
544         status = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
545                            (xdrproc_t)xdr_pmap, (void *)parms,
546                            (xdrproc_t)xdr_u_long, (void *)&port,
547                            timeout);
548
549         if (status != RPC_SUCCESS) {
550                 rpc_createerr.cf_stat = status;
551                 clnt_geterr(client, &rpc_createerr.cf_error);
552                 port = 0;
553         } else if (port == 0)
554                 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
555
556         return port;
557 }
558
559 #ifdef HAVE_LIBTIRPC
560
561 static unsigned short nfs_gp_getport_rpcb(CLIENT *client,
562                                           const struct sockaddr *sap,
563                                           const rpcprog_t program,
564                                           const rpcvers_t version,
565                                           const unsigned short protocol,
566                                           struct timeval timeout)
567 {
568         unsigned short port = 0;
569         struct rpcb parms;
570
571         if (nfs_gp_init_rpcb_parms(sap, program, version,
572                                         protocol, &parms) != 0) {
573                 port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
574                 nfs_gp_free_rpcb_parms(&parms);
575         }
576
577         return port;
578 }
579
580 #endif  /* HAVE_LIBTIRPC */
581
582 static unsigned long nfs_gp_getport_pmap(CLIENT *client,
583                                          const rpcprog_t program,
584                                          const rpcvers_t version,
585                                          const unsigned short protocol,
586                                          struct timeval timeout)
587 {
588         struct pmap parms = {
589                 .pm_prog        = program,
590                 .pm_vers        = version,
591                 .pm_prot        = protocol,
592         };
593         rpcvers_t pmap_version = PMAPVERS;
594
595         CLNT_CONTROL(client, CLSET_VERS, (void *)&pmap_version);
596         return nfs_gp_pmap_getport(client, &parms, timeout);
597 }
598
599 /*
600  * Try an AF_INET6 request via rpcbind v4/v3; try an AF_INET
601  * request via rpcbind v2.
602  *
603  * Returns non-zero port number on success; otherwise returns
604  * zero.  rpccreateerr is set to reflect the nature of the error.
605  */
606 static unsigned short nfs_gp_getport(CLIENT *client,
607                                      const struct sockaddr *sap,
608                                      const rpcprog_t program,
609                                      const rpcvers_t version,
610                                      const unsigned short protocol,
611                                      struct timeval timeout)
612 {
613         switch (sap->sa_family) {
614 #ifdef HAVE_LIBTIRPC
615         case AF_INET6:
616                 return nfs_gp_getport_rpcb(client, sap, program,
617                                                 version, protocol, timeout);
618 #endif  /* HAVE_LIBTIRPC */
619         case AF_INET:
620                 return nfs_gp_getport_pmap(client, program, version,
621                                                         protocol, timeout);
622         }
623
624         rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
625         return 0;
626 }
627
628 /**
629  * nfs_rpc_ping - Determine if RPC service is responding to requests
630  * @sap: pointer to address of server to query (port is already filled in)
631  * @salen: length of server address
632  * @program: requested RPC program number
633  * @version: requested RPC version number
634  * @protocol: requested IPPROTO_ value of transport protocol
635  * @timeout: pointer to request timeout (NULL means use default timeout)
636  *
637  * Returns 1 if the remote service responded without an error; otherwise
638  * zero.
639  */
640 int nfs_rpc_ping(const struct sockaddr *sap, const socklen_t salen,
641                  const rpcprog_t program, const rpcvers_t version,
642                  const unsigned short protocol, const struct timeval *timeout)
643 {
644         struct sockaddr_storage address;
645         struct sockaddr *saddr = (struct sockaddr *)&address;
646         CLIENT *client;
647         struct timeval tout = { -1, 0 };
648         int result = 0;
649
650         if (timeout != NULL)
651                 tout = *timeout;
652
653         nfs_clear_rpc_createerr();
654
655         memcpy(saddr, sap, (size_t)salen);
656         client = nfs_get_rpcclient(saddr, salen, protocol,
657                                                 program, version, &tout);
658         if (client != NULL) {
659                 result = nfs_gp_ping(client, tout);
660                 nfs_gp_map_tcp_errorcodes(protocol);
661                 CLNT_DESTROY(client);
662         }
663
664         return result;
665 }
666
667 /**
668  * nfs_getport - query server's rpcbind to get port number for an RPC service
669  * @sap: pointer to address of server to query
670  * @salen: length of server's address
671  * @program: requested RPC program number
672  * @version: requested RPC version number
673  * @protocol: IPPROTO_ value of requested transport protocol
674  *
675  * Uses any acceptable rpcbind version to discover the port number for the
676  * RPC service described by the given [program, version, transport] tuple.
677  * Uses a quick timeout and an ephemeral source port.  Supports AF_INET and
678  * AF_INET6 server addresses.
679  *
680  * Returns a positive integer representing the port number of the RPC
681  * service advertised by the server (in host byte order), or zero if the
682  * service is not advertised or there was some problem querying the server's
683  * rpcbind daemon.  rpccreateerr is set to reflect the underlying cause of
684  * the error.
685  *
686  * There are a variety of ways to choose which transport and rpcbind versions
687  * to use.  We chose to conserve local resources and try to avoid incurring
688  * timeouts.
689  *
690  * Transport
691  * To provide rudimentary support for traversing firewalls, query the remote
692  * using the same transport as the requested service.  This provides some
693  * guarantee that the requested transport is available between this client
694  * and the server, and if the caller specifically requests TCP, for example,
695  * this may be becuase a firewall is in place that blocks UDP traffic.  We
696  * could try both, but that could involve a lengthy timeout in several cases,
697  * and would often consume an extra ephemeral port.
698  *
699  * Rpcbind version
700  * To avoid using up too many ephemeral ports, AF_INET queries use tried-and-
701  * true rpcbindv2, and don't try the newer versions; and AF_INET6 queries use
702  * rpcbindv4, then rpcbindv3 on the same socket.  The newer rpcbind protocol
703  * versions can adequately detect if a remote RPC service does not support
704  * AF_INET6 at all.  The rpcbind socket is re-used in an attempt to keep the
705  * overall number of consumed ephemeral ports low.
706  */
707 unsigned short nfs_getport(const struct sockaddr *sap,
708                            const socklen_t salen,
709                            const rpcprog_t program,
710                            const rpcvers_t version,
711                            const unsigned short protocol)
712 {
713         struct sockaddr_storage address;
714         struct sockaddr *saddr = (struct sockaddr *)&address;
715         struct timeval timeout = { -1, 0 };
716         unsigned short port = 0;
717         CLIENT *client;
718
719         nfs_clear_rpc_createerr();
720
721         memcpy(saddr, sap, (size_t)salen);
722         client = nfs_gp_get_rpcbclient(saddr, salen, protocol,
723                                                 default_rpcb_version, &timeout);
724         if (client != NULL) {
725                 port = nfs_gp_getport(client, saddr, program,
726                                         version, protocol, timeout);
727                 CLNT_DESTROY(client);
728         }
729
730         return port;
731 }
732
733 /**
734  * nfs_getport_ping - query server's rpcbind and do RPC ping to verify result
735  * @sap: IN: pointer to address of server to query;
736  *       OUT: pointer to updated address
737  * @salen: length of server's address
738  * @program: requested RPC program number
739  * @version: requested RPC version number
740  * @protocol: IPPROTO_ value of requested transport protocol
741  *
742  * Uses any acceptable rpcbind version to discover the port number for the
743  * RPC service described by the given [program, version, transport] tuple.
744  * Uses a quick timeout and an ephemeral source port.  Supports AF_INET and
745  * AF_INET6 server addresses.
746  *
747  * Returns a 1 and sets the port number in the passed-in server address
748  * if both the query and the ping were successful; otherwise zero.
749  * rpccreateerr is set to reflect the underlying cause of the error.
750  */
751 int nfs_getport_ping(struct sockaddr *sap, const socklen_t salen,
752                      const rpcprog_t program, const rpcvers_t version,
753                      const unsigned short protocol)
754 {
755         struct timeval timeout = { -1, 0 };
756         unsigned short port = 0;
757         CLIENT *client;
758         int result = 0;
759         
760         nfs_clear_rpc_createerr();
761
762         client = nfs_gp_get_rpcbclient(sap, salen, protocol,
763                                                 default_rpcb_version, &timeout);
764         if (client != NULL) {
765                 port = nfs_gp_getport(client, sap, program,
766                                         version, protocol, timeout);
767                 CLNT_DESTROY(client);
768                 client = NULL;
769         }
770
771         if (port != 0) {
772                 struct sockaddr_storage address;
773                 struct sockaddr *saddr = (struct sockaddr *)&address;
774
775                 memcpy(saddr, sap, (size_t)salen);
776                 nfs_gp_set_port(saddr, htons(port));
777
778                 nfs_clear_rpc_createerr();
779
780                 client = nfs_get_rpcclient(saddr, salen, protocol,
781                                                 program, version, &timeout);
782                 if (client != NULL) {
783                         result = nfs_gp_ping(client, timeout);
784                         nfs_gp_map_tcp_errorcodes(protocol);
785                         CLNT_DESTROY(client);
786                 }
787         }
788
789         if (result)
790                 nfs_gp_set_port(sap, htons(port));
791
792         return result;
793 }
794
795 /**
796  * nfs_getlocalport - query local rpcbind to get port number for an RPC service
797  * @program: requested RPC program number
798  * @version: requested RPC version number
799  * @protocol: IPPROTO_ value of requested transport protocol
800  *
801  * Uses any acceptable rpcbind version to discover the port number for the
802  * RPC service described by the given [program, version, transport] tuple.
803  * Uses a quick timeout and an ephemeral source port.  Supports AF_INET and
804  * AF_INET6 local addresses.
805  *
806  * Returns a positive integer representing the port number of the RPC
807  * service advertised by the server (in host byte order), or zero if the
808  * service is not advertised or there was some problem querying the server's
809  * rpcbind daemon.  rpccreateerr is set to reflect the underlying cause of
810  * the error.
811  *
812  * Try an AF_LOCAL connection first.  The rpcbind daemon implementation should
813  * listen on AF_LOCAL.
814  *
815  * If that doesn't work (for example, if portmapper is running, or rpcbind
816  * isn't listening on /var/run/rpcbind.sock), send a query via UDP to localhost
817  * (UDP doesn't leave a socket in TIME_WAIT, and the timeout is a relatively
818  * short 3 seconds).
819  */
820 unsigned short nfs_getlocalport(const rpcprot_t program,
821                                 const rpcvers_t version,
822                                 const unsigned short protocol)
823 {
824         struct sockaddr_storage address;
825         struct sockaddr *lb_addr = (struct sockaddr *)&address;
826         socklen_t lb_len = sizeof(*lb_addr);
827         unsigned short port = 0;
828
829 #ifdef NFS_GP_LOCAL
830         const struct sockaddr_un sun = {
831                 .sun_family     = AF_LOCAL,
832                 .sun_path       = _PATH_RPCBINDSOCK,
833         };
834         const struct sockaddr *sap = (struct sockaddr *)&sun;
835         const socklen_t salen = SUN_LEN(&sun);
836         CLIENT *client;
837         struct timeval timeout = { -1, 0 };
838
839         nfs_clear_rpc_createerr();
840
841         client = nfs_gp_get_rpcbclient(sap, salen, 0, RPCBVERS_4, &timeout);
842         if (client != NULL) {
843                 struct rpcb parms;
844
845                 if (nfs_gp_init_rpcb_parms(sap, program, version,
846                                                 protocol, &parms) != 0) {
847                         port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
848                         nfs_gp_free_rpcb_parms(&parms);
849                 }
850                 CLNT_DESTROY(client);
851         }
852 #endif  /* NFS_GP_LOCAL */
853
854         if (port == 0) {
855                 nfs_clear_rpc_createerr();
856
857                 if (nfs_gp_loopback_address(lb_addr, &lb_len)) {
858                         port = nfs_getport(lb_addr, lb_len,
859                                                 program, version, protocol);
860                 } else
861                         rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
862         }
863
864         return port;
865 }
866
867 /**
868  * nfs_rpcb_getaddr - query rpcbind via rpcbind versions 4 and 3
869  * @sap: pointer to address of server to query
870  * @salen: length of server address
871  * @transport: transport protocol to use for the query
872  * @addr: pointer to r_addr address
873  * @program: requested RPC program number
874  * @version: requested RPC version number
875  * @protocol: requested IPPROTO_ value of transport protocol
876  * @timeout: pointer to request timeout (NULL means use default timeout)
877  *
878  * Returns a positive integer representing the port number of the RPC
879  * service advertised by the server (in host byte order), or zero if the
880  * service is not advertised or there was some problem querying the
881  * server's rpcbind daemon.  rpccreateerr is set to reflect the
882  * underlying cause of the error.
883  *
884  * This function provides similar functionality to nfs_pmap_getport(),
885  * but performs the rpcbind lookup via rpcbind version 4.  If the server
886  * doesn't support rpcbind version 4, it will retry with version 3.
887  * The GETADDR procedure is exactly the same in these two versions of
888  * the rpcbind protocol, so the socket, RPC client, and arguments are
889  * re-used when retrying, saving ephemeral port space.
890  *
891  * These RPC procedures take a universal address as an argument, so the
892  * query will fail if the remote rpcbind daemon doesn't find an entry
893  * with a matching address.  A matching address includes an ANYADDR
894  * address of the same address family.  In this way an RPC server can
895  * advertise via rpcbind that it does not support AF_INET6.
896  */
897 #ifdef HAVE_LIBTIRPC
898
899 unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
900                                 const socklen_t salen,
901                                 const unsigned short transport,
902                                 const struct sockaddr *addr,
903                                 const rpcprog_t program,
904                                 const rpcvers_t version,
905                                 const unsigned short protocol,
906                                 const struct timeval *timeout)
907 {
908         struct sockaddr_storage address;
909         struct sockaddr *saddr = (struct sockaddr *)&address;
910         CLIENT *client;
911         struct rpcb parms;
912         struct timeval tout = { -1, 0 };
913         unsigned short port = 0;
914
915         if (timeout != NULL)
916                 tout = *timeout;
917
918         nfs_clear_rpc_createerr();
919
920         memcpy(saddr, sap, (size_t)salen);
921         client = nfs_gp_get_rpcbclient(saddr, salen, transport,
922                                                         RPCBVERS_4, &tout);
923         if (client != NULL) {
924                 if (nfs_gp_init_rpcb_parms(addr, program, version,
925                                                 protocol, &parms) != 0) {
926                         port = nfs_gp_rpcb_getaddr(client, &parms, tout);
927                         nfs_gp_free_rpcb_parms(&parms);
928                 }
929                 CLNT_DESTROY(client);
930         }
931
932         return port;
933 }
934
935 #else   /* !HAVE_LIBTIRPC */
936
937 unsigned short nfs_rpcb_getaddr(__attribute__((unused)) const struct sockaddr *sap,
938                                 __attribute__((unused)) const socklen_t salen,
939                                 __attribute__((unused)) const unsigned short transport,
940                                 __attribute__((unused)) const struct sockaddr *addr,
941                                 __attribute__((unused)) const rpcprog_t program,
942                                 __attribute__((unused)) const rpcvers_t version,
943                                 __attribute__((unused)) const unsigned short protocol,
944                                 __attribute__((unused)) const struct timeval *timeout)
945 {
946         nfs_clear_rpc_createerr();
947
948         rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
949         return 0;
950 }
951
952 #endif  /* !HAVE_LIBTIRPC */
953
954 /**
955  * nfs_pmap_getport - query rpcbind via the portmap protocol (rpcbindv2)
956  * @sin: pointer to AF_INET address of server to query
957  * @transport: transport protocol to use for the query
958  * @program: requested RPC program number
959  * @version: requested RPC version number
960  * @protocol: requested IPPROTO_ value of transport protocol
961  * @timeout: pointer to request timeout (NULL means use default timeout)
962  *
963  * Returns a positive integer representing the port number of the RPC service
964  * advertised by the server (in host byte order), or zero if the service is
965  * not advertised or there was some problem querying the server's rpcbind
966  * daemon.  rpccreateerr is set to reflect the underlying cause of the error.
967  *
968  * nfs_pmap_getport() is very similar to pmap_getport(), except that:
969  *
970  *  1.  This version always tries to use an ephemeral port, since reserved
971  *      ports are not needed for GETPORT queries.  This conserves the very
972  *      limited reserved port space, helping reduce failed socket binds
973  *      during mount storms.
974  *
975  *  2.  This version times out quickly by default.  It time-limits the
976  *      connect process as well as the actual RPC call, and even allows the
977  *      caller to specify the timeout.
978  *
979  *  3.  This version shares code with the rpcbindv3 and rpcbindv4 query
980  *      functions.  It can use a TI-RPC generated CLIENT.
981  */
982 unsigned long nfs_pmap_getport(const struct sockaddr_in *sin,
983                                const unsigned short transport,
984                                const unsigned long program,
985                                const unsigned long version,
986                                const unsigned long protocol,
987                                const struct timeval *timeout)
988 {
989         struct sockaddr_in address;
990         struct sockaddr *saddr = (struct sockaddr *)&address;
991         CLIENT *client;
992         struct pmap parms = {
993                 .pm_prog        = program,
994                 .pm_vers        = version,
995                 .pm_prot        = protocol,
996         };
997         struct timeval tout = { -1, 0 };
998         unsigned long port = 0;
999
1000         if (timeout != NULL)
1001                 tout = *timeout;
1002
1003         nfs_clear_rpc_createerr();
1004
1005         memcpy(saddr, sin, sizeof(address));
1006         client = nfs_gp_get_rpcbclient(saddr, (socklen_t)sizeof(*sin),
1007                                         transport, PMAPVERS, &tout);
1008         if (client != NULL) {
1009                 port = nfs_gp_pmap_getport(client, &parms, tout);
1010                 CLNT_DESTROY(client);
1011         }
1012
1013         return port;
1014 }