[PATCH 23/29] statd: Support IPv6 in sm_mon_1_svc()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Replace deprecated gethostbyname(3) and gethostbyaddr(3) calls.

Handle IPv6 remotes and IDN labels properly.  At least with fairly
recent glibc's we are guaranteed that the returned hostnames will
contain only ASCII characters, allowing DNS labels to continue to be
used as file names as IDNs become commonplace.

Also address a couple of memory leaks.

Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx>
---

 utils/statd/hostname.c |   30 ++++++++++++++++++++++++++++++
 utils/statd/monitor.c  |   31 ++++++++++++++++++-------------
 utils/statd/statd.h    |    2 ++
 3 files changed, 50 insertions(+), 13 deletions(-)

diff --git a/utils/statd/hostname.c b/utils/statd/hostname.c
index 6f532b8..f790d35 100644
--- a/utils/statd/hostname.c
+++ b/utils/statd/hostname.c
@@ -136,6 +136,36 @@ get_addrinfo(const char *hostname, const struct addrinfo* gai_hint)
 	return NULL;
 }
 
+/**
+ * nsm_forward_lookup - hostname or presentation address to sockaddr list
+ * @hostname: C string containing hostname or presentation address
+ *
+ * Returns addrinfo list, including the host's canonical DNS name,
+ * or NULL if an error occurs.  Caller must free addrinfo list via
+ * freeaddrinfo(3).
+ *
+ * AI_ADDRCONFIG should prevent us from monitoring a host that we can't
+ * reach.  If IPv6 is not enabled on this system, then we don't want to
+ * monitor remote hosts that have only IPv6 addresses.
+ */
+struct addrinfo *
+nsm_forward_lookup(const char *hostname)
+{
+	static const struct addrinfo gai_hint = {
+#ifdef IPV6_SUPPORTED
+		.ai_family	= AF_UNSPEC,
+		.ai_flags	= AI_CANONNAME | AI_ADDRCONFIG |
+				  AI_IDN | AI_IDN_USE_STD3_ASCII_RULES,
+#else	/* !IPV6_SUPPORTED */
+		.ai_family	= AF_INET,
+		.ai_flags	= AI_CANONNAME |
+				  AI_IDN | AI_IDN_USE_STD3_ASCII_RULES,
+#endif	/* !IPV6_SUPPORTED */
+	};
+
+	return get_addrinfo(hostname, &gai_hint);
+}
+
 #ifdef IPV6_SUPPORTED
 static int
 compare_sockaddrs(const struct sockaddr *sa1, const struct sockaddr *sa2)
diff --git a/utils/statd/monitor.c b/utils/statd/monitor.c
index 3db7ce8..df3206a 100644
--- a/utils/statd/monitor.c
+++ b/utils/statd/monitor.c
@@ -72,8 +72,8 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
 		.sin_family		= AF_INET,
 		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
 	};
-	char		*dnsname;
-	struct hostent	*hostinfo = NULL;
+	struct addrinfo *gai_results;
+	char *dnsname = NULL;
 
 	xlog(D_CALL, "Received SM_MON for %s from %s", mon_name, my_name);
 
@@ -115,9 +115,6 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
 		     "or starting '.': %s", mon_name);
 		xlog(L_ERROR, "POSSIBLE SPOOF/ATTACK ATTEMPT!");
 		goto failure;
-	} else if ((hostinfo = gethostbyname(mon_name)) == NULL) {
-		xlog_warn("gethostbyname error for %s", mon_name);
-		goto failure;
 	}
 
 	/* my_name must not have white space */
@@ -130,15 +127,21 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
 	 * Now choose a hostname to use for matching.  We cannot
 	 * really trust much in the incoming NOTIFY, so to make
 	 * sure that multi-homed hosts work nicely, we get an
-	 * FQDN now, and use that for matching
+	 * FQDN now, and use that for matching.  If the kernel
+	 * handed us an IP presentation address, getaddrinfo(3)
+	 * copies that into ai_canonname.
 	 */
-	hostinfo = gethostbyaddr(hostinfo->h_addr,
-				 hostinfo->h_length,
-				 hostinfo->h_addrtype);
-	if (hostinfo)
-		dnsname = xstrdup(hostinfo->h_name);
-	else
-		dnsname = xstrdup(my_name);
+	gai_results = nsm_forward_lookup(mon_name);
+	if (gai_results == NULL) {
+		xlog(L_WARNING, "No canonical hostname found for %s", mon_name);
+		goto failure;
+	}
+	dnsname = strdup(gai_results->ai_canonname);
+	freeaddrinfo(gai_results);
+	if (dnsname == NULL) {
+		xlog(L_ERROR, "Failed to allocate memory");
+		goto failure;
+	}
 
 	/* Now check to see if this is a duplicate, and warn if so.
 	 * I will also return STAT_FAIL. (I *think* this is how I should
@@ -164,6 +167,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
 				mon_name, my_name);
 
 			/* But we'll let you pass anyway. */
+			free(dnsname);
 			goto success;
 		}
 		clnt = NL_NEXT(clnt);
@@ -174,6 +178,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
 	 * doesn't fail.  (I should probably fix this assumption.)
 	 */
 	if (!(clnt = nlist_new(my_name, mon_name, 0))) {
+		free(dnsname);
 		xlog_warn("out of memory");
 		goto failure;
 	}
diff --git a/utils/statd/statd.h b/utils/statd/statd.h
index 71a77e2..5ee3ea6 100644
--- a/utils/statd/statd.h
+++ b/utils/statd/statd.h
@@ -25,6 +25,8 @@
 extern int	nsm_matchhostname(const char *hostname1, const char *hostname2);
 extern int	nsm_present_address(const struct sockaddr *sap, socklen_t salen,
 					char *buf, const size_t buflen);
+extern struct addrinfo *
+		nsm_forward_lookup(const char *hostname);
 extern void	my_svc_run(void);
 extern void	notify_hosts(void);
 extern void	shuffle_dirs(void);

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux