1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@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 http://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 "strequal.h" 55#include "if2ip.h" 56 57#define _MPRINTF_REPLACE /* use our functions only */ 58#include <curl/mprintf.h> 59 60#include "curl_memory.h" 61/* The last #include file should be: */ 62#include "memdebug.h" 63 64/* ------------------------------------------------------------------ */ 65 66#if defined(HAVE_GETIFADDRS) 67 68bool Curl_if_is_interface_name(const char *interf) 69{ 70 bool result = FALSE; 71 72 struct ifaddrs *iface, *head; 73 74 if(getifaddrs(&head) >= 0) { 75 for(iface=head; iface != NULL; iface=iface->ifa_next) { 76 if(curl_strequal(iface->ifa_name, interf)) { 77 result = TRUE; 78 break; 79 } 80 } 81 freeifaddrs(head); 82 } 83 return result; 84} 85 86if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, 87 const char *interf, char *buf, int buf_size) 88{ 89 struct ifaddrs *iface, *head; 90 if2ip_result_t res = IF2IP_NOT_FOUND; 91 92#ifndef ENABLE_IPV6 93 (void) remote_scope; 94#endif 95 96 if(getifaddrs(&head) >= 0) { 97 for(iface=head; iface != NULL; iface=iface->ifa_next) { 98 if(iface->ifa_addr != NULL) { 99 if(iface->ifa_addr->sa_family == af) { 100 if(curl_strequal(iface->ifa_name, interf)) { 101 void *addr; 102 char *ip; 103 char scope[12]=""; 104 char ipstr[64]; 105#ifdef ENABLE_IPV6 106 if(af == AF_INET6) { 107 unsigned int scopeid = 0; 108 addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr; 109#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 110 /* Include the scope of this interface as part of the address */ 111 scopeid = 112 ((struct sockaddr_in6 *)iface->ifa_addr)->sin6_scope_id; 113#endif 114 if(scopeid != remote_scope) { 115 /* We are interested only in interface addresses whose 116 scope ID matches the remote address we want to 117 connect to: global (0) for global, link-local for 118 link-local, etc... */ 119 if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED; 120 continue; 121 } 122 if(scopeid) 123 snprintf(scope, sizeof(scope), "%%%u", scopeid); 124 } 125 else 126#endif 127 addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr; 128 res = IF2IP_FOUND; 129 ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr)); 130 snprintf(buf, buf_size, "%s%s", ip, scope); 131 break; 132 } 133 } 134 else if((res == IF2IP_NOT_FOUND) && 135 curl_strequal(iface->ifa_name, interf)) { 136 res = IF2IP_AF_NOT_SUPPORTED; 137 } 138 } 139 } 140 freeifaddrs(head); 141 } 142 return res; 143} 144 145#elif defined(HAVE_IOCTL_SIOCGIFADDR) 146 147bool Curl_if_is_interface_name(const char *interf) 148{ 149 /* This is here just to support the old interfaces */ 150 char buf[256]; 151 152 return (Curl_if2ip(AF_INET, 0, interf, buf, sizeof(buf)) == 153 IF2IP_NOT_FOUND) ? FALSE : TRUE; 154} 155 156if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, 157 const char *interf, char *buf, int buf_size) 158{ 159 struct ifreq req; 160 struct in_addr in; 161 struct sockaddr_in *s; 162 curl_socket_t dummy; 163 size_t len; 164 165 (void)remote_scope; 166 167 if(!interf || (af != AF_INET)) 168 return IF2IP_NOT_FOUND; 169 170 len = strlen(interf); 171 if(len >= sizeof(req.ifr_name)) 172 return IF2IP_NOT_FOUND; 173 174 dummy = socket(AF_INET, SOCK_STREAM, 0); 175 if(CURL_SOCKET_BAD == dummy) 176 return IF2IP_NOT_FOUND; 177 178 memset(&req, 0, sizeof(req)); 179 memcpy(req.ifr_name, interf, len+1); 180 req.ifr_addr.sa_family = AF_INET; 181 182 if(ioctl(dummy, SIOCGIFADDR, &req) < 0) { 183 sclose(dummy); 184 /* With SIOCGIFADDR, we cannot tell the difference between an interface 185 that does not exist and an interface that has no address of the 186 correct family. Assume the interface does not exist */ 187 return IF2IP_NOT_FOUND; 188 } 189 190 s = (struct sockaddr_in *)&req.ifr_addr; 191 memcpy(&in, &s->sin_addr, sizeof(in)); 192 Curl_inet_ntop(s->sin_family, &in, buf, buf_size); 193 194 sclose(dummy); 195 return IF2IP_FOUND; 196} 197 198#else 199 200bool Curl_if_is_interface_name(const char *interf) 201{ 202 (void) interf; 203 204 return FALSE; 205} 206 207if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, 208 const char *interf, char *buf, int buf_size) 209{ 210 (void) af; 211 (void) remote_scope; 212 (void) interf; 213 (void) buf; 214 (void) buf_size; 215 return IF2IP_NOT_FOUND; 216} 217 218#endif 219