blob: d003de6783ef98783898aa41ec32e8280a2fac3e [file] [log] [blame]
Kristian Monsen5ab50182010-05-14 18:53:44 +01001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
Haibo Huang34ab3462019-05-22 00:50:27 -07008 * Copyright (C) 1998 - 2019, 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 -070099if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
Haibo Huang34ab3462019-05-22 00:50:27 -0700100 unsigned int local_scope_id, const char *interf,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700101 char *buf, int buf_size)
102{
103 struct ifaddrs *iface, *head;
104 if2ip_result_t res = IF2IP_NOT_FOUND;
105
106#ifndef ENABLE_IPV6
107 (void) remote_scope;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700108#endif
109
Elliott Hughes82be86d2017-09-20 17:00:17 -0700110#if !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) || \
111 !defined(ENABLE_IPV6)
Haibo Huang34ab3462019-05-22 00:50:27 -0700112 (void) local_scope_id;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700113#endif
114
115 if(getifaddrs(&head) >= 0) {
Alex Deymo486467e2017-12-19 19:04:07 +0100116 for(iface = head; iface != NULL; iface = iface->ifa_next) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700117 if(iface->ifa_addr != NULL) {
118 if(iface->ifa_addr->sa_family == af) {
Elliott Hughescee03382017-06-23 12:17:18 -0700119 if(strcasecompare(iface->ifa_name, interf)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700120 void *addr;
121 char *ip;
122 char scope[12] = "";
123 char ipstr[64];
124#ifdef ENABLE_IPV6
125 if(af == AF_INET6) {
Haibo Huang34ab3462019-05-22 00:50:27 -0700126#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700127 unsigned int scopeid = 0;
Haibo Huang34ab3462019-05-22 00:50:27 -0700128#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700129 unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr);
130
131 if(ifscope != remote_scope) {
132 /* We are interested only in interface addresses whose
133 scope matches the remote address we want to
134 connect to: global for global, link-local for
135 link-local, etc... */
136 if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED;
137 continue;
138 }
139
Alex Deymo8f1a2142016-06-28 14:49:26 -0700140 addr =
141 &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700142#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
143 /* Include the scope of this interface as part of the address */
Alex Deymo8f1a2142016-06-28 14:49:26 -0700144 scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr)
145 ->sin6_scope_id;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700146
147 /* If given, scope id should match. */
Haibo Huang34ab3462019-05-22 00:50:27 -0700148 if(local_scope_id && scopeid != local_scope_id) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700149 if(res == IF2IP_NOT_FOUND)
150 res = IF2IP_AF_NOT_SUPPORTED;
151
152 continue;
153 }
Haibo Huang34ab3462019-05-22 00:50:27 -0700154
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700155 if(scopeid)
Haibo Huang34ab3462019-05-22 00:50:27 -0700156 msnprintf(scope, sizeof(scope), "%%%u", scopeid);
157#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700158 }
159 else
160#endif
Alex Deymo8f1a2142016-06-28 14:49:26 -0700161 addr =
162 &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700163 res = IF2IP_FOUND;
164 ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
Haibo Huang21926d52019-01-08 14:27:10 -0800165 msnprintf(buf, buf_size, "%s%s", ip, scope);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700166 break;
167 }
168 }
169 else if((res == IF2IP_NOT_FOUND) &&
Elliott Hughescee03382017-06-23 12:17:18 -0700170 strcasecompare(iface->ifa_name, interf)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700171 res = IF2IP_AF_NOT_SUPPORTED;
172 }
173 }
174 }
175
176 freeifaddrs(head);
177 }
178
179 return res;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100180}
181
182#elif defined(HAVE_IOCTL_SIOCGIFADDR)
183
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700184if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
Haibo Huang34ab3462019-05-22 00:50:27 -0700185 unsigned int local_scope_id, const char *interf,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700186 char *buf, int buf_size)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100187{
188 struct ifreq req;
189 struct in_addr in;
190 struct sockaddr_in *s;
191 curl_socket_t dummy;
192 size_t len;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100193
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700194 (void)remote_scope;
Haibo Huang34ab3462019-05-22 00:50:27 -0700195 (void)local_scope_id;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100196
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700197 if(!interf || (af != AF_INET))
198 return IF2IP_NOT_FOUND;
199
200 len = strlen(interf);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100201 if(len >= sizeof(req.ifr_name))
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700202 return IF2IP_NOT_FOUND;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100203
204 dummy = socket(AF_INET, SOCK_STREAM, 0);
205 if(CURL_SOCKET_BAD == dummy)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700206 return IF2IP_NOT_FOUND;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100207
208 memset(&req, 0, sizeof(req));
Alex Deymo486467e2017-12-19 19:04:07 +0100209 memcpy(req.ifr_name, interf, len + 1);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100210 req.ifr_addr.sa_family = AF_INET;
211
212 if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
213 sclose(dummy);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700214 /* With SIOCGIFADDR, we cannot tell the difference between an interface
215 that does not exist and an interface that has no address of the
216 correct family. Assume the interface does not exist */
217 return IF2IP_NOT_FOUND;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100218 }
219
Elliott Hughes82be86d2017-09-20 17:00:17 -0700220 s = (struct sockaddr_in *)(void *)&req.ifr_addr;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100221 memcpy(&in, &s->sin_addr, sizeof(in));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700222 Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100223
224 sclose(dummy);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700225 return IF2IP_FOUND;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100226}
227
228#else
229
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700230if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
Haibo Huang34ab3462019-05-22 00:50:27 -0700231 unsigned int local_scope_id, const char *interf,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700232 char *buf, int buf_size)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100233{
234 (void) af;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700235 (void) remote_scope;
Haibo Huang34ab3462019-05-22 00:50:27 -0700236 (void) local_scope_id;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100237 (void) interf;
238 (void) buf;
239 (void) buf_size;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700240 return IF2IP_NOT_FOUND;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100241}
242
243#endif