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