145392Sbrian/*-
245392Sbrian * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
345392Sbrian * All rights reserved.
445392Sbrian *
545392Sbrian * Redistribution and use in source and binary forms, with or without
645392Sbrian * modification, are permitted provided that the following conditions
745392Sbrian * are met:
845392Sbrian * 1. Redistributions of source code must retain the above copyright
945392Sbrian *    notice, this list of conditions and the following disclaimer.
1045392Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1145392Sbrian *    notice, this list of conditions and the following disclaimer in the
1245392Sbrian *    documentation and/or other materials provided with the distribution.
1345392Sbrian *
1445392Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1545392Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1645392Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1745392Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1845392Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1945392Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2045392Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2145392Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2245392Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2345392Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2445392Sbrian * SUCH DAMAGE.
2545392Sbrian */
2645392Sbrian
2784225Sdillon#include <sys/cdefs.h>
2884225Sdillon__FBSDID("$FreeBSD$");
2984225Sdillon
3045392Sbrian#include <sys/param.h>
31116344Smarkm#include <sys/socket.h>
3245392Sbrian
3345392Sbrian#include <netdb.h>
3445392Sbrian#include <netinet/in.h>
3545392Sbrian#include <arpa/inet.h>
3645392Sbrian
3745392Sbrian#include <stdio.h>
3845392Sbrian#include <string.h>
3945392Sbrian
4045392Sbrian#include "libutil.h"
4145392Sbrian
4256590Sshinstruct sockinet {
4356590Sshin	u_char	si_len;
4456590Sshin	u_char	si_family;
4556590Sshin	u_short	si_port;
4656590Sshin};
4756590Sshin
4845392Sbrianint
4945392Sbrianrealhostname(char *host, size_t hsize, const struct in_addr *ip)
5045392Sbrian{
5174260Sbrian	char trimmed[MAXHOSTNAMELEN];
5245392Sbrian	int result;
5345392Sbrian	struct hostent *hp;
5445392Sbrian
5545392Sbrian	result = HOSTNAME_INVALIDADDR;
56121193Smarkm	hp = gethostbyaddr((const char *)ip, sizeof(*ip), AF_INET);
5745392Sbrian
5871753Sbrian	if (hp != NULL) {
5971753Sbrian		strlcpy(trimmed, hp->h_name, sizeof(trimmed));
6071753Sbrian		trimdomain(trimmed, strlen(trimmed));
6171753Sbrian		if (strlen(trimmed) <= hsize) {
6271753Sbrian			char lookup[MAXHOSTNAMELEN];
6345392Sbrian
64183989Sdelphij			strlcpy(lookup, hp->h_name, sizeof(lookup));
6571753Sbrian			hp = gethostbyname(lookup);
6671753Sbrian			if (hp == NULL)
6771753Sbrian				result = HOSTNAME_INVALIDNAME;
6871753Sbrian			else for (; ; hp->h_addr_list++) {
6971753Sbrian				if (*hp->h_addr_list == NULL) {
7071753Sbrian					result = HOSTNAME_INCORRECTNAME;
7171753Sbrian					break;
7271753Sbrian				}
7371753Sbrian				if (!memcmp(*hp->h_addr_list, ip, sizeof(*ip))) {
7471753Sbrian					strncpy(host, trimmed, hsize);
7571753Sbrian					return HOSTNAME_FOUND;
7671753Sbrian				}
7745392Sbrian			}
7845392Sbrian		}
7945392Sbrian	}
8045392Sbrian
8145392Sbrian	strncpy(host, inet_ntoa(*ip), hsize);
8245392Sbrian
8345392Sbrian	return result;
8445392Sbrian}
8556590Sshin
86184683Sdes/*
87184683Sdes * struct sockaddr has very lax alignment requirements, since all its
88184683Sdes * members are char or equivalent.  This is a problem when trying to
89184683Sdes * dereference a struct sockaddr_in6 * that was passed in as a struct
90184683Sdes * sockaddr *.  Although we know (or trust) that the passed-in struct was
91184683Sdes * properly aligned, the compiler doesn't, and (rightly) complains.  These
92184683Sdes * macros perform the cast in a way that the compiler will accept.
93184683Sdes */
94184683Sdes#define SOCKADDR_IN6(p) ((struct sockaddr_in6 *)(void *)(p))
95184683Sdes#define SOCKADDR_IN(p) ((struct sockaddr_in *)(void *)(p))
96184683Sdes#define SOCKINET(p) ((struct sockinet *)(void *)(p))
97184683Sdes
9856590Sshinint
9956590Sshinrealhostname_sa(char *host, size_t hsize, struct sockaddr *addr, int addrlen)
10056590Sshin{
10156590Sshin	int result, error;
10257789Sume	char buf[NI_MAXHOST];
103185277Savatar#ifdef INET6
104121193Smarkm	struct sockaddr_in lsin;
105185277Savatar#endif
10656590Sshin
10756590Sshin	result = HOSTNAME_INVALIDADDR;
10856590Sshin
10980223Sume#ifdef INET6
11080223Sume	/* IPv4 mapped IPv6 addr consideraton, specified in rfc2373. */
11180223Sume	if (addr->sa_family == AF_INET6 &&
11280223Sume	    addrlen == sizeof(struct sockaddr_in6) &&
113184683Sdes	    IN6_IS_ADDR_V4MAPPED(&SOCKADDR_IN6(addr)->sin6_addr)) {
11480223Sume		struct sockaddr_in6 *sin6;
11580223Sume
116184683Sdes		sin6 = SOCKADDR_IN6(addr);
11780223Sume
118121193Smarkm		memset(&lsin, 0, sizeof(lsin));
119121193Smarkm		lsin.sin_len = sizeof(struct sockaddr_in);
120121193Smarkm		lsin.sin_family = AF_INET;
121121193Smarkm		lsin.sin_port = sin6->sin6_port;
122121193Smarkm		memcpy(&lsin.sin_addr, &sin6->sin6_addr.s6_addr[12],
12380223Sume		       sizeof(struct in_addr));
124121193Smarkm		addr = (struct sockaddr *)&lsin;
125121193Smarkm		addrlen = lsin.sin_len;
12680223Sume	}
12780223Sume#endif
12880223Sume
12980223Sume	error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
130146187Sume			    NI_NAMEREQD);
13157789Sume	if (error == 0) {
13256590Sshin		struct addrinfo hints, *res, *ores;
13356590Sshin		struct sockaddr *sa;
13456590Sshin
13556590Sshin		memset(&hints, 0, sizeof(struct addrinfo));
13680223Sume		hints.ai_family = addr->sa_family;
13780223Sume		hints.ai_flags = AI_CANONNAME | AI_PASSIVE;
13880223Sume		hints.ai_socktype = SOCK_STREAM;
13956590Sshin
14057789Sume		error = getaddrinfo(buf, NULL, &hints, &res);
14156590Sshin		if (error) {
14256590Sshin			result = HOSTNAME_INVALIDNAME;
14356590Sshin			goto numeric;
14480223Sume		}
14580223Sume		for (ores = res; ; res = res->ai_next) {
14656590Sshin			if (res == NULL) {
14756590Sshin				freeaddrinfo(ores);
14856590Sshin				result = HOSTNAME_INCORRECTNAME;
14956590Sshin				goto numeric;
15056590Sshin			}
15156590Sshin			sa = res->ai_addr;
15256590Sshin			if (sa == NULL) {
15356590Sshin				freeaddrinfo(ores);
15456590Sshin				result = HOSTNAME_INCORRECTNAME;
15556590Sshin				goto numeric;
15656590Sshin			}
15756590Sshin			if (sa->sa_len == addrlen &&
15856590Sshin			    sa->sa_family == addr->sa_family) {
159184683Sdes				SOCKINET(sa)->si_port = SOCKINET(addr)->si_port;
16080223Sume#ifdef INET6
16180223Sume				/*
16280223Sume				 * XXX: sin6_socpe_id may not been
16380223Sume				 * filled by DNS
16480223Sume				 */
16580223Sume				if (sa->sa_family == AF_INET6 &&
166184683Sdes				    SOCKADDR_IN6(sa)->sin6_scope_id == 0)
167184683Sdes					SOCKADDR_IN6(sa)->sin6_scope_id =
168184683Sdes					    SOCKADDR_IN6(addr)->sin6_scope_id;
16980223Sume#endif
17056590Sshin				if (!memcmp(sa, addr, sa->sa_len)) {
17156590Sshin					result = HOSTNAME_FOUND;
17280223Sume					if (ores->ai_canonname == NULL) {
17357789Sume						freeaddrinfo(ores);
17457789Sume						goto numeric;
17557789Sume					}
17674260Sbrian					strlcpy(buf, ores->ai_canonname,
17771753Sbrian						sizeof(buf));
17871753Sbrian					trimdomain(buf, hsize);
17974260Sbrian					if (strlen(buf) > hsize &&
18071753Sbrian					    addr->sa_family == AF_INET) {
18171753Sbrian						freeaddrinfo(ores);
18271753Sbrian						goto numeric;
18371753Sbrian					}
18474260Sbrian					strncpy(host, buf, hsize);
18556590Sshin					break;
18656590Sshin				}
18756590Sshin			}
18856590Sshin		}
18956590Sshin		freeaddrinfo(ores);
19056590Sshin	} else {
19156590Sshin    numeric:
19257789Sume		if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
193146187Sume				NI_NUMERICHOST) == 0)
19457789Sume			strncpy(host, buf, hsize);
19556590Sshin	}
19656590Sshin
19756590Sshin	return result;
19856590Sshin}
19956590Sshin
20056590Sshin
201