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.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 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>
52 * Try a local socket first to access the local rpcbind daemon
54 * Rpcbind's local socket service does not seem to be working.
55 * Disable this logic for now.
59 #else /* !HAVE_LIBTIRPC */
61 #endif /* !HAVE_LIBTIRPC */
64 static const rpcvers_t default_rpcb_version = RPCBVERS_4;
65 #else /* !HAVE_LIBTIRPC */
66 static const rpcvers_t default_rpcb_version = PMAPVERS;
67 #endif /* !HAVE_LIBTIRPC */
70 * Historical: Map TCP connect timeouts to timeout
71 * error code used by UDP.
74 nfs_gp_map_tcp_errorcodes(const unsigned short protocol)
76 if (protocol != IPPROTO_TCP)
79 switch (rpc_createerr.cf_error.re_errno) {
81 rpc_createerr.cf_stat = RPC_TIMEDOUT;
84 rpc_createerr.cf_stat = RPC_CANTRECV;
90 * There's no easy way to tell how the local system's networking
91 * and rpcbind is configured (ie. whether we want to use IPv6 or
92 * IPv4 loopback to contact RPC services on the local host). We
93 * punt and simply try to look up "localhost".
95 * Returns TRUE on success.
97 static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen)
99 struct addrinfo *gai_results;
102 if (getaddrinfo("localhost", NULL, NULL, &gai_results))
105 if (*salen >= gai_results->ai_addrlen) {
106 memcpy(sap, gai_results->ai_addr,
107 gai_results->ai_addrlen);
108 *salen = gai_results->ai_addrlen;
112 freeaddrinfo(gai_results);
117 * Look up a network service in /etc/services and return the
118 * network-order port number of that service.
120 static in_port_t nfs_gp_getservbyname(const char *service,
121 const unsigned short protocol)
123 const struct addrinfo gai_hint = {
124 .ai_family = AF_INET,
125 .ai_protocol = protocol,
126 .ai_flags = AI_PASSIVE,
128 struct addrinfo *gai_results;
129 const struct sockaddr_in *sin;
132 if (getaddrinfo(NULL, service, &gai_hint, &gai_results) != 0)
135 sin = (const struct sockaddr_in *)gai_results->ai_addr;
136 port = sin->sin_port;
138 freeaddrinfo(gai_results);
143 * Discover the port number that should be used to contact an
144 * rpcbind service. This will detect if the port has a local
145 * value that may have been set in /etc/services.
147 * Returns network byte-order port number of rpcbind service
150 static in_port_t nfs_gp_get_rpcb_port(const unsigned short protocol)
152 static const char *rpcb_netnametbl[] = {
160 for (i = 0; rpcb_netnametbl[i] != NULL; i++) {
163 port = nfs_gp_getservbyname(rpcb_netnametbl[i], protocol);
168 return (in_port_t)htons((uint16_t)PMAPPORT);
172 * Set up an RPC client for communicating with an rpcbind daemon at
173 * @sap over @transport with protocol version @version.
175 * Returns a pointer to a prepared RPC client if successful, and
176 * @timeout is initialized; caller must destroy a non-NULL returned RPC
177 * client. Otherwise returns NULL, and rpc_createerr.cf_stat is set to
180 static CLIENT *nfs_gp_get_rpcbclient(struct sockaddr *sap,
181 const socklen_t salen,
182 const unsigned short transport,
183 const rpcvers_t version,
184 struct timeval *timeout)
186 static const char *rpcb_pgmtbl[] = {
193 rpcprog_t rpcb_prog = nfs_getrpcbyname(RPCBPROG, rpcb_pgmtbl);
196 nfs_set_port(sap, ntohs(nfs_gp_get_rpcb_port(transport)));
197 clnt = nfs_get_rpcclient(sap, salen, transport, rpcb_prog,
199 nfs_gp_map_tcp_errorcodes(transport);
204 * nfs_get_proto - Convert a netid to an address family and protocol number
205 * @netid: C string containing a netid
206 * @family: OUT: address family
207 * @protocol: OUT: protocol number
209 * Returns 1 and fills in @protocol if the netid was recognized;
210 * otherwise zero is returned.
214 nfs_get_proto(const char *netid, sa_family_t *family, unsigned long *protocol)
216 struct netconfig *nconf;
217 struct protoent *proto;
220 * IANA does not define a protocol number for rdma netids,
221 * since "rdma" is not an IP protocol.
223 if (strcmp(netid, "rdma") == 0) {
225 *protocol = NFSPROTO_RDMA;
228 if (strcmp(netid, "rdma6") == 0) {
230 *protocol = NFSPROTO_RDMA;
234 nconf = getnetconfigent(netid);
238 proto = getprotobyname(nconf->nc_proto);
240 freenetconfigent(nconf);
245 if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
247 if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
249 freenetconfigent(nconf);
251 *protocol = (unsigned long)proto->p_proto;
254 #else /* !HAVE_LIBTIRPC */
256 nfs_get_proto(const char *netid, sa_family_t *family, unsigned long *protocol)
258 struct protoent *proto;
261 * IANA does not define a protocol number for rdma netids,
262 * since "rdma" is not an IP protocol.
264 if (strcmp(netid, "rdma") == 0) {
266 *protocol = NFSPROTO_RDMA;
270 proto = getprotobyname(netid);
275 *protocol = (unsigned long)proto->p_proto;
278 #endif /* !HAVE_LIBTIRPC */
281 * nfs_get_netid - Convert a protocol family and protocol name to a netid
282 * @family: protocol family
283 * @protocol: protocol number
285 * One of the arguments passed when querying remote rpcbind services
286 * via rpcbind v3 or v4 is a netid string. This replaces the pm_prot
287 * field used in legacy PMAP_GETPORT calls.
289 * RFC 1833 says netids are not standard but rather defined on the local
290 * host. There are, however, standard definitions for nc_protofmly and
291 * nc_proto that can be used to derive a netid string on the local host,
292 * based on the contents of /etc/netconfig.
294 * Walk through the local netconfig database and grab the netid of the
295 * first entry that matches @family and @protocol and whose netid string
296 * fits in the provided buffer.
298 * Returns a '\0'-terminated string if successful. Caller must
299 * free the returned string. Otherwise NULL is returned, and
300 * rpc_createerr.cf_stat is set to reflect the error.
303 char *nfs_get_netid(const sa_family_t family, const unsigned long protocol)
305 char *nc_protofmly, *nc_proto, *nc_netid;
306 struct netconfig *nconf;
307 struct protoent *proto;
313 nc_protofmly = NC_INET;
316 nc_protofmly = NC_INET6;
322 proto = getprotobynumber(protocol);
325 nc_proto = proto->p_name;
327 handle = setnetconfig();
328 while ((nconf = getnetconfig(handle)) != NULL) {
330 if (nconf->nc_protofmly != NULL &&
331 strcmp(nconf->nc_protofmly, nc_protofmly) != 0)
333 if (nconf->nc_proto != NULL &&
334 strcmp(nconf->nc_proto, nc_proto) != 0)
337 nc_netid = strdup(nconf->nc_netid);
338 endnetconfig(handle);
340 if (nc_netid == NULL)
341 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
344 endnetconfig(handle);
347 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
350 #else /* !HAVE_LIBTIRPC */
351 char *nfs_get_netid(const sa_family_t family, const unsigned long protocol)
353 struct protoent *proto;
356 if (family != AF_INET)
358 proto = getprotobynumber((int)protocol);
362 netid = strdup(proto->p_name);
364 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
368 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
371 #endif /* !HAVE_LIBTIRPC */
374 * Extract a port number from a universal address, and terminate the
375 * string in @addrstr just after the address part.
377 * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
380 static int nfs_gp_universal_porthelper(char *addrstr)
383 unsigned long portlo, porthi;
386 p = strrchr(addrstr, '.');
389 portlo = strtoul(p + 1, &endptr, 10);
390 if (*endptr != '\0' || portlo > 255)
394 p = strrchr(addrstr, '.');
397 porthi = strtoul(p + 1, &endptr, 10);
398 if (*endptr != '\0' || porthi > 255)
401 port = (porthi << 8) | portlo;
408 * nfs_universal2port - extract port number from a "universal address"
409 * @uaddr: '\0'-terminated C string containing a universal address
411 * Universal addresses (defined in RFC 1833) are used when calling an
412 * rpcbind daemon via protocol versions 3 or 4..
414 * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
417 int nfs_universal2port(const char *uaddr)
422 addrstr = strdup(uaddr);
423 if (addrstr != NULL) {
424 port = nfs_gp_universal_porthelper(addrstr);
431 * nfs_sockaddr2universal - convert a sockaddr to a "universal address"
432 * @sap: pointer to a socket address
434 * Universal addresses (defined in RFC 1833) are used when calling an
435 * rpcbind daemon via protocol versions 3 or 4..
437 * Returns a '\0'-terminated string if successful; caller must free
438 * the returned string. Otherwise NULL is returned and
439 * rpc_createerr.cf_stat is set to reflect the error.
441 * inet_ntop(3) is used here, since getnameinfo(3) is not available
442 * in some earlier glibc releases, and we don't require support for
443 * scope IDs for universal addresses.
445 char *nfs_sockaddr2universal(const struct sockaddr *sap)
447 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
448 const struct sockaddr_un *sun = (const struct sockaddr_un *)sap;
449 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
450 char buf[INET6_ADDRSTRLEN + 8 /* for port information */];
456 switch (sap->sa_family) {
458 return strndup(sun->sun_path, sizeof(sun->sun_path));
460 if (inet_ntop(AF_INET, (const void *)&sin->sin_addr.s_addr,
461 buf, (socklen_t)sizeof(buf)) == NULL)
463 port = ntohs(sin->sin_port);
466 if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
467 buf, (socklen_t)sizeof(buf)) == NULL)
469 port = ntohs(sin6->sin6_port);
475 count = sizeof(buf) - strlen(buf);
476 len = snprintf(buf + strlen(buf), count, ".%u.%u",
477 (unsigned)(port >> 8), (unsigned)(port & 0xff));
478 /* before glibc 2.0.6, snprintf(3) could return -1 */
479 if (len < 0 || (size_t)len > count)
482 result = strdup(buf);
487 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
492 * Send a NULL request to the indicated RPC service.
494 * Returns 1 if the service responded; otherwise 0;
496 static int nfs_gp_ping(CLIENT *client, struct timeval timeout)
498 enum clnt_stat status;
500 status = CLNT_CALL(client, NULLPROC,
501 (xdrproc_t)xdr_void, NULL,
502 (xdrproc_t)xdr_void, NULL,
505 if (status != RPC_SUCCESS) {
506 rpc_createerr.cf_stat = status;
507 CLNT_GETERR(client, &rpc_createerr.cf_error);
509 return (int)(status == RPC_SUCCESS);
515 * Initialize the rpcb argument for a GETADDR request.
517 * Returns 1 if successful, and caller must free strings pointed
518 * to by r_netid and r_addr; otherwise 0.
520 static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap,
521 const rpcprog_t program,
522 const rpcvers_t version,
523 const unsigned short protocol,
528 netid = nfs_get_netid(sap->sa_family, protocol);
532 addr = nfs_sockaddr2universal(sap);
538 memset(parms, 0, sizeof(*parms));
539 parms->r_prog = program;
540 parms->r_vers = version;
541 parms->r_netid = netid;
542 parms->r_addr = addr;
548 static void nfs_gp_free_rpcb_parms(struct rpcb *parms)
550 free(parms->r_netid);
555 * Try rpcbind GETADDR via version 4. If that fails, try same
556 * request via version 3.
558 * Returns non-zero port number on success; otherwise returns
559 * zero. rpccreateerr is set to reflect the nature of the error.
561 static unsigned short nfs_gp_rpcb_getaddr(CLIENT *client,
563 struct timeval timeout)
565 rpcvers_t rpcb_version;
566 struct rpc_err rpcerr;
569 for (rpcb_version = RPCBVERS_4;
570 rpcb_version >= RPCBVERS_3;
572 enum clnt_stat status;
575 CLNT_CONTROL(client, CLSET_VERS, (void *)&rpcb_version);
576 status = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR,
577 (xdrproc_t)xdr_rpcb, (void *)parms,
578 (xdrproc_t)xdr_wrapstring, (void *)&uaddr,
583 if ((uaddr == NULL) || (uaddr[0] == '\0')) {
584 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
588 port = nfs_universal2port(uaddr);
589 xdr_free((xdrproc_t)xdr_wrapstring, (char *)&uaddr);
591 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
594 return (unsigned short)port;
595 case RPC_PROGVERSMISMATCH:
596 clnt_geterr(client, &rpcerr);
597 if (rpcerr.re_vers.low > RPCBVERS4)
600 case RPC_PROCUNAVAIL:
601 case RPC_PROGUNAVAIL:
604 /* Most likely RPC_TIMEDOUT or RPC_CANTRECV */
605 rpc_createerr.cf_stat = status;
606 clnt_geterr(client, &rpc_createerr.cf_error);
613 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
614 clnt_geterr(client, &rpc_createerr.cf_error);
619 #endif /* HAVE_LIBTIRPC */
622 * Try GETPORT request via rpcbind version 2.
624 * Returns non-zero port number on success; otherwise returns
625 * zero. rpccreateerr is set to reflect the nature of the error.
627 static unsigned long nfs_gp_pmap_getport(CLIENT *client,
629 struct timeval timeout)
631 enum clnt_stat status;
634 status = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
635 (xdrproc_t)xdr_pmap, (void *)parms,
636 (xdrproc_t)xdr_u_long, (void *)&port,
639 if (status != RPC_SUCCESS) {
640 rpc_createerr.cf_stat = status;
641 CLNT_GETERR(client, &rpc_createerr.cf_error);
643 } else if (port == 0)
644 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
651 static unsigned short nfs_gp_getport_rpcb(CLIENT *client,
652 const struct sockaddr *sap,
653 const rpcprog_t program,
654 const rpcvers_t version,
655 const unsigned short protocol,
656 struct timeval timeout)
658 unsigned short port = 0;
661 if (nfs_gp_init_rpcb_parms(sap, program, version,
662 protocol, &parms) != 0) {
663 port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
664 nfs_gp_free_rpcb_parms(&parms);
670 #endif /* HAVE_LIBTIRPC */
672 static unsigned long nfs_gp_getport_pmap(CLIENT *client,
673 const rpcprog_t program,
674 const rpcvers_t version,
675 const unsigned short protocol,
676 struct timeval timeout)
678 struct pmap parms = {
683 rpcvers_t pmap_version = PMAPVERS;
685 CLNT_CONTROL(client, CLSET_VERS, (void *)&pmap_version);
686 return nfs_gp_pmap_getport(client, &parms, timeout);
690 * Try an AF_INET6 request via rpcbind v4/v3; try an AF_INET
691 * request via rpcbind v2.
693 * Returns non-zero port number on success; otherwise returns
694 * zero. rpccreateerr is set to reflect the nature of the error.
696 static unsigned short nfs_gp_getport(CLIENT *client,
697 const struct sockaddr *sap,
698 const rpcprog_t program,
699 const rpcvers_t version,
700 const unsigned short protocol,
701 struct timeval timeout)
703 switch (sap->sa_family) {
706 return nfs_gp_getport_rpcb(client, sap, program,
707 version, protocol, timeout);
708 #endif /* HAVE_LIBTIRPC */
710 return nfs_gp_getport_pmap(client, program, version,
714 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
719 * nfs_rpc_ping - Determine if RPC service is responding to requests
720 * @sap: pointer to address of server to query (port is already filled in)
721 * @salen: length of server address
722 * @program: requested RPC program number
723 * @version: requested RPC version number
724 * @protocol: requested IPPROTO_ value of transport protocol
725 * @timeout: pointer to request timeout (NULL means use default timeout)
727 * Returns 1 if the remote service responded without an error; otherwise
730 int nfs_rpc_ping(const struct sockaddr *sap, const socklen_t salen,
731 const rpcprog_t program, const rpcvers_t version,
732 const unsigned short protocol, const struct timeval *timeout)
734 union nfs_sockaddr address;
735 struct sockaddr *saddr = &address.sa;
737 struct timeval tout = { -1, 0 };
743 nfs_clear_rpc_createerr();
745 memcpy(saddr, sap, (size_t)salen);
746 client = nfs_get_rpcclient(saddr, salen, protocol,
747 program, version, &tout);
748 if (client != NULL) {
749 result = nfs_gp_ping(client, tout);
750 nfs_gp_map_tcp_errorcodes(protocol);
751 CLNT_DESTROY(client);
758 * nfs_getport - query server's rpcbind to get port number for an RPC service
759 * @sap: pointer to address of server to query
760 * @salen: length of server's address
761 * @program: requested RPC program number
762 * @version: requested RPC version number
763 * @protocol: IPPROTO_ value of requested transport protocol
765 * Uses any acceptable rpcbind version to discover the port number for the
766 * RPC service described by the given [program, version, transport] tuple.
767 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
768 * AF_INET6 server addresses.
770 * Returns a positive integer representing the port number of the RPC
771 * service advertised by the server (in host byte order), or zero if the
772 * service is not advertised or there was some problem querying the server's
773 * rpcbind daemon. rpccreateerr is set to reflect the underlying cause of
776 * There are a variety of ways to choose which transport and rpcbind versions
777 * to use. We chose to conserve local resources and try to avoid incurring
781 * To provide rudimentary support for traversing firewalls, query the remote
782 * using the same transport as the requested service. This provides some
783 * guarantee that the requested transport is available between this client
784 * and the server, and if the caller specifically requests TCP, for example,
785 * this may be becuase a firewall is in place that blocks UDP traffic. We
786 * could try both, but that could involve a lengthy timeout in several cases,
787 * and would often consume an extra ephemeral port.
790 * To avoid using up too many ephemeral ports, AF_INET queries use tried-and-
791 * true rpcbindv2, and don't try the newer versions; and AF_INET6 queries use
792 * rpcbindv4, then rpcbindv3 on the same socket. The newer rpcbind protocol
793 * versions can adequately detect if a remote RPC service does not support
794 * AF_INET6 at all. The rpcbind socket is re-used in an attempt to keep the
795 * overall number of consumed ephemeral ports low.
797 unsigned short nfs_getport(const struct sockaddr *sap,
798 const socklen_t salen,
799 const rpcprog_t program,
800 const rpcvers_t version,
801 const unsigned short protocol)
803 union nfs_sockaddr address;
804 struct sockaddr *saddr = &address.sa;
805 struct timeval timeout = { -1, 0 };
806 unsigned short port = 0;
809 nfs_clear_rpc_createerr();
811 memcpy(saddr, sap, (size_t)salen);
812 client = nfs_gp_get_rpcbclient(saddr, salen, protocol,
813 default_rpcb_version, &timeout);
814 if (client != NULL) {
815 port = nfs_gp_getport(client, saddr, program,
816 version, protocol, timeout);
817 CLNT_DESTROY(client);
824 * nfs_getport_ping - query server's rpcbind and do RPC ping to verify result
825 * @sap: IN: pointer to address of server to query;
826 * OUT: pointer to updated address
827 * @salen: length of server's address
828 * @program: requested RPC program number
829 * @version: requested RPC version number
830 * @protocol: IPPROTO_ value of requested transport protocol
832 * Uses any acceptable rpcbind version to discover the port number for the
833 * RPC service described by the given [program, version, transport] tuple.
834 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
835 * AF_INET6 server addresses.
837 * Returns a 1 and sets the port number in the passed-in server address
838 * if both the query and the ping were successful; otherwise zero.
839 * rpccreateerr is set to reflect the underlying cause of the error.
841 int nfs_getport_ping(struct sockaddr *sap, const socklen_t salen,
842 const rpcprog_t program, const rpcvers_t version,
843 const unsigned short protocol)
845 struct timeval timeout = { -1, 0 };
846 unsigned short port = 0;
850 nfs_clear_rpc_createerr();
852 client = nfs_gp_get_rpcbclient(sap, salen, protocol,
853 default_rpcb_version, &timeout);
854 if (client != NULL) {
855 port = nfs_gp_getport(client, sap, program,
856 version, protocol, timeout);
857 CLNT_DESTROY(client);
862 union nfs_sockaddr address;
863 struct sockaddr *saddr = &address.sa;
865 memcpy(saddr, sap, (size_t)salen);
866 nfs_set_port(saddr, port);
868 nfs_clear_rpc_createerr();
870 client = nfs_get_rpcclient(saddr, salen, protocol,
871 program, version, &timeout);
872 if (client != NULL) {
873 result = nfs_gp_ping(client, timeout);
874 nfs_gp_map_tcp_errorcodes(protocol);
875 CLNT_DESTROY(client);
880 nfs_set_port(sap, port);
886 * nfs_getlocalport - query local rpcbind to get port number for an RPC service
887 * @program: requested RPC program number
888 * @version: requested RPC version number
889 * @protocol: IPPROTO_ value of requested transport protocol
891 * Uses any acceptable rpcbind version to discover the port number for the
892 * RPC service described by the given [program, version, transport] tuple.
893 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
894 * AF_INET6 local addresses.
896 * Returns a positive integer representing the port number of the RPC
897 * service advertised by the server (in host byte order), or zero if the
898 * service is not advertised or there was some problem querying the server's
899 * rpcbind daemon. rpccreateerr is set to reflect the underlying cause of
902 * Try an AF_LOCAL connection first. The rpcbind daemon implementation should
903 * listen on AF_LOCAL.
905 * If that doesn't work (for example, if portmapper is running, or rpcbind
906 * isn't listening on /var/run/rpcbind.sock), send a query via UDP to localhost
907 * (UDP doesn't leave a socket in TIME_WAIT, and the timeout is a relatively
910 unsigned short nfs_getlocalport(const rpcprot_t program,
911 const rpcvers_t version,
912 const unsigned short protocol)
914 union nfs_sockaddr address;
915 struct sockaddr *lb_addr = &address.sa;
916 socklen_t lb_len = sizeof(*lb_addr);
917 unsigned short port = 0;
920 const struct sockaddr_un sun = {
921 .sun_family = AF_LOCAL,
922 .sun_path = _PATH_RPCBINDSOCK,
924 const struct sockaddr *sap = (struct sockaddr *)&sun;
925 const socklen_t salen = SUN_LEN(&sun);
927 struct timeval timeout = { -1, 0 };
929 nfs_clear_rpc_createerr();
931 client = nfs_gp_get_rpcbclient(sap, salen, 0, RPCBVERS_4, &timeout);
932 if (client != NULL) {
935 if (nfs_gp_init_rpcb_parms(sap, program, version,
936 protocol, &parms) != 0) {
937 port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
938 nfs_gp_free_rpcb_parms(&parms);
940 CLNT_DESTROY(client);
942 #endif /* NFS_GP_LOCAL */
945 nfs_clear_rpc_createerr();
947 if (nfs_gp_loopback_address(lb_addr, &lb_len)) {
948 port = nfs_getport(lb_addr, lb_len,
949 program, version, protocol);
951 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
958 * nfs_rpcb_getaddr - query rpcbind via rpcbind versions 4 and 3
959 * @sap: pointer to address of server to query
960 * @salen: length of server address
961 * @transport: transport protocol to use for the query
962 * @addr: pointer to r_addr address
963 * @program: requested RPC program number
964 * @version: requested RPC version number
965 * @protocol: requested IPPROTO_ value of transport protocol
966 * @timeout: pointer to request timeout (NULL means use default timeout)
968 * Returns a positive integer representing the port number of the RPC
969 * service advertised by the server (in host byte order), or zero if the
970 * service is not advertised or there was some problem querying the
971 * server's rpcbind daemon. rpccreateerr is set to reflect the
972 * underlying cause of the error.
974 * This function provides similar functionality to nfs_pmap_getport(),
975 * but performs the rpcbind lookup via rpcbind version 4. If the server
976 * doesn't support rpcbind version 4, it will retry with version 3.
977 * The GETADDR procedure is exactly the same in these two versions of
978 * the rpcbind protocol, so the socket, RPC client, and arguments are
979 * re-used when retrying, saving ephemeral port space.
981 * These RPC procedures take a universal address as an argument, so the
982 * query will fail if the remote rpcbind daemon doesn't find an entry
983 * with a matching address. A matching address includes an ANYADDR
984 * address of the same address family. In this way an RPC server can
985 * advertise via rpcbind that it does not support AF_INET6.
989 unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
990 const socklen_t salen,
991 const unsigned short transport,
992 const struct sockaddr *addr,
993 const rpcprog_t program,
994 const rpcvers_t version,
995 const unsigned short protocol,
996 const struct timeval *timeout)
998 union nfs_sockaddr address;
999 struct sockaddr *saddr = &address.sa;
1002 struct timeval tout = { -1, 0 };
1003 unsigned short port = 0;
1005 if (timeout != NULL)
1008 nfs_clear_rpc_createerr();
1010 memcpy(saddr, sap, (size_t)salen);
1011 client = nfs_gp_get_rpcbclient(saddr, salen, transport,
1013 if (client != NULL) {
1014 if (nfs_gp_init_rpcb_parms(addr, program, version,
1015 protocol, &parms) != 0) {
1016 port = nfs_gp_rpcb_getaddr(client, &parms, tout);
1017 nfs_gp_free_rpcb_parms(&parms);
1019 CLNT_DESTROY(client);
1025 #else /* !HAVE_LIBTIRPC */
1027 unsigned short nfs_rpcb_getaddr(__attribute__((unused)) const struct sockaddr *sap,
1028 __attribute__((unused)) const socklen_t salen,
1029 __attribute__((unused)) const unsigned short transport,
1030 __attribute__((unused)) const struct sockaddr *addr,
1031 __attribute__((unused)) const rpcprog_t program,
1032 __attribute__((unused)) const rpcvers_t version,
1033 __attribute__((unused)) const unsigned short protocol,
1034 __attribute__((unused)) const struct timeval *timeout)
1036 nfs_clear_rpc_createerr();
1038 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
1042 #endif /* !HAVE_LIBTIRPC */
1045 * nfs_pmap_getport - query rpcbind via the portmap protocol (rpcbindv2)
1046 * @sin: pointer to AF_INET address of server to query
1047 * @transport: transport protocol to use for the query
1048 * @program: requested RPC program number
1049 * @version: requested RPC version number
1050 * @protocol: requested IPPROTO_ value of transport protocol
1051 * @timeout: pointer to request timeout (NULL means use default timeout)
1053 * Returns a positive integer representing the port number of the RPC service
1054 * advertised by the server (in host byte order), or zero if the service is
1055 * not advertised or there was some problem querying the server's rpcbind
1056 * daemon. rpccreateerr is set to reflect the underlying cause of the error.
1058 * nfs_pmap_getport() is very similar to pmap_getport(), except that:
1060 * 1. This version always tries to use an ephemeral port, since reserved
1061 * ports are not needed for GETPORT queries. This conserves the very
1062 * limited reserved port space, helping reduce failed socket binds
1063 * during mount storms.
1065 * 2. This version times out quickly by default. It time-limits the
1066 * connect process as well as the actual RPC call, and even allows the
1067 * caller to specify the timeout.
1069 * 3. This version shares code with the rpcbindv3 and rpcbindv4 query
1070 * functions. It can use a TI-RPC generated CLIENT.
1072 unsigned long nfs_pmap_getport(const struct sockaddr_in *sin,
1073 const unsigned short transport,
1074 const unsigned long program,
1075 const unsigned long version,
1076 const unsigned long protocol,
1077 const struct timeval *timeout)
1079 struct sockaddr_in address;
1080 struct sockaddr *saddr = (struct sockaddr *)&address;
1082 struct pmap parms = {
1085 .pm_prot = protocol,
1087 struct timeval tout = { -1, 0 };
1088 unsigned long port = 0;
1090 if (timeout != NULL)
1093 nfs_clear_rpc_createerr();
1095 memcpy(saddr, sin, sizeof(address));
1096 client = nfs_gp_get_rpcbclient(saddr, (socklen_t)sizeof(*sin),
1097 transport, PMAPVERS, &tout);
1098 if (client != NULL) {
1099 port = nfs_gp_pmap_getport(client, &parms, tout);
1100 CLNT_DESTROY(client);