2 * support/export/hostname.c
4 * Functions for hostname.
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
25 #define xmalloc malloc
34 #ifndef HAVE_DECL_AI_ADDRCONFIG
35 #define AI_ADDRCONFIG 0
38 #define ALIGNMENT sizeof (char *)
41 align (int len, int al)
51 get_hostent (const char *addr, int len, int type)
58 int len_aliases = sizeof (char *);
59 int num_addr_list = 1;
60 int len_addr_list = sizeof (char *);
67 ipv4 = (struct in_addr *) addr;
68 name = inet_ntoa (*ipv4);
75 len_ent = align (sizeof (*cp), ALIGNMENT);
76 len_name = align (strlen (name) + 1, ALIGNMENT);
79 len_addr_list += align (len, ALIGNMENT) + sizeof (char *);
81 cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
84 cp->h_addrtype = type;
87 cp->h_name = (char *) &(((char *) cp) [pos]);
88 strcpy (cp->h_name, name);
91 cp->h_aliases = (char **) &(((char *) cp) [pos]);
92 pos += num_aliases * sizeof (char *);
93 cp->h_aliases [0] = NULL;
95 pos = len_ent + len_name + len_aliases;
96 cp->h_addr_list = (char **) &(((char *) cp) [pos]);
97 pos += num_addr_list * sizeof (char *);
98 cp->h_addr_list [0] = (char *) &(((char *) cp) [pos]);
99 memcpy (cp->h_addr_list [0], addr, cp->h_length);
100 pos += align (cp->h_length, ALIGNMENT);
101 cp->h_addr_list [1] = NULL;
107 hostent_dup (struct hostent *hp)
109 int len_ent = align (sizeof (*hp), ALIGNMENT);
110 int len_name = align (strlen (hp->h_name) + 1, ALIGNMENT);
112 int len_aliases = sizeof (char *);
113 int num_addr_list = 1;
114 int len_addr_list = sizeof (char *);
119 for (sp = hp->h_aliases; sp && *sp; sp++)
122 len_aliases += align (strlen (*sp) + 1, ALIGNMENT)
126 for (sp = hp->h_addr_list; *sp; sp++)
129 len_addr_list += align (hp->h_length, ALIGNMENT)
133 cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
138 cp->h_name = (char *) &(((char *) cp) [pos]);
139 strcpy (cp->h_name, hp->h_name);
142 cp->h_aliases = (char **) &(((char *) cp) [pos]);
143 pos += num_aliases * sizeof (char *);
144 for (sp = hp->h_aliases, i = 0; i < num_aliases; i++, sp++)
147 cp->h_aliases [i] = (char *) &(((char *) cp) [pos]);
148 strcpy (cp->h_aliases [i], *sp);
149 pos += align (strlen (*sp) + 1, ALIGNMENT);
152 cp->h_aliases [i] = NULL;
154 pos = len_ent + len_name + len_aliases;
155 cp->h_addr_list = (char **) &(((char *) cp) [pos]);
156 pos += num_addr_list * sizeof (char *);
157 for (sp = hp->h_addr_list, i = 0; i < num_addr_list; i++, sp++)
160 cp->h_addr_list [i] = (char *) &(((char *) cp) [pos]);
161 memcpy (cp->h_addr_list [i], *sp, hp->h_length);
162 pos += align (hp->h_length, ALIGNMENT);
165 cp->h_addr_list [i] = *sp;
170 #ifdef HAVE_GETNAMEINFO
172 sockaddr_size(const struct sockaddr *sap)
174 if (sap->sa_family != AF_INET)
176 return (socklen_t)sizeof(struct sockaddr_in);
178 #endif /* HAVE_GETNAMEINFO */
181 * host_ntop - generate presentation address given a sockaddr
182 * @sap: pointer to socket address
183 * @buf: working storage
184 * @buflen: size of @buf in bytes
186 * Returns a pointer to a @buf.
188 #ifdef HAVE_GETNAMEINFO
190 host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
192 socklen_t salen = sockaddr_size(sap);
195 memset(buf, 0, buflen);
198 (void)strncpy(buf, "bad family", buflen - 1);
202 error = getnameinfo(sap, salen, buf, (socklen_t)buflen,
203 NULL, 0, NI_NUMERICHOST);
206 (void)strncpy(buf, "bad address", buflen - 1);
211 #else /* !HAVE_GETNAMEINFO */
213 host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
215 const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
217 memset(buf, 0, buflen);
219 if (sin->sin_family != AF_INET)
220 (void)strncpy(buf, "bad family", buflen - 1);
224 if (inet_ntop(AF_INET, &sin->sin_addr.s_addr, buf, buflen) != NULL)
228 (void)strncpy(buf, "bad address", buflen - 1);
231 #endif /* !HAVE_GETNAMEINFO */
234 * host_pton - return addrinfo for a given presentation address
235 * @paddr: pointer to a '\0'-terminated ASCII string containing an
236 * IP presentation address
238 * Returns address info structure, or NULL if an error occurs. Caller
239 * must free the returned structure with freeaddrinfo(3).
243 host_pton(const char *paddr)
245 struct addrinfo *ai = NULL;
246 struct addrinfo hint = {
247 /* don't return duplicates */
248 .ai_protocol = (int)IPPROTO_UDP,
249 .ai_flags = AI_NUMERICHOST,
250 .ai_family = AF_UNSPEC,
252 struct sockaddr_in sin;
256 * Although getaddrinfo(3) is easier to use and supports
257 * IPv6, it recognizes incomplete addresses like "10.4"
258 * as valid AF_INET addresses. It also accepts presentation
259 * addresses that end with a blank.
261 * inet_pton(3) is much stricter. Use it to be certain we
262 * have a real AF_INET presentation address, before invoking
263 * getaddrinfo(3) to generate the full addrinfo list.
265 if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0)
268 error = getaddrinfo(paddr, NULL, &hint, &ai);
274 xlog(D_GENERAL, "%s: passed a NULL presentation address",
278 xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m",
279 __func__, paddr, errno);
282 xlog(D_GENERAL, "%s: failed to convert %s: %s",
283 __func__, paddr, gai_strerror(error));
291 * host_addrinfo - return addrinfo for a given hostname
292 * @hostname: pointer to a '\0'-terminated ASCII string containing a hostname
294 * Returns address info structure with ai_canonname filled in, or NULL
295 * if no information is available for @hostname. Caller must free the
296 * returned structure with freeaddrinfo(3).
300 host_addrinfo(const char *hostname)
302 struct addrinfo *ai = NULL;
303 struct addrinfo hint = {
304 .ai_family = AF_INET,
305 /* don't return duplicates */
306 .ai_protocol = (int)IPPROTO_UDP,
307 .ai_flags = AI_ADDRCONFIG | AI_CANONNAME,
311 error = getaddrinfo(hostname, NULL, &hint, &ai);
316 xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m",
317 __func__, hostname, errno);
320 xlog(D_GENERAL, "%s: failed to resolve %s: %s",
321 __func__, hostname, gai_strerror(error));
329 * host_canonname - return canonical hostname bound to an address
330 * @sap: pointer to socket address to look up
332 * Discover the canonical hostname associated with the given socket
333 * address. The host's reverse mapping is verified in the process.
335 * Returns a '\0'-terminated ASCII string containing a hostname, or
336 * NULL if no hostname can be found for @sap. Caller must free
339 #ifdef HAVE_GETNAMEINFO
342 host_canonname(const struct sockaddr *sap)
344 socklen_t salen = sockaddr_size(sap);
345 char buf[NI_MAXHOST];
349 xlog(D_GENERAL, "%s: unsupported address family %d",
350 __func__, sap->sa_family);
354 memset(buf, 0, sizeof(buf));
355 error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
356 NULL, 0, NI_NAMEREQD);
361 xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
365 (void)getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
366 NULL, 0, NI_NUMERICHOST);
367 xlog(D_GENERAL, "%s: failed to resolve %s: %s",
368 __func__, buf, gai_strerror(error));
374 #else /* !HAVE_GETNAMEINFO */
377 host_canonname(const struct sockaddr *sap)
379 const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
380 const struct in_addr *addr = &sin->sin_addr;
383 if (sap->sa_family != AF_INET)
386 hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET);
390 return strdup(hp->h_name);
392 #endif /* !HAVE_GETNAMEINFO */
395 * host_reliable_addrinfo - return addrinfo for a given address
396 * @sap: pointer to socket address to look up
398 * Reverse and forward lookups are performed to ensure the address has
399 * proper forward and reverse mappings.
401 * Returns address info structure with ai_canonname filled in, or NULL
402 * if no information is available for @sap. Caller must free the returned
403 * structure with freeaddrinfo(3).
407 host_reliable_addrinfo(const struct sockaddr *sap)
412 hostname = host_canonname(sap);
413 if (hostname == NULL)
416 ai = host_addrinfo(hostname);
423 * host_numeric_addrinfo - return addrinfo without doing DNS queries
424 * @sap: pointer to socket address
426 * Returns address info structure, or NULL if an error occurred.
427 * Caller must free the returned structure with freeaddrinfo(3).
429 #ifdef HAVE_GETNAMEINFO
432 host_numeric_addrinfo(const struct sockaddr *sap)
434 socklen_t salen = sockaddr_size(sap);
435 char buf[INET_ADDRSTRLEN];
440 xlog(D_GENERAL, "%s: unsupported address family %d",
441 __func__, sap->sa_family);
445 memset(buf, 0, sizeof(buf));
446 error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
447 NULL, 0, NI_NUMERICHOST);
452 xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
456 xlog(D_GENERAL, "%s: getnameinfo(3) failed: %s",
457 __func__, gai_strerror(error));
464 * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
467 free(ai->ai_canonname); /* just in case */
468 ai->ai_canonname = strdup(buf);
469 if (ai->ai_canonname == NULL) {
477 #else /* !HAVE_GETNAMEINFO */
480 host_numeric_addrinfo(const struct sockaddr *sap)
482 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
483 const struct in_addr *addr = &sin->sin_addr;
484 char buf[INET_ADDRSTRLEN];
487 if (sap->sa_family != AF_INET)
490 memset(buf, 0, sizeof(buf));
491 if (inet_ntop(AF_INET, (char *)addr, buf,
492 (socklen_t)sizeof(buf)) == NULL)
498 * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
501 ai->ai_canonname = strdup(buf);
502 if (ai->ai_canonname == NULL) {
510 #endif /* !HAVE_GETNAMEINFO */
513 is_hostname(const char *sp)
515 if (*sp == '\0' || *sp == '@')
520 if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
522 if (*sp == '\\' && sp[1])
530 matchhostname (const char *h1, const char *h2)
532 struct hostent *hp1, *hp2;
535 if (strcasecmp (h1, h2) == 0)
538 if (!is_hostname (h1) || !is_hostname (h2))
541 hp1 = gethostbyname (h1);
545 hp1 = hostent_dup (hp1);
547 hp2 = gethostbyname (h2);
550 if (strcasecmp (hp1->h_name, hp2->h_name) == 0)
557 for (ap1 = hp1->h_addr_list; *ap1 && status == 0; ap1++)
558 for (ap2 = hp2->h_addr_list; *ap2; ap2++)
559 if (memcmp (*ap1, *ap2, sizeof (struct in_addr)) == 0)
574 /* Map IP to hostname, and then map back to addr to make sure it is a
578 get_reliable_hostbyaddr(const char *addr, int len, int type)
580 struct hostent *hp = NULL;
582 struct hostent *reverse;
583 struct hostent *forward;
586 reverse = gethostbyaddr (addr, len, type);
590 /* must make sure the hostent is authorative. */
592 reverse = hostent_dup (reverse);
593 forward = gethostbyname (reverse->h_name);
596 /* now make sure the "addr" is in the list */
597 for (sp = forward->h_addr_list ; *sp ; sp++) {
598 if (memcmp (*sp, addr, forward->h_length) == 0)
604 hp = hostent_dup (forward);
608 xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't match reverse",
609 reverse->h_name, inet_ntoa(*(struct in_addr*)addr));
613 /* never heard of it. misconfigured DNS? */
614 xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't exist",
615 reverse->h_name, inet_ntoa(*(struct in_addr*)addr));
625 print_host (struct hostent *hp)
631 printf ("official hostname: %s\n", hp->h_name);
632 printf ("aliases:\n");
633 for (sp = hp->h_aliases; *sp; sp++)
634 printf (" %s\n", *sp);
635 printf ("IP addresses:\n");
636 for (sp = hp->h_addr_list; *sp; sp++)
637 printf (" %s\n", inet_ntoa (*(struct in_addr *) *sp));
640 printf ("Not host information\n");
644 main (int argc, char **argv)
646 struct hostent *hp = gethostbyname (argv [1]);
654 cp = hostent_dup (hp);
658 printf ("127.0.0.1 == %s: %d\n", argv [1],
659 matchhostname ("127.0.0.1", argv [1]));
660 addr.s_addr = inet_addr(argv [2]);
661 printf ("%s\n", inet_ntoa (addr));
662 cp = get_hostent ((const char *)&addr, sizeof(addr), AF_INET);