summaryrefslogtreecommitdiffstats
path: root/utils/statd
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2011-08-29 13:22:21 -0400
committerSteve Dickson <steved@redhat.com>2011-08-29 13:43:28 -0400
commitbbd9f5a98c3a401371bc642ac8545b1ccfeeab4d (patch)
treefde0f7906fcef9cd3c8881264faeebaef1c573d3 /utils/statd
parent140468c2968472e871b972e400f58ad659458a2d (diff)
downloadnfs-utils-bbd9f5a98c3a401371bc642ac8545b1ccfeeab4d.tar.gz
nfs-utils-bbd9f5a98c3a401371bc642ac8545b1ccfeeab4d.tar.xz
nfs-utils-bbd9f5a98c3a401371bc642ac8545b1ccfeeab4d.zip
sm-notify: sm-notify doesn't handle localhost properly
It looks like the existing algorithm for verifying the passed-in bind address is as broken as statd_matchhostname() used to be: for IP addresses, AI_CANONNAME is useless. We need to have getnameinfo(3) or equivalent in there. Clean up: extract the logic that verifies the command line bind address into its own function, and make it handle canonical name lookup correctly. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Steve Dickson <steved@redhat.com>
Diffstat (limited to 'utils/statd')
-rw-r--r--utils/statd/sm-notify.c127
1 files changed, 102 insertions, 25 deletions
diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c
index f05eadf..2421f8b 100644
--- a/utils/statd/sm-notify.c
+++ b/utils/statd/sm-notify.c
@@ -93,6 +93,101 @@ smn_lookup(const char *name)
return ai;
}
+#ifdef HAVE_GETNAMEINFO
+static char *
+smn_get_hostname(const struct sockaddr *sap, const socklen_t salen,
+ const char *name)
+{
+ char buf[NI_MAXHOST];
+ int error;
+
+ error = getnameinfo(sap, salen, buf, sizeof(buf), NULL, 0, NI_NAMEREQD);
+ if (error != 0) {
+ xlog(L_ERROR, "my_name '%s' is unusable: %s",
+ name, gai_strerror(error));
+ return NULL;
+ }
+ return strdup(buf);
+}
+#else /* !HAVE_GETNAMEINFO */
+static char *
+smn_get_hostname(const struct sockaddr *sap,
+ __attribute__ ((unused)) const socklen_t salen,
+ const char *name)
+{
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
+ const struct in_addr *addr = &sin->sin_addr;
+ struct hostent *hp;
+
+ if (sap->sa_family != AF_INET) {
+ xlog(L_ERROR, "my_name '%s' is unusable: Bad address family",
+ name);
+ return NULL;
+ }
+
+ hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET);
+ if (hp == NULL) {
+ xlog(L_ERROR, "my_name '%s' is unusable: %s",
+ name, hstrerror(h_errno));
+ return NULL;
+ }
+ return strdup(hp->h_name);
+}
+#endif /* !HAVE_GETNAMEINFO */
+
+/*
+ * Presentation addresses are converted to their canonical hostnames.
+ * If the IP address does not map to a hostname, it is an error:
+ * we never send a presentation address as the argument of SM_NOTIFY.
+ *
+ * If "name" is not a presentation address, it is left alone. This
+ * allows the administrator some flexibility if DNS isn't configured
+ * exactly how sm-notify prefers it.
+ *
+ * Returns NUL-terminated C string containing the result, or NULL
+ * if the canonical name doesn't exist or cannot be determined.
+ * The caller must free the result with free(3).
+ */
+__attribute_malloc__
+static char *
+smn_verify_my_name(const char *name)
+{
+ struct addrinfo *ai = NULL;
+ struct addrinfo hint = {
+#ifdef IPV6_SUPPORTED
+ .ai_family = AF_UNSPEC,
+#else /* !IPV6_SUPPORTED */
+ .ai_family = AF_INET,
+#endif /* !IPV6_SUPPORTED */
+ .ai_flags = AI_NUMERICHOST,
+ };
+ char *retval;
+ int error;
+
+ error = getaddrinfo(name, NULL, &hint, &ai);
+ switch (error) {
+ case 0:
+ /* @name was a presentation address */
+ retval = smn_get_hostname(ai->ai_addr, ai->ai_addrlen, name);
+ freeaddrinfo(ai);
+ if (retval == NULL)
+ return NULL;
+ break;
+ case EAI_NONAME:
+ /* @name was not a presentation address */
+ retval = strdup(name);
+ break;
+ default:
+ xlog(L_ERROR, "my_name '%s' is unusable: %s",
+ name, gai_strerror(error));
+ return NULL;
+ }
+
+ xlog(D_GENERAL, "Canonical name for my_name '%s': %s",
+ name, retval);
+ return retval;
+}
+
__attribute_malloc__
static struct nsm_host *
smn_alloc_host(const char *hostname, const char *mon_name,
@@ -416,32 +511,14 @@ usage: fprintf(stderr,
}
if (opt_srcaddr != NULL) {
- struct addrinfo *ai = NULL;
- struct addrinfo hint = {
- .ai_family = AF_UNSPEC,
- .ai_flags = AI_NUMERICHOST,
- };
-
- if (getaddrinfo(opt_srcaddr, NULL, &hint, &ai))
- /* not a presentation address - use it */
- strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname));
- else {
- /* was a presentation address - look it up in
- * /etc/hosts, so it can be used for my_name */
- int error;
+ char *name;
- freeaddrinfo(ai);
- hint.ai_flags = AI_CANONNAME;
- error = getaddrinfo(opt_srcaddr, NULL, &hint, &ai);
- if (error != 0) {
- xlog(L_ERROR, "Bind address %s is unusable: %s",
- opt_srcaddr, gai_strerror(error));
- exit(1);
- }
- strncpy(nsm_hostname, ai->ai_canonname,
- sizeof(nsm_hostname));
- freeaddrinfo(ai);
- }
+ name = smn_verify_my_name(opt_srcaddr);
+ if (name == NULL)
+ exit(1);
+
+ strncpy(nsm_hostname, name, sizeof(nsm_hostname));
+ free(name);
}
(void)nsm_retire_monitored_hosts();