summaryrefslogtreecommitdiff
path: root/support/misc
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2010-01-15 15:53:07 -0500
committerSteve Dickson <steved@redhat.com>2010-01-17 16:45:12 -0500
commit4bc0dbaed1ba2f58beea2cdb0595b461e0c88b8e (patch)
treeb618147519a75390227a370f95c2d4de2e0daf41 /support/misc
parente8c917f53741100d6ea710100dca7c914791880b (diff)
downloadnfs-utils-4bc0dbaed1ba2f58beea2cdb0595b461e0c88b8e.tar.gz
tcp_wrappers: Use getifaddrs(3) if it is available
After glibc 2.3.3, getifaddrs(3) can return AF_INET6 addresses for local network interfaces. Using the library call is easier than trying to update the open code in from_local(), and means we have less to maintain in nfs-utils going forward. And, since from_local() can now support IPv6, change its synopsis to take a "struct sockaddr *" . Note that the original code discovers local addresses once. These days, with wifi, DHCP, and NetworkManager, the local network configuration can change dynamically over time. So, call getifaddrs() more often to ensure from_local() has up-to-date network configuration information. This implementation refreshes the list if from_local() has not been called in the last second. This is actually not terribly honerous. check_default() invokes from_local() only when the remote host is not in its access cache, or the access/deny files have changed. So new hosts will cause a refresh, but previously seen hosts (including localhost) should not. On the other hand, it still may not be often enough. After the first call, if only previously seen hosts attempt to access our daemons, from_local() would never be called, and the local list would never be updated. This might be possible during steady-state operation with a small number of servers and clients. It would also be nice if we could free the local interface address list at shutdown time, but that would be a lot of trouble for little gain. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Diffstat (limited to 'support/misc')
-rw-r--r--support/misc/from_local.c96
-rw-r--r--support/misc/tcpwrapper.c2
2 files changed, 90 insertions, 8 deletions
diff --git a/support/misc/from_local.c b/support/misc/from_local.c
index 3f46b99..e2de969 100644
--- a/support/misc/from_local.c
+++ b/support/misc/from_local.c
@@ -43,6 +43,7 @@ static char sccsid[] = "@(#) from_local.c 1.3 96/05/31 15:52:57";
#include <sys/types.h>
#include <sys/socket.h>
+#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <netdb.h>
@@ -52,6 +53,7 @@ static char sccsid[] = "@(#) from_local.c 1.3 96/05/31 15:52:57";
#include <stdlib.h>
#include <string.h>
+#include "sockaddr.h"
#include "tcpwrapper.h"
#include "xlog.h"
@@ -60,11 +62,75 @@ static char sccsid[] = "@(#) from_local.c 1.3 96/05/31 15:52:57";
#define FALSE 0
#endif
- /*
- * With virtual hosting, each hardware network interface can have multiple
- * network addresses. On such machines the number of machine addresses can
- * be surprisingly large.
- */
+#ifdef HAVE_GETIFADDRS
+
+#include <ifaddrs.h>
+#include <time.h>
+
+/**
+ * from_local - determine whether request comes from the local system
+ * @sap: pointer to socket address to check
+ *
+ * With virtual hosting, each hardware network interface can have
+ * multiple network addresses. On such machines the number of machine
+ * addresses can be surprisingly large.
+ *
+ * We also expect the local network configuration to change over time,
+ * so call getifaddrs(3) more than once, but not too often.
+ *
+ * Returns TRUE if the sockaddr contains an address of one of the local
+ * network interfaces. Otherwise FALSE is returned.
+ */
+int
+from_local(const struct sockaddr *sap)
+{
+ static struct ifaddrs *ifaddr = NULL;
+ static time_t last_update = 0;
+ struct ifaddrs *ifa;
+ unsigned int count;
+ time_t now;
+
+ if (time(&now) == ((time_t)-1)) {
+ xlog(L_ERROR, "%s: time(2): %m", __func__);
+
+ /* If we don't know what time it is, use the
+ * existing ifaddr list, if one exists */
+ now = last_update;
+ if (ifaddr == NULL)
+ now++;
+ }
+ if (now != last_update) {
+ xlog(D_GENERAL, "%s: updating local if addr list", __func__);
+
+ if (ifaddr)
+ freeifaddrs(ifaddr);
+
+ if (getifaddrs(&ifaddr) == -1) {
+ xlog(L_ERROR, "%s: getifaddrs(3): %m", __func__);
+ return FALSE;
+ }
+
+ last_update = now;
+ }
+
+ count = 0;
+ for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+ if ((ifa->ifa_flags & IFF_UP) &&
+ nfs_compare_sockaddr(sap, ifa->ifa_addr)) {
+ xlog(D_GENERAL, "%s: incoming address matches "
+ "local interface address", __func__);
+ return TRUE;
+ } else
+ count++;
+ }
+
+ xlog(D_GENERAL, "%s: checked %u local if addrs; "
+ "incoming address not found", __func__, count);
+ return FALSE;
+}
+
+#else /* !HAVE_GETIFADDRS */
+
static int num_local;
static int num_addrs;
static struct in_addr *addrs;
@@ -155,12 +221,26 @@ find_local(void)
return (num_local);
}
-/* from_local - determine whether request comes from the local system */
+/**
+ * from_local - determine whether request comes from the local system
+ * @sap: pointer to socket address to check
+ *
+ * With virtual hosting, each hardware network interface can have
+ * multiple network addresses. On such machines the number of machine
+ * addresses can be surprisingly large.
+ *
+ * Returns TRUE if the sockaddr contains an address of one of the local
+ * network interfaces. Otherwise FALSE is returned.
+ */
int
-from_local(struct sockaddr_in *addr)
+from_local(const struct sockaddr *sap)
{
+ const struct sockaddr_in *addr = (const struct sockaddr_in *)sap;
int i;
+ if (sap->sa_family != AF_INET)
+ return (FALSE);
+
if (addrs == 0 && find_local() == 0)
xlog(L_ERROR, "Cannot find any active local network interfaces");
@@ -184,3 +264,5 @@ int main(void)
}
#endif /* TEST */
+
+#endif /* !HAVE_GETIFADDRS */
diff --git a/support/misc/tcpwrapper.c b/support/misc/tcpwrapper.c
index 1da6020..af626ad 100644
--- a/support/misc/tcpwrapper.c
+++ b/support/misc/tcpwrapper.c
@@ -202,7 +202,7 @@ u_long prog;
if (acc && changed == 0)
return (acc->access);
- if (!(from_local(addr) || good_client(daemon, addr))) {
+ if (!(from_local((struct sockaddr *)addr) || good_client(daemon, addr))) {
log_bad_host(addr, proc, prog);
if (acc)
acc->access = FALSE;