]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - support/nfs/getport.c
support: Use HAVE_LIBTIRPC to switch in bindresvport_sa(3t)
[nfs-utils.git] / support / nfs / getport.c
index 2b80dcea5960a35bc439ad4b97122ba93ef4a67c..bc0f1211d6354c66279b23f5c305e8b3bec2f549 100644 (file)
@@ -65,59 +65,32 @@ static const rpcvers_t default_rpcb_version = RPCBVERS_4;
 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.
- */
-static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen)
-{
-       struct sockaddr_in *sin = (struct sockaddr_in *)sap;
-
-       memset(sin, 0, sizeof(*sin));
-
-       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.
@@ -348,7 +321,6 @@ int nfs_universal2port(const char *uaddr)
 /**
  * nfs_sockaddr2universal - convert a sockaddr to a "universal address"
  * @sap: pointer to a socket address
- * @salen: length of socket address
  *
  * Universal addresses (defined in RFC 1833) are used when calling an
  * rpcbind daemon via protocol versions 3 or 4..
@@ -357,81 +329,56 @@ int nfs_universal2port(const char *uaddr)
  * the returned string.  Otherwise NULL is returned and
  * rpc_createerr.cf_stat is set to reflect the error.
  *
+ * inet_ntop(3) is used here, since getnameinfo(3) is not available
+ * in some earlier glibc releases, and we don't require support for
+ * scope IDs for universal addresses.
  */
-#ifdef HAVE_GETNAMEINFO
-
-char *nfs_sockaddr2universal(const struct sockaddr *sap,
-                            const socklen_t salen)
+char *nfs_sockaddr2universal(const struct sockaddr *sap)
 {
-       struct sockaddr_un *sun = (struct sockaddr_un *)sap;
-       char buf[NI_MAXHOST];
+       const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
+       const struct sockaddr_un *sun = (const struct sockaddr_un *)sap;
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
+       char buf[INET6_ADDRSTRLEN + 8 /* for port information */];
        uint16_t port;
+       size_t count;
+       char *result;
+       int len;
 
        switch (sap->sa_family) {
        case AF_LOCAL:
                return strndup(sun->sun_path, sizeof(sun->sun_path));
        case AF_INET:
-               if (getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
-                                       NULL, 0, NI_NUMERICHOST) != 0)
+               if (inet_ntop(AF_INET, (const void *)&sin->sin_addr.s_addr,
+                                       buf, (socklen_t)sizeof(buf)) == NULL)
                        goto out_err;
-               port = ntohs(((struct sockaddr_in *)sap)->sin_port);
+               port = ntohs(sin->sin_port);
                break;
        case AF_INET6:
-               if (getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
-                                       NULL, 0, NI_NUMERICHOST) != 0)
+               if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
+                                       buf, (socklen_t)sizeof(buf)) == NULL)
                        goto out_err;
-               port = ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
+               port = ntohs(sin6->sin6_port);
                break;
        default:
                goto out_err;
        }
 
-       (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%u.%u",
+       count = sizeof(buf) - strlen(buf);
+       len = snprintf(buf + strlen(buf), count, ".%u.%u",
                        (unsigned)(port >> 8), (unsigned)(port & 0xff));
-
-       return strdup(buf);
-
-out_err:
-       rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
-       return NULL;
-}
-
-#else  /* HAVE_GETNAMEINFO */
-
-char *nfs_sockaddr2universal(const struct sockaddr *sap,
-                            const socklen_t salen)
-{
-       struct sockaddr_un *sun = (struct sockaddr_un *)sap;
-       char buf[NI_MAXHOST];
-       uint16_t port;
-       char *addr;
-
-       switch (sap->sa_family) {
-       case AF_LOCAL:
-               return strndup(sun->sun_path, sizeof(sun->sun_path));
-       case AF_INET:
-               addr = inet_ntoa(((struct sockaddr_in *)sap)->sin_addr);
-               if (addr != NULL && strlen(addr) > sizeof(buf))
-                       goto out_err;
-               strcpy(buf, addr);
-               port = ntohs(((struct sockaddr_in *)sap)->sin_port);
-               break;
-       default:
+       /* before glibc 2.0.6, snprintf(3) could return -1 */
+       if (len < 0 || (size_t)len > count)
                goto out_err;
-       }
-
-       (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%u.%u",
-                       (unsigned)(port >> 8), (unsigned)(port & 0xff));
 
-       return strdup(buf);
+       result = strdup(buf);
+       if (result != NULL)
+               return result;
 
 out_err:
        rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
        return NULL;
 }
 
-#endif /* HAVE_GETNAMEINFO */
-
 /*
  * Send a NULL request to the indicated RPC service.
  *
@@ -458,7 +405,6 @@ static int nfs_gp_ping(CLIENT *client, struct timeval timeout)
  * to by r_netid and r_addr; otherwise 0.
  */
 static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap,
-                                 const socklen_t salen,
                                  const rpcprog_t program,
                                  const rpcvers_t version,
                                  const unsigned short protocol,
@@ -470,7 +416,7 @@ static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap,
        if (netid == NULL)
                return 0;
 
-       addr = nfs_sockaddr2universal(sap, salen);
+       addr = nfs_sockaddr2universal(sap);
        if (addr == NULL) {
                free(netid);
                return 0;
@@ -591,7 +537,6 @@ static unsigned long nfs_gp_pmap_getport(CLIENT *client,
 
 static unsigned short nfs_gp_getport_rpcb(CLIENT *client,
                                          const struct sockaddr *sap,
-                                         const socklen_t salen,
                                          const rpcprog_t program,
                                          const rpcvers_t version,
                                          const unsigned short protocol,
@@ -600,8 +545,8 @@ static unsigned short nfs_gp_getport_rpcb(CLIENT *client,
        unsigned short port = 0;
        struct rpcb parms;
 
-       if (nfs_gp_init_rpcb_parms(sap, salen, program,
-                                       version, protocol, &parms) != 0) {
+       if (nfs_gp_init_rpcb_parms(sap, program, version,
+                                       protocol, &parms) != 0) {
                port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
                nfs_gp_free_rpcb_parms(&parms);
        }
@@ -637,7 +582,6 @@ static unsigned long nfs_gp_getport_pmap(CLIENT *client,
  */
 static unsigned short nfs_gp_getport(CLIENT *client,
                                     const struct sockaddr *sap,
-                                    const socklen_t salen,
                                     const rpcprog_t program,
                                     const rpcvers_t version,
                                     const unsigned short protocol,
@@ -646,7 +590,7 @@ static unsigned short nfs_gp_getport(CLIENT *client,
        switch (sap->sa_family) {
 #ifdef HAVE_LIBTIRPC
        case AF_INET6:
-               return nfs_gp_getport_rpcb(client, sap, salen, program,
+               return nfs_gp_getport_rpcb(client, sap, program,
                                                version, protocol, timeout);
 #endif /* HAVE_LIBTIRPC */
        case AF_INET:
@@ -750,7 +694,7 @@ unsigned short nfs_getport(const struct sockaddr *sap,
        client = nfs_gp_get_rpcbclient(saddr, salen, protocol,
                                                default_rpcb_version, &timeout);
        if (client != NULL) {
-               port = nfs_gp_getport(client, saddr, salen, program,
+               port = nfs_gp_getport(client, saddr, program,
                                        version, protocol, timeout);
                CLNT_DESTROY(client);
        }
@@ -788,7 +732,7 @@ int nfs_getport_ping(struct sockaddr *sap, const socklen_t salen,
        client = nfs_gp_get_rpcbclient(sap, salen, protocol,
                                                default_rpcb_version, &timeout);
        if (client != NULL) {
-               port = nfs_gp_getport(client, sap, salen, program,
+               port = nfs_gp_getport(client, sap, program,
                                        version, protocol, timeout);
                CLNT_DESTROY(client);
                client = NULL;
@@ -839,13 +783,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,
@@ -870,7 +807,7 @@ unsigned short nfs_getlocalport(const rpcprot_t program,
        if (client != NULL) {
                struct rpcb parms;
 
-               if (nfs_gp_init_rpcb_parms(sap, salen, program, version,
+               if (nfs_gp_init_rpcb_parms(sap, program, version,
                                                protocol, &parms) != 0) {
                        port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
                        nfs_gp_free_rpcb_parms(&parms);
@@ -896,7 +833,6 @@ unsigned short nfs_getlocalport(const rpcprot_t program,
  * @salen: length of server address
  * @transport: transport protocol to use for the query
  * @addr: pointer to r_addr address
- * @addrlen: length of address
  * @program: requested RPC program number
  * @version: requested RPC version number
  * @protocol: requested IPPROTO_ value of transport protocol
@@ -927,7 +863,6 @@ unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
                                const socklen_t salen,
                                const unsigned short transport,
                                const struct sockaddr *addr,
-                               const socklen_t addrlen,
                                const rpcprog_t program,
                                const rpcvers_t version,
                                const unsigned short protocol,
@@ -947,7 +882,7 @@ unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
        client = nfs_gp_get_rpcbclient(saddr, salen, transport,
                                                        RPCBVERS_4, &tout);
        if (client != NULL) {
-               if (nfs_gp_init_rpcb_parms(addr, addrlen, program, version,
+               if (nfs_gp_init_rpcb_parms(addr, program, version,
                                                protocol, &parms) != 0) {
                        port = nfs_gp_rpcb_getaddr(client, &parms, tout);
                        nfs_gp_free_rpcb_parms(&parms);
@@ -960,15 +895,14 @@ unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
 
 #else  /* !HAVE_LIBTIRPC */
 
-unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
-                               const socklen_t salen,
-                               const unsigned short transport,
-                               const struct sockaddr *addr,
-                               const socklen_t addrlen,
-                               const rpcprog_t program,
-                               const rpcvers_t version,
-                               const unsigned short protocol,
-                               const struct timeval *timeout)
+unsigned short nfs_rpcb_getaddr(__attribute__((unused)) const struct sockaddr *sap,
+                               __attribute__((unused)) const socklen_t salen,
+                               __attribute__((unused)) const unsigned short transport,
+                               __attribute__((unused)) const struct sockaddr *addr,
+                               __attribute__((unused)) const rpcprog_t program,
+                               __attribute__((unused)) const rpcvers_t version,
+                               __attribute__((unused)) const unsigned short protocol,
+                               __attribute__((unused)) const struct timeval *timeout)
 {
        rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
        return 0;