Home | History | Annotate | Line # | Download | only in net
getnameinfo.c revision 1.4.4.1
      1  1.4.4.1  wrstuden /*	$NetBSD: getnameinfo.c,v 1.4.4.1 1999/12/27 18:29:42 wrstuden Exp $	*/
      2      1.2    itojun 
      3      1.1    itojun /*
      4      1.1    itojun  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
      5      1.1    itojun  * All rights reserved.
      6      1.1    itojun  *
      7      1.1    itojun  * Redistribution and use in source and binary forms, with or without
      8      1.1    itojun  * modification, are permitted provided that the following conditions
      9      1.1    itojun  * are met:
     10      1.1    itojun  * 1. Redistributions of source code must retain the above copyright
     11      1.1    itojun  *    notice, this list of conditions and the following disclaimer.
     12      1.1    itojun  * 2. Redistributions in binary form must reproduce the above copyright
     13      1.1    itojun  *    notice, this list of conditions and the following disclaimer in the
     14      1.1    itojun  *    documentation and/or other materials provided with the distribution.
     15      1.1    itojun  * 3. Neither the name of the project nor the names of its contributors
     16      1.1    itojun  *    may be used to endorse or promote products derived from this software
     17      1.1    itojun  *    without specific prior written permission.
     18      1.1    itojun  *
     19      1.1    itojun  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     20      1.1    itojun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21      1.1    itojun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22      1.1    itojun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     23      1.1    itojun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24      1.1    itojun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25      1.1    itojun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26      1.1    itojun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27      1.1    itojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28      1.1    itojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29      1.1    itojun  * SUCH DAMAGE.
     30      1.1    itojun  */
     31      1.1    itojun 
     32      1.1    itojun /*
     33      1.1    itojun  * Issues to be discussed:
     34      1.1    itojun  * - Thread safe-ness must be checked
     35  1.4.4.1  wrstuden  * - Return values.  There seems to be no standard for return value (RFC2553)
     36      1.1    itojun  *   but INRIA implementation returns EAI_xxx defined for getaddrinfo().
     37  1.4.4.1  wrstuden  * - RFC2553 says that we should raise error on short buffer.  X/Open says
     38  1.4.4.1  wrstuden  *   we need to truncate the result.  We obey RFC2553 (and X/Open should be
     39  1.4.4.1  wrstuden  *   modified).
     40      1.1    itojun  */
     41      1.1    itojun 
     42  1.4.4.1  wrstuden #if 0
     43  1.4.4.1  wrstuden #ifdef HAVE_CONFIG_H
     44  1.4.4.1  wrstuden #include "config.h"
     45  1.4.4.1  wrstuden #endif
     46  1.4.4.1  wrstuden #else
     47  1.4.4.1  wrstuden #define HAVE_SA_LEN
     48  1.4.4.1  wrstuden #endif
     49  1.4.4.1  wrstuden 
     50      1.1    itojun #include <sys/types.h>
     51      1.1    itojun #include <sys/socket.h>
     52  1.4.4.1  wrstuden #include <net/if.h>
     53      1.1    itojun #include <netinet/in.h>
     54      1.1    itojun #include <arpa/inet.h>
     55      1.1    itojun #include <arpa/nameser.h>
     56      1.1    itojun #include <netdb.h>
     57      1.1    itojun #include <resolv.h>
     58      1.1    itojun #include <string.h>
     59      1.1    itojun #include <stddef.h>
     60      1.1    itojun 
     61  1.4.4.1  wrstuden #if 0
     62  1.4.4.1  wrstuden #ifndef HAVE_PORTABLE_PROTOTYPE
     63  1.4.4.1  wrstuden #include "cdecl_ext.h"
     64  1.4.4.1  wrstuden #endif
     65  1.4.4.1  wrstuden 
     66  1.4.4.1  wrstuden #ifndef HAVE_ADDRINFO
     67  1.4.4.1  wrstuden #include "addrinfo.h"
     68  1.4.4.1  wrstuden #endif
     69  1.4.4.1  wrstuden #endif
     70  1.4.4.1  wrstuden 
     71      1.1    itojun #define SUCCESS 0
     72      1.1    itojun #define ANY 0
     73      1.1    itojun #define YES 1
     74      1.1    itojun #define NO  0
     75      1.1    itojun 
     76      1.1    itojun static struct afd {
     77      1.1    itojun 	int a_af;
     78      1.1    itojun 	int a_addrlen;
     79      1.1    itojun 	int a_socklen;
     80      1.1    itojun 	int a_off;
     81      1.1    itojun } afdl [] = {
     82      1.1    itojun #ifdef INET6
     83      1.1    itojun 	{PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
     84      1.1    itojun 		offsetof(struct sockaddr_in6, sin6_addr)},
     85      1.1    itojun #endif
     86      1.1    itojun 	{PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
     87      1.1    itojun 		offsetof(struct sockaddr_in, sin_addr)},
     88      1.1    itojun 	{0, 0, 0},
     89      1.1    itojun };
     90      1.1    itojun 
     91      1.1    itojun struct sockinet {
     92      1.1    itojun 	u_char	si_len;
     93      1.1    itojun 	u_char	si_family;
     94      1.1    itojun 	u_short	si_port;
     95      1.1    itojun };
     96      1.1    itojun 
     97      1.1    itojun #define ENI_NOSOCKET 	0
     98      1.1    itojun #define ENI_NOSERVNAME	1
     99      1.1    itojun #define ENI_NOHOSTNAME	2
    100      1.1    itojun #define ENI_MEMORY	3
    101      1.1    itojun #define ENI_SYSTEM	4
    102      1.1    itojun #define ENI_FAMILY	5
    103      1.1    itojun #define ENI_SALEN	6
    104      1.1    itojun 
    105      1.1    itojun int
    106      1.1    itojun getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
    107      1.1    itojun 	const struct sockaddr *sa;
    108      1.1    itojun 	size_t salen;
    109      1.1    itojun 	char *host;
    110      1.1    itojun 	size_t hostlen;
    111      1.1    itojun 	char *serv;
    112      1.1    itojun 	size_t servlen;
    113      1.1    itojun 	int flags;
    114      1.1    itojun {
    115      1.1    itojun 	struct afd *afd;
    116      1.1    itojun 	struct servent *sp;
    117      1.1    itojun 	struct hostent *hp;
    118      1.1    itojun 	u_short port;
    119  1.4.4.1  wrstuden 	int family, i;
    120      1.1    itojun 	char *addr, *p;
    121  1.4.4.1  wrstuden 	u_int32_t v4a;
    122      1.1    itojun 	int h_error;
    123      1.1    itojun 	char numserv[512];
    124      1.1    itojun 	char numaddr[512];
    125      1.1    itojun 
    126      1.1    itojun 	if (sa == NULL)
    127      1.1    itojun 		return ENI_NOSOCKET;
    128      1.1    itojun 
    129  1.4.4.1  wrstuden #ifdef HAVE_SA_LEN
    130  1.4.4.1  wrstuden 	if (sa->sa_len != salen)
    131  1.4.4.1  wrstuden 		return ENI_SALEN;
    132  1.4.4.1  wrstuden #endif
    133      1.1    itojun 
    134      1.1    itojun 	family = sa->sa_family;
    135      1.1    itojun 	for (i = 0; afdl[i].a_af; i++)
    136      1.1    itojun 		if (afdl[i].a_af == family) {
    137      1.1    itojun 			afd = &afdl[i];
    138      1.1    itojun 			goto found;
    139      1.1    itojun 		}
    140      1.1    itojun 	return ENI_FAMILY;
    141      1.1    itojun 
    142      1.1    itojun  found:
    143  1.4.4.1  wrstuden 	if (salen != afd->a_socklen)
    144  1.4.4.1  wrstuden 		return ENI_SALEN;
    145      1.1    itojun 
    146      1.1    itojun 	port = ((struct sockinet *)sa)->si_port; /* network byte order */
    147      1.1    itojun 	addr = (char *)sa + afd->a_off;
    148      1.1    itojun 
    149      1.1    itojun 	if (serv == NULL || servlen == 0) {
    150  1.4.4.1  wrstuden 		/*
    151  1.4.4.1  wrstuden 		 * do nothing in this case.
    152  1.4.4.1  wrstuden 		 * in case you are wondering if "&&" is more correct than
    153  1.4.4.1  wrstuden 		 * "||" here: RFC2553 says that serv == NULL OR servlen == 0
    154  1.4.4.1  wrstuden 		 * means that the caller does not want the result.
    155  1.4.4.1  wrstuden 		 */
    156      1.1    itojun 	} else {
    157  1.4.4.1  wrstuden 		if (flags & NI_NUMERICSERV)
    158  1.4.4.1  wrstuden 			sp = NULL;
    159  1.4.4.1  wrstuden 		else {
    160  1.4.4.1  wrstuden 			sp = getservbyport(port,
    161  1.4.4.1  wrstuden 				(flags & NI_DGRAM) ? "udp" : "tcp");
    162  1.4.4.1  wrstuden 		}
    163      1.1    itojun 		if (sp) {
    164      1.1    itojun 			if (strlen(sp->s_name) > servlen)
    165      1.1    itojun 				return ENI_MEMORY;
    166      1.1    itojun 			strcpy(serv, sp->s_name);
    167  1.4.4.1  wrstuden 		} else {
    168  1.4.4.1  wrstuden 			snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
    169  1.4.4.1  wrstuden 			if (strlen(numserv) > servlen)
    170  1.4.4.1  wrstuden 				return ENI_MEMORY;
    171  1.4.4.1  wrstuden 			strcpy(serv, numserv);
    172  1.4.4.1  wrstuden 		}
    173      1.1    itojun 	}
    174      1.1    itojun 
    175      1.1    itojun 	switch (sa->sa_family) {
    176      1.1    itojun 	case AF_INET:
    177  1.4.4.1  wrstuden 		v4a = (u_int32_t)
    178  1.4.4.1  wrstuden 			ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
    179      1.1    itojun 		if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
    180      1.1    itojun 			flags |= NI_NUMERICHOST;
    181      1.1    itojun 		v4a >>= IN_CLASSA_NSHIFT;
    182      1.1    itojun 		if (v4a == 0 || v4a == IN_LOOPBACKNET)
    183      1.1    itojun 			flags |= NI_NUMERICHOST;
    184      1.1    itojun 		break;
    185      1.1    itojun #ifdef INET6
    186      1.1    itojun 	case AF_INET6:
    187      1.3    itojun 	    {
    188      1.3    itojun 		struct sockaddr_in6 *sin6;
    189      1.3    itojun 		sin6 = (struct sockaddr_in6 *)sa;
    190  1.4.4.1  wrstuden 		switch (sin6->sin6_addr.s6_addr[0]) {
    191      1.3    itojun 		case 0x00:
    192      1.3    itojun 			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
    193      1.3    itojun 				;
    194      1.3    itojun 			else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
    195      1.3    itojun 				;
    196      1.3    itojun 			else
    197      1.3    itojun 				flags |= NI_NUMERICHOST;
    198      1.3    itojun 			break;
    199      1.3    itojun 		default:
    200  1.4.4.1  wrstuden 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
    201      1.3    itojun 				flags |= NI_NUMERICHOST;
    202  1.4.4.1  wrstuden 			}
    203      1.3    itojun 			else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
    204      1.3    itojun 				flags |= NI_NUMERICHOST;
    205      1.3    itojun 			break;
    206      1.3    itojun 		}
    207      1.3    itojun 	    }
    208      1.1    itojun 		break;
    209      1.1    itojun #endif
    210      1.1    itojun 	}
    211      1.1    itojun 	if (host == NULL || hostlen == 0) {
    212  1.4.4.1  wrstuden 		/*
    213  1.4.4.1  wrstuden 		 * do nothing in this case.
    214  1.4.4.1  wrstuden 		 * in case you are wondering if "&&" is more correct than
    215  1.4.4.1  wrstuden 		 * "||" here: RFC2553 says that host == NULL OR hostlen == 0
    216  1.4.4.1  wrstuden 		 * means that the caller does not want the result.
    217  1.4.4.1  wrstuden 		 */
    218      1.1    itojun 	} else if (flags & NI_NUMERICHOST) {
    219      1.3    itojun 		/* NUMERICHOST and NAMEREQD conflicts with each other */
    220      1.3    itojun 		if (flags & NI_NAMEREQD)
    221      1.3    itojun 			return ENI_NOHOSTNAME;
    222      1.1    itojun 		if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
    223      1.1    itojun 		    == NULL)
    224      1.1    itojun 			return ENI_SYSTEM;
    225      1.1    itojun 		if (strlen(numaddr) > hostlen)
    226      1.1    itojun 			return ENI_MEMORY;
    227      1.1    itojun 		strcpy(host, numaddr);
    228  1.4.4.1  wrstuden #if defined(INET6) && defined(NI_WITHSCOPEID)
    229  1.4.4.1  wrstuden 		if (afd->a_af == AF_INET6 &&
    230  1.4.4.1  wrstuden 		    (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) ||
    231  1.4.4.1  wrstuden 		     IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) &&
    232  1.4.4.1  wrstuden 		    ((struct sockaddr_in6 *)sa)->sin6_scope_id) {
    233  1.4.4.1  wrstuden #ifndef ALWAYS_WITHSCOPE
    234  1.4.4.1  wrstuden 			if (flags & NI_WITHSCOPEID)
    235  1.4.4.1  wrstuden #endif /* !ALWAYS_WITHSCOPE */
    236  1.4.4.1  wrstuden 			{
    237  1.4.4.1  wrstuden 				char *ep = strchr(host, '\0');
    238  1.4.4.1  wrstuden 				unsigned int ifindex =
    239  1.4.4.1  wrstuden 					((struct sockaddr_in6 *)sa)->sin6_scope_id;
    240  1.4.4.1  wrstuden 
    241  1.4.4.1  wrstuden 				*ep = SCOPE_DELIMITER;
    242  1.4.4.1  wrstuden 				if ((if_indextoname(ifindex, ep + 1)) == NULL)
    243  1.4.4.1  wrstuden 					/* XXX what should we do? */
    244  1.4.4.1  wrstuden 					strncpy(ep + 1, "???", 3);
    245  1.4.4.1  wrstuden 			}
    246  1.4.4.1  wrstuden 		}
    247  1.4.4.1  wrstuden #endif /* INET6 */
    248      1.1    itojun 	} else {
    249      1.1    itojun #ifdef USE_GETIPNODEBY
    250      1.1    itojun 		hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
    251      1.1    itojun #else
    252      1.1    itojun 		hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
    253      1.1    itojun 		h_error = h_errno;
    254      1.1    itojun #endif
    255      1.1    itojun 
    256      1.1    itojun 		if (hp) {
    257      1.1    itojun 			if (flags & NI_NOFQDN) {
    258      1.1    itojun 				p = strchr(hp->h_name, '.');
    259      1.1    itojun 				if (p) *p = '\0';
    260      1.1    itojun 			}
    261      1.1    itojun 			if (strlen(hp->h_name) > hostlen) {
    262      1.1    itojun #ifdef USE_GETIPNODEBY
    263      1.1    itojun 				freehostent(hp);
    264      1.1    itojun #endif
    265      1.1    itojun 				return ENI_MEMORY;
    266      1.1    itojun 			}
    267      1.1    itojun 			strcpy(host, hp->h_name);
    268      1.1    itojun #ifdef USE_GETIPNODEBY
    269      1.1    itojun 			freehostent(hp);
    270      1.1    itojun #endif
    271      1.1    itojun 		} else {
    272      1.1    itojun 			if (flags & NI_NAMEREQD)
    273      1.1    itojun 				return ENI_NOHOSTNAME;
    274      1.1    itojun 			if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
    275      1.1    itojun 			    == NULL)
    276      1.1    itojun 				return ENI_NOHOSTNAME;
    277      1.1    itojun 			if (strlen(numaddr) > hostlen)
    278      1.1    itojun 				return ENI_MEMORY;
    279      1.1    itojun 			strcpy(host, numaddr);
    280      1.1    itojun 		}
    281      1.1    itojun 	}
    282      1.1    itojun 	return SUCCESS;
    283      1.1    itojun }
    284