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 * There's no easy way to tell how the local system's networking
70 * and rpcbind is configured (ie. whether we want to use IPv6 or
71 * IPv4 loopback to contact RPC services on the local host). We
72 * punt and simply try to look up "localhost".
74 * Returns TRUE on success.
76 static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen)
78 struct addrinfo *gai_results;
81 if (getaddrinfo("localhost", NULL, NULL, &gai_results))
84 if (*salen >= gai_results->ai_addrlen) {
85 memcpy(sap, gai_results->ai_addr,
86 gai_results->ai_addrlen);
87 *salen = gai_results->ai_addrlen;
91 freeaddrinfo(gai_results);
96 * Plant port number in @sap. @port is already in network byte order.
98 static void nfs_gp_set_port(struct sockaddr *sap, const in_port_t port)
100 struct sockaddr_in *sin = (struct sockaddr_in *)sap;
101 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
103 switch (sap->sa_family) {
105 sin->sin_port = port;
108 sin6->sin6_port = port;
114 * Look up a network service in /etc/services and return the
115 * network-order port number of that service.
117 static in_port_t nfs_gp_getservbyname(const char *service,
118 const unsigned short protocol)
120 const struct addrinfo gai_hint = {
121 .ai_family = AF_INET,
122 .ai_protocol = protocol,
123 .ai_flags = AI_PASSIVE,
125 struct addrinfo *gai_results;
126 const struct sockaddr_in *sin;
129 if (getaddrinfo(NULL, service, &gai_hint, &gai_results) != 0)
132 sin = (const struct sockaddr_in *)gai_results->ai_addr;
133 port = sin->sin_port;
135 freeaddrinfo(gai_results);
140 * Discover the port number that should be used to contact an
141 * rpcbind service. This will detect if the port has a local
142 * value that may have been set in /etc/services.
144 * Returns network byte-order port number of rpcbind service
147 static in_port_t nfs_gp_get_rpcb_port(const unsigned short protocol)
149 static const char *rpcb_netnametbl[] = {
157 for (i = 0; rpcb_netnametbl[i] != NULL; i++) {
160 port = nfs_gp_getservbyname(rpcb_netnametbl[i], protocol);
165 return (in_port_t)htons((uint16_t)PMAPPORT);
169 * Set up an RPC client for communicating with an rpcbind daemon at
170 * @sap over @transport with protocol version @version.
172 * Returns a pointer to a prepared RPC client if successful, and
173 * @timeout is initialized; caller must destroy a non-NULL returned RPC
174 * client. Otherwise returns NULL, and rpc_createerr.cf_stat is set to
177 static CLIENT *nfs_gp_get_rpcbclient(struct sockaddr *sap,
178 const socklen_t salen,
179 const unsigned short transport,
180 const rpcvers_t version,
181 struct timeval *timeout)
183 static const char *rpcb_pgmtbl[] = {
190 rpcprog_t rpcb_prog = nfs_getrpcbyname(RPCBPROG, rpcb_pgmtbl);
192 nfs_gp_set_port(sap, nfs_gp_get_rpcb_port(transport));
193 return nfs_get_rpcclient(sap, salen, transport, rpcb_prog,
198 * One of the arguments passed when querying remote rpcbind services
199 * via rpcbind v3 or v4 is a netid string. This replaces the pm_prot
200 * field used in legacy PMAP_GETPORT calls.
202 * RFC 1833 says netids are not standard but rather defined on the local
203 * host. There are, however, standard definitions for nc_protofmly and
204 * nc_proto that can be used to derive a netid string on the local host,
205 * based on the contents of /etc/netconfig.
207 * Walk through the local netconfig database and grab the netid of the
208 * first entry that matches @family and @protocol and whose netid string
209 * fits in the provided buffer.
211 * Returns a '\0'-terminated string if successful; otherwise NULL.
212 * rpc_createerr.cf_stat is set to reflect the error.
216 static char *nfs_gp_get_netid(const sa_family_t family,
217 const unsigned short protocol)
219 char *nc_protofmly, *nc_proto, *nc_netid;
220 struct netconfig *nconf;
221 struct protoent *proto;
227 nc_protofmly = NC_INET;
230 nc_protofmly = NC_INET6;
236 proto = getprotobynumber(protocol);
239 nc_proto = proto->p_name;
241 handle = setnetconfig();
242 while ((nconf = getnetconfig(handle)) != NULL) {
244 if (nconf->nc_protofmly != NULL &&
245 strcmp(nconf->nc_protofmly, nc_protofmly) != 0)
247 if (nconf->nc_proto != NULL &&
248 strcmp(nconf->nc_proto, nc_proto) != 0)
251 nc_netid = strdup(nconf->nc_netid);
252 endnetconfig(handle);
255 endnetconfig(handle);
258 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
262 #endif /* HAVE_LIBTIRPC */
265 * Extract a port number from a universal address, and terminate the
266 * string in @addrstr just after the address part.
268 * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
271 static int nfs_gp_universal_porthelper(char *addrstr)
274 unsigned long portlo, porthi;
277 p = strrchr(addrstr, '.');
280 portlo = strtoul(p + 1, &endptr, 10);
281 if (*endptr != '\0' || portlo > 255)
285 p = strrchr(addrstr, '.');
288 porthi = strtoul(p + 1, &endptr, 10);
289 if (*endptr != '\0' || porthi > 255)
292 port = (porthi << 8) | portlo;
299 * nfs_universal2port - extract port number from a "universal address"
300 * @uaddr: '\0'-terminated C string containing a universal address
302 * Universal addresses (defined in RFC 1833) are used when calling an
303 * rpcbind daemon via protocol versions 3 or 4..
305 * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
308 int nfs_universal2port(const char *uaddr)
313 addrstr = strdup(uaddr);
314 if (addrstr != NULL) {
315 port = nfs_gp_universal_porthelper(addrstr);
322 * nfs_sockaddr2universal - convert a sockaddr to a "universal address"
323 * @sap: pointer to a socket address
324 * @salen: length of socket address
326 * Universal addresses (defined in RFC 1833) are used when calling an
327 * rpcbind daemon via protocol versions 3 or 4..
329 * Returns a '\0'-terminated string if successful; caller must free
330 * the returned string. Otherwise NULL is returned and
331 * rpc_createerr.cf_stat is set to reflect the error.
334 #ifdef HAVE_GETNAMEINFO
336 char *nfs_sockaddr2universal(const struct sockaddr *sap,
337 const socklen_t salen)
339 struct sockaddr_un *sun = (struct sockaddr_un *)sap;
340 char buf[NI_MAXHOST];
343 switch (sap->sa_family) {
345 return strndup(sun->sun_path, sizeof(sun->sun_path));
347 if (getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
348 NULL, 0, NI_NUMERICHOST) != 0)
350 port = ntohs(((struct sockaddr_in *)sap)->sin_port);
353 if (getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
354 NULL, 0, NI_NUMERICHOST) != 0)
356 port = ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
362 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%u.%u",
363 (unsigned)(port >> 8), (unsigned)(port & 0xff));
368 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
372 #else /* HAVE_GETNAMEINFO */
374 char *nfs_sockaddr2universal(const struct sockaddr *sap,
375 const socklen_t salen)
377 struct sockaddr_un *sun = (struct sockaddr_un *)sap;
378 char buf[NI_MAXHOST];
382 switch (sap->sa_family) {
384 return strndup(sun->sun_path, sizeof(sun->sun_path));
386 addr = inet_ntoa(((struct sockaddr_in *)sap)->sin_addr);
387 if (addr != NULL && strlen(addr) > sizeof(buf))
390 port = ntohs(((struct sockaddr_in *)sap)->sin_port);
396 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%u.%u",
397 (unsigned)(port >> 8), (unsigned)(port & 0xff));
402 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
406 #endif /* HAVE_GETNAMEINFO */
409 * Send a NULL request to the indicated RPC service.
411 * Returns 1 if the service responded; otherwise 0;
413 static int nfs_gp_ping(CLIENT *client, struct timeval timeout)
415 enum clnt_stat status;
417 status = CLNT_CALL(client, NULLPROC,
418 (xdrproc_t)xdr_void, NULL,
419 (xdrproc_t)xdr_void, NULL,
422 return (int)(status == RPC_SUCCESS);
428 * Initialize the rpcb argument for a GETADDR request.
430 * Returns 1 if successful, and caller must free strings pointed
431 * to by r_netid and r_addr; otherwise 0.
433 static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap,
434 const socklen_t salen,
435 const rpcprog_t program,
436 const rpcvers_t version,
437 const unsigned short protocol,
442 netid = nfs_gp_get_netid(sap->sa_family, protocol);
446 addr = nfs_sockaddr2universal(sap, salen);
452 memset(parms, 0, sizeof(*parms));
453 parms->r_prog = program;
454 parms->r_vers = version;
455 parms->r_netid = netid;
456 parms->r_addr = addr;
462 static void nfs_gp_free_rpcb_parms(struct rpcb *parms)
464 free(parms->r_netid);
469 * Try rpcbind GETADDR via version 4. If that fails, try same
470 * request via version 3.
472 * Returns non-zero port number on success; otherwise returns
473 * zero. rpccreateerr is set to reflect the nature of the error.
475 static unsigned short nfs_gp_rpcb_getaddr(CLIENT *client,
477 struct timeval timeout)
479 rpcvers_t rpcb_version;
480 struct rpc_err rpcerr;
483 for (rpcb_version = RPCBVERS_4;
484 rpcb_version >= RPCBVERS_3;
486 enum clnt_stat status;
489 CLNT_CONTROL(client, CLSET_VERS, (void *)&rpcb_version);
490 status = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR,
491 (xdrproc_t)xdr_rpcb, (void *)parms,
492 (xdrproc_t)xdr_wrapstring, (void *)&uaddr,
497 if ((uaddr == NULL) || (uaddr[0] == '\0')) {
498 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
502 port = nfs_universal2port(uaddr);
503 xdr_free((xdrproc_t)xdr_wrapstring, (char *)&uaddr);
505 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
508 return (unsigned short)port;
509 case RPC_PROGVERSMISMATCH:
510 clnt_geterr(client, &rpcerr);
511 if (rpcerr.re_vers.low > RPCBVERS4)
514 case RPC_PROCUNAVAIL:
515 case RPC_PROGUNAVAIL:
518 /* Most likely RPC_TIMEDOUT or RPC_CANTRECV */
519 rpc_createerr.cf_stat = status;
520 clnt_geterr(client, &rpc_createerr.cf_error);
527 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
528 clnt_geterr(client, &rpc_createerr.cf_error);
533 #endif /* HAVE_LIBTIRPC */
536 * Try GETPORT request via rpcbind version 2.
538 * Returns non-zero port number on success; otherwise returns
539 * zero. rpccreateerr is set to reflect the nature of the error.
541 static unsigned long nfs_gp_pmap_getport(CLIENT *client,
543 struct timeval timeout)
545 enum clnt_stat status;
548 status = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
549 (xdrproc_t)xdr_pmap, (void *)parms,
550 (xdrproc_t)xdr_u_long, (void *)&port,
553 if (status != RPC_SUCCESS) {
554 rpc_createerr.cf_stat = status;
555 clnt_geterr(client, &rpc_createerr.cf_error);
557 } else if (port == 0)
558 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
565 static unsigned short nfs_gp_getport_rpcb(CLIENT *client,
566 const struct sockaddr *sap,
567 const socklen_t salen,
568 const rpcprog_t program,
569 const rpcvers_t version,
570 const unsigned short protocol,
571 struct timeval timeout)
573 unsigned short port = 0;
576 if (nfs_gp_init_rpcb_parms(sap, salen, program,
577 version, protocol, &parms) != 0) {
578 port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
579 nfs_gp_free_rpcb_parms(&parms);
585 #endif /* HAVE_LIBTIRPC */
587 static unsigned long nfs_gp_getport_pmap(CLIENT *client,
588 const rpcprog_t program,
589 const rpcvers_t version,
590 const unsigned short protocol,
591 struct timeval timeout)
593 struct pmap parms = {
598 rpcvers_t pmap_version = PMAPVERS;
600 CLNT_CONTROL(client, CLSET_VERS, (void *)&pmap_version);
601 return nfs_gp_pmap_getport(client, &parms, timeout);
605 * Try an AF_INET6 request via rpcbind v4/v3; try an AF_INET
606 * request via rpcbind v2.
608 * Returns non-zero port number on success; otherwise returns
609 * zero. rpccreateerr is set to reflect the nature of the error.
611 static unsigned short nfs_gp_getport(CLIENT *client,
612 const struct sockaddr *sap,
613 const socklen_t salen,
614 const rpcprog_t program,
615 const rpcvers_t version,
616 const unsigned short protocol,
617 struct timeval timeout)
619 switch (sap->sa_family) {
622 return nfs_gp_getport_rpcb(client, sap, salen, program,
623 version, protocol, timeout);
624 #endif /* HAVE_LIBTIRPC */
626 return nfs_gp_getport_pmap(client, program, version,
630 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
635 * nfs_rpc_ping - Determine if RPC service is responding to requests
636 * @sap: pointer to address of server to query (port is already filled in)
637 * @salen: length of server address
638 * @program: requested RPC program number
639 * @version: requested RPC version number
640 * @protocol: requested IPPROTO_ value of transport protocol
641 * @timeout: pointer to request timeout (NULL means use default timeout)
643 * Returns 1 if the remote service responded without an error; otherwise
646 int nfs_rpc_ping(const struct sockaddr *sap, const socklen_t salen,
647 const rpcprog_t program, const rpcvers_t version,
648 const unsigned short protocol, const struct timeval *timeout)
650 struct sockaddr_storage address;
651 struct sockaddr *saddr = (struct sockaddr *)&address;
653 struct timeval tout = { -1, 0 };
659 memcpy(saddr, sap, (size_t)salen);
660 client = nfs_get_rpcclient(saddr, salen, protocol,
661 program, version, &tout);
662 if (client != NULL) {
663 result = nfs_gp_ping(client, tout);
664 CLNT_DESTROY(client);
671 * nfs_getport - query server's rpcbind to get port number for an RPC service
672 * @sap: pointer to address of server to query
673 * @salen: length of server's address
674 * @program: requested RPC program number
675 * @version: requested RPC version number
676 * @protocol: IPPROTO_ value of requested transport protocol
678 * Uses any acceptable rpcbind version to discover the port number for the
679 * RPC service described by the given [program, version, transport] tuple.
680 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
681 * AF_INET6 server addresses.
683 * Returns a positive integer representing the port number of the RPC
684 * service advertised by the server (in host byte order), or zero if the
685 * service is not advertised or there was some problem querying the server's
686 * rpcbind daemon. rpccreateerr is set to reflect the underlying cause of
689 * There are a variety of ways to choose which transport and rpcbind versions
690 * to use. We chose to conserve local resources and try to avoid incurring
694 * To provide rudimentary support for traversing firewalls, query the remote
695 * using the same transport as the requested service. This provides some
696 * guarantee that the requested transport is available between this client
697 * and the server, and if the caller specifically requests TCP, for example,
698 * this may be becuase a firewall is in place that blocks UDP traffic. We
699 * could try both, but that could involve a lengthy timeout in several cases,
700 * and would often consume an extra ephemeral port.
703 * To avoid using up too many ephemeral ports, AF_INET queries use tried-and-
704 * true rpcbindv2, and don't try the newer versions; and AF_INET6 queries use
705 * rpcbindv4, then rpcbindv3 on the same socket. The newer rpcbind protocol
706 * versions can adequately detect if a remote RPC service does not support
707 * AF_INET6 at all. The rpcbind socket is re-used in an attempt to keep the
708 * overall number of consumed ephemeral ports low.
710 unsigned short nfs_getport(const struct sockaddr *sap,
711 const socklen_t salen,
712 const rpcprog_t program,
713 const rpcvers_t version,
714 const unsigned short protocol)
716 struct sockaddr_storage address;
717 struct sockaddr *saddr = (struct sockaddr *)&address;
718 struct timeval timeout = { -1, 0 };
719 unsigned short port = 0;
722 memcpy(saddr, sap, (size_t)salen);
723 client = nfs_gp_get_rpcbclient(saddr, salen, protocol,
724 default_rpcb_version, &timeout);
725 if (client != NULL) {
726 port = nfs_gp_getport(client, saddr, salen, program,
727 version, protocol, timeout);
728 CLNT_DESTROY(client);
735 * nfs_getport_ping - query server's rpcbind and do RPC ping to verify result
736 * @sap: IN: pointer to address of server to query;
737 * OUT: pointer to updated address
738 * @salen: length of server's address
739 * @program: requested RPC program number
740 * @version: requested RPC version number
741 * @protocol: IPPROTO_ value of requested transport protocol
743 * Uses any acceptable rpcbind version to discover the port number for the
744 * RPC service described by the given [program, version, transport] tuple.
745 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
746 * AF_INET6 server addresses.
748 * Returns a 1 and sets the port number in the passed-in server address
749 * if both the query and the ping were successful; otherwise zero.
750 * rpccreateerr is set to reflect the underlying cause of the error.
752 int nfs_getport_ping(struct sockaddr *sap, const socklen_t salen,
753 const rpcprog_t program, const rpcvers_t version,
754 const unsigned short protocol)
756 struct timeval timeout = { -1, 0 };
757 unsigned short port = 0;
761 client = nfs_gp_get_rpcbclient(sap, salen, protocol,
762 default_rpcb_version, &timeout);
763 if (client != NULL) {
764 port = nfs_gp_getport(client, sap, salen, program,
765 version, protocol, timeout);
766 CLNT_DESTROY(client);
771 struct sockaddr_storage address;
772 struct sockaddr *saddr = (struct sockaddr *)&address;
774 memcpy(saddr, sap, (size_t)salen);
775 nfs_gp_set_port(saddr, htons(port));
777 client = nfs_get_rpcclient(saddr, salen, protocol,
778 program, version, &timeout);
779 if (client != NULL) {
780 result = nfs_gp_ping(client, timeout);
781 CLNT_DESTROY(client);
786 nfs_gp_set_port(sap, htons(port));
792 * nfs_getlocalport - query local rpcbind to get port number for an RPC service
793 * @program: requested RPC program number
794 * @version: requested RPC version number
795 * @protocol: IPPROTO_ value of requested transport protocol
797 * Uses any acceptable rpcbind version to discover the port number for the
798 * RPC service described by the given [program, version, transport] tuple.
799 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
800 * AF_INET6 local addresses.
802 * Returns a positive integer representing the port number of the RPC
803 * service advertised by the server (in host byte order), or zero if the
804 * service is not advertised or there was some problem querying the server's
805 * rpcbind daemon. rpccreateerr is set to reflect the underlying cause of
808 * Try an AF_LOCAL connection first. The rpcbind daemon implementation should
809 * listen on AF_LOCAL.
811 * If that doesn't work (for example, if portmapper is running, or rpcbind
812 * isn't listening on /var/run/rpcbind.sock), send a query via UDP to localhost
813 * (UDP doesn't leave a socket in TIME_WAIT, and the timeout is a relatively
816 unsigned short nfs_getlocalport(const rpcprot_t program,
817 const rpcvers_t version,
818 const unsigned short protocol)
820 struct sockaddr_storage address;
821 struct sockaddr *lb_addr = (struct sockaddr *)&address;
822 socklen_t lb_len = sizeof(*lb_addr);
823 unsigned short port = 0;
826 const struct sockaddr_un sun = {
827 .sun_family = AF_LOCAL,
828 .sun_path = _PATH_RPCBINDSOCK,
830 const struct sockaddr *sap = (struct sockaddr *)&sun;
831 const socklen_t salen = SUN_LEN(&sun);
833 struct timeval timeout = { -1, 0 };
835 client = nfs_gp_get_rpcbclient(sap, salen, 0, RPCBVERS_4, &timeout);
836 if (client != NULL) {
839 if (nfs_gp_init_rpcb_parms(sap, salen, program, version,
840 protocol, &parms) != 0) {
841 port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
842 nfs_gp_free_rpcb_parms(&parms);
844 CLNT_DESTROY(client);
846 #endif /* NFS_GP_LOCAL */
849 if (nfs_gp_loopback_address(lb_addr, &lb_len)) {
850 port = nfs_getport(lb_addr, lb_len,
851 program, version, protocol);
853 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
860 * nfs_rpcb_getaddr - query rpcbind via rpcbind versions 4 and 3
861 * @sap: pointer to address of server to query
862 * @salen: length of server address
863 * @transport: transport protocol to use for the query
864 * @addr: pointer to r_addr address
865 * @addrlen: length of address
866 * @program: requested RPC program number
867 * @version: requested RPC version number
868 * @protocol: requested IPPROTO_ value of transport protocol
869 * @timeout: pointer to request timeout (NULL means use default timeout)
871 * Returns a positive integer representing the port number of the RPC
872 * service advertised by the server (in host byte order), or zero if the
873 * service is not advertised or there was some problem querying the
874 * server's rpcbind daemon. rpccreateerr is set to reflect the
875 * underlying cause of the error.
877 * This function provides similar functionality to nfs_pmap_getport(),
878 * but performs the rpcbind lookup via rpcbind version 4. If the server
879 * doesn't support rpcbind version 4, it will retry with version 3.
880 * The GETADDR procedure is exactly the same in these two versions of
881 * the rpcbind protocol, so the socket, RPC client, and arguments are
882 * re-used when retrying, saving ephemeral port space.
884 * These RPC procedures take a universal address as an argument, so the
885 * query will fail if the remote rpcbind daemon doesn't find an entry
886 * with a matching address. A matching address includes an ANYADDR
887 * address of the same address family. In this way an RPC server can
888 * advertise via rpcbind that it does not support AF_INET6.
892 unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
893 const socklen_t salen,
894 const unsigned short transport,
895 const struct sockaddr *addr,
896 const socklen_t addrlen,
897 const rpcprog_t program,
898 const rpcvers_t version,
899 const unsigned short protocol,
900 const struct timeval *timeout)
902 struct sockaddr_storage address;
903 struct sockaddr *saddr = (struct sockaddr *)&address;
906 struct timeval tout = { -1, 0 };
907 unsigned short port = 0;
912 memcpy(saddr, sap, (size_t)salen);
913 client = nfs_gp_get_rpcbclient(saddr, salen, transport,
915 if (client != NULL) {
916 if (nfs_gp_init_rpcb_parms(addr, addrlen, program, version,
917 protocol, &parms) != 0) {
918 port = nfs_gp_rpcb_getaddr(client, &parms, tout);
919 nfs_gp_free_rpcb_parms(&parms);
921 CLNT_DESTROY(client);
927 #else /* !HAVE_LIBTIRPC */
929 unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
930 const socklen_t salen,
931 const unsigned short transport,
932 const struct sockaddr *addr,
933 const socklen_t addrlen,
934 const rpcprog_t program,
935 const rpcvers_t version,
936 const unsigned short protocol,
937 const struct timeval *timeout)
939 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
943 #endif /* !HAVE_LIBTIRPC */
946 * nfs_pmap_getport - query rpcbind via the portmap protocol (rpcbindv2)
947 * @sin: pointer to AF_INET address of server to query
948 * @transport: transport protocol to use for the query
949 * @program: requested RPC program number
950 * @version: requested RPC version number
951 * @protocol: requested IPPROTO_ value of transport protocol
952 * @timeout: pointer to request timeout (NULL means use default timeout)
954 * Returns a positive integer representing the port number of the RPC service
955 * advertised by the server (in host byte order), or zero if the service is
956 * not advertised or there was some problem querying the server's rpcbind
957 * daemon. rpccreateerr is set to reflect the underlying cause of the error.
959 * nfs_pmap_getport() is very similar to pmap_getport(), except that:
961 * 1. This version always tries to use an ephemeral port, since reserved
962 * ports are not needed for GETPORT queries. This conserves the very
963 * limited reserved port space, helping reduce failed socket binds
964 * during mount storms.
966 * 2. This version times out quickly by default. It time-limits the
967 * connect process as well as the actual RPC call, and even allows the
968 * caller to specify the timeout.
970 * 3. This version shares code with the rpcbindv3 and rpcbindv4 query
971 * functions. It can use a TI-RPC generated CLIENT.
973 unsigned long nfs_pmap_getport(const struct sockaddr_in *sin,
974 const unsigned short transport,
975 const unsigned long program,
976 const unsigned long version,
977 const unsigned long protocol,
978 const struct timeval *timeout)
980 struct sockaddr_in address;
981 struct sockaddr *saddr = (struct sockaddr *)&address;
983 struct pmap parms = {
988 struct timeval tout = { -1, 0 };
989 unsigned long port = 0;
994 memcpy(saddr, sin, sizeof(address));
995 client = nfs_gp_get_rpcbclient(saddr, (socklen_t)sizeof(*sin),
996 transport, PMAPVERS, &tout);
997 if (client != NULL) {
998 port = nfs_gp_pmap_getport(client, &parms, tout);
999 CLNT_DESTROY(client);