2 * Provide a variety of APIs that query an rpcbind daemon to
3 * discover RPC service ports and allowed protocol version
6 * Copyright (C) 2008 Oracle Corporation. All rights reserved.
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.
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.
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.
29 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
38 #include <arpa/inet.h>
41 #include <rpc/pmap_prot.h>
44 #include <netconfig.h>
45 #include <rpc/rpcb_prot.h>
51 * Try a local socket first to access the local rpcbind daemon
53 * Rpcbind's local socket service does not seem to be working.
54 * Disable this logic for now.
58 #else /* !HAVE_LIBTIRPC */
60 #endif /* !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 */
69 * Historical: Map TCP connect timeouts to timeout
70 * error code used by UDP.
73 nfs_gp_map_tcp_errorcodes(const unsigned short protocol)
75 if (protocol != IPPROTO_TCP)
78 switch (rpc_createerr.cf_error.re_errno) {
80 rpc_createerr.cf_stat = RPC_TIMEDOUT;
86 * There's no easy way to tell how the local system's networking
87 * and rpcbind is configured (ie. whether we want to use IPv6 or
88 * IPv4 loopback to contact RPC services on the local host). We
89 * punt and simply try to look up "localhost".
91 * Returns TRUE on success.
93 static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen)
95 struct addrinfo *gai_results;
98 if (getaddrinfo("localhost", NULL, NULL, &gai_results))
101 if (*salen >= gai_results->ai_addrlen) {
102 memcpy(sap, gai_results->ai_addr,
103 gai_results->ai_addrlen);
104 *salen = gai_results->ai_addrlen;
108 freeaddrinfo(gai_results);
113 * Plant port number in @sap. @port is already in network byte order.
115 static void nfs_gp_set_port(struct sockaddr *sap, const in_port_t port)
117 struct sockaddr_in *sin = (struct sockaddr_in *)sap;
118 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
120 switch (sap->sa_family) {
122 sin->sin_port = port;
125 sin6->sin6_port = port;
131 * Look up a network service in /etc/services and return the
132 * network-order port number of that service.
134 static in_port_t nfs_gp_getservbyname(const char *service,
135 const unsigned short protocol)
137 const struct addrinfo gai_hint = {
138 .ai_family = AF_INET,
139 .ai_protocol = protocol,
140 .ai_flags = AI_PASSIVE,
142 struct addrinfo *gai_results;
143 const struct sockaddr_in *sin;
146 if (getaddrinfo(NULL, service, &gai_hint, &gai_results) != 0)
149 sin = (const struct sockaddr_in *)gai_results->ai_addr;
150 port = sin->sin_port;
152 freeaddrinfo(gai_results);
157 * Discover the port number that should be used to contact an
158 * rpcbind service. This will detect if the port has a local
159 * value that may have been set in /etc/services.
161 * Returns network byte-order port number of rpcbind service
164 static in_port_t nfs_gp_get_rpcb_port(const unsigned short protocol)
166 static const char *rpcb_netnametbl[] = {
174 for (i = 0; rpcb_netnametbl[i] != NULL; i++) {
177 port = nfs_gp_getservbyname(rpcb_netnametbl[i], protocol);
182 return (in_port_t)htons((uint16_t)PMAPPORT);
186 * Set up an RPC client for communicating with an rpcbind daemon at
187 * @sap over @transport with protocol version @version.
189 * Returns a pointer to a prepared RPC client if successful, and
190 * @timeout is initialized; caller must destroy a non-NULL returned RPC
191 * client. Otherwise returns NULL, and rpc_createerr.cf_stat is set to
194 static CLIENT *nfs_gp_get_rpcbclient(struct sockaddr *sap,
195 const socklen_t salen,
196 const unsigned short transport,
197 const rpcvers_t version,
198 struct timeval *timeout)
200 static const char *rpcb_pgmtbl[] = {
207 rpcprog_t rpcb_prog = nfs_getrpcbyname(RPCBPROG, rpcb_pgmtbl);
210 nfs_gp_set_port(sap, nfs_gp_get_rpcb_port(transport));
211 clnt = nfs_get_rpcclient(sap, salen, transport, rpcb_prog,
213 nfs_gp_map_tcp_errorcodes(transport);
218 * One of the arguments passed when querying remote rpcbind services
219 * via rpcbind v3 or v4 is a netid string. This replaces the pm_prot
220 * field used in legacy PMAP_GETPORT calls.
222 * RFC 1833 says netids are not standard but rather defined on the local
223 * host. There are, however, standard definitions for nc_protofmly and
224 * nc_proto that can be used to derive a netid string on the local host,
225 * based on the contents of /etc/netconfig.
227 * Walk through the local netconfig database and grab the netid of the
228 * first entry that matches @family and @protocol and whose netid string
229 * fits in the provided buffer.
231 * Returns a '\0'-terminated string if successful; otherwise NULL.
232 * rpc_createerr.cf_stat is set to reflect the error.
236 static char *nfs_gp_get_netid(const sa_family_t family,
237 const unsigned short protocol)
239 char *nc_protofmly, *nc_proto, *nc_netid;
240 struct netconfig *nconf;
241 struct protoent *proto;
247 nc_protofmly = NC_INET;
250 nc_protofmly = NC_INET6;
256 proto = getprotobynumber(protocol);
259 nc_proto = proto->p_name;
261 handle = setnetconfig();
262 while ((nconf = getnetconfig(handle)) != NULL) {
264 if (nconf->nc_protofmly != NULL &&
265 strcmp(nconf->nc_protofmly, nc_protofmly) != 0)
267 if (nconf->nc_proto != NULL &&
268 strcmp(nconf->nc_proto, nc_proto) != 0)
271 nc_netid = strdup(nconf->nc_netid);
272 endnetconfig(handle);
275 endnetconfig(handle);
278 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
282 #endif /* HAVE_LIBTIRPC */
285 * Extract a port number from a universal address, and terminate the
286 * string in @addrstr just after the address part.
288 * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
291 static int nfs_gp_universal_porthelper(char *addrstr)
294 unsigned long portlo, porthi;
297 p = strrchr(addrstr, '.');
300 portlo = strtoul(p + 1, &endptr, 10);
301 if (*endptr != '\0' || portlo > 255)
305 p = strrchr(addrstr, '.');
308 porthi = strtoul(p + 1, &endptr, 10);
309 if (*endptr != '\0' || porthi > 255)
312 port = (porthi << 8) | portlo;
319 * nfs_universal2port - extract port number from a "universal address"
320 * @uaddr: '\0'-terminated C string containing a universal address
322 * Universal addresses (defined in RFC 1833) are used when calling an
323 * rpcbind daemon via protocol versions 3 or 4..
325 * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
328 int nfs_universal2port(const char *uaddr)
333 addrstr = strdup(uaddr);
334 if (addrstr != NULL) {
335 port = nfs_gp_universal_porthelper(addrstr);
342 * nfs_sockaddr2universal - convert a sockaddr to a "universal address"
343 * @sap: pointer to a socket address
345 * Universal addresses (defined in RFC 1833) are used when calling an
346 * rpcbind daemon via protocol versions 3 or 4..
348 * Returns a '\0'-terminated string if successful; caller must free
349 * the returned string. Otherwise NULL is returned and
350 * rpc_createerr.cf_stat is set to reflect the error.
352 * inet_ntop(3) is used here, since getnameinfo(3) is not available
353 * in some earlier glibc releases, and we don't require support for
354 * scope IDs for universal addresses.
356 char *nfs_sockaddr2universal(const struct sockaddr *sap)
358 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
359 const struct sockaddr_un *sun = (const struct sockaddr_un *)sap;
360 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
361 char buf[INET6_ADDRSTRLEN + 8 /* for port information */];
367 switch (sap->sa_family) {
369 return strndup(sun->sun_path, sizeof(sun->sun_path));
371 if (inet_ntop(AF_INET, (const void *)&sin->sin_addr.s_addr,
372 buf, (socklen_t)sizeof(buf)) == NULL)
374 port = ntohs(sin->sin_port);
377 if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
378 buf, (socklen_t)sizeof(buf)) == NULL)
380 port = ntohs(sin6->sin6_port);
386 count = sizeof(buf) - strlen(buf);
387 len = snprintf(buf + strlen(buf), count, ".%u.%u",
388 (unsigned)(port >> 8), (unsigned)(port & 0xff));
389 /* before glibc 2.0.6, snprintf(3) could return -1 */
390 if (len < 0 || (size_t)len > count)
393 result = strdup(buf);
398 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
403 * Send a NULL request to the indicated RPC service.
405 * Returns 1 if the service responded; otherwise 0;
407 static int nfs_gp_ping(CLIENT *client, struct timeval timeout)
409 enum clnt_stat status;
411 status = CLNT_CALL(client, NULLPROC,
412 (xdrproc_t)xdr_void, NULL,
413 (xdrproc_t)xdr_void, NULL,
416 return (int)(status == RPC_SUCCESS);
422 * Initialize the rpcb argument for a GETADDR request.
424 * Returns 1 if successful, and caller must free strings pointed
425 * to by r_netid and r_addr; otherwise 0.
427 static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap,
428 const rpcprog_t program,
429 const rpcvers_t version,
430 const unsigned short protocol,
435 netid = nfs_gp_get_netid(sap->sa_family, protocol);
439 addr = nfs_sockaddr2universal(sap);
445 memset(parms, 0, sizeof(*parms));
446 parms->r_prog = program;
447 parms->r_vers = version;
448 parms->r_netid = netid;
449 parms->r_addr = addr;
455 static void nfs_gp_free_rpcb_parms(struct rpcb *parms)
457 free(parms->r_netid);
462 * Try rpcbind GETADDR via version 4. If that fails, try same
463 * request via version 3.
465 * Returns non-zero port number on success; otherwise returns
466 * zero. rpccreateerr is set to reflect the nature of the error.
468 static unsigned short nfs_gp_rpcb_getaddr(CLIENT *client,
470 struct timeval timeout)
472 rpcvers_t rpcb_version;
473 struct rpc_err rpcerr;
476 for (rpcb_version = RPCBVERS_4;
477 rpcb_version >= RPCBVERS_3;
479 enum clnt_stat status;
482 CLNT_CONTROL(client, CLSET_VERS, (void *)&rpcb_version);
483 status = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR,
484 (xdrproc_t)xdr_rpcb, (void *)parms,
485 (xdrproc_t)xdr_wrapstring, (void *)&uaddr,
490 if ((uaddr == NULL) || (uaddr[0] == '\0')) {
491 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
495 port = nfs_universal2port(uaddr);
496 xdr_free((xdrproc_t)xdr_wrapstring, (char *)&uaddr);
498 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
501 return (unsigned short)port;
502 case RPC_PROGVERSMISMATCH:
503 clnt_geterr(client, &rpcerr);
504 if (rpcerr.re_vers.low > RPCBVERS4)
507 case RPC_PROCUNAVAIL:
508 case RPC_PROGUNAVAIL:
511 /* Most likely RPC_TIMEDOUT or RPC_CANTRECV */
512 rpc_createerr.cf_stat = status;
513 clnt_geterr(client, &rpc_createerr.cf_error);
520 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
521 clnt_geterr(client, &rpc_createerr.cf_error);
526 #endif /* HAVE_LIBTIRPC */
529 * Try GETPORT request via rpcbind version 2.
531 * Returns non-zero port number on success; otherwise returns
532 * zero. rpccreateerr is set to reflect the nature of the error.
534 static unsigned long nfs_gp_pmap_getport(CLIENT *client,
536 struct timeval timeout)
538 enum clnt_stat status;
541 status = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
542 (xdrproc_t)xdr_pmap, (void *)parms,
543 (xdrproc_t)xdr_u_long, (void *)&port,
546 if (status != RPC_SUCCESS) {
547 rpc_createerr.cf_stat = status;
548 clnt_geterr(client, &rpc_createerr.cf_error);
550 } else if (port == 0)
551 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
558 static unsigned short nfs_gp_getport_rpcb(CLIENT *client,
559 const struct sockaddr *sap,
560 const rpcprog_t program,
561 const rpcvers_t version,
562 const unsigned short protocol,
563 struct timeval timeout)
565 unsigned short port = 0;
568 if (nfs_gp_init_rpcb_parms(sap, program, version,
569 protocol, &parms) != 0) {
570 port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
571 nfs_gp_free_rpcb_parms(&parms);
577 #endif /* HAVE_LIBTIRPC */
579 static unsigned long nfs_gp_getport_pmap(CLIENT *client,
580 const rpcprog_t program,
581 const rpcvers_t version,
582 const unsigned short protocol,
583 struct timeval timeout)
585 struct pmap parms = {
590 rpcvers_t pmap_version = PMAPVERS;
592 CLNT_CONTROL(client, CLSET_VERS, (void *)&pmap_version);
593 return nfs_gp_pmap_getport(client, &parms, timeout);
597 * Try an AF_INET6 request via rpcbind v4/v3; try an AF_INET
598 * request via rpcbind v2.
600 * Returns non-zero port number on success; otherwise returns
601 * zero. rpccreateerr is set to reflect the nature of the error.
603 static unsigned short nfs_gp_getport(CLIENT *client,
604 const struct sockaddr *sap,
605 const rpcprog_t program,
606 const rpcvers_t version,
607 const unsigned short protocol,
608 struct timeval timeout)
610 switch (sap->sa_family) {
613 return nfs_gp_getport_rpcb(client, sap, program,
614 version, protocol, timeout);
615 #endif /* HAVE_LIBTIRPC */
617 return nfs_gp_getport_pmap(client, program, version,
621 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
626 * nfs_rpc_ping - Determine if RPC service is responding to requests
627 * @sap: pointer to address of server to query (port is already filled in)
628 * @salen: length of server address
629 * @program: requested RPC program number
630 * @version: requested RPC version number
631 * @protocol: requested IPPROTO_ value of transport protocol
632 * @timeout: pointer to request timeout (NULL means use default timeout)
634 * Returns 1 if the remote service responded without an error; otherwise
637 int nfs_rpc_ping(const struct sockaddr *sap, const socklen_t salen,
638 const rpcprog_t program, const rpcvers_t version,
639 const unsigned short protocol, const struct timeval *timeout)
641 struct sockaddr_storage address;
642 struct sockaddr *saddr = (struct sockaddr *)&address;
644 struct timeval tout = { -1, 0 };
650 nfs_clear_rpc_createerr();
652 memcpy(saddr, sap, (size_t)salen);
653 client = nfs_get_rpcclient(saddr, salen, protocol,
654 program, version, &tout);
655 if (client != NULL) {
656 result = nfs_gp_ping(client, tout);
657 nfs_gp_map_tcp_errorcodes(protocol);
658 CLNT_DESTROY(client);
665 * nfs_getport - query server's rpcbind to get port number for an RPC service
666 * @sap: pointer to address of server to query
667 * @salen: length of server's address
668 * @program: requested RPC program number
669 * @version: requested RPC version number
670 * @protocol: IPPROTO_ value of requested transport protocol
672 * Uses any acceptable rpcbind version to discover the port number for the
673 * RPC service described by the given [program, version, transport] tuple.
674 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
675 * AF_INET6 server addresses.
677 * Returns a positive integer representing the port number of the RPC
678 * service advertised by the server (in host byte order), or zero if the
679 * service is not advertised or there was some problem querying the server's
680 * rpcbind daemon. rpccreateerr is set to reflect the underlying cause of
683 * There are a variety of ways to choose which transport and rpcbind versions
684 * to use. We chose to conserve local resources and try to avoid incurring
688 * To provide rudimentary support for traversing firewalls, query the remote
689 * using the same transport as the requested service. This provides some
690 * guarantee that the requested transport is available between this client
691 * and the server, and if the caller specifically requests TCP, for example,
692 * this may be becuase a firewall is in place that blocks UDP traffic. We
693 * could try both, but that could involve a lengthy timeout in several cases,
694 * and would often consume an extra ephemeral port.
697 * To avoid using up too many ephemeral ports, AF_INET queries use tried-and-
698 * true rpcbindv2, and don't try the newer versions; and AF_INET6 queries use
699 * rpcbindv4, then rpcbindv3 on the same socket. The newer rpcbind protocol
700 * versions can adequately detect if a remote RPC service does not support
701 * AF_INET6 at all. The rpcbind socket is re-used in an attempt to keep the
702 * overall number of consumed ephemeral ports low.
704 unsigned short nfs_getport(const struct sockaddr *sap,
705 const socklen_t salen,
706 const rpcprog_t program,
707 const rpcvers_t version,
708 const unsigned short protocol)
710 struct sockaddr_storage address;
711 struct sockaddr *saddr = (struct sockaddr *)&address;
712 struct timeval timeout = { -1, 0 };
713 unsigned short port = 0;
716 nfs_clear_rpc_createerr();
718 memcpy(saddr, sap, (size_t)salen);
719 client = nfs_gp_get_rpcbclient(saddr, salen, protocol,
720 default_rpcb_version, &timeout);
721 if (client != NULL) {
722 port = nfs_gp_getport(client, saddr, program,
723 version, protocol, timeout);
724 CLNT_DESTROY(client);
731 * nfs_getport_ping - query server's rpcbind and do RPC ping to verify result
732 * @sap: IN: pointer to address of server to query;
733 * OUT: pointer to updated address
734 * @salen: length of server's address
735 * @program: requested RPC program number
736 * @version: requested RPC version number
737 * @protocol: IPPROTO_ value of requested transport protocol
739 * Uses any acceptable rpcbind version to discover the port number for the
740 * RPC service described by the given [program, version, transport] tuple.
741 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
742 * AF_INET6 server addresses.
744 * Returns a 1 and sets the port number in the passed-in server address
745 * if both the query and the ping were successful; otherwise zero.
746 * rpccreateerr is set to reflect the underlying cause of the error.
748 int nfs_getport_ping(struct sockaddr *sap, const socklen_t salen,
749 const rpcprog_t program, const rpcvers_t version,
750 const unsigned short protocol)
752 struct timeval timeout = { -1, 0 };
753 unsigned short port = 0;
757 nfs_clear_rpc_createerr();
759 client = nfs_gp_get_rpcbclient(sap, salen, protocol,
760 default_rpcb_version, &timeout);
761 if (client != NULL) {
762 port = nfs_gp_getport(client, sap, program,
763 version, protocol, timeout);
764 CLNT_DESTROY(client);
769 struct sockaddr_storage address;
770 struct sockaddr *saddr = (struct sockaddr *)&address;
772 memcpy(saddr, sap, (size_t)salen);
773 nfs_gp_set_port(saddr, htons(port));
775 nfs_clear_rpc_createerr();
777 client = nfs_get_rpcclient(saddr, salen, protocol,
778 program, version, &timeout);
779 if (client != NULL) {
780 result = nfs_gp_ping(client, timeout);
781 nfs_gp_map_tcp_errorcodes(protocol);
782 CLNT_DESTROY(client);
787 nfs_gp_set_port(sap, htons(port));
793 * nfs_getlocalport - query local rpcbind to get port number for an RPC service
794 * @program: requested RPC program number
795 * @version: requested RPC version number
796 * @protocol: IPPROTO_ value of requested transport protocol
798 * Uses any acceptable rpcbind version to discover the port number for the
799 * RPC service described by the given [program, version, transport] tuple.
800 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
801 * AF_INET6 local addresses.
803 * Returns a positive integer representing the port number of the RPC
804 * service advertised by the server (in host byte order), or zero if the
805 * service is not advertised or there was some problem querying the server's
806 * rpcbind daemon. rpccreateerr is set to reflect the underlying cause of
809 * Try an AF_LOCAL connection first. The rpcbind daemon implementation should
810 * listen on AF_LOCAL.
812 * If that doesn't work (for example, if portmapper is running, or rpcbind
813 * isn't listening on /var/run/rpcbind.sock), send a query via UDP to localhost
814 * (UDP doesn't leave a socket in TIME_WAIT, and the timeout is a relatively
817 unsigned short nfs_getlocalport(const rpcprot_t program,
818 const rpcvers_t version,
819 const unsigned short protocol)
821 struct sockaddr_storage address;
822 struct sockaddr *lb_addr = (struct sockaddr *)&address;
823 socklen_t lb_len = sizeof(*lb_addr);
824 unsigned short port = 0;
827 const struct sockaddr_un sun = {
828 .sun_family = AF_LOCAL,
829 .sun_path = _PATH_RPCBINDSOCK,
831 const struct sockaddr *sap = (struct sockaddr *)&sun;
832 const socklen_t salen = SUN_LEN(&sun);
834 struct timeval timeout = { -1, 0 };
836 nfs_clear_rpc_createerr();
838 client = nfs_gp_get_rpcbclient(sap, salen, 0, RPCBVERS_4, &timeout);
839 if (client != NULL) {
842 if (nfs_gp_init_rpcb_parms(sap, program, version,
843 protocol, &parms) != 0) {
844 port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
845 nfs_gp_free_rpcb_parms(&parms);
847 CLNT_DESTROY(client);
849 #endif /* NFS_GP_LOCAL */
852 nfs_clear_rpc_createerr();
854 if (nfs_gp_loopback_address(lb_addr, &lb_len)) {
855 port = nfs_getport(lb_addr, lb_len,
856 program, version, protocol);
858 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
865 * nfs_rpcb_getaddr - query rpcbind via rpcbind versions 4 and 3
866 * @sap: pointer to address of server to query
867 * @salen: length of server address
868 * @transport: transport protocol to use for the query
869 * @addr: pointer to r_addr address
870 * @program: requested RPC program number
871 * @version: requested RPC version number
872 * @protocol: requested IPPROTO_ value of transport protocol
873 * @timeout: pointer to request timeout (NULL means use default timeout)
875 * Returns a positive integer representing the port number of the RPC
876 * service advertised by the server (in host byte order), or zero if the
877 * service is not advertised or there was some problem querying the
878 * server's rpcbind daemon. rpccreateerr is set to reflect the
879 * underlying cause of the error.
881 * This function provides similar functionality to nfs_pmap_getport(),
882 * but performs the rpcbind lookup via rpcbind version 4. If the server
883 * doesn't support rpcbind version 4, it will retry with version 3.
884 * The GETADDR procedure is exactly the same in these two versions of
885 * the rpcbind protocol, so the socket, RPC client, and arguments are
886 * re-used when retrying, saving ephemeral port space.
888 * These RPC procedures take a universal address as an argument, so the
889 * query will fail if the remote rpcbind daemon doesn't find an entry
890 * with a matching address. A matching address includes an ANYADDR
891 * address of the same address family. In this way an RPC server can
892 * advertise via rpcbind that it does not support AF_INET6.
896 unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
897 const socklen_t salen,
898 const unsigned short transport,
899 const struct sockaddr *addr,
900 const rpcprog_t program,
901 const rpcvers_t version,
902 const unsigned short protocol,
903 const struct timeval *timeout)
905 struct sockaddr_storage address;
906 struct sockaddr *saddr = (struct sockaddr *)&address;
909 struct timeval tout = { -1, 0 };
910 unsigned short port = 0;
915 nfs_clear_rpc_createerr();
917 memcpy(saddr, sap, (size_t)salen);
918 client = nfs_gp_get_rpcbclient(saddr, salen, transport,
920 if (client != NULL) {
921 if (nfs_gp_init_rpcb_parms(addr, program, version,
922 protocol, &parms) != 0) {
923 port = nfs_gp_rpcb_getaddr(client, &parms, tout);
924 nfs_gp_free_rpcb_parms(&parms);
926 CLNT_DESTROY(client);
932 #else /* !HAVE_LIBTIRPC */
934 unsigned short nfs_rpcb_getaddr(__attribute__((unused)) const struct sockaddr *sap,
935 __attribute__((unused)) const socklen_t salen,
936 __attribute__((unused)) const unsigned short transport,
937 __attribute__((unused)) const struct sockaddr *addr,
938 __attribute__((unused)) const rpcprog_t program,
939 __attribute__((unused)) const rpcvers_t version,
940 __attribute__((unused)) const unsigned short protocol,
941 __attribute__((unused)) const struct timeval *timeout)
943 nfs_clear_rpc_createerr();
945 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
949 #endif /* !HAVE_LIBTIRPC */
952 * nfs_pmap_getport - query rpcbind via the portmap protocol (rpcbindv2)
953 * @sin: pointer to AF_INET address of server to query
954 * @transport: transport protocol to use for the query
955 * @program: requested RPC program number
956 * @version: requested RPC version number
957 * @protocol: requested IPPROTO_ value of transport protocol
958 * @timeout: pointer to request timeout (NULL means use default timeout)
960 * Returns a positive integer representing the port number of the RPC service
961 * advertised by the server (in host byte order), or zero if the service is
962 * not advertised or there was some problem querying the server's rpcbind
963 * daemon. rpccreateerr is set to reflect the underlying cause of the error.
965 * nfs_pmap_getport() is very similar to pmap_getport(), except that:
967 * 1. This version always tries to use an ephemeral port, since reserved
968 * ports are not needed for GETPORT queries. This conserves the very
969 * limited reserved port space, helping reduce failed socket binds
970 * during mount storms.
972 * 2. This version times out quickly by default. It time-limits the
973 * connect process as well as the actual RPC call, and even allows the
974 * caller to specify the timeout.
976 * 3. This version shares code with the rpcbindv3 and rpcbindv4 query
977 * functions. It can use a TI-RPC generated CLIENT.
979 unsigned long nfs_pmap_getport(const struct sockaddr_in *sin,
980 const unsigned short transport,
981 const unsigned long program,
982 const unsigned long version,
983 const unsigned long protocol,
984 const struct timeval *timeout)
986 struct sockaddr_in address;
987 struct sockaddr *saddr = (struct sockaddr *)&address;
989 struct pmap parms = {
994 struct timeval tout = { -1, 0 };
995 unsigned long port = 0;
1000 nfs_clear_rpc_createerr();
1002 memcpy(saddr, sin, sizeof(address));
1003 client = nfs_gp_get_rpcbclient(saddr, (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);