1 /*
2 * Copyright (c) 2013, 2014
3 * Inferno Nettverk A/S, Norway. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. The above copyright notice, this list of conditions and the following
9 * disclaimer must appear in all copies of the software, derivative works
10 * or modified versions, and any portions thereof, aswell as in all
11 * supporting documentation.
12 * 2. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by
15 * Inferno Nettverk A/S, Norway.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Inferno Nettverk A/S requests users of this software to return to
31 *
32 * Software Distribution Coordinator or sdc@inet.no
33 * Inferno Nettverk A/S
34 * Oslo Research Park
35 * Gaustadall�en 21
36 * NO-0349 Oslo
37 * Norway
38 *
39 * any improvements or extensions that they make and grant Inferno Nettverk A/S
40 * the rights to redistribute these changes.
41 *
42 */
43
44 #include "common.h"
45
46 static const char rcsid[] =
47 "$Id: ipv6.c,v 1.6.4.5 2014/08/15 18:16:41 karls Exp $";
48
49 int
socks_inet_pton(af,src,dst,dstscope)50 socks_inet_pton(af, src, dst, dstscope)
51 const int af;
52 const void *src;
53 void *dst;
54 uint32_t *dstscope;
55 {
56 const char *function = "socks_inet_pton()";
57 dnsinfo_t resmem;
58 struct addrinfo *res, hints;
59 char visbuf[1024];
60 int rc;
61
62 if (strchr(src, '%') == NULL) /* no scope ids, can use inet_pton(). */
63 return inet_pton(af, src, dst);
64
65 bzero(&hints, sizeof(hints));
66 hints.ai_flags = AI_NUMERICHOST;
67 hints.ai_family = af;
68
69 if ((rc = cgetaddrinfo(src, NULL, &hints, &res, &resmem)) == 0) {
70 SASSERTX(res->ai_addr != NULL);
71
72 memcpy(dst, GET_SOCKADDRADDR(TOSS(res->ai_addr)), res->ai_addrlen);
73
74 switch (af) {
75 case AF_INET:
76 break;
77
78 case AF_INET6:
79 if (dstscope != NULL)
80 *dstscope = TOIN6(res->ai_addr)->sin6_scope_id;
81
82 break;
83
84 default:
85 SERRX(af);
86 }
87
88 return 1;
89 }
90
91 slog(LOG_DEBUG, "%s: getaddrinfo(3) on %s failed: %s",
92 function,
93 str2vis(src, strlen(src), visbuf, sizeof(visbuf)),
94 gai_strerror(rc));
95
96 if (rc == EAI_FAMILY) {
97 errno = EAFNOSUPPORT;
98 return -1;
99 }
100
101 return 0;
102 }
103
104 void
set_hints_ai_family(ai_family)105 set_hints_ai_family(ai_family)
106 int *ai_family;
107 {
108 #if !SOCKS_CLIENT
109 const char *function = "set_hints_ai_family";
110
111 if (external_has_only_safamily(AF_INET))
112 *ai_family = AF_INET;
113 else if (external_has_only_safamily(AF_INET6)
114 && external_has_global_safamily(AF_INET6))
115 *ai_family = AF_INET6;
116 else
117 /*
118 * else; have both ipv4 and ipv6 available (or none), so don't care
119 * what we are returned.
120 */
121 *ai_family = 0;
122
123 slog(LOG_DEBUG, "%s: ai_family = %d", function, *ai_family);
124 #endif /* !SOCKS_CLIENT */
125 }
126
127 #if !SOCKS_CLIENT
128 struct in_addr *
ipv4_mapped_to_regular(ipv4_mapped,ipv4_regular)129 ipv4_mapped_to_regular(ipv4_mapped, ipv4_regular)
130 const struct in6_addr *ipv4_mapped;
131 struct in_addr *ipv4_regular;
132 {
133 const char *function = "ipv4_mapped_to_regular";
134
135 memcpy(ipv4_regular,
136 &ipv4_mapped->s6_addr[sizeof(*ipv4_mapped) - sizeof(*ipv4_regular)],
137 sizeof(*ipv4_regular));
138
139 if (sockscf.option.debug) {
140 char mapped[MAX(INET6_ADDRSTRLEN, 32)], regular[MAX(INET_ADDRSTRLEN, 32)];
141
142 if (inet_ntop(AF_INET6, ipv4_mapped, mapped, sizeof(mapped)) == NULL)
143 STRCPY_ASSERTSIZE(mapped, "<nonsense address>");
144
145 if (inet_ntop(AF_INET, ipv4_regular, regular, sizeof(regular)) == NULL)
146 STRCPY_ASSERTSIZE(mapped, "<nonsense address>");
147
148 slog(LOG_DEBUG, "converted from %s to %s", mapped, regular);
149 }
150
151 return ipv4_regular;
152 }
153
154 #endif /* !SOCKS_CLIENT */
155
156
157 #undef gai_strerror
158 const char *
socks_gai_strerror(errcode)159 socks_gai_strerror(errcode)
160 int errcode;
161 {
162 static char emsg[1024];
163
164 #if !SOCKS_CLIENT
165 int isaflimit = 0, hasaf = 0;
166
167 switch (errcode) {
168 case EAI_FAMILY:
169 case EAI_FAIL:
170 case EAI_NONAME:
171 #ifdef EAI_NODATA
172 case EAI_NODATA:
173 #endif
174 if (external_has_only_safamily(AF_INET)) {
175 isaflimit = 1;
176 hasaf = AF_INET;
177 }
178 else if (external_has_only_safamily(AF_INET6)) {
179 isaflimit = 1;
180 hasaf = AF_INET6;
181 }
182 break;
183
184 default:
185 break;
186 }
187
188 snprintf(emsg, sizeof(emsg), "%s%s%s",
189 gai_strerror(errcode),
190 isaflimit ? " for " : "",
191 isaflimit ? safamily2string(hasaf) : "");
192
193 #else /* SOCKS_CLIENT */
194
195 snprintf(emsg, sizeof(emsg), "%s", gai_strerror(errcode));
196
197 #endif /* SOCKS_CLIENT */
198
199
200 return emsg;
201 }
202