2 * Copyright 2009 Oracle. All rights reserved.
4 * This file is part of nfs-utils.
6 * nfs-utils is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * nfs-utils is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>.
28 #include <sys/types.h>
29 #include <sys/socket.h>
36 #include <arpa/inet.h>
43 * statd_present_address - convert sockaddr to presentation address
44 * @sap: pointer to socket address to convert
45 * @buf: pointer to buffer to fill in
46 * @buflen: length of buffer
48 * Convert the passed-in sockaddr-style address to presentation format.
49 * The presentation format address is placed in @buf and is
52 * Returns true if successful; otherwise false.
54 * getnameinfo(3) is preferred, since it can parse IPv6 scope IDs.
55 * An alternate version of statd_present_address() is available to
56 * handle older glibcs that do not have getnameinfo(3).
58 #ifdef HAVE_GETNAMEINFO
60 statd_present_address(const struct sockaddr *sap, char *buf, const size_t buflen)
65 salen = nfs_sockaddr_length(sap);
67 xlog(D_GENERAL, "%s: unsupported address family",
72 error = getnameinfo(sap, salen, buf, (socklen_t)buflen,
73 NULL, 0, NI_NUMERICHOST);
75 xlog(D_GENERAL, "%s: getnameinfo(3): %s",
76 __func__, gai_strerror(error));
81 #else /* !HAVE_GETNAMEINFO */
83 statd_present_address(const struct sockaddr *sap, char *buf, const size_t buflen)
85 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
87 if (sin->sin_family != AF_INET) {
88 xlog(D_GENERAL, "%s: unsupported address family", __func__);
92 /* ensure '\0' termination */
93 memset(buf, 0, buflen);
95 if (inet_ntop(AF_INET, (char *)&sin->sin_addr,
96 buf, (socklen_t)buflen) == NULL) {
97 xlog(D_GENERAL, "%s: inet_ntop(3): %m", __func__);
102 #endif /* !HAVE_GETNAMEINFO */
105 * Look up the hostname; report exceptional errors. Caller must
106 * call freeaddrinfo(3) if a valid addrinfo is returned.
109 static struct addrinfo *
110 get_addrinfo(const char *hostname, const struct addrinfo *hint)
112 struct addrinfo *ai = NULL;
115 error = getaddrinfo(hostname, NULL, hint, &ai);
122 xlog(D_GENERAL, "%s: failed to resolve host %s: %s",
123 __func__, hostname, gai_strerror(error));
129 #ifdef HAVE_GETNAMEINFO
131 get_nameinfo(const struct sockaddr *sap, const socklen_t salen,
132 /*@out@*/ char *buf, const socklen_t buflen)
136 error = getnameinfo(sap, salen, buf, buflen, NULL, 0, NI_NAMEREQD);
138 xlog(D_GENERAL, "%s: failed to resolve address: %s",
139 __func__, gai_strerror(error));
145 #else /* !HAVE_GETNAMEINFO */
147 get_nameinfo(const struct sockaddr *sap,
148 __attribute__ ((unused)) const socklen_t salen,
149 /*@out@*/ char *buf, socklen_t buflen)
151 struct sockaddr_in *sin = (struct sockaddr_in *)(char *)sap;
154 if (sin->sin_family != AF_INET) {
155 xlog(D_GENERAL, "%s: unknown address family: %d",
160 hp = gethostbyaddr((const char *)&(sin->sin_addr.s_addr),
161 sizeof(struct in_addr), AF_INET);
163 xlog(D_GENERAL, "%s: failed to resolve address: %m", __func__);
167 strncpy(buf, hp->h_name, (size_t)buflen);
170 #endif /* !HAVE_GETNAMEINFO */
173 * statd_canonical_name - choose file name for monitor record files
174 * @hostname: C string containing hostname or presentation address
176 * Returns a '\0'-terminated ASCII string containing a fully qualified
177 * canonical hostname, or NULL if @hostname does not have a reverse
178 * mapping. Caller must free the result with free(3).
180 * Incoming hostnames are looked up to determine the canonical hostname,
181 * and incoming presentation addresses are converted to canonical
184 * We won't monitor peers that don't have a reverse map. The canonical
185 * name gives us a key for our monitor list.
189 statd_canonical_name(const char *hostname)
191 struct addrinfo hint = {
192 #ifdef IPV6_SUPPORTED
193 .ai_family = AF_UNSPEC,
194 #else /* !IPV6_SUPPORTED */
195 .ai_family = AF_INET,
196 #endif /* !IPV6_SUPPORTED */
197 .ai_flags = AI_NUMERICHOST,
198 .ai_protocol = (int)IPPROTO_UDP,
200 char buf[NI_MAXHOST];
203 ai = get_addrinfo(hostname, &hint);
205 /* @hostname was a presentation address */
207 result = get_nameinfo(ai->ai_addr, ai->ai_addrlen,
208 buf, (socklen_t)sizeof(buf));
211 /* OK to use presentation address,
212 * if no reverse map exists */
213 return strdup(hostname);
217 /* @hostname was a hostname */
218 hint.ai_flags = AI_CANONNAME;
219 ai = get_addrinfo(hostname, &hint);
222 strcpy(buf, ai->ai_canonname);
229 * Take care to perform an explicit reverse lookup on presentation
230 * addresses. Otherwise we don't get a real canonical name or a
231 * complete list of addresses.
233 * Returns an addrinfo list that has ai_canonname filled in, or
234 * NULL if some error occurs. Caller must free the returned
235 * list with freeaddrinfo(3).
238 static struct addrinfo *
239 statd_canonical_list(const char *hostname)
241 struct addrinfo hint = {
242 #ifdef IPV6_SUPPORTED
243 .ai_family = AF_UNSPEC,
244 #else /* !IPV6_SUPPORTED */
245 .ai_family = AF_INET,
246 #endif /* !IPV6_SUPPORTED */
247 .ai_flags = AI_NUMERICHOST,
248 .ai_protocol = (int)IPPROTO_UDP,
250 char buf[NI_MAXHOST];
253 ai = get_addrinfo(hostname, &hint);
255 /* @hostname was a presentation address */
257 result = get_nameinfo(ai->ai_addr, ai->ai_addrlen,
258 buf, (socklen_t)sizeof(buf));
263 /* @hostname was a hostname or had no reverse mapping */
264 strcpy(buf, hostname);
267 hint.ai_flags = AI_CANONNAME;
268 return get_addrinfo(buf, &hint);
272 * statd_matchhostname - check if two hostnames are equivalent
273 * @hostname1: C string containing hostname
274 * @hostname2: C string containing hostname
276 * Returns true if the hostnames are the same, the hostnames resolve
277 * to the same canonical name, or the hostnames resolve to at least
278 * one address that is the same. False is returned if the hostnames
279 * do not match in any of these ways, if either hostname contains
280 * wildcard characters, if either hostname is a netgroup name, or
281 * if an error occurs.
284 statd_matchhostname(const char *hostname1, const char *hostname2)
286 struct addrinfo *ai1, *ai2, *results1 = NULL, *results2 = NULL;
287 _Bool result = false;
289 if (strcasecmp(hostname1, hostname2) == 0) {
294 results1 = statd_canonical_list(hostname1);
295 if (results1 == NULL)
297 results2 = statd_canonical_list(hostname2);
298 if (results2 == NULL)
301 if (strcasecmp(results1->ai_canonname, results2->ai_canonname) == 0) {
306 for (ai1 = results1; ai1 != NULL; ai1 = ai1->ai_next)
307 for (ai2 = results2; ai2 != NULL; ai2 = ai2->ai_next)
308 if (nfs_compare_sockaddr(ai1->ai_addr, ai2->ai_addr)) {
314 freeaddrinfo(results2);
315 freeaddrinfo(results1);
317 xlog(D_CALL, "%s: hostnames %s and %s %s", __func__,
318 hostname1, hostname2,
319 (result ? "matched" : "did not match"));