1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel (at) haxx.se>, et al. 9 * 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. 13 * 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 23 #include "curl_setup.h" 24 25 #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" 54 #include "strcase.h" 55 #include "if2ip.h" 56 /* The last 3 #include files should be in this order */ 57 #include "curl_printf.h" 58 #include "curl_memory.h" 59 #include "memdebug.h" 60 61 /* ------------------------------------------------------------------ */ 62 63 /* Return the scope of the given address. */ 64 unsigned 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) { 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]); 73 74 switch(w & 0xFFC0) { 75 case 0xFE80: 76 return IPV6_SCOPE_LINKLOCAL; 77 case 0xFEC0: 78 return IPV6_SCOPE_SITELOCAL; 79 case 0x0000: 80 w = b[1] | b[2] | b[3] | b[4] | b[5] | b[6] | b[7] | b[8] | b[9] | 81 b[10] | b[11] | b[12] | b[13] | b[14]; 82 if(w || b[15] != 0x01) 83 break; 84 return IPV6_SCOPE_NODELOCAL; 85 default: 86 break; 87 } 88 } 89 #endif 90 91 return IPV6_SCOPE_GLOBAL; 92 } 93 94 95 #if defined(HAVE_GETIFADDRS) 96 97 bool Curl_if_is_interface_name(const char *interf) 98 { 99 bool result = FALSE; 100 101 struct ifaddrs *iface, *head; 102 103 if(getifaddrs(&head) >= 0) { 104 for(iface=head; iface != NULL; iface=iface->ifa_next) { 105 if(strcasecompare(iface->ifa_name, interf)) { 106 result = TRUE; 107 break; 108 } 109 } 110 freeifaddrs(head); 111 } 112 return result; 113 } 114 115 if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, 116 unsigned int remote_scope_id, const char *interf, 117 char *buf, int buf_size) 118 { 119 struct ifaddrs *iface, *head; 120 if2ip_result_t res = IF2IP_NOT_FOUND; 121 122 #ifndef ENABLE_IPV6 123 (void) remote_scope; 124 125 #ifndef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 126 (void) remote_scope_id; 127 #endif 128 129 #endif 130 131 if(getifaddrs(&head) >= 0) { 132 for(iface = head; iface != NULL; iface=iface->ifa_next) { 133 if(iface->ifa_addr != NULL) { 134 if(iface->ifa_addr->sa_family == af) { 135 if(strcasecompare(iface->ifa_name, interf)) { 136 void *addr; 137 char *ip; 138 char scope[12] = ""; 139 char ipstr[64]; 140 #ifdef ENABLE_IPV6 141 if(af == AF_INET6) { 142 unsigned int scopeid = 0; 143 unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr); 144 145 if(ifscope != remote_scope) { 146 /* We are interested only in interface addresses whose 147 scope matches the remote address we want to 148 connect to: global for global, link-local for 149 link-local, etc... */ 150 if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED; 151 continue; 152 } 153 154 addr = 155 &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr; 156 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 157 /* Include the scope of this interface as part of the address */ 158 scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr) 159 ->sin6_scope_id; 160 161 /* If given, scope id should match. */ 162 if(remote_scope_id && scopeid != remote_scope_id) { 163 if(res == IF2IP_NOT_FOUND) 164 res = IF2IP_AF_NOT_SUPPORTED; 165 166 continue; 167 } 168 #endif 169 if(scopeid) 170 snprintf(scope, sizeof(scope), "%%%u", scopeid); 171 } 172 else 173 #endif 174 addr = 175 &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr; 176 res = IF2IP_FOUND; 177 ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr)); 178 snprintf(buf, buf_size, "%s%s", ip, scope); 179 break; 180 } 181 } 182 else if((res == IF2IP_NOT_FOUND) && 183 strcasecompare(iface->ifa_name, interf)) { 184 res = IF2IP_AF_NOT_SUPPORTED; 185 } 186 } 187 } 188 189 freeifaddrs(head); 190 } 191 192 return res; 193 } 194 195 #elif defined(HAVE_IOCTL_SIOCGIFADDR) 196 197 bool Curl_if_is_interface_name(const char *interf) 198 { 199 /* This is here just to support the old interfaces */ 200 char buf[256]; 201 202 return (Curl_if2ip(AF_INET, 0 /* unused */, 0, interf, buf, sizeof(buf)) == 203 IF2IP_NOT_FOUND) ? FALSE : TRUE; 204 } 205 206 if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, 207 unsigned int remote_scope_id, const char *interf, 208 char *buf, int buf_size) 209 { 210 struct ifreq req; 211 struct in_addr in; 212 struct sockaddr_in *s; 213 curl_socket_t dummy; 214 size_t len; 215 216 (void)remote_scope; 217 (void)remote_scope_id; 218 219 if(!interf || (af != AF_INET)) 220 return IF2IP_NOT_FOUND; 221 222 len = strlen(interf); 223 if(len >= sizeof(req.ifr_name)) 224 return IF2IP_NOT_FOUND; 225 226 dummy = socket(AF_INET, SOCK_STREAM, 0); 227 if(CURL_SOCKET_BAD == dummy) 228 return IF2IP_NOT_FOUND; 229 230 memset(&req, 0, sizeof(req)); 231 memcpy(req.ifr_name, interf, len+1); 232 req.ifr_addr.sa_family = AF_INET; 233 234 if(ioctl(dummy, SIOCGIFADDR, &req) < 0) { 235 sclose(dummy); 236 /* With SIOCGIFADDR, we cannot tell the difference between an interface 237 that does not exist and an interface that has no address of the 238 correct family. Assume the interface does not exist */ 239 return IF2IP_NOT_FOUND; 240 } 241 242 s = (struct sockaddr_in *)&req.ifr_addr; 243 memcpy(&in, &s->sin_addr, sizeof(in)); 244 Curl_inet_ntop(s->sin_family, &in, buf, buf_size); 245 246 sclose(dummy); 247 return IF2IP_FOUND; 248 } 249 250 #else 251 252 bool Curl_if_is_interface_name(const char *interf) 253 { 254 (void) interf; 255 256 return FALSE; 257 } 258 259 if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, 260 unsigned int remote_scope_id, const char *interf, 261 char *buf, int buf_size) 262 { 263 (void) af; 264 (void) remote_scope; 265 (void) remote_scope_id; 266 (void) interf; 267 (void) buf; 268 (void) buf_size; 269 return IF2IP_NOT_FOUND; 270 } 271 272 #endif 273