2 * Copyright 2010 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/>.
26 #include <arpa/inet.h>
34 * host_ntop - generate presentation address given a sockaddr
35 * @sap: pointer to socket address
36 * @buf: working storage
37 * @buflen: size of @buf in bytes
39 * Returns a pointer to a @buf.
41 #ifdef HAVE_GETNAMEINFO
43 host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
45 socklen_t salen = nfs_sockaddr_length(sap);
48 memset(buf, 0, buflen);
51 (void)strncpy(buf, "bad family", buflen - 1);
55 error = getnameinfo(sap, salen, buf, (socklen_t)buflen,
56 NULL, 0, NI_NUMERICHOST);
59 (void)strncpy(buf, "bad address", buflen - 1);
64 #else /* !HAVE_GETNAMEINFO */
66 host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
68 const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
70 memset(buf, 0, buflen);
72 if (sin->sin_family != AF_INET)
73 (void)strncpy(buf, "bad family", buflen - 1);
77 if (inet_ntop(AF_INET, &sin->sin_addr.s_addr, buf, buflen) != NULL)
81 (void)strncpy(buf, "bad address", buflen - 1);
84 #endif /* !HAVE_GETNAMEINFO */
87 * host_pton - return addrinfo for a given presentation address
88 * @paddr: pointer to a '\0'-terminated ASCII string containing an
89 * IP presentation address
91 * Returns address info structure, or NULL if an error occurs. Caller
92 * must free the returned structure with freeaddrinfo(3).
96 host_pton(const char *paddr)
98 struct addrinfo *ai = NULL;
99 struct addrinfo hint = {
100 /* don't return duplicates */
101 .ai_protocol = (int)IPPROTO_UDP,
102 .ai_flags = AI_NUMERICHOST,
103 .ai_family = AF_UNSPEC,
105 struct sockaddr_in sin;
109 * Although getaddrinfo(3) is easier to use and supports
110 * IPv6, it recognizes incomplete addresses like "10.4"
111 * as valid AF_INET addresses. It also accepts presentation
112 * addresses that end with a blank.
114 * inet_pton(3) is much stricter. Use it to be certain we
115 * have a real AF_INET presentation address, before invoking
116 * getaddrinfo(3) to generate the full addrinfo list.
119 if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0)
122 error = getaddrinfo(paddr, NULL, &hint, &ai);
125 if (!inet4 && ai->ai_addr->sa_family == AF_INET) {
132 xlog(D_GENERAL, "%s: passed a NULL presentation address",
136 xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m",
137 __func__, paddr, errno);
140 xlog(D_GENERAL, "%s: failed to convert %s: %s",
141 __func__, paddr, gai_strerror(error));
149 * host_addrinfo - return addrinfo for a given hostname
150 * @hostname: pointer to a '\0'-terminated ASCII string containing a hostname
152 * Returns address info structure with ai_canonname filled in, or NULL
153 * if no information is available for @hostname. Caller must free the
154 * returned structure with freeaddrinfo(3).
158 host_addrinfo(const char *hostname)
160 struct addrinfo *ai = NULL;
161 struct addrinfo hint = {
162 #ifdef IPV6_SUPPORTED
163 .ai_family = AF_UNSPEC,
165 .ai_family = AF_INET,
167 /* don't return duplicates */
168 .ai_protocol = (int)IPPROTO_UDP,
169 .ai_flags = AI_CANONNAME,
173 error = getaddrinfo(hostname, NULL, &hint, &ai);
178 xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m",
179 __func__, hostname, errno);
182 xlog(D_GENERAL, "%s: failed to resolve %s: %s",
183 __func__, hostname, gai_strerror(error));
191 * host_canonname - return canonical hostname bound to an address
192 * @sap: pointer to socket address to look up
194 * Discover the canonical hostname associated with the given socket
195 * address. The host's reverse mapping is verified in the process.
197 * Returns a '\0'-terminated ASCII string containing a hostname, or
198 * NULL if no hostname can be found for @sap. Caller must free
201 #ifdef HAVE_GETNAMEINFO
204 host_canonname(const struct sockaddr *sap)
206 socklen_t salen = nfs_sockaddr_length(sap);
207 char buf[NI_MAXHOST];
211 xlog(D_GENERAL, "%s: unsupported address family %d",
212 __func__, sap->sa_family);
216 memset(buf, 0, sizeof(buf));
217 error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
218 NULL, 0, NI_NAMEREQD);
223 xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
227 (void)getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
228 NULL, 0, NI_NUMERICHOST);
229 xlog(D_GENERAL, "%s: failed to resolve %s: %s",
230 __func__, buf, gai_strerror(error));
236 #else /* !HAVE_GETNAMEINFO */
239 host_canonname(const struct sockaddr *sap)
241 const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
242 const struct in_addr *addr = &sin->sin_addr;
245 if (sap->sa_family != AF_INET)
248 hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET);
252 return strdup(hp->h_name);
254 #endif /* !HAVE_GETNAMEINFO */
257 * host_reliable_addrinfo - return addrinfo for a given address
258 * @sap: pointer to socket address to look up
260 * Reverse and forward lookups are performed to ensure the address has
261 * proper forward and reverse mappings.
263 * Returns address info structure with ai_canonname filled in, or NULL
264 * if no information is available for @sap. Caller must free the returned
265 * structure with freeaddrinfo(3).
269 host_reliable_addrinfo(const struct sockaddr *sap)
274 hostname = host_canonname(sap);
275 if (hostname == NULL)
278 ai = host_addrinfo(hostname);
285 * host_numeric_addrinfo - return addrinfo without doing DNS queries
286 * @sap: pointer to socket address
288 * Returns address info structure, or NULL if an error occurred.
289 * Caller must free the returned structure with freeaddrinfo(3).
291 #ifdef HAVE_GETNAMEINFO
294 host_numeric_addrinfo(const struct sockaddr *sap)
296 socklen_t salen = nfs_sockaddr_length(sap);
297 char buf[INET6_ADDRSTRLEN];
302 xlog(D_GENERAL, "%s: unsupported address family %d",
303 __func__, sap->sa_family);
307 memset(buf, 0, sizeof(buf));
308 error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
309 NULL, 0, NI_NUMERICHOST);
314 xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
318 xlog(D_GENERAL, "%s: getnameinfo(3) failed: %s",
319 __func__, gai_strerror(error));
326 * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
329 free(ai->ai_canonname); /* just in case */
330 ai->ai_canonname = strdup(buf);
331 if (ai->ai_canonname == NULL) {
339 #else /* !HAVE_GETNAMEINFO */
342 host_numeric_addrinfo(const struct sockaddr *sap)
344 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
345 const struct in_addr *addr = &sin->sin_addr;
346 char buf[INET_ADDRSTRLEN];
349 if (sap->sa_family != AF_INET)
352 memset(buf, 0, sizeof(buf));
353 if (inet_ntop(AF_INET, (char *)addr, buf,
354 (socklen_t)sizeof(buf)) == NULL)
360 * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
363 ai->ai_canonname = strdup(buf);
364 if (ai->ai_canonname == NULL) {
372 #endif /* !HAVE_GETNAMEINFO */