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