156893Sfenner/*
256893Sfenner * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
356893Sfenner * All rights reserved.
4127668Sbms *
556893Sfenner * Redistribution and use in source and binary forms, with or without
656893Sfenner * modification, are permitted provided that the following conditions
756893Sfenner * are met:
856893Sfenner * 1. Redistributions of source code must retain the above copyright
956893Sfenner *    notice, this list of conditions and the following disclaimer.
1056893Sfenner * 2. Redistributions in binary form must reproduce the above copyright
1156893Sfenner *    notice, this list of conditions and the following disclaimer in the
1256893Sfenner *    documentation and/or other materials provided with the distribution.
1356893Sfenner * 3. Neither the name of the project nor the names of its contributors
1456893Sfenner *    may be used to endorse or promote products derived from this software
1556893Sfenner *    without specific prior written permission.
16127668Sbms *
1756893Sfenner * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1856893Sfenner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1956893Sfenner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2056893Sfenner * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2156893Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2256893Sfenner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2356893Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2456893Sfenner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2556893Sfenner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2656893Sfenner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2756893Sfenner * SUCH DAMAGE.
2856893Sfenner */
2956893Sfenner
3056893Sfenner/*
3156893Sfenner * Issues to be discussed:
3256893Sfenner * - Thread safe-ness must be checked
3356893Sfenner * - Return values.  There seems to be no standard for return value (RFC2553)
3456893Sfenner *   but INRIA implementation returns EAI_xxx defined for getaddrinfo().
3556893Sfenner * - RFC2553 says that we should raise error on short buffer.  X/Open says
3656893Sfenner *   we need to truncate the result.  We obey RFC2553 (and X/Open should be
3756893Sfenner *   modified).
3856893Sfenner */
3956893Sfenner
4056893Sfenner#ifdef HAVE_CONFIG_H
4156893Sfenner#include <config.h>
42127668Sbms#endif
4356893Sfenner
4456893Sfenner#ifndef lint
45127668Sbmsstatic const char rcsid[] _U_ =
46190207Srpaulo     "@(#) $Header: /tcpdump/master/tcpdump/missing/getnameinfo.c,v 1.11 2003-11-16 09:36:49 guy Exp $";
4756893Sfenner#endif
4856893Sfenner
4956893Sfenner#include <sys/types.h>
5056893Sfenner#include <sys/socket.h>
5156893Sfenner#include <net/if.h>
5256893Sfenner#include <netinet/in.h>
5356893Sfenner#include <arpa/inet.h>
5456893Sfenner#include <arpa/nameser.h>
5556893Sfenner#include <netdb.h>
5656893Sfenner#include <resolv.h>
5756893Sfenner#include <string.h>
5856893Sfenner#include <stddef.h>
5956893Sfenner#include <errno.h>
6056893Sfenner
6156893Sfenner#ifdef NEED_ADDRINFO_H
6256893Sfenner#include "addrinfo.h"
6356893Sfenner#endif
6456893Sfenner
6556893Sfenner#define SUCCESS 0
6656893Sfenner#define ANY 0
6756893Sfenner#define YES 1
6856893Sfenner#define NO  0
6956893Sfenner
7056893Sfennerstatic struct afd {
7156893Sfenner	int a_af;
7256893Sfenner	int a_addrlen;
7356893Sfenner	int a_socklen;
7456893Sfenner	int a_off;
7556893Sfenner} afdl [] = {
7656893Sfenner#ifdef INET6
7756893Sfenner	{PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
7856893Sfenner		offsetof(struct sockaddr_in6, sin6_addr)},
7956893Sfenner#endif
8056893Sfenner	{PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
8156893Sfenner		offsetof(struct sockaddr_in, sin_addr)},
8256893Sfenner	{0, 0, 0},
8356893Sfenner};
8456893Sfenner
8556893Sfennerstruct sockinet {
8656893Sfenner	u_char	si_len;
8756893Sfenner	u_char	si_family;
8856893Sfenner	u_short	si_port;
8956893Sfenner};
9056893Sfenner
9156893Sfenner#define ENI_NOSOCKET 	0
9256893Sfenner#define ENI_NOSERVNAME	1
9356893Sfenner#define ENI_NOHOSTNAME	2
9456893Sfenner#define ENI_MEMORY	3
9556893Sfenner#define ENI_SYSTEM	4
9656893Sfenner#define ENI_FAMILY	5
9756893Sfenner#define ENI_SALEN	6
9856893Sfenner
9956893Sfennerint
10056893Sfennergetnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
10156893Sfenner	const struct sockaddr *sa;
10256893Sfenner	size_t salen;
10356893Sfenner	char *host;
10456893Sfenner	size_t hostlen;
10556893Sfenner	char *serv;
10656893Sfenner	size_t servlen;
10756893Sfenner	int flags;
10856893Sfenner{
10956893Sfenner	struct afd *afd;
11056893Sfenner	struct servent *sp;
11156893Sfenner	struct hostent *hp;
11256893Sfenner	u_short port;
11356893Sfenner	int family, i;
11456893Sfenner	char *addr, *p;
11556893Sfenner	u_int32_t v4a;
11656893Sfenner	int h_error;
11756893Sfenner	char numserv[512];
11856893Sfenner	char numaddr[512];
11956893Sfenner
12056893Sfenner	if (sa == NULL)
12156893Sfenner		return ENI_NOSOCKET;
12256893Sfenner
12356893Sfenner#ifdef HAVE_SA_LEN	/*XXX*/
12456893Sfenner	if (sa->sa_len != salen)
12556893Sfenner		return ENI_SALEN;
12656893Sfenner#endif
127127668Sbms
12856893Sfenner	family = sa->sa_family;
12956893Sfenner	for (i = 0; afdl[i].a_af; i++)
13056893Sfenner		if (afdl[i].a_af == family) {
13156893Sfenner			afd = &afdl[i];
13256893Sfenner			goto found;
13356893Sfenner		}
13456893Sfenner	return ENI_FAMILY;
135127668Sbms
13656893Sfenner found:
13756893Sfenner	if (salen != afd->a_socklen)
13856893Sfenner		return ENI_SALEN;
139127668Sbms
14056893Sfenner	port = ((struct sockinet *)sa)->si_port; /* network byte order */
14156893Sfenner	addr = (char *)sa + afd->a_off;
14256893Sfenner
14356893Sfenner	if (serv == NULL || servlen == 0) {
14456893Sfenner		/*
14556893Sfenner		 * do nothing in this case.
14656893Sfenner		 * in case you are wondering if "&&" is more correct than
14756893Sfenner		 * "||" here: RFC2553 says that serv == NULL OR servlen == 0
14856893Sfenner		 * means that the caller does not want the result.
14956893Sfenner		 */
15056893Sfenner	} else {
15156893Sfenner		if (flags & NI_NUMERICSERV)
15256893Sfenner			sp = NULL;
15356893Sfenner		else {
15456893Sfenner			sp = getservbyport(port,
15556893Sfenner				(flags & NI_DGRAM) ? "udp" : "tcp");
15656893Sfenner		}
15756893Sfenner		if (sp) {
15875115Sfenner			if (strlen(sp->s_name) + 1 > servlen)
15956893Sfenner				return ENI_MEMORY;
16056893Sfenner			strcpy(serv, sp->s_name);
16156893Sfenner		} else {
16275115Sfenner			snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
16375115Sfenner			if (strlen(numserv) + 1 > servlen)
16456893Sfenner				return ENI_MEMORY;
16556893Sfenner			strcpy(serv, numserv);
16656893Sfenner		}
16756893Sfenner	}
16856893Sfenner
16956893Sfenner	switch (sa->sa_family) {
17056893Sfenner	case AF_INET:
17156893Sfenner		v4a = (u_int32_t)
17256893Sfenner			ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
17356893Sfenner		if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
17456893Sfenner			flags |= NI_NUMERICHOST;
17556893Sfenner		v4a >>= IN_CLASSA_NSHIFT;
17656893Sfenner		if (v4a == 0)
177127668Sbms			flags |= NI_NUMERICHOST;
17856893Sfenner		break;
17956893Sfenner#ifdef INET6
18056893Sfenner	case AF_INET6:
18156893Sfenner	    {
18256893Sfenner		struct sockaddr_in6 *sin6;
18356893Sfenner		sin6 = (struct sockaddr_in6 *)sa;
18456893Sfenner		switch (sin6->sin6_addr.s6_addr[0]) {
18556893Sfenner		case 0x00:
18656893Sfenner			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
18756893Sfenner				;
18856893Sfenner			else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
18956893Sfenner				;
19056893Sfenner			else
19156893Sfenner				flags |= NI_NUMERICHOST;
19256893Sfenner			break;
19356893Sfenner		default:
19456893Sfenner			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
19556893Sfenner				flags |= NI_NUMERICHOST;
19656893Sfenner			}
19756893Sfenner			else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
19856893Sfenner				flags |= NI_NUMERICHOST;
19956893Sfenner			break;
20056893Sfenner		}
20156893Sfenner	    }
20256893Sfenner		break;
20356893Sfenner#endif
20456893Sfenner	}
20556893Sfenner	if (host == NULL || hostlen == 0) {
20656893Sfenner		/*
20756893Sfenner		 * do nothing in this case.
20856893Sfenner		 * in case you are wondering if "&&" is more correct than
20956893Sfenner		 * "||" here: RFC2553 says that host == NULL OR hostlen == 0
21056893Sfenner		 * means that the caller does not want the result.
21156893Sfenner		 */
21256893Sfenner	} else if (flags & NI_NUMERICHOST) {
21356893Sfenner		/* NUMERICHOST and NAMEREQD conflicts with each other */
21456893Sfenner		if (flags & NI_NAMEREQD)
21556893Sfenner			return ENI_NOHOSTNAME;
21656893Sfenner		if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
21756893Sfenner		    == NULL)
21856893Sfenner			return ENI_SYSTEM;
21975115Sfenner		if (strlen(numaddr) + 1 > hostlen)
22056893Sfenner			return ENI_MEMORY;
22156893Sfenner		strcpy(host, numaddr);
22256893Sfenner#if defined(INET6) && defined(NI_WITHSCOPEID)
22356893Sfenner		if (afd->a_af == AF_INET6 &&
22456893Sfenner		    (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) ||
22556893Sfenner		     IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) &&
22656893Sfenner		    ((struct sockaddr_in6 *)sa)->sin6_scope_id) {
22756893Sfenner#ifndef ALWAYS_WITHSCOPE
22856893Sfenner			if (flags & NI_WITHSCOPEID)
22956893Sfenner#endif /* !ALWAYS_WITHSCOPE */
23056893Sfenner			{
23156893Sfenner				char *ep = strchr(host, '\0');
23256893Sfenner				unsigned int ifindex =
23356893Sfenner					((struct sockaddr_in6 *)sa)->sin6_scope_id;
23456893Sfenner
23556893Sfenner				*ep = SCOPE_DELIMITER;
23656893Sfenner				if ((if_indextoname(ifindex, ep + 1)) == NULL)
23756893Sfenner					/* XXX what should we do? */
23856893Sfenner					strncpy(ep + 1, "???", 3);
23956893Sfenner			}
24056893Sfenner		}
24156893Sfenner#endif /* INET6 */
24256893Sfenner	} else {
24356893Sfenner#ifdef USE_GETIPNODEBY
24456893Sfenner		hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
24556893Sfenner#else
24656893Sfenner		hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
24756893Sfenner#ifdef HAVE_H_ERRNO
24856893Sfenner		h_error = h_errno;
24956893Sfenner#else
25056893Sfenner		h_error = EINVAL;
25156893Sfenner#endif
25256893Sfenner#endif
25356893Sfenner
25456893Sfenner		if (hp) {
25556893Sfenner			if (flags & NI_NOFQDN) {
25656893Sfenner				p = strchr(hp->h_name, '.');
25756893Sfenner				if (p) *p = '\0';
25856893Sfenner			}
25975115Sfenner			if (strlen(hp->h_name) + 1 > hostlen) {
26056893Sfenner#ifdef USE_GETIPNODEBY
26156893Sfenner				freehostent(hp);
26256893Sfenner#endif
26356893Sfenner				return ENI_MEMORY;
26456893Sfenner			}
26556893Sfenner			strcpy(host, hp->h_name);
26656893Sfenner#ifdef USE_GETIPNODEBY
26756893Sfenner			freehostent(hp);
26856893Sfenner#endif
26956893Sfenner		} else {
27056893Sfenner			if (flags & NI_NAMEREQD)
27156893Sfenner				return ENI_NOHOSTNAME;
27256893Sfenner			if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
27356893Sfenner			    == NULL)
27456893Sfenner				return ENI_NOHOSTNAME;
27575115Sfenner			if (strlen(numaddr) + 1 > hostlen)
27656893Sfenner				return ENI_MEMORY;
27756893Sfenner			strcpy(host, numaddr);
27856893Sfenner		}
27956893Sfenner	}
28056893Sfenner	return SUCCESS;
28156893Sfenner}
282