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>
33 #ifndef HAVE_DECL_AI_ADDRCONFIG
34 #define AI_ADDRCONFIG 0
38 * host_ntop - generate presentation address given a sockaddr
39 * @sap: pointer to socket address
40 * @buf: working storage
41 * @buflen: size of @buf in bytes
43 * Returns a pointer to a @buf.
45 #ifdef HAVE_GETNAMEINFO
47 host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
49 socklen_t salen = nfs_sockaddr_length(sap);
52 memset(buf, 0, buflen);
55 (void)strncpy(buf, "bad family", buflen - 1);
59 error = getnameinfo(sap, salen, buf, (socklen_t)buflen,
60 NULL, 0, NI_NUMERICHOST);
63 (void)strncpy(buf, "bad address", buflen - 1);
68 #else /* !HAVE_GETNAMEINFO */
70 host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
72 const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
74 memset(buf, 0, buflen);
76 if (sin->sin_family != AF_INET)
77 (void)strncpy(buf, "bad family", buflen - 1);
81 if (inet_ntop(AF_INET, &sin->sin_addr.s_addr, buf, buflen) != NULL)
85 (void)strncpy(buf, "bad address", buflen - 1);
88 #endif /* !HAVE_GETNAMEINFO */
91 * host_pton - return addrinfo for a given presentation address
92 * @paddr: pointer to a '\0'-terminated ASCII string containing an
93 * IP presentation address
95 * Returns address info structure, or NULL if an error occurs. Caller
96 * must free the returned structure with freeaddrinfo(3).
100 host_pton(const char *paddr)
102 struct addrinfo *ai = NULL;
103 struct addrinfo hint = {
104 /* don't return duplicates */
105 .ai_protocol = (int)IPPROTO_UDP,
106 .ai_flags = AI_NUMERICHOST,
107 .ai_family = AF_UNSPEC,
109 struct sockaddr_in sin;
113 * Although getaddrinfo(3) is easier to use and supports
114 * IPv6, it recognizes incomplete addresses like "10.4"
115 * as valid AF_INET addresses. It also accepts presentation
116 * addresses that end with a blank.
118 * inet_pton(3) is much stricter. Use it to be certain we
119 * have a real AF_INET presentation address, before invoking
120 * getaddrinfo(3) to generate the full addrinfo list.
123 if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0)
126 error = getaddrinfo(paddr, NULL, &hint, &ai);
129 if (!inet4 && ai->ai_addr->sa_family == AF_INET) {
136 xlog(D_GENERAL, "%s: passed a NULL presentation address",
140 xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m",
141 __func__, paddr, errno);
144 xlog(D_GENERAL, "%s: failed to convert %s: %s",
145 __func__, paddr, gai_strerror(error));
153 * host_addrinfo - return addrinfo for a given hostname
154 * @hostname: pointer to a '\0'-terminated ASCII string containing a hostname
156 * Returns address info structure with ai_canonname filled in, or NULL
157 * if no information is available for @hostname. Caller must free the
158 * returned structure with freeaddrinfo(3).
162 host_addrinfo(const char *hostname)
164 struct addrinfo *ai = NULL;
165 struct addrinfo hint = {
166 #ifdef IPV6_SUPPORTED
167 .ai_family = AF_UNSPEC,
169 .ai_family = AF_INET,
171 /* don't return duplicates */
172 .ai_protocol = (int)IPPROTO_UDP,
173 .ai_flags = AI_ADDRCONFIG | AI_CANONNAME,
177 error = getaddrinfo(hostname, NULL, &hint, &ai);
182 xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m",
183 __func__, hostname, errno);
186 xlog(D_GENERAL, "%s: failed to resolve %s: %s",
187 __func__, hostname, gai_strerror(error));
195 * host_canonname - return canonical hostname bound to an address
196 * @sap: pointer to socket address to look up
198 * Discover the canonical hostname associated with the given socket
199 * address. The host's reverse mapping is verified in the process.
201 * Returns a '\0'-terminated ASCII string containing a hostname, or
202 * NULL if no hostname can be found for @sap. Caller must free
205 #ifdef HAVE_GETNAMEINFO
208 host_canonname(const struct sockaddr *sap)
210 socklen_t salen = nfs_sockaddr_length(sap);
211 char buf[NI_MAXHOST];
215 xlog(D_GENERAL, "%s: unsupported address family %d",
216 __func__, sap->sa_family);
220 memset(buf, 0, sizeof(buf));
221 error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
222 NULL, 0, NI_NAMEREQD);
227 xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
231 (void)getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
232 NULL, 0, NI_NUMERICHOST);
233 xlog(D_GENERAL, "%s: failed to resolve %s: %s",
234 __func__, buf, gai_strerror(error));
240 #else /* !HAVE_GETNAMEINFO */
243 host_canonname(const struct sockaddr *sap)
245 const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
246 const struct in_addr *addr = &sin->sin_addr;
249 if (sap->sa_family != AF_INET)
252 hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET);
256 return strdup(hp->h_name);
258 #endif /* !HAVE_GETNAMEINFO */
261 * host_reliable_addrinfo - return addrinfo for a given address
262 * @sap: pointer to socket address to look up
264 * Reverse and forward lookups are performed to ensure the address has
265 * proper forward and reverse mappings.
267 * Returns address info structure with ai_canonname filled in, or NULL
268 * if no information is available for @sap. Caller must free the returned
269 * structure with freeaddrinfo(3).
273 host_reliable_addrinfo(const struct sockaddr *sap)
278 hostname = host_canonname(sap);
279 if (hostname == NULL)
282 ai = host_addrinfo(hostname);
289 * host_numeric_addrinfo - return addrinfo without doing DNS queries
290 * @sap: pointer to socket address
292 * Returns address info structure, or NULL if an error occurred.
293 * Caller must free the returned structure with freeaddrinfo(3).
295 #ifdef HAVE_GETNAMEINFO
298 host_numeric_addrinfo(const struct sockaddr *sap)
300 socklen_t salen = nfs_sockaddr_length(sap);
301 char buf[INET6_ADDRSTRLEN];
306 xlog(D_GENERAL, "%s: unsupported address family %d",
307 __func__, sap->sa_family);
311 memset(buf, 0, sizeof(buf));
312 error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
313 NULL, 0, NI_NUMERICHOST);
318 xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
322 xlog(D_GENERAL, "%s: getnameinfo(3) failed: %s",
323 __func__, gai_strerror(error));
330 * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
333 free(ai->ai_canonname); /* just in case */
334 ai->ai_canonname = strdup(buf);
335 if (ai->ai_canonname == NULL) {
343 #else /* !HAVE_GETNAMEINFO */
346 host_numeric_addrinfo(const struct sockaddr *sap)
348 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
349 const struct in_addr *addr = &sin->sin_addr;
350 char buf[INET_ADDRSTRLEN];
353 if (sap->sa_family != AF_INET)
356 memset(buf, 0, sizeof(buf));
357 if (inet_ntop(AF_INET, (char *)addr, buf,
358 (socklen_t)sizeof(buf)) == NULL)
364 * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
367 ai->ai_canonname = strdup(buf);
368 if (ai->ai_canonname == NULL) {
376 #endif /* !HAVE_GETNAMEINFO */