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