xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/inet.c (revision 0:68f95e015346)
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 */
inet_htop(const char * hostname)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  */
inet_stop(struct SOCKSTORAGE * ss)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 
wu_gethostbyname(const char * hostname)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 
wu_gethostbyaddr(struct SOCKSTORAGE * ss,char * hostname,int hostlen)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 */
sock_cmp_inaddr(struct SOCKSTORAGE * ss,struct in_addr addr)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 */
sock_set_inaddr(struct SOCKSTORAGE * ss,struct in_addr 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 */
sock_cmp_addr(struct SOCKSTORAGE * ss1,struct SOCKSTORAGE * ss2)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 
sock_set_scope(struct SOCKSTORAGE * dst,struct SOCKSTORAGE * src)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  */
inet_pton6(char * str,struct in6_addr * addr)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  */
inet_ntop_native(int af,const void * addr,char * dst,size_t size)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