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>
43 #ifdef HAVE_TIRPC_NETCONFIG_H
44 #include <tirpc/netconfig.h>
45 #include <tirpc/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_XDR_RPCB */
60 #endif /* HAVE_XDR_RPCB */
63 const static rpcvers_t default_rpcb_version = RPCBVERS_4;
65 const static rpcvers_t default_rpcb_version = PMAPVERS;
68 static const char *nfs_gp_rpcb_pgmtbl[] = {
76 #ifdef HAVE_DECL_AI_ADDRCONFIG
78 * getaddrinfo(3) generates a usable loopback address based on how the
79 * local network interfaces are configured. RFC 3484 requires that the
80 * results are sorted so that the first result has the best likelihood
81 * of working, so we try just that first result.
83 * Returns TRUE on success.
85 static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen)
87 struct addrinfo *gai_results;
88 struct addrinfo gai_hint = {
89 .ai_flags = AI_ADDRCONFIG,
91 socklen_t len = *salen;
94 if (getaddrinfo(NULL, "sunrpc", &gai_hint, &gai_results))
97 switch (gai_results->ai_addr->sa_family) {
100 if (len >= gai_results->ai_addrlen) {
101 memcpy(sap, gai_results->ai_addr,
102 gai_results->ai_addrlen);
103 *salen = gai_results->ai_addrlen;
108 freeaddrinfo(gai_results);
113 * Old versions of getaddrinfo(3) don't support AI_ADDRCONFIG, so we
114 * have a fallback for building on legacy systems.
116 static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen)
118 struct sockaddr_in *sin = (struct sockaddr_in *)sap;
120 memset(sin, 0, sizeof(*sin));
122 sin->sin_family = AF_INET;
123 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
124 *salen = sizeof(*sin);
131 * Discover the port number that should be used to contact an
132 * rpcbind service. This will detect if the port has a local
133 * value that may have been set in /etc/services.
135 * NB: s_port is already in network byte order.
137 * Returns network byte-order port number of rpcbind service
140 static in_port_t nfs_gp_get_rpcb_port(const unsigned short protocol)
142 struct protoent *proto;
144 proto = getprotobynumber((int)protocol);
146 struct servent *entry;
148 entry = getservbyname("rpcbind", proto->p_name);
150 return (in_port_t)entry->s_port;
152 entry = getservbyname("portmapper", proto->p_name);
154 return (in_port_t)entry->s_port;
156 entry = getservbyname("sunrpc", proto->p_name);
158 return (in_port_t)entry->s_port;
160 return htons((uint16_t)PMAPPORT);
164 * Plant port number in @sap. @port is already in network byte order.
166 static void nfs_gp_set_port(struct sockaddr *sap, const in_port_t port)
168 struct sockaddr_in *sin = (struct sockaddr_in *)sap;
169 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
171 switch (sap->sa_family) {
173 sin->sin_port = port;
176 sin6->sin6_port = port;
179 fprintf(stderr, "%s: unrecognized address family\n",
185 * Set up an RPC client for communicating with an rpcbind daemon at
186 * @sap over @transport with protocol version @version.
188 * Returns a pointer to a prepared RPC client if successful, and
189 * @timeout is initialized; caller must destroy a non-NULL returned RPC
190 * client. Otherwise returns NULL, and rpc_createerr.cf_stat is set to
193 static CLIENT *nfs_gp_get_rpcbclient(const struct sockaddr *sap,
194 const socklen_t salen,
195 const unsigned short transport,
196 const rpcvers_t version,
197 struct timeval *timeout)
199 struct sockaddr_storage address;
200 struct sockaddr *saddr = (struct sockaddr *)&address;
201 rpcprog_t rpcb_prog = nfs_getrpcbyname(RPCBPROG, nfs_gp_rpcb_pgmtbl);
203 memcpy(saddr, sap, (size_t)salen);
204 nfs_gp_set_port(saddr, nfs_gp_get_rpcb_port(transport));
206 return nfs_get_rpcclient(saddr, salen, transport, rpcb_prog,
211 * One of the arguments passed when querying remote rpcbind services
212 * via rpcbind v3 or v4 is a netid string. This replaces the pm_prot
213 * field used in legacy PMAP_GETPORT calls.
215 * RFC 1833 says netids are not standard but rather defined on the local
216 * host. There are, however, standard definitions for nc_protofmly and
217 * nc_proto that can be used to derive a netid string on the local host,
218 * based on the contents of /etc/netconfig.
220 * Walk through the local netconfig database and grab the netid of the
221 * first entry that matches @family and @protocol and whose netid string
222 * fits in the provided buffer.
224 * Returns a '\0'-terminated string if successful; otherwise NULL.
225 * rpc_createerr.cf_stat is set to reflect the error.
229 static char *nfs_gp_get_netid(const sa_family_t family,
230 const unsigned short protocol)
232 char *nc_protofmly, *nc_proto, *nc_netid;
233 struct netconfig *nconf;
234 struct protoent *proto;
240 nc_protofmly = NC_INET;
243 nc_protofmly = NC_INET6;
249 proto = getprotobynumber(protocol);
252 nc_proto = proto->p_name;
254 handle = setnetconfig();
255 while ((nconf = getnetconfig(handle)) != NULL) {
257 if (nconf->nc_protofmly != NULL &&
258 strcmp(nconf->nc_protofmly, nc_protofmly) != 0)
260 if (nconf->nc_proto != NULL &&
261 strcmp(nconf->nc_proto, nc_proto) != 0)
264 nc_netid = strdup(nconf->nc_netid);
265 endnetconfig(handle);
268 endnetconfig(handle);
271 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
275 #endif /* HAVE_XDR_RPCB */
278 * Extract a port number from a universal address, and terminate the
279 * string in @addrstr just after the address part.
281 * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
284 static int nfs_gp_universal_porthelper(char *addrstr)
287 unsigned long portlo, porthi;
290 p = strrchr(addrstr, '.');
293 portlo = strtoul(p + 1, &endptr, 10);
294 if (*endptr != '\0' || portlo > 255)
298 p = strrchr(addrstr, '.');
301 porthi = strtoul(p + 1, &endptr, 10);
302 if (*endptr != '\0' || porthi > 255)
305 port = (porthi << 8) | portlo;
312 * nfs_universal2port - extract port number from a "universal address"
313 * @uaddr: '\0'-terminated C string containing a universal address
315 * Universal addresses (defined in RFC 1833) are used when calling an
316 * rpcbind daemon via protocol versions 3 or 4..
318 * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
321 int nfs_universal2port(const char *uaddr)
326 addrstr = strdup(uaddr);
327 if (addrstr != NULL) {
328 port = nfs_gp_universal_porthelper(addrstr);
335 * nfs_sockaddr2universal - convert a sockaddr to a "universal address"
336 * @sap: pointer to a socket address
337 * @salen: length of socket address
339 * Universal addresses (defined in RFC 1833) are used when calling an
340 * rpcbind daemon via protocol versions 3 or 4..
342 * Returns a '\0'-terminated string if successful; caller must free
343 * the returned string. Otherwise NULL is returned and
344 * rpc_createerr.cf_stat is set to reflect the error.
347 #ifdef HAVE_GETNAMEINFO
349 char *nfs_sockaddr2universal(const struct sockaddr *sap,
350 const socklen_t salen)
352 struct sockaddr_un *sun = (struct sockaddr_un *)sap;
353 char buf[NI_MAXHOST];
356 switch (sap->sa_family) {
358 return strndup(sun->sun_path, sizeof(sun->sun_path));
360 if (getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
361 NULL, 0, NI_NUMERICHOST) != 0)
363 port = ntohs(((struct sockaddr_in *)sap)->sin_port);
366 if (getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
367 NULL, 0, NI_NUMERICHOST) != 0)
369 port = ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
375 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%u.%u",
376 (unsigned)(port >> 8), (unsigned)(port & 0xff));
381 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
385 #else /* HAVE_GETNAMEINFO */
387 char *nfs_sockaddr2universal(const struct sockaddr *sap,
388 const socklen_t salen)
390 struct sockaddr_un *sun = (struct sockaddr_un *)sap;
391 char buf[NI_MAXHOST];
395 switch (sap->sa_family) {
397 return strndup(sun->sun_path, sizeof(sun->sun_path));
399 addr = inet_ntoa(((struct sockaddr_in *)sap)->sin_addr);
400 if (addr != NULL && strlen(addr) > sizeof(buf))
403 port = ntohs(((struct sockaddr_in *)sap)->sin_port);
409 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%u.%u",
410 (unsigned)(port >> 8), (unsigned)(port & 0xff));
415 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
419 #endif /* HAVE_GETNAMEINFO */
422 * Send a NULL request to the indicated RPC service.
424 * Returns 1 if the service responded; otherwise 0;
426 static int nfs_gp_ping(CLIENT *client, struct timeval timeout)
428 enum clnt_stat status;
430 status = CLNT_CALL(client, NULLPROC,
431 (xdrproc_t)xdr_void, NULL,
432 (xdrproc_t)xdr_void, NULL,
435 return (int)(status == RPC_SUCCESS);
441 * Initialize the rpcb argument for a GETADDR request.
443 * The rpcbind daemon ignores the parms.r_owner field in GETADDR
444 * requests, but we plant an eye-catcher to help distinguish these
445 * requests in network traces.
447 * Returns 1 if successful, and caller must free strings pointed
448 * to by r_netid and r_addr; otherwise 0.
450 static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap,
451 const socklen_t salen,
452 const rpcprog_t program,
453 const rpcvers_t version,
454 const unsigned short protocol,
459 netid = nfs_gp_get_netid(sap->sa_family, protocol);
463 addr = nfs_sockaddr2universal(sap, salen);
469 memset(parms, 0, sizeof(*parms));
470 parms->r_prog = program;
471 parms->r_vers = version;
472 parms->r_netid = netid;
473 parms->r_addr = addr;
474 parms->r_owner = "nfs-utils"; /* eye-catcher */
479 static void nfs_gp_free_rpcb_parms(struct rpcb *parms)
481 free(parms->r_netid);
486 * Try rpcbind GETADDR via version 4. If that fails, try same
487 * request via version 3.
489 * Returns non-zero port number on success; otherwise returns
490 * zero. rpccreateerr is set to reflect the nature of the error.
492 static unsigned short nfs_gp_rpcb_getaddr(CLIENT *client,
494 struct timeval timeout)
496 rpcvers_t rpcb_version;
497 struct rpc_err rpcerr;
500 for (rpcb_version = RPCBVERS_4;
501 rpcb_version >= RPCBVERS_3;
503 enum clnt_stat status;
506 CLNT_CONTROL(client, CLSET_VERS, (void *)&rpcb_version);
507 status = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR,
508 (xdrproc_t)xdr_rpcb, (void *)parms,
509 (xdrproc_t)xdr_wrapstring, (void *)&uaddr,
514 if ((uaddr == NULL) || (uaddr[0] == '\0')) {
515 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
519 port = nfs_universal2port(uaddr);
520 xdr_free((xdrproc_t)xdr_wrapstring, (char *)&uaddr);
522 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
525 return (unsigned short)port;
526 case RPC_PROGVERSMISMATCH:
527 clnt_geterr(client, &rpcerr);
528 if (rpcerr.re_vers.low > RPCBVERS4)
531 case RPC_PROCUNAVAIL:
532 case RPC_PROGUNAVAIL:
535 /* Most likely RPC_TIMEDOUT or RPC_CANTRECV */
536 rpc_createerr.cf_stat = status;
537 clnt_geterr(client, &rpc_createerr.cf_error);
544 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
545 clnt_geterr(client, &rpc_createerr.cf_error);
550 #endif /* HAVE_XDR_RPCB */
553 * Try GETPORT request via rpcbind version 2.
555 * Returns non-zero port number on success; otherwise returns
556 * zero. rpccreateerr is set to reflect the nature of the error.
558 static unsigned long nfs_gp_pmap_getport(CLIENT *client,
560 struct timeval timeout)
562 enum clnt_stat status;
565 status = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
566 (xdrproc_t)xdr_pmap, (void *)parms,
567 (xdrproc_t)xdr_u_long, (void *)&port,
570 if (status != RPC_SUCCESS) {
571 rpc_createerr.cf_stat = status;
572 clnt_geterr(client, &rpc_createerr.cf_error);
574 } else if (port == 0)
575 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
582 static unsigned short nfs_gp_getport_rpcb(CLIENT *client,
583 const struct sockaddr *sap,
584 const socklen_t salen,
585 const rpcprog_t program,
586 const rpcvers_t version,
587 const unsigned short protocol,
588 struct timeval timeout)
590 unsigned short port = 0;
593 if (nfs_gp_init_rpcb_parms(sap, salen, program,
594 version, protocol, &parms) != 0) {
595 port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
596 nfs_gp_free_rpcb_parms(&parms);
602 #endif /* HAVE_XDR_RPCB */
604 static unsigned long nfs_gp_getport_pmap(CLIENT *client,
605 const rpcprog_t program,
606 const rpcvers_t version,
607 const unsigned short protocol,
608 struct timeval timeout)
610 struct pmap parms = {
615 rpcvers_t pmap_version = PMAPVERS;
617 CLNT_CONTROL(client, CLSET_VERS, (void *)&pmap_version);
618 return nfs_gp_pmap_getport(client, &parms, timeout);
622 * Try an AF_INET6 request via rpcbind v4/v3; try an AF_INET
623 * request via rpcbind v2.
625 * Returns non-zero port number on success; otherwise returns
626 * zero. rpccreateerr is set to reflect the nature of the error.
628 static unsigned short nfs_gp_getport(CLIENT *client,
629 const struct sockaddr *sap,
630 const socklen_t salen,
631 const rpcprog_t program,
632 const rpcvers_t version,
633 const unsigned short protocol,
634 struct timeval timeout)
636 switch (sap->sa_family) {
639 return nfs_gp_getport_rpcb(client, sap, salen, program,
640 version, protocol, timeout);
641 #endif /* HAVE_XDR_RPCB */
643 return nfs_gp_getport_pmap(client, program, version,
647 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
652 * nfs_rcp_ping - Determine if RPC service is responding to requests
653 * @sap: pointer to address of server to query (port is already filled in)
654 * @salen: length of server address
655 * @program: requested RPC program number
656 * @version: requested RPC version number
657 * @protocol: requested IPPROTO_ value of transport protocol
658 * @timeout: pointer to request timeout (NULL means use default timeout)
660 * Returns 1 if the remote service responded without an error; otherwise
663 int nfs_rpc_ping(const struct sockaddr *sap, const socklen_t salen,
664 const rpcprog_t program, const rpcvers_t version,
665 const unsigned short protocol, const struct timeval *timeout)
668 struct timeval tout = { -1, 0 };
674 client = nfs_get_rpcclient(sap, salen, protocol, program, version, &tout);
675 if (client != NULL) {
676 result = nfs_gp_ping(client, tout);
677 CLNT_DESTROY(client);
684 * nfs_getport - query server's rpcbind to get port number for an RPC service
685 * @sap: pointer to address of server to query
686 * @salen: length of server's address
687 * @program: requested RPC program number
688 * @version: requested RPC version number
689 * @protocol: IPPROTO_ value of requested transport protocol
691 * Uses any acceptable rpcbind version to discover the port number for the
692 * RPC service described by the given [program, version, transport] tuple.
693 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
694 * AF_INET6 server addresses.
696 * Returns a positive integer representing the port number of the RPC
697 * service advertised by the server (in host byte order), or zero if the
698 * service is not advertised or there was some problem querying the server's
699 * rpcbind daemon. rpccreateerr is set to reflect the underlying cause of
702 * There are a variety of ways to choose which transport and rpcbind versions
703 * to use. We chose to conserve local resources and try to avoid incurring
707 * To provide rudimentary support for traversing firewalls, query the remote
708 * using the same transport as the requested service. This provides some
709 * guarantee that the requested transport is available between this client
710 * and the server, and if the caller specifically requests TCP, for example,
711 * this may be becuase a firewall is in place that blocks UDP traffic. We
712 * could try both, but that could involve a lengthy timeout in several cases,
713 * and would often consume an extra ephemeral port.
716 * To avoid using up too many ephemeral ports, AF_INET queries use tried-and-
717 * true rpcbindv2, and don't try the newer versions; and AF_INET6 queries use
718 * rpcbindv4, then rpcbindv3 on the same socket. The newer rpcbind protocol
719 * versions can adequately detect if a remote RPC service does not support
720 * AF_INET6 at all. The rpcbind socket is re-used in an attempt to keep the
721 * overall number of consumed ephemeral ports low.
723 unsigned short nfs_getport(const struct sockaddr *sap,
724 const socklen_t salen,
725 const rpcprog_t program,
726 const rpcvers_t version,
727 const unsigned short protocol)
729 struct timeval timeout = { -1, 0 };
730 unsigned short port = 0;
733 client = nfs_gp_get_rpcbclient(sap, salen, protocol,
734 default_rpcb_version, &timeout);
735 if (client != NULL) {
736 port = nfs_gp_getport(client, sap, salen, program,
737 version, protocol, timeout);
738 CLNT_DESTROY(client);
745 * nfs_getport_ping - query server's rpcbind and do RPC ping to verify result
746 * @sap: IN: pointer to address of server to query;
747 * OUT: pointer to updated address
748 * @salen: length of server's address
749 * @program: requested RPC program number
750 * @version: requested RPC version number
751 * @protocol: IPPROTO_ value of requested transport protocol
753 * Uses any acceptable rpcbind version to discover the port number for the
754 * RPC service described by the given [program, version, transport] tuple.
755 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
756 * AF_INET6 server addresses.
758 * Returns a 1 and sets the port number in the passed-in server address
759 * if both the query and the ping were successful; otherwise zero.
760 * rpccreateerr is set to reflect the underlying cause of the error.
762 int nfs_getport_ping(struct sockaddr *sap, const socklen_t salen,
763 const rpcprog_t program, const rpcvers_t version,
764 const unsigned short protocol)
766 struct timeval timeout = { -1, 0 };
767 unsigned short port = 0;
771 client = nfs_gp_get_rpcbclient(sap, salen, protocol,
772 default_rpcb_version, &timeout);
773 if (client != NULL) {
774 port = nfs_gp_getport(client, sap, salen, program,
775 version, protocol, timeout);
776 CLNT_DESTROY(client);
781 struct sockaddr_storage address;
782 struct sockaddr *saddr = (struct sockaddr *)&address;
784 memcpy(saddr, sap, (size_t)salen);
785 nfs_gp_set_port(saddr, htons(port));
787 client = nfs_get_rpcclient(saddr, salen, protocol,
788 program, version, &timeout);
789 if (client != NULL) {
790 result = nfs_gp_ping(client, timeout);
791 CLNT_DESTROY(client);
796 nfs_gp_set_port(sap, htons(port));
802 * nfs_getlocalport - query local rpcbind to get port number for an RPC service
803 * @program: requested RPC program number
804 * @version: requested RPC version number
805 * @protocol: IPPROTO_ value of requested transport protocol
807 * Uses any acceptable rpcbind version to discover the port number for the
808 * RPC service described by the given [program, version, transport] tuple.
809 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
810 * AF_INET6 local addresses.
812 * Returns a positive integer representing the port number of the RPC
813 * service advertised by the server (in host byte order), or zero if the
814 * service is not advertised or there was some problem querying the server's
815 * rpcbind daemon. rpccreateerr is set to reflect the underlying cause of
818 * Try an AF_LOCAL connection first. The rpcbind daemon implementation should
819 * listen on AF_LOCAL.
821 * If that doesn't work (for example, if portmapper is running, or rpcbind
822 * isn't listening on /var/run/rpcbind.sock), send a query via UDP to localhost
823 * (UDP doesn't leave a socket in TIME_WAIT, and the timeout is a relatively
826 * getaddrinfo(3) generates a usable loopback address. RFC 3484 requires that
827 * the results are sorted so that the first result has the best likelihood of
828 * working, so we try just that first result. If IPv6 is all that is
829 * available, we are sure to generate an AF_INET6 loopback address and use
830 * rpcbindv4/v3 GETADDR. AF_INET6 requests go via rpcbind v4/3 in order to
831 * detect if the requested RPC service supports AF_INET6 or not.
833 unsigned short nfs_getlocalport(const rpcprot_t program,
834 const rpcvers_t version,
835 const unsigned short protocol)
837 struct sockaddr_storage address;
838 struct sockaddr *lb_addr = (struct sockaddr *)&address;
839 socklen_t lb_len = sizeof(lb_addr);
840 unsigned short port = 0;
843 const struct sockaddr_un sun = {
844 .sun_family = AF_LOCAL,
845 .sun_path = _PATH_RPCBINDSOCK,
847 const struct sockaddr *sap = (struct sockaddr *)&sun;
848 const socklen_t salen = SUN_LEN(&sun);
850 struct timeval timeout = { -1, 0 };
852 client = nfs_gp_get_rpcbclient(sap, salen, 0, RPCBVERS_4, &timeout);
853 if (client != NULL) {
856 if (nfs_gp_init_rpcb_parms(sap, salen, program, version,
857 protocol, &parms) != 0) {
858 port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
859 nfs_gp_free_rpcb_parms(&parms);
861 CLNT_DESTROY(client);
863 #endif /* NFS_GP_LOCAL */
866 if (nfs_gp_loopback_address(lb_addr, &lb_len)) {
867 port = nfs_getport(lb_addr, lb_len,
868 program, version, protocol);
870 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
877 * nfs_rpcb_getaddr - query rpcbind via rpcbind versions 4 and 3
878 * @sap: pointer to address of server to query
879 * @salen: length of server address
880 * @transport: transport protocol to use for the query
881 * @addr: pointer to r_addr address
882 * @addrlen: length of address
883 * @program: requested RPC program number
884 * @version: requested RPC version number
885 * @protocol: requested IPPROTO_ value of transport protocol
886 * @timeout: pointer to request timeout (NULL means use default timeout)
888 * Returns a positive integer representing the port number of the RPC
889 * service advertised by the server (in host byte order), or zero if the
890 * service is not advertised or there was some problem querying the
891 * server's rpcbind daemon. rpccreateerr is set to reflect the
892 * underlying cause of the error.
894 * This function provides similar functionality to nfs_pmap_getport(),
895 * but performs the rpcbind lookup via rpcbind version 4. If the server
896 * doesn't support rpcbind version 4, it will retry with version 3.
897 * The GETADDR procedure is exactly the same in these two versions of
898 * the rpcbind protocol, so the socket, RPC client, and arguments are
899 * re-used when retrying, saving ephemeral port space.
901 * These RPC procedures take a universal address as an argument, so the
902 * query will fail if the remote rpcbind daemon doesn't find an entry
903 * with a matching address. A matching address includes an ANYADDR
904 * address of the same address family. In this way an RPC server can
905 * advertise via rpcbind that it does not support AF_INET6.
909 unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
910 const socklen_t salen,
911 const unsigned short transport,
912 const struct sockaddr *addr,
913 const socklen_t addrlen,
914 const rpcprog_t program,
915 const rpcvers_t version,
916 const unsigned short protocol,
917 const struct timeval *timeout)
921 struct timeval tout = { -1, 0 };
922 unsigned short port = 0;
927 client = nfs_gp_get_rpcbclient(sap, salen, transport, RPCBVERS_4, &tout);
928 if (client != NULL) {
929 if (nfs_gp_init_rpcb_parms(addr, addrlen, program, version,
930 protocol, &parms) != 0) {
931 port = nfs_gp_rpcb_getaddr(client, &parms, tout);
932 nfs_gp_free_rpcb_parms(&parms);
934 CLNT_DESTROY(client);
940 #else /* HAVE_XDR_RPCB */
942 unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
943 const socklen_t salen,
944 const unsigned short transport,
945 const struct sockaddr *addr,
946 const socklen_t addrlen,
947 const rpcprog_t program,
948 const rpcvers_t version,
949 const unsigned short protocol,
950 const struct timeval *timeout)
952 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
956 #endif /* HAVE_XDR_RPCB */
959 * nfs_pmap_getport - query rpcbind via the portmap protocol (rpcbindv2)
960 * @sin: pointer to AF_INET address of server to query
961 * @transport: transport protocol to use for the query
962 * @program: requested RPC program number
963 * @version: requested RPC version number
964 * @protocol: requested IPPROTO_ value of transport protocol
965 * @timeout: pointer to request timeout (NULL means use default timeout)
967 * Returns a positive integer representing the port number of the RPC service
968 * advertised by the server (in host byte order), or zero if the service is
969 * not advertised or there was some problem querying the server's rpcbind
970 * daemon. rpccreateerr is set to reflect the underlying cause of the error.
972 * nfs_pmap_getport() is very similar to pmap_getport(), except that:
974 * 1. This version always tries to use an ephemeral port, since reserved
975 * ports are not needed for GETPORT queries. This conserves the very
976 * limited reserved port space, helping reduce failed socket binds
977 * during mount storms.
979 * 2. This version times out quickly by default. It time-limits the
980 * connect process as well as the actual RPC call, and even allows the
981 * caller to specify the timeout.
983 * 3. This version shares code with the rpcbindv3 and rpcbindv4 query
984 * functions. It can use a TI-RPC generated CLIENT.
986 unsigned long nfs_pmap_getport(const struct sockaddr_in *sin,
987 const unsigned short transport,
988 const unsigned long program,
989 const unsigned long version,
990 const unsigned long protocol,
991 const struct timeval *timeout)
994 struct pmap parms = {
999 struct timeval tout = { -1, 0 };
1000 unsigned long port = 0;
1002 if (timeout != NULL)
1005 client = nfs_gp_get_rpcbclient((struct sockaddr *)sin,
1006 (socklen_t)sizeof(*sin),
1007 transport, PMAPVERS, &tout);
1008 if (client != NULL) {
1009 port = nfs_gp_pmap_getport(client, &parms, tout);
1010 CLNT_DESTROY(client);