Home | History | Annotate | Download | only in in.ftpd
      1 /*
      2  * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      7 
      8 /*
      9  * Utility functions which help with address and hostname manipulation in a
     10  * mixed IPv4 / IPv6 environment.
     11  */
     12 
     13 #include "config.h"
     14 #include <sys/socket.h>
     15 #include <netinet/in.h>
     16 #include <arpa/inet.h>
     17 #include <netdb.h>
     18 #include <string.h>
     19 #include "proto.h"
     20 
     21 #ifndef MAXHOSTNAMELEN
     22 #define MAXHOSTNAMELEN 64
     23 #endif
     24 
     25 /* Converts a hostname into an IP address in presentation form */
     26 char *inet_htop(const char *hostname)
     27 {
     28 #ifdef INET6
     29     static char abuf[INET6_ADDRSTRLEN];
     30     struct addrinfo hints, *result;
     31     char *str = NULL;
     32     void *addr = NULL;
     33 
     34     memset(&hints, 0, sizeof(hints));
     35     hints.ai_flags = AI_CANONNAME;
     36     hints.ai_family = PF_UNSPEC;
     37 
     38     if (getaddrinfo(hostname, NULL, &hints, &result) == 0) {
     39 	if (result->ai_family == AF_INET)
     40 	    addr = ((void *)&((struct sockaddr_in *)result->ai_addr)->sin_addr);
     41 	else if (result->ai_family == AF_INET6)
     42 	    addr = ((void *)&((struct sockaddr_in6 *)result->ai_addr)->sin6_addr);
     43 	if (addr)
     44 	    str = (char *)inet_ntop_native(result->ai_family, addr, abuf,
     45 					   sizeof(abuf));
     46 	freeaddrinfo(result);
     47 	return str;
     48     }
     49 #else
     50     struct hostent *hp;
     51     struct in_addr in;
     52 
     53     if ((hp = gethostbyname(hostname)) != NULL) {
     54 	memcpy(&in, hp->h_addr, sizeof(in));
     55 	return inet_ntoa(in);
     56     }
     57 #endif
     58     return NULL;
     59 }
     60 
     61 /*
     62  * Converts a socket structures IP address into presentation form.
     63  * Note: returns a pointer to a buffer which is overwritten on each call.
     64  */
     65 char *inet_stop(struct SOCKSTORAGE *ss)
     66 {
     67 #ifdef INET6
     68     static char abuf[INET6_ADDRSTRLEN];
     69     struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss;
     70 
     71     if (ss->ss_family == AF_INET6)
     72         return (char *)inet_ntop_native(AF_INET6, &sin6->sin6_addr, abuf, sizeof (abuf));
     73 #endif
     74     return inet_ntoa(((struct sockaddr_in *)ss)->sin_addr);
     75 }
     76 
     77 char *wu_gethostbyname(const char *hostname)
     78 {
     79 #ifdef INET6
     80     static char hostbuf[MAXHOSTNAMELEN];
     81     struct addrinfo hints, *result;
     82 
     83     memset(&hints, 0, sizeof(hints));
     84     hints.ai_flags = AI_CANONNAME;
     85     hints.ai_family = PF_UNSPEC;
     86 
     87     if (getaddrinfo(hostname, NULL, &hints, &result) == 0) {
     88 	strncpy(hostbuf, result->ai_canonname, sizeof(hostbuf));
     89 	hostbuf[sizeof(hostbuf) - 1] = '\0';
     90 	freeaddrinfo(result);
     91 	return hostbuf;
     92     }
     93 #else
     94     struct hostent *hp = gethostbyname(hostname);
     95 
     96     if (hp)
     97 	return hp->h_name;
     98 #endif
     99     return NULL;
    100 }
    101 
    102 int wu_gethostbyaddr(struct SOCKSTORAGE *ss, char *hostname, int hostlen)
    103 {
    104 #ifdef INET6
    105     char hostbuf[NI_MAXHOST];
    106 #else
    107     struct hostent *hp;
    108 #endif
    109 
    110     if ((ss == NULL) || (hostname == NULL) || (hostlen < 1))
    111 	return 0;
    112 
    113 #ifdef INET6
    114     if (getnameinfo((struct sockaddr *)ss, SOCK_LEN(*ss), hostbuf,
    115 		    sizeof(hostbuf), NULL, 0, NI_NAMEREQD) == 0) {
    116 	strncpy(hostname, hostbuf, hostlen);
    117 	hostname[hostlen - 1] = '\0';
    118 	return 1;
    119     }
    120 #else
    121     hp = gethostbyaddr((char *)&ss->sin_addr, sizeof(struct in_addr), AF_INET);
    122     if (hp) {
    123 	strncpy(hostname, hp->h_name, hostlen);
    124 	hostname[hostlen - 1] = '\0';
    125 	return 1;
    126     }
    127 #endif
    128     return 0;
    129 }
    130 
    131 /* Compares a socket structures IP address with addr, returning 0 on a match */
    132 int sock_cmp_inaddr(struct SOCKSTORAGE *ss, struct in_addr addr) {
    133 #ifdef INET6
    134     if (ss->ss_family == AF_INET6) {
    135 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss;
    136 
    137 	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
    138 	    u_char *a = (u_char *)&sin6->sin6_addr;
    139 
    140 	    /* compare the IPv4 part of an IPv4-mapped IPv6 address */
    141 	    return memcmp(&addr, a + sizeof(struct in6_addr) - sizeof(struct in_addr), sizeof(struct in_addr));
    142 	}
    143 	return 1;
    144     }
    145 #endif
    146     return ((struct sockaddr_in *)ss)->sin_addr.s_addr != addr.s_addr;
    147 }
    148 
    149 #ifdef INET6
    150 /* Sets a socket structures IP address to addr */
    151 void sock_set_inaddr(struct SOCKSTORAGE *ss, struct in_addr addr) {
    152     if (ss->ss_family == AF_INET6) {
    153 	struct in6_addr *in6;
    154 
    155 	in6 = &((struct sockaddr_in6 *)ss)->sin6_addr;
    156 	memset(&in6->s6_addr[0], 0, 10);
    157 	memset(&in6->s6_addr[10], 0xff, 2);
    158 	memcpy(&in6->s6_addr[12], &addr, sizeof(struct in_addr));
    159 	return;
    160     }
    161     ((struct sockaddr_in *)ss)->sin_addr = addr;
    162 }
    163 
    164 /* Compares two socket structure IP addresses, returning 0 if they match */
    165 int sock_cmp_addr(struct SOCKSTORAGE *ss1, struct SOCKSTORAGE *ss2) {
    166     if (ss1->ss_family == AF_INET6) {
    167 	if (ss2->ss_family == AF_INET6)
    168 	    return memcmp(&((struct sockaddr_in6 *)ss1)->sin6_addr,
    169 			  &((struct sockaddr_in6 *)ss2)->sin6_addr,
    170 			  sizeof(struct in6_addr));
    171 	return sock_cmp_inaddr(ss1, ((struct sockaddr_in *)ss2)->sin_addr);
    172     }
    173     return sock_cmp_inaddr(ss2, ((struct sockaddr_in *)ss1)->sin_addr);
    174 }
    175 
    176 void sock_set_scope(struct SOCKSTORAGE *dst, struct SOCKSTORAGE *src) {
    177 #ifdef HAVE_SIN6_SCOPE_ID
    178     struct sockaddr_in6 *src_in6 = (struct sockaddr_in6 *)src;
    179     struct sockaddr_in6 *dst_in6 = (struct sockaddr_in6 *)dst;
    180 
    181     if (dst->ss_family == AF_INET6) {
    182 	if ((src->ss_family == AF_INET6) &&
    183 	    (memcmp(&src_in6->sin6_addr, &dst_in6->sin6_addr,
    184 		    sizeof(struct in6_addr)) == 0))
    185 	    dst_in6->sin6_scope_id = src_in6->sin6_scope_id;
    186 	else
    187 	    dst_in6->sin6_scope_id = 0;
    188     }
    189 #endif
    190 }
    191 
    192 /*
    193  * Similar to inet_pton(), str can be an IPv4 or IPv6 address, but an IPv6
    194  * address is returned in addr.
    195  */
    196 int inet_pton6(char *str, struct in6_addr *addr)
    197 {
    198     struct in_addr v4addr;
    199 
    200     /* Try v6 first */
    201     if (inet_pton(AF_INET6, str, addr) != 1) {
    202 	/* If that fails, try v4 and map it */
    203 	if (inet_pton(AF_INET, str, &v4addr) == 1) {
    204 	    memset(&addr->s6_addr[0], 0, 10);
    205 	    memset(&addr->s6_addr[10], 0xff, 2);
    206 	    memcpy(&addr->s6_addr[12], &v4addr, sizeof(struct in_addr));
    207 	}
    208 	else
    209 	    return 0;
    210     }
    211     return 1;
    212 }
    213 
    214 /*
    215  * Similar to inet_ntop(), except when addr is an IPv4-mapped IPv6 address
    216  * returns a printable IPv4 address (not an IPv4-mapped IPv6 address).
    217  */
    218 const char *inet_ntop_native(int af, const void *addr, char *dst, size_t size)
    219 {
    220     const char *result;
    221 
    222     if (af == AF_INET6) {
    223 	if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr))
    224 	    result = inet_ntop(AF_INET, (char *)addr + sizeof(struct in6_addr)
    225 			       - sizeof(struct in_addr), dst, size);
    226 	else
    227 	    result = inet_ntop(AF_INET6, addr, dst, size);
    228     }
    229     else
    230 	result = inet_ntop(af, addr, dst, size);
    231     return result;
    232 }
    233 #endif /* INET6 */
    234