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 */
68 #ifdef HAVE_DECL_AI_ADDRCONFIG
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.
75 * Returns TRUE on success.
77 static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen)
79 struct addrinfo *gai_results;
80 struct addrinfo gai_hint = {
81 .ai_flags = AI_ADDRCONFIG,
83 socklen_t len = *salen;
86 if (getaddrinfo(NULL, "sunrpc", &gai_hint, &gai_results))
89 switch (gai_results->ai_addr->sa_family) {
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;
100 freeaddrinfo(gai_results);
105 * Old versions of getaddrinfo(3) don't support AI_ADDRCONFIG, so we
106 * have a fallback for building on legacy systems.
108 static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen)
110 struct sockaddr_in *sin = (struct sockaddr_in *)sap;
112 memset(sin, 0, sizeof(*sin));
114 sin->sin_family = AF_INET;
115 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
116 *salen = sizeof(*sin);
123 * Plant port number in @sap. @port is already in network byte order.
125 static void nfs_gp_set_port(struct sockaddr *sap, const in_port_t port)
127 struct sockaddr_in *sin = (struct sockaddr_in *)sap;
128 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
130 switch (sap->sa_family) {
132 sin->sin_port = port;
135 sin6->sin6_port = port;
141 * Look up a network service in /etc/services and return the
142 * network-order port number of that service.
144 static in_port_t nfs_gp_getservbyname(const char *service,
145 const unsigned short protocol)
147 const struct addrinfo gai_hint = {
148 .ai_family = AF_INET,
149 .ai_protocol = protocol,
150 .ai_flags = AI_PASSIVE,
152 struct addrinfo *gai_results;
153 const struct sockaddr_in *sin;
156 if (getaddrinfo(NULL, service, &gai_hint, &gai_results) != 0)
159 sin = (const struct sockaddr_in *)gai_results->ai_addr;
160 port = sin->sin_port;
162 freeaddrinfo(gai_results);
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.
171 * Returns network byte-order port number of rpcbind service
174 static in_port_t nfs_gp_get_rpcb_port(const unsigned short protocol)
176 static const char *rpcb_netnametbl[] = {
184 for (i = 0; rpcb_netnametbl[i] != NULL; i++) {
187 port = nfs_gp_getservbyname(rpcb_netnametbl[i], protocol);
192 return (in_port_t)htons((uint16_t)PMAPPORT);
196 * Set up an RPC client for communicating with an rpcbind daemon at
197 * @sap over @transport with protocol version @version.
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
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)
210 static const char *rpcb_pgmtbl[] = {
217 rpcprog_t rpcb_prog = nfs_getrpcbyname(RPCBPROG, rpcb_pgmtbl);
219 nfs_gp_set_port(sap, nfs_gp_get_rpcb_port(transport));
220 return nfs_get_rpcclient(sap, salen, transport, rpcb_prog,
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.
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.
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.
238 * Returns a '\0'-terminated string if successful; otherwise NULL.
239 * rpc_createerr.cf_stat is set to reflect the error.
243 static char *nfs_gp_get_netid(const sa_family_t family,
244 const unsigned short protocol)
246 char *nc_protofmly, *nc_proto, *nc_netid;
247 struct netconfig *nconf;
248 struct protoent *proto;
254 nc_protofmly = NC_INET;
257 nc_protofmly = NC_INET6;
263 proto = getprotobynumber(protocol);
266 nc_proto = proto->p_name;
268 handle = setnetconfig();
269 while ((nconf = getnetconfig(handle)) != NULL) {
271 if (nconf->nc_protofmly != NULL &&
272 strcmp(nconf->nc_protofmly, nc_protofmly) != 0)
274 if (nconf->nc_proto != NULL &&
275 strcmp(nconf->nc_proto, nc_proto) != 0)
278 nc_netid = strdup(nconf->nc_netid);
279 endnetconfig(handle);
282 endnetconfig(handle);
285 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
289 #endif /* HAVE_LIBTIRPC */
292 * Extract a port number from a universal address, and terminate the
293 * string in @addrstr just after the address part.
295 * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
298 static int nfs_gp_universal_porthelper(char *addrstr)
301 unsigned long portlo, porthi;
304 p = strrchr(addrstr, '.');
307 portlo = strtoul(p + 1, &endptr, 10);
308 if (*endptr != '\0' || portlo > 255)
312 p = strrchr(addrstr, '.');
315 porthi = strtoul(p + 1, &endptr, 10);
316 if (*endptr != '\0' || porthi > 255)
319 port = (porthi << 8) | portlo;
326 * nfs_universal2port - extract port number from a "universal address"
327 * @uaddr: '\0'-terminated C string containing a universal address
329 * Universal addresses (defined in RFC 1833) are used when calling an
330 * rpcbind daemon via protocol versions 3 or 4..
332 * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
335 int nfs_universal2port(const char *uaddr)
340 addrstr = strdup(uaddr);
341 if (addrstr != NULL) {
342 port = nfs_gp_universal_porthelper(addrstr);
349 * nfs_sockaddr2universal - convert a sockaddr to a "universal address"
350 * @sap: pointer to a socket address
351 * @salen: length of socket address
353 * Universal addresses (defined in RFC 1833) are used when calling an
354 * rpcbind daemon via protocol versions 3 or 4..
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.
361 #ifdef HAVE_GETNAMEINFO
363 char *nfs_sockaddr2universal(const struct sockaddr *sap,
364 const socklen_t salen)
366 struct sockaddr_un *sun = (struct sockaddr_un *)sap;
367 char buf[NI_MAXHOST];
370 switch (sap->sa_family) {
372 return strndup(sun->sun_path, sizeof(sun->sun_path));
374 if (getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
375 NULL, 0, NI_NUMERICHOST) != 0)
377 port = ntohs(((struct sockaddr_in *)sap)->sin_port);
380 if (getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
381 NULL, 0, NI_NUMERICHOST) != 0)
383 port = ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
389 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%u.%u",
390 (unsigned)(port >> 8), (unsigned)(port & 0xff));
395 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
399 #else /* HAVE_GETNAMEINFO */
401 char *nfs_sockaddr2universal(const struct sockaddr *sap,
402 const socklen_t salen)
404 struct sockaddr_un *sun = (struct sockaddr_un *)sap;
405 char buf[NI_MAXHOST];
409 switch (sap->sa_family) {
411 return strndup(sun->sun_path, sizeof(sun->sun_path));
413 addr = inet_ntoa(((struct sockaddr_in *)sap)->sin_addr);
414 if (addr != NULL && strlen(addr) > sizeof(buf))
417 port = ntohs(((struct sockaddr_in *)sap)->sin_port);
423 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%u.%u",
424 (unsigned)(port >> 8), (unsigned)(port & 0xff));
429 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
433 #endif /* HAVE_GETNAMEINFO */
436 * Send a NULL request to the indicated RPC service.
438 * Returns 1 if the service responded; otherwise 0;
440 static int nfs_gp_ping(CLIENT *client, struct timeval timeout)
442 enum clnt_stat status;
444 status = CLNT_CALL(client, NULLPROC,
445 (xdrproc_t)xdr_void, NULL,
446 (xdrproc_t)xdr_void, NULL,
449 return (int)(status == RPC_SUCCESS);
455 * Initialize the rpcb argument for a GETADDR request.
457 * Returns 1 if successful, and caller must free strings pointed
458 * to by r_netid and r_addr; otherwise 0.
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,
469 netid = nfs_gp_get_netid(sap->sa_family, protocol);
473 addr = nfs_sockaddr2universal(sap, salen);
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;
489 static void nfs_gp_free_rpcb_parms(struct rpcb *parms)
491 free(parms->r_netid);
496 * Try rpcbind GETADDR via version 4. If that fails, try same
497 * request via version 3.
499 * Returns non-zero port number on success; otherwise returns
500 * zero. rpccreateerr is set to reflect the nature of the error.
502 static unsigned short nfs_gp_rpcb_getaddr(CLIENT *client,
504 struct timeval timeout)
506 rpcvers_t rpcb_version;
507 struct rpc_err rpcerr;
510 for (rpcb_version = RPCBVERS_4;
511 rpcb_version >= RPCBVERS_3;
513 enum clnt_stat status;
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,
524 if ((uaddr == NULL) || (uaddr[0] == '\0')) {
525 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
529 port = nfs_universal2port(uaddr);
530 xdr_free((xdrproc_t)xdr_wrapstring, (char *)&uaddr);
532 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
535 return (unsigned short)port;
536 case RPC_PROGVERSMISMATCH:
537 clnt_geterr(client, &rpcerr);
538 if (rpcerr.re_vers.low > RPCBVERS4)
541 case RPC_PROCUNAVAIL:
542 case RPC_PROGUNAVAIL:
545 /* Most likely RPC_TIMEDOUT or RPC_CANTRECV */
546 rpc_createerr.cf_stat = status;
547 clnt_geterr(client, &rpc_createerr.cf_error);
554 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
555 clnt_geterr(client, &rpc_createerr.cf_error);
560 #endif /* HAVE_LIBTIRPC */
563 * Try GETPORT request via rpcbind version 2.
565 * Returns non-zero port number on success; otherwise returns
566 * zero. rpccreateerr is set to reflect the nature of the error.
568 static unsigned long nfs_gp_pmap_getport(CLIENT *client,
570 struct timeval timeout)
572 enum clnt_stat status;
575 status = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
576 (xdrproc_t)xdr_pmap, (void *)parms,
577 (xdrproc_t)xdr_u_long, (void *)&port,
580 if (status != RPC_SUCCESS) {
581 rpc_createerr.cf_stat = status;
582 clnt_geterr(client, &rpc_createerr.cf_error);
584 } else if (port == 0)
585 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
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)
600 unsigned short port = 0;
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);
612 #endif /* HAVE_LIBTIRPC */
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)
620 struct pmap parms = {
625 rpcvers_t pmap_version = PMAPVERS;
627 CLNT_CONTROL(client, CLSET_VERS, (void *)&pmap_version);
628 return nfs_gp_pmap_getport(client, &parms, timeout);
632 * Try an AF_INET6 request via rpcbind v4/v3; try an AF_INET
633 * request via rpcbind v2.
635 * Returns non-zero port number on success; otherwise returns
636 * zero. rpccreateerr is set to reflect the nature of the error.
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)
646 switch (sap->sa_family) {
649 return nfs_gp_getport_rpcb(client, sap, salen, program,
650 version, protocol, timeout);
651 #endif /* HAVE_LIBTIRPC */
653 return nfs_gp_getport_pmap(client, program, version,
657 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
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)
670 * Returns 1 if the remote service responded without an error; otherwise
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)
677 struct sockaddr_storage address;
678 struct sockaddr *saddr = (struct sockaddr *)&address;
680 struct timeval tout = { -1, 0 };
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);
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
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.
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
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
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.
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.
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)
743 struct sockaddr_storage address;
744 struct sockaddr *saddr = (struct sockaddr *)&address;
745 struct timeval timeout = { -1, 0 };
746 unsigned short port = 0;
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);
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
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.
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.
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)
783 struct timeval timeout = { -1, 0 };
784 unsigned short port = 0;
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);
798 struct sockaddr_storage address;
799 struct sockaddr *saddr = (struct sockaddr *)&address;
801 memcpy(saddr, sap, (size_t)salen);
802 nfs_gp_set_port(saddr, htons(port));
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);
813 nfs_gp_set_port(sap, htons(port));
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
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.
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
835 * Try an AF_LOCAL connection first. The rpcbind daemon implementation should
836 * listen on AF_LOCAL.
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
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.
850 unsigned short nfs_getlocalport(const rpcprot_t program,
851 const rpcvers_t version,
852 const unsigned short protocol)
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;
860 const struct sockaddr_un sun = {
861 .sun_family = AF_LOCAL,
862 .sun_path = _PATH_RPCBINDSOCK,
864 const struct sockaddr *sap = (struct sockaddr *)&sun;
865 const socklen_t salen = SUN_LEN(&sun);
867 struct timeval timeout = { -1, 0 };
869 client = nfs_gp_get_rpcbclient(sap, salen, 0, RPCBVERS_4, &timeout);
870 if (client != NULL) {
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);
878 CLNT_DESTROY(client);
880 #endif /* NFS_GP_LOCAL */
883 if (nfs_gp_loopback_address(lb_addr, &lb_len)) {
884 port = nfs_getport(lb_addr, lb_len,
885 program, version, protocol);
887 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
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)
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.
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.
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.
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)
936 struct sockaddr_storage address;
937 struct sockaddr *saddr = (struct sockaddr *)&address;
940 struct timeval tout = { -1, 0 };
941 unsigned short port = 0;
946 memcpy(saddr, sap, (size_t)salen);
947 client = nfs_gp_get_rpcbclient(saddr, salen, transport,
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);
955 CLNT_DESTROY(client);
961 #else /* !HAVE_LIBTIRPC */
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)
973 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
977 #endif /* !HAVE_LIBTIRPC */
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)
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.
993 * nfs_pmap_getport() is very similar to pmap_getport(), except that:
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.
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.
1004 * 3. This version shares code with the rpcbindv3 and rpcbindv4 query
1005 * functions. It can use a TI-RPC generated CLIENT.
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)
1014 struct sockaddr_in address;
1015 struct sockaddr *saddr = (struct sockaddr *)&address;
1017 struct pmap parms = {
1020 .pm_prot = protocol,
1022 struct timeval tout = { -1, 0 };
1023 unsigned long port = 0;
1025 if (timeout != NULL)
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);