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