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