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