blob: ce38ea117b70c45a8c007f0dfd8f0f93d69bd121 [file] [log] [blame]
Kristian Monsen5ab50182010-05-14 18:53:44 +01001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
Elliott Hughes82be86d2017-09-20 17:00:17 -07008 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
Kristian Monsen5ab50182010-05-14 18:53:44 +01009 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
Alex Deymo8f1a2142016-06-28 14:49:26 -070012 * are also available at https://curl.haxx.se/docs/copyright.html.
Kristian Monsen5ab50182010-05-14 18:53:44 +010013 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070023#include "curl_setup.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010024
Kristian Monsen5ab50182010-05-14 18:53:44 +010025#ifdef HAVE_NETINET_IN_H
26# include <netinet/in.h>
27#endif
28#ifdef HAVE_ARPA_INET_H
29# include <arpa/inet.h>
30#endif
31#ifdef HAVE_NET_IF_H
32# include <net/if.h>
33#endif
34#ifdef HAVE_SYS_IOCTL_H
35# include <sys/ioctl.h>
36#endif
37#ifdef HAVE_NETDB_H
38# include <netdb.h>
39#endif
40#ifdef HAVE_SYS_SOCKIO_H
41# include <sys/sockio.h>
42#endif
43#ifdef HAVE_IFADDRS_H
44# include <ifaddrs.h>
45#endif
46#ifdef HAVE_STROPTS_H
47# include <stropts.h>
48#endif
49#ifdef __VMS
50# include <inet.h>
51#endif
52
53#include "inet_ntop.h"
Elliott Hughescee03382017-06-23 12:17:18 -070054#include "strcase.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010055#include "if2ip.h"
Alex Deymo8f1a2142016-06-28 14:49:26 -070056/* The last 3 #include files should be in this order */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070057#include "curl_printf.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010058#include "curl_memory.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010059#include "memdebug.h"
60
61/* ------------------------------------------------------------------ */
62
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070063/* Return the scope of the given address. */
64unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
65{
66#ifndef ENABLE_IPV6
67 (void) sa;
68#else
69 if(sa->sa_family == AF_INET6) {
Alex Deymo8f1a2142016-06-28 14:49:26 -070070 const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa;
Elliott Hughescee03382017-06-23 12:17:18 -070071 const unsigned char *b = sa6->sin6_addr.s6_addr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070072 unsigned short w = (unsigned short) ((b[0] << 8) | b[1]);
73
Elliott Hughes82be86d2017-09-20 17:00:17 -070074 if((b[0] & 0xFE) == 0xFC) /* Handle ULAs */
75 return IPV6_SCOPE_UNIQUELOCAL;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070076 switch(w & 0xFFC0) {
77 case 0xFE80:
78 return IPV6_SCOPE_LINKLOCAL;
79 case 0xFEC0:
80 return IPV6_SCOPE_SITELOCAL;
81 case 0x0000:
82 w = b[1] | b[2] | b[3] | b[4] | b[5] | b[6] | b[7] | b[8] | b[9] |
83 b[10] | b[11] | b[12] | b[13] | b[14];
84 if(w || b[15] != 0x01)
85 break;
86 return IPV6_SCOPE_NODELOCAL;
87 default:
88 break;
89 }
90 }
91#endif
92
93 return IPV6_SCOPE_GLOBAL;
94}
95
96
Kristian Monsen5ab50182010-05-14 18:53:44 +010097#if defined(HAVE_GETIFADDRS)
98
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070099bool Curl_if_is_interface_name(const char *interf)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100100{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700101 bool result = FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100102
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700103 struct ifaddrs *iface, *head;
104
105 if(getifaddrs(&head) >= 0) {
Alex Deymo486467e2017-12-19 19:04:07 +0100106 for(iface = head; iface != NULL; iface = iface->ifa_next) {
Elliott Hughescee03382017-06-23 12:17:18 -0700107 if(strcasecompare(iface->ifa_name, interf)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700108 result = TRUE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100109 break;
110 }
111 }
112 freeifaddrs(head);
113 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700114 return result;
115}
116
117if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
118 unsigned int remote_scope_id, const char *interf,
119 char *buf, int buf_size)
120{
121 struct ifaddrs *iface, *head;
122 if2ip_result_t res = IF2IP_NOT_FOUND;
123
124#ifndef ENABLE_IPV6
125 (void) remote_scope;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700126#endif
127
Elliott Hughes82be86d2017-09-20 17:00:17 -0700128#if !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) || \
129 !defined(ENABLE_IPV6)
130 (void) remote_scope_id;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700131#endif
132
133 if(getifaddrs(&head) >= 0) {
Alex Deymo486467e2017-12-19 19:04:07 +0100134 for(iface = head; iface != NULL; iface = iface->ifa_next) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700135 if(iface->ifa_addr != NULL) {
136 if(iface->ifa_addr->sa_family == af) {
Elliott Hughescee03382017-06-23 12:17:18 -0700137 if(strcasecompare(iface->ifa_name, interf)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700138 void *addr;
139 char *ip;
140 char scope[12] = "";
141 char ipstr[64];
142#ifdef ENABLE_IPV6
143 if(af == AF_INET6) {
144 unsigned int scopeid = 0;
145 unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr);
146
147 if(ifscope != remote_scope) {
148 /* We are interested only in interface addresses whose
149 scope matches the remote address we want to
150 connect to: global for global, link-local for
151 link-local, etc... */
152 if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED;
153 continue;
154 }
155
Alex Deymo8f1a2142016-06-28 14:49:26 -0700156 addr =
157 &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700158#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
159 /* Include the scope of this interface as part of the address */
Alex Deymo8f1a2142016-06-28 14:49:26 -0700160 scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr)
161 ->sin6_scope_id;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700162
163 /* If given, scope id should match. */
164 if(remote_scope_id && scopeid != remote_scope_id) {
165 if(res == IF2IP_NOT_FOUND)
166 res = IF2IP_AF_NOT_SUPPORTED;
167
168 continue;
169 }
170#endif
171 if(scopeid)
172 snprintf(scope, sizeof(scope), "%%%u", scopeid);
173 }
174 else
175#endif
Alex Deymo8f1a2142016-06-28 14:49:26 -0700176 addr =
177 &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700178 res = IF2IP_FOUND;
179 ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
180 snprintf(buf, buf_size, "%s%s", ip, scope);
181 break;
182 }
183 }
184 else if((res == IF2IP_NOT_FOUND) &&
Elliott Hughescee03382017-06-23 12:17:18 -0700185 strcasecompare(iface->ifa_name, interf)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700186 res = IF2IP_AF_NOT_SUPPORTED;
187 }
188 }
189 }
190
191 freeifaddrs(head);
192 }
193
194 return res;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100195}
196
197#elif defined(HAVE_IOCTL_SIOCGIFADDR)
198
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700199bool Curl_if_is_interface_name(const char *interf)
200{
201 /* This is here just to support the old interfaces */
202 char buf[256];
203
204 return (Curl_if2ip(AF_INET, 0 /* unused */, 0, interf, buf, sizeof(buf)) ==
205 IF2IP_NOT_FOUND) ? FALSE : TRUE;
206}
207
208if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
209 unsigned int remote_scope_id, const char *interf,
210 char *buf, int buf_size)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100211{
212 struct ifreq req;
213 struct in_addr in;
214 struct sockaddr_in *s;
215 curl_socket_t dummy;
216 size_t len;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100217
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700218 (void)remote_scope;
219 (void)remote_scope_id;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100220
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700221 if(!interf || (af != AF_INET))
222 return IF2IP_NOT_FOUND;
223
224 len = strlen(interf);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100225 if(len >= sizeof(req.ifr_name))
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700226 return IF2IP_NOT_FOUND;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100227
228 dummy = socket(AF_INET, SOCK_STREAM, 0);
229 if(CURL_SOCKET_BAD == dummy)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700230 return IF2IP_NOT_FOUND;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100231
232 memset(&req, 0, sizeof(req));
Alex Deymo486467e2017-12-19 19:04:07 +0100233 memcpy(req.ifr_name, interf, len + 1);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100234 req.ifr_addr.sa_family = AF_INET;
235
236 if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
237 sclose(dummy);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700238 /* With SIOCGIFADDR, we cannot tell the difference between an interface
239 that does not exist and an interface that has no address of the
240 correct family. Assume the interface does not exist */
241 return IF2IP_NOT_FOUND;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100242 }
243
Elliott Hughes82be86d2017-09-20 17:00:17 -0700244 s = (struct sockaddr_in *)(void *)&req.ifr_addr;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100245 memcpy(&in, &s->sin_addr, sizeof(in));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700246 Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100247
248 sclose(dummy);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700249 return IF2IP_FOUND;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100250}
251
252#else
253
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700254bool Curl_if_is_interface_name(const char *interf)
255{
256 (void) interf;
257
258 return FALSE;
259}
260
261if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
262 unsigned int remote_scope_id, const char *interf,
263 char *buf, int buf_size)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100264{
265 (void) af;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700266 (void) remote_scope;
267 (void) remote_scope_id;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100268 (void) interf;
269 (void) buf;
270 (void) buf_size;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700271 return IF2IP_NOT_FOUND;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100272}
273
274#endif