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
37 #ifdef HAVE_GETNAMEINFO
39 sockaddr_size(const struct sockaddr *sap)
41 if (sap->sa_family != AF_INET)
43 return (socklen_t)sizeof(struct sockaddr_in);
45 #endif /* HAVE_GETNAMEINFO */
48 * host_ntop - generate presentation address given a sockaddr
49 * @sap: pointer to socket address
50 * @buf: working storage
51 * @buflen: size of @buf in bytes
53 * Returns a pointer to a @buf.
55 #ifdef HAVE_GETNAMEINFO
57 host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
59 socklen_t salen = sockaddr_size(sap);
62 memset(buf, 0, buflen);
65 (void)strncpy(buf, "bad family", buflen - 1);
69 error = getnameinfo(sap, salen, buf, (socklen_t)buflen,
70 NULL, 0, NI_NUMERICHOST);
73 (void)strncpy(buf, "bad address", buflen - 1);
78 #else /* !HAVE_GETNAMEINFO */
80 host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
82 const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
84 memset(buf, 0, buflen);
86 if (sin->sin_family != AF_INET)
87 (void)strncpy(buf, "bad family", buflen - 1);
91 if (inet_ntop(AF_INET, &sin->sin_addr.s_addr, buf, buflen) != NULL)
95 (void)strncpy(buf, "bad address", buflen - 1);
98 #endif /* !HAVE_GETNAMEINFO */
101 * host_pton - return addrinfo for a given presentation address
102 * @paddr: pointer to a '\0'-terminated ASCII string containing an
103 * IP presentation address
105 * Returns address info structure, or NULL if an error occurs. Caller
106 * must free the returned structure with freeaddrinfo(3).
110 host_pton(const char *paddr)
112 struct addrinfo *ai = NULL;
113 struct addrinfo hint = {
114 /* don't return duplicates */
115 .ai_protocol = (int)IPPROTO_UDP,
116 .ai_flags = AI_NUMERICHOST,
117 .ai_family = AF_UNSPEC,
119 struct sockaddr_in sin;
123 * Although getaddrinfo(3) is easier to use and supports
124 * IPv6, it recognizes incomplete addresses like "10.4"
125 * as valid AF_INET addresses. It also accepts presentation
126 * addresses that end with a blank.
128 * inet_pton(3) is much stricter. Use it to be certain we
129 * have a real AF_INET presentation address, before invoking
130 * getaddrinfo(3) to generate the full addrinfo list.
132 if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0)
135 error = getaddrinfo(paddr, NULL, &hint, &ai);
141 xlog(D_GENERAL, "%s: passed a NULL presentation address",
145 xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m",
146 __func__, paddr, errno);
149 xlog(D_GENERAL, "%s: failed to convert %s: %s",
150 __func__, paddr, gai_strerror(error));
158 * host_addrinfo - return addrinfo for a given hostname
159 * @hostname: pointer to a '\0'-terminated ASCII string containing a hostname
161 * Returns address info structure with ai_canonname filled in, or NULL
162 * if no information is available for @hostname. Caller must free the
163 * returned structure with freeaddrinfo(3).
167 host_addrinfo(const char *hostname)
169 struct addrinfo *ai = NULL;
170 struct addrinfo hint = {
171 .ai_family = AF_INET,
172 /* don't return duplicates */
173 .ai_protocol = (int)IPPROTO_UDP,
174 .ai_flags = AI_ADDRCONFIG | AI_CANONNAME,
178 error = getaddrinfo(hostname, NULL, &hint, &ai);
183 xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m",
184 __func__, hostname, errno);
187 xlog(D_GENERAL, "%s: failed to resolve %s: %s",
188 __func__, hostname, gai_strerror(error));
196 * host_canonname - return canonical hostname bound to an address
197 * @sap: pointer to socket address to look up
199 * Discover the canonical hostname associated with the given socket
200 * address. The host's reverse mapping is verified in the process.
202 * Returns a '\0'-terminated ASCII string containing a hostname, or
203 * NULL if no hostname can be found for @sap. Caller must free
206 #ifdef HAVE_GETNAMEINFO
209 host_canonname(const struct sockaddr *sap)
211 socklen_t salen = sockaddr_size(sap);
212 char buf[NI_MAXHOST];
216 xlog(D_GENERAL, "%s: unsupported address family %d",
217 __func__, sap->sa_family);
221 memset(buf, 0, sizeof(buf));
222 error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
223 NULL, 0, NI_NAMEREQD);
228 xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
232 (void)getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
233 NULL, 0, NI_NUMERICHOST);
234 xlog(D_GENERAL, "%s: failed to resolve %s: %s",
235 __func__, buf, gai_strerror(error));
241 #else /* !HAVE_GETNAMEINFO */
244 host_canonname(const struct sockaddr *sap)
246 const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
247 const struct in_addr *addr = &sin->sin_addr;
250 if (sap->sa_family != AF_INET)
253 hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET);
257 return strdup(hp->h_name);
259 #endif /* !HAVE_GETNAMEINFO */
262 * host_reliable_addrinfo - return addrinfo for a given address
263 * @sap: pointer to socket address to look up
265 * Reverse and forward lookups are performed to ensure the address has
266 * proper forward and reverse mappings.
268 * Returns address info structure with ai_canonname filled in, or NULL
269 * if no information is available for @sap. Caller must free the returned
270 * structure with freeaddrinfo(3).
274 host_reliable_addrinfo(const struct sockaddr *sap)
279 hostname = host_canonname(sap);
280 if (hostname == NULL)
283 ai = host_addrinfo(hostname);
290 * host_numeric_addrinfo - return addrinfo without doing DNS queries
291 * @sap: pointer to socket address
293 * Returns address info structure, or NULL if an error occurred.
294 * Caller must free the returned structure with freeaddrinfo(3).
296 #ifdef HAVE_GETNAMEINFO
299 host_numeric_addrinfo(const struct sockaddr *sap)
301 socklen_t salen = sockaddr_size(sap);
302 char buf[INET_ADDRSTRLEN];
307 xlog(D_GENERAL, "%s: unsupported address family %d",
308 __func__, sap->sa_family);
312 memset(buf, 0, sizeof(buf));
313 error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
314 NULL, 0, NI_NUMERICHOST);
319 xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
323 xlog(D_GENERAL, "%s: getnameinfo(3) failed: %s",
324 __func__, gai_strerror(error));
331 * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
334 free(ai->ai_canonname); /* just in case */
335 ai->ai_canonname = strdup(buf);
336 if (ai->ai_canonname == NULL) {
344 #else /* !HAVE_GETNAMEINFO */
347 host_numeric_addrinfo(const struct sockaddr *sap)
349 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
350 const struct in_addr *addr = &sin->sin_addr;
351 char buf[INET_ADDRSTRLEN];
354 if (sap->sa_family != AF_INET)
357 memset(buf, 0, sizeof(buf));
358 if (inet_ntop(AF_INET, (char *)addr, buf,
359 (socklen_t)sizeof(buf)) == NULL)
365 * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
368 ai->ai_canonname = strdup(buf);
369 if (ai->ai_canonname == NULL) {
377 #endif /* !HAVE_GETNAMEINFO */