X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=support%2Fnfs%2Fgetport.c;h=9d85e897090f97e5a26bcd2dbd21783209f306e8;hp=47824a24e5a969410cad9424206d927eafbf1bd9;hb=2fcfd397bc555a6c31082c09e6fee7750e41fdb0;hpb=e9dbcba18defacbee9b5a48ddea9f6d3449b34e9 diff --git a/support/nfs/getport.c b/support/nfs/getport.c index 47824a2..9d85e89 100644 --- a/support/nfs/getport.c +++ b/support/nfs/getport.c @@ -40,9 +40,9 @@ #include #include -#ifdef HAVE_TIRPC_NETCONFIG_H -#include -#include +#ifdef HAVE_LIBTIRPC +#include +#include #endif #include "nfsrpc.h" @@ -53,132 +53,116 @@ * Rpcbind's local socket service does not seem to be working. * Disable this logic for now. */ -#ifdef HAVE_XDR_RPCB +#ifdef HAVE_LIBTIRPC #undef NFS_GP_LOCAL -#else /* HAVE_XDR_RPCB */ +#else /* !HAVE_LIBTIRPC */ #undef NFS_GP_LOCAL -#endif /* HAVE_XDR_RPCB */ +#endif /* !HAVE_LIBTIRPC */ -#ifdef HAVE_XDR_RPCB -const static rpcvers_t default_rpcb_version = RPCBVERS_4; -#else -const static rpcvers_t default_rpcb_version = PMAPVERS; -#endif - -static const char *nfs_gp_rpcb_pgmtbl[] = { - "rpcbind", - "portmap", - "portmapper", - "sunrpc", - NULL, -}; +#ifdef HAVE_LIBTIRPC +static const rpcvers_t default_rpcb_version = RPCBVERS_4; +#else /* !HAVE_LIBTIRPC */ +static const rpcvers_t default_rpcb_version = PMAPVERS; +#endif /* !HAVE_LIBTIRPC */ -#ifdef HAVE_DECL_AI_ADDRCONFIG /* - * getaddrinfo(3) generates a usable loopback address based on how the - * local network interfaces are configured. RFC 3484 requires that the - * results are sorted so that the first result has the best likelihood - * of working, so we try just that first result. + * There's no easy way to tell how the local system's networking + * and rpcbind is configured (ie. whether we want to use IPv6 or + * IPv4 loopback to contact RPC services on the local host). We + * punt and simply try to look up "localhost". * * Returns TRUE on success. */ static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen) { struct addrinfo *gai_results; - struct addrinfo gai_hint = { - .ai_flags = AI_ADDRCONFIG, - }; - socklen_t len = *salen; int ret = 0; - if (getaddrinfo(NULL, "sunrpc", &gai_hint, &gai_results)) + if (getaddrinfo("localhost", NULL, NULL, &gai_results)) return 0; - switch (gai_results->ai_addr->sa_family) { - case AF_INET: - case AF_INET6: - if (len >= gai_results->ai_addrlen) { - memcpy(sap, gai_results->ai_addr, - gai_results->ai_addrlen); - *salen = gai_results->ai_addrlen; - ret = 1; - } + if (*salen >= gai_results->ai_addrlen) { + memcpy(sap, gai_results->ai_addr, + gai_results->ai_addrlen); + *salen = gai_results->ai_addrlen; + ret = 1; } freeaddrinfo(gai_results); return ret; } -#else + /* - * Old versions of getaddrinfo(3) don't support AI_ADDRCONFIG, so we - * have a fallback for building on legacy systems. + * Plant port number in @sap. @port is already in network byte order. */ -static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen) +static void nfs_gp_set_port(struct sockaddr *sap, const in_port_t port) { struct sockaddr_in *sin = (struct sockaddr_in *)sap; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; - memset(sin, 0, sizeof(*sin)); + switch (sap->sa_family) { + case AF_INET: + sin->sin_port = port; + break; + case AF_INET6: + sin6->sin6_port = port; + break; + } +} - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - *salen = sizeof(*sin); +/* + * Look up a network service in /etc/services and return the + * network-order port number of that service. + */ +static in_port_t nfs_gp_getservbyname(const char *service, + const unsigned short protocol) +{ + const struct addrinfo gai_hint = { + .ai_family = AF_INET, + .ai_protocol = protocol, + .ai_flags = AI_PASSIVE, + }; + struct addrinfo *gai_results; + const struct sockaddr_in *sin; + in_port_t port; - return 1; + if (getaddrinfo(NULL, service, &gai_hint, &gai_results) != 0) + return 0; + + sin = (const struct sockaddr_in *)gai_results->ai_addr; + port = sin->sin_port; + + freeaddrinfo(gai_results); + return port; } -#endif /* * Discover the port number that should be used to contact an * rpcbind service. This will detect if the port has a local * value that may have been set in /etc/services. * - * NB: s_port is already in network byte order. - * * Returns network byte-order port number of rpcbind service * on this system. */ static in_port_t nfs_gp_get_rpcb_port(const unsigned short protocol) { - struct protoent *proto; - - proto = getprotobynumber((int)protocol); - if (proto != NULL) { - struct servent *entry; - - entry = getservbyname("rpcbind", proto->p_name); - if (entry != NULL) - return (in_port_t)entry->s_port; + static const char *rpcb_netnametbl[] = { + "rpcbind", + "portmapper", + "sunrpc", + NULL, + }; + unsigned int i; - entry = getservbyname("portmapper", proto->p_name); - if (entry != NULL) - return (in_port_t)entry->s_port; + for (i = 0; rpcb_netnametbl[i] != NULL; i++) { + in_port_t port; - entry = getservbyname("sunrpc", proto->p_name); - if (entry != NULL) - return (in_port_t)entry->s_port; + port = nfs_gp_getservbyname(rpcb_netnametbl[i], protocol); + if (port != 0) + return port; } - return htons((uint16_t)PMAPPORT); -} - -/* - * Plant port number in @sap. @port is already in network byte order. - */ -static void nfs_gp_set_port(struct sockaddr *sap, const in_port_t port) -{ - struct sockaddr_in *sin = (struct sockaddr_in *)sap; - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; - switch (sap->sa_family) { - case AF_INET: - sin->sin_port = port; - break; - case AF_INET6: - sin6->sin6_port = port; - break; - default: - fprintf(stderr, "%s: unrecognized address family\n", - __func__); - } + return (in_port_t)htons((uint16_t)PMAPPORT); } /* @@ -190,20 +174,23 @@ static void nfs_gp_set_port(struct sockaddr *sap, const in_port_t port) * client. Otherwise returns NULL, and rpc_createerr.cf_stat is set to * reflect the error. */ -static CLIENT *nfs_gp_get_rpcbclient(const struct sockaddr *sap, +static CLIENT *nfs_gp_get_rpcbclient(struct sockaddr *sap, const socklen_t salen, const unsigned short transport, const rpcvers_t version, struct timeval *timeout) { - struct sockaddr_storage address; - struct sockaddr *saddr = (struct sockaddr *)&address; - rpcprog_t rpcb_prog = nfs_getrpcbyname(RPCBPROG, nfs_gp_rpcb_pgmtbl); - - memcpy(saddr, sap, (size_t)salen); - nfs_gp_set_port(saddr, nfs_gp_get_rpcb_port(transport)); + static const char *rpcb_pgmtbl[] = { + "rpcbind", + "portmap", + "portmapper", + "sunrpc", + NULL, + }; + rpcprog_t rpcb_prog = nfs_getrpcbyname(RPCBPROG, rpcb_pgmtbl); - return nfs_get_rpcclient(saddr, salen, transport, rpcb_prog, + nfs_gp_set_port(sap, nfs_gp_get_rpcb_port(transport)); + return nfs_get_rpcclient(sap, salen, transport, rpcb_prog, version, timeout); } @@ -224,7 +211,7 @@ static CLIENT *nfs_gp_get_rpcbclient(const struct sockaddr *sap, * Returns a '\0'-terminated string if successful; otherwise NULL. * rpc_createerr.cf_stat is set to reflect the error. */ -#ifdef HAVE_XDR_RPCB +#ifdef HAVE_LIBTIRPC static char *nfs_gp_get_netid(const sa_family_t family, const unsigned short protocol) @@ -272,7 +259,7 @@ out: return NULL; } -#endif /* HAVE_XDR_RPCB */ +#endif /* HAVE_LIBTIRPC */ /* * Extract a port number from a universal address, and terminate the @@ -435,15 +422,11 @@ static int nfs_gp_ping(CLIENT *client, struct timeval timeout) return (int)(status == RPC_SUCCESS); } -#ifdef HAVE_XDR_RPCB +#ifdef HAVE_LIBTIRPC /* * Initialize the rpcb argument for a GETADDR request. * - * The rpcbind daemon ignores the parms.r_owner field in GETADDR - * requests, but we plant an eye-catcher to help distinguish these - * requests in network traces. - * * Returns 1 if successful, and caller must free strings pointed * to by r_netid and r_addr; otherwise 0. */ @@ -471,7 +454,7 @@ static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap, parms->r_vers = version; parms->r_netid = netid; parms->r_addr = addr; - parms->r_owner = "nfs-utils"; /* eye-catcher */ + parms->r_owner = ""; return 1; } @@ -547,7 +530,7 @@ static unsigned short nfs_gp_rpcb_getaddr(CLIENT *client, return port; } -#endif /* HAVE_XDR_RPCB */ +#endif /* HAVE_LIBTIRPC */ /* * Try GETPORT request via rpcbind version 2. @@ -577,7 +560,7 @@ static unsigned long nfs_gp_pmap_getport(CLIENT *client, return port; } -#ifdef HAVE_XDR_RPCB +#ifdef HAVE_LIBTIRPC static unsigned short nfs_gp_getport_rpcb(CLIENT *client, const struct sockaddr *sap, @@ -599,7 +582,7 @@ static unsigned short nfs_gp_getport_rpcb(CLIENT *client, return port; } -#endif /* HAVE_XDR_RPCB */ +#endif /* HAVE_LIBTIRPC */ static unsigned long nfs_gp_getport_pmap(CLIENT *client, const rpcprog_t program, @@ -634,11 +617,11 @@ static unsigned short nfs_gp_getport(CLIENT *client, struct timeval timeout) { switch (sap->sa_family) { -#ifdef HAVE_XDR_RPCB +#ifdef HAVE_LIBTIRPC case AF_INET6: return nfs_gp_getport_rpcb(client, sap, salen, program, version, protocol, timeout); -#endif /* HAVE_XDR_RPCB */ +#endif /* HAVE_LIBTIRPC */ case AF_INET: return nfs_gp_getport_pmap(client, program, version, protocol, timeout); @@ -649,7 +632,7 @@ static unsigned short nfs_gp_getport(CLIENT *client, } /** - * nfs_rcp_ping - Determine if RPC service is responding to requests + * nfs_rpc_ping - Determine if RPC service is responding to requests * @sap: pointer to address of server to query (port is already filled in) * @salen: length of server address * @program: requested RPC program number @@ -664,6 +647,8 @@ int nfs_rpc_ping(const struct sockaddr *sap, const socklen_t salen, const rpcprog_t program, const rpcvers_t version, const unsigned short protocol, const struct timeval *timeout) { + struct sockaddr_storage address; + struct sockaddr *saddr = (struct sockaddr *)&address; CLIENT *client; struct timeval tout = { -1, 0 }; int result = 0; @@ -671,7 +656,9 @@ int nfs_rpc_ping(const struct sockaddr *sap, const socklen_t salen, if (timeout != NULL) tout = *timeout; - client = nfs_get_rpcclient(sap, salen, protocol, program, version, &tout); + memcpy(saddr, sap, (size_t)salen); + client = nfs_get_rpcclient(saddr, salen, protocol, + program, version, &tout); if (client != NULL) { result = nfs_gp_ping(client, tout); CLNT_DESTROY(client); @@ -726,14 +713,17 @@ unsigned short nfs_getport(const struct sockaddr *sap, const rpcvers_t version, const unsigned short protocol) { + struct sockaddr_storage address; + struct sockaddr *saddr = (struct sockaddr *)&address; struct timeval timeout = { -1, 0 }; unsigned short port = 0; CLIENT *client; - client = nfs_gp_get_rpcbclient(sap, salen, protocol, + memcpy(saddr, sap, (size_t)salen); + client = nfs_gp_get_rpcbclient(saddr, salen, protocol, default_rpcb_version, &timeout); if (client != NULL) { - port = nfs_gp_getport(client, sap, salen, program, + port = nfs_gp_getport(client, saddr, salen, program, version, protocol, timeout); CLNT_DESTROY(client); } @@ -822,13 +812,6 @@ int nfs_getport_ping(struct sockaddr *sap, const socklen_t salen, * isn't listening on /var/run/rpcbind.sock), send a query via UDP to localhost * (UDP doesn't leave a socket in TIME_WAIT, and the timeout is a relatively * short 3 seconds). - * - * getaddrinfo(3) generates a usable loopback address. RFC 3484 requires that - * the results are sorted so that the first result has the best likelihood of - * working, so we try just that first result. If IPv6 is all that is - * available, we are sure to generate an AF_INET6 loopback address and use - * rpcbindv4/v3 GETADDR. AF_INET6 requests go via rpcbind v4/3 in order to - * detect if the requested RPC service supports AF_INET6 or not. */ unsigned short nfs_getlocalport(const rpcprot_t program, const rpcvers_t version, @@ -836,7 +819,7 @@ unsigned short nfs_getlocalport(const rpcprot_t program, { struct sockaddr_storage address; struct sockaddr *lb_addr = (struct sockaddr *)&address; - socklen_t lb_len = sizeof(lb_addr); + socklen_t lb_len = sizeof(*lb_addr); unsigned short port = 0; #ifdef NFS_GP_LOCAL @@ -904,7 +887,7 @@ unsigned short nfs_getlocalport(const rpcprot_t program, * address of the same address family. In this way an RPC server can * advertise via rpcbind that it does not support AF_INET6. */ -#ifdef HAVE_XDR_RPCB +#ifdef HAVE_LIBTIRPC unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap, const socklen_t salen, @@ -916,6 +899,8 @@ unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap, const unsigned short protocol, const struct timeval *timeout) { + struct sockaddr_storage address; + struct sockaddr *saddr = (struct sockaddr *)&address; CLIENT *client; struct rpcb parms; struct timeval tout = { -1, 0 }; @@ -924,7 +909,9 @@ unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap, if (timeout != NULL) tout = *timeout; - client = nfs_gp_get_rpcbclient(sap, salen, transport, RPCBVERS_4, &tout); + memcpy(saddr, sap, (size_t)salen); + client = nfs_gp_get_rpcbclient(saddr, salen, transport, + RPCBVERS_4, &tout); if (client != NULL) { if (nfs_gp_init_rpcb_parms(addr, addrlen, program, version, protocol, &parms) != 0) { @@ -937,7 +924,7 @@ unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap, return port; } -#else /* HAVE_XDR_RPCB */ +#else /* !HAVE_LIBTIRPC */ unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap, const socklen_t salen, @@ -953,7 +940,7 @@ unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap, return 0; } -#endif /* HAVE_XDR_RPCB */ +#endif /* !HAVE_LIBTIRPC */ /** * nfs_pmap_getport - query rpcbind via the portmap protocol (rpcbindv2) @@ -990,6 +977,8 @@ unsigned long nfs_pmap_getport(const struct sockaddr_in *sin, const unsigned long protocol, const struct timeval *timeout) { + struct sockaddr_in address; + struct sockaddr *saddr = (struct sockaddr *)&address; CLIENT *client; struct pmap parms = { .pm_prog = program, @@ -1002,8 +991,8 @@ unsigned long nfs_pmap_getport(const struct sockaddr_in *sin, if (timeout != NULL) tout = *timeout; - client = nfs_gp_get_rpcbclient((struct sockaddr *)sin, - (socklen_t)sizeof(*sin), + memcpy(saddr, sin, sizeof(address)); + client = nfs_gp_get_rpcbclient(saddr, (socklen_t)sizeof(*sin), transport, PMAPVERS, &tout); if (client != NULL) { port = nfs_gp_pmap_getport(client, &parms, tout);