X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;ds=sidebyside;f=support%2Fnfs%2Fgetport.c;h=2255b7d1bc86f344bd2f51ac175325bdad1468b6;hb=d271666403a87e60bbdee85372b6dcf35c2975ed;hp=25dca6c0a9da38372332df67a0c057d49f280f2e;hpb=9888a72c18c0798b0fd352f02d5985aa75637743;p=nfs-utils.git diff --git a/support/nfs/getport.c b/support/nfs/getport.c index 25dca6c..2255b7d 100644 --- a/support/nfs/getport.c +++ b/support/nfs/getport.c @@ -40,7 +40,7 @@ #include #include -#ifdef HAVE_TIRPC_NETCONFIG_H +#ifdef HAVE_LIBTIRPC #include #include #endif @@ -53,58 +53,71 @@ * 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 +#ifdef HAVE_LIBTIRPC const static rpcvers_t default_rpcb_version = RPCBVERS_4; -#else +#else /* !HAVE_LIBTIRPC */ const static rpcvers_t default_rpcb_version = PMAPVERS; -#endif - -static const char *nfs_gp_rpcb_pgmtbl[] = { - "rpcbind", - "portmap", - "portmapper", - "sunrpc", - NULL, -}; +#endif /* !HAVE_LIBTIRPC */ +#ifdef HAVE_DECL_AI_ADDRCONFIG /* - * 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. + * 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. * - * Returns network byte-order port number of rpcbind service - * on this system. + * Returns TRUE on success. */ -static in_port_t nfs_gp_get_rpcb_port(const unsigned short protocol) +static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen) { - struct protoent *proto; + 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)) + return 0; - proto = getprotobynumber((int)protocol); - if (proto != NULL) { - struct servent *entry; + 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; + } + } - entry = getservbyname("rpcbind", proto->p_name); - if (entry != NULL) - return (in_port_t)entry->s_port; + 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. + */ +static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen) +{ + struct sockaddr_in *sin = (struct sockaddr_in *)sap; - entry = getservbyname("portmapper", proto->p_name); - if (entry != NULL) - return (in_port_t)entry->s_port; + memset(sin, 0, sizeof(*sin)); - entry = getservbyname("sunrpc", proto->p_name); - if (entry != NULL) - return (in_port_t)entry->s_port; - } - return htons((uint16_t)PMAPPORT); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + *salen = sizeof(*sin); + + return 1; } +#endif /* * Plant port number in @sap. @port is already in network byte order. @@ -121,12 +134,64 @@ static void nfs_gp_set_port(struct sockaddr *sap, const in_port_t port) case AF_INET6: sin6->sin6_port = port; break; - default: - fprintf(stderr, "%s: unrecognized address family\n", - __func__); } } +/* + * 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; + + 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; +} + +/* + * 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. + * + * 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) +{ + static const char *rpcb_netnametbl[] = { + "rpcbind", + "portmapper", + "sunrpc", + NULL, + }; + unsigned int i; + + for (i = 0; rpcb_netnametbl[i] != NULL; i++) { + in_port_t port; + + port = nfs_gp_getservbyname(rpcb_netnametbl[i], protocol); + if (port != 0) + return port; + } + + return (in_port_t)htons((uint16_t)PMAPPORT); +} + /* * Set up an RPC client for communicating with an rpcbind daemon at * @sap over @transport with protocol version @version. @@ -142,9 +207,16 @@ static CLIENT *nfs_gp_get_rpcbclient(const struct sockaddr *sap, const rpcvers_t version, struct timeval *timeout) { + static const char *rpcb_pgmtbl[] = { + "rpcbind", + "portmap", + "portmapper", + "sunrpc", + NULL, + }; struct sockaddr_storage address; struct sockaddr *saddr = (struct sockaddr *)&address; - rpcprog_t rpcb_prog = nfs_getrpcbyname(RPCBPROG, nfs_gp_rpcb_pgmtbl); + rpcprog_t rpcb_prog = nfs_getrpcbyname(RPCBPROG, rpcb_pgmtbl); memcpy(saddr, sap, (size_t)salen); nfs_gp_set_port(saddr, nfs_gp_get_rpcb_port(transport)); @@ -170,7 +242,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) @@ -218,7 +290,7 @@ out: return NULL; } -#endif /* HAVE_XDR_RPCB */ +#endif /* HAVE_LIBTIRPC */ /* * Extract a port number from a universal address, and terminate the @@ -381,7 +453,7 @@ 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. @@ -493,7 +565,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. @@ -523,7 +595,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, @@ -545,7 +617,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, @@ -580,11 +652,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); @@ -780,12 +852,10 @@ unsigned short nfs_getlocalport(const rpcprot_t program, const rpcvers_t version, const unsigned short protocol) { - struct addrinfo *gai_results; - struct addrinfo gai_hint = { - .ai_flags = AI_ADDRCONFIG, - }; + struct sockaddr_storage address; + struct sockaddr *lb_addr = (struct sockaddr *)&address; + socklen_t lb_len = sizeof(*lb_addr); unsigned short port = 0; - int error; #ifdef NFS_GP_LOCAL const struct sockaddr_un sun = { @@ -811,12 +881,9 @@ unsigned short nfs_getlocalport(const rpcprot_t program, #endif /* NFS_GP_LOCAL */ if (port == 0) { - error = getaddrinfo(NULL, "sunrpc", &gai_hint, &gai_results); - if (error == 0) { - port = nfs_getport(gai_results->ai_addr, - gai_results->ai_addrlen, + if (nfs_gp_loopback_address(lb_addr, &lb_len)) { + port = nfs_getport(lb_addr, lb_len, program, version, protocol); - freeaddrinfo(gai_results); } else rpc_createerr.cf_stat = RPC_UNKNOWNADDR; } @@ -855,7 +922,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, @@ -888,7 +955,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, @@ -904,7 +971,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)