/avm2_env/usr/src/lib/libutil/realhostname.c
C | 200 lines | 138 code | 24 blank | 38 comment | 35 complexity | b9da9474271756cdd6bd12bfc34e0a6b MD5 | raw file
Possible License(s): GPL-3.0, Apache-2.0, CC-BY-SA-3.0, LGPL-3.0, MPL-2.0-no-copyleft-exception, GPL-2.0, LGPL-2.1, AGPL-1.0, BSD-3-Clause, LGPL-2.0
- /*-
- * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- #include <sys/cdefs.h>
- __FBSDID("$FreeBSD: src/lib/libutil/realhostname.c,v 1.21.2.1.6.1 2010/12/21 17:09:25 kensmith Exp $");
- #include <sys/param.h>
- #include <sys/socket.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <stdio.h>
- #include <string.h>
- #include "libutil.h"
- struct sockinet {
- u_char si_len;
- u_char si_family;
- u_short si_port;
- };
- int
- realhostname(char *host, size_t hsize, const struct in_addr *ip)
- {
- char trimmed[MAXHOSTNAMELEN];
- int result;
- struct hostent *hp;
- result = HOSTNAME_INVALIDADDR;
- hp = gethostbyaddr((const char *)ip, sizeof(*ip), AF_INET);
- if (hp != NULL) {
- strlcpy(trimmed, hp->h_name, sizeof(trimmed));
- trimdomain(trimmed, strlen(trimmed));
- if (strlen(trimmed) <= hsize) {
- char lookup[MAXHOSTNAMELEN];
- strlcpy(lookup, hp->h_name, sizeof(lookup));
- hp = gethostbyname(lookup);
- if (hp == NULL)
- result = HOSTNAME_INVALIDNAME;
- else for (; ; hp->h_addr_list++) {
- if (*hp->h_addr_list == NULL) {
- result = HOSTNAME_INCORRECTNAME;
- break;
- }
- if (!memcmp(*hp->h_addr_list, ip, sizeof(*ip))) {
- strncpy(host, trimmed, hsize);
- return HOSTNAME_FOUND;
- }
- }
- }
- }
- strncpy(host, inet_ntoa(*ip), hsize);
- return result;
- }
- /*
- * struct sockaddr has very lax alignment requirements, since all its
- * members are char or equivalent. This is a problem when trying to
- * dereference a struct sockaddr_in6 * that was passed in as a struct
- * sockaddr *. Although we know (or trust) that the passed-in struct was
- * properly aligned, the compiler doesn't, and (rightly) complains. These
- * macros perform the cast in a way that the compiler will accept.
- */
- #define SOCKADDR_IN6(p) ((struct sockaddr_in6 *)(void *)(p))
- #define SOCKADDR_IN(p) ((struct sockaddr_in *)(void *)(p))
- #define SOCKINET(p) ((struct sockinet *)(void *)(p))
- int
- realhostname_sa(char *host, size_t hsize, struct sockaddr *addr, int addrlen)
- {
- int result, error;
- char buf[NI_MAXHOST];
- #ifdef INET6
- struct sockaddr_in lsin;
- #endif
- result = HOSTNAME_INVALIDADDR;
- #ifdef INET6
- /* IPv4 mapped IPv6 addr consideraton, specified in rfc2373. */
- if (addr->sa_family == AF_INET6 &&
- addrlen == sizeof(struct sockaddr_in6) &&
- IN6_IS_ADDR_V4MAPPED(&SOCKADDR_IN6(addr)->sin6_addr)) {
- struct sockaddr_in6 *sin6;
- sin6 = SOCKADDR_IN6(addr);
- memset(&lsin, 0, sizeof(lsin));
- lsin.sin_len = sizeof(struct sockaddr_in);
- lsin.sin_family = AF_INET;
- lsin.sin_port = sin6->sin6_port;
- memcpy(&lsin.sin_addr, &sin6->sin6_addr.s6_addr[12],
- sizeof(struct in_addr));
- addr = (struct sockaddr *)&lsin;
- addrlen = lsin.sin_len;
- }
- #endif
- error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
- NI_NAMEREQD);
- if (error == 0) {
- struct addrinfo hints, *res, *ores;
- struct sockaddr *sa;
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_family = addr->sa_family;
- hints.ai_flags = AI_CANONNAME | AI_PASSIVE;
- hints.ai_socktype = SOCK_STREAM;
- error = getaddrinfo(buf, NULL, &hints, &res);
- if (error) {
- result = HOSTNAME_INVALIDNAME;
- goto numeric;
- }
- for (ores = res; ; res = res->ai_next) {
- if (res == NULL) {
- freeaddrinfo(ores);
- result = HOSTNAME_INCORRECTNAME;
- goto numeric;
- }
- sa = res->ai_addr;
- if (sa == NULL) {
- freeaddrinfo(ores);
- result = HOSTNAME_INCORRECTNAME;
- goto numeric;
- }
- if (sa->sa_len == addrlen &&
- sa->sa_family == addr->sa_family) {
- SOCKINET(sa)->si_port = SOCKINET(addr)->si_port;
- #ifdef INET6
- /*
- * XXX: sin6_socpe_id may not been
- * filled by DNS
- */
- if (sa->sa_family == AF_INET6 &&
- SOCKADDR_IN6(sa)->sin6_scope_id == 0)
- SOCKADDR_IN6(sa)->sin6_scope_id =
- SOCKADDR_IN6(addr)->sin6_scope_id;
- #endif
- if (!memcmp(sa, addr, sa->sa_len)) {
- result = HOSTNAME_FOUND;
- if (ores->ai_canonname == NULL) {
- freeaddrinfo(ores);
- goto numeric;
- }
- strlcpy(buf, ores->ai_canonname,
- sizeof(buf));
- trimdomain(buf, hsize);
- if (strlen(buf) > hsize &&
- addr->sa_family == AF_INET) {
- freeaddrinfo(ores);
- goto numeric;
- }
- strncpy(host, buf, hsize);
- break;
- }
- }
- }
- freeaddrinfo(ores);
- } else {
- numeric:
- if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
- NI_NUMERICHOST) == 0)
- strncpy(host, buf, hsize);
- }
- return result;
- }