1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #ifdef HAVE_NETINET_IN_H
26 # include <netinet/in.h>
28 #ifdef HAVE_ARPA_INET_H
29 # include <arpa/inet.h>
34 #ifdef HAVE_SYS_IOCTL_H
35 # include <sys/ioctl.h>
40 #ifdef HAVE_SYS_SOCKIO_H
41 # include <sys/sockio.h>
53 #include "inet_ntop.h"
56 /* The last 3 #include files should be in this order */
57 #include "curl_printf.h"
58 #include "curl_memory.h"
61 /* ------------------------------------------------------------------ */
63 /* Return the scope of the given address. */
64 unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
69 if(sa->sa_family == AF_INET6) {
70 const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa;
71 const unsigned char *b = sa6->sin6_addr.s6_addr;
72 unsigned short w = (unsigned short) ((b[0] << 8) | b[1]);
74 if((b[0] & 0xFE) == 0xFC) /* Handle ULAs */
75 return IPV6_SCOPE_UNIQUELOCAL;
78 return IPV6_SCOPE_LINKLOCAL;
80 return IPV6_SCOPE_SITELOCAL;
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)
86 return IPV6_SCOPE_NODELOCAL;
93 return IPV6_SCOPE_GLOBAL;
97 #if defined(HAVE_GETIFADDRS)
99 bool Curl_if_is_interface_name(const char *interf)
103 struct ifaddrs *iface, *head;
105 if(getifaddrs(&head) >= 0) {
106 for(iface = head; iface != NULL; iface = iface->ifa_next) {
107 if(strcasecompare(iface->ifa_name, interf)) {
117 if2ip_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)
121 struct ifaddrs *iface, *head;
122 if2ip_result_t res = IF2IP_NOT_FOUND;
128 #if !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) || \
129 !defined(ENABLE_IPV6)
130 (void) remote_scope_id;
133 if(getifaddrs(&head) >= 0) {
134 for(iface = head; iface != NULL; iface = iface->ifa_next) {
135 if(iface->ifa_addr != NULL) {
136 if(iface->ifa_addr->sa_family == af) {
137 if(strcasecompare(iface->ifa_name, interf)) {
144 unsigned int scopeid = 0;
145 unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr);
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;
157 &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr;
158 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
159 /* Include the scope of this interface as part of the address */
160 scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr)
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;
172 snprintf(scope, sizeof(scope), "%%%u", scopeid);
177 &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
179 ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
180 snprintf(buf, buf_size, "%s%s", ip, scope);
184 else if((res == IF2IP_NOT_FOUND) &&
185 strcasecompare(iface->ifa_name, interf)) {
186 res = IF2IP_AF_NOT_SUPPORTED;
197 #elif defined(HAVE_IOCTL_SIOCGIFADDR)
199 bool Curl_if_is_interface_name(const char *interf)
201 /* This is here just to support the old interfaces */
204 return (Curl_if2ip(AF_INET, 0 /* unused */, 0, interf, buf, sizeof(buf)) ==
205 IF2IP_NOT_FOUND) ? FALSE : TRUE;
208 if2ip_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)
214 struct sockaddr_in *s;
219 (void)remote_scope_id;
221 if(!interf || (af != AF_INET))
222 return IF2IP_NOT_FOUND;
224 len = strlen(interf);
225 if(len >= sizeof(req.ifr_name))
226 return IF2IP_NOT_FOUND;
228 dummy = socket(AF_INET, SOCK_STREAM, 0);
229 if(CURL_SOCKET_BAD == dummy)
230 return IF2IP_NOT_FOUND;
232 memset(&req, 0, sizeof(req));
233 memcpy(req.ifr_name, interf, len + 1);
234 req.ifr_addr.sa_family = AF_INET;
236 if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
238 /* 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;
244 s = (struct sockaddr_in *)(void *)&req.ifr_addr;
245 memcpy(&in, &s->sin_addr, sizeof(in));
246 Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
254 bool Curl_if_is_interface_name(const char *interf)
261 if2ip_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)
267 (void) remote_scope_id;
271 return IF2IP_NOT_FOUND;