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