if2ip.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 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 https://curl.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. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. #include "curl_setup.h"
  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. #include "inet_ntop.h"
  53. #include "strcase.h"
  54. #include "if2ip.h"
  55. /* The last 3 #include files should be in this order */
  56. #include "curl_printf.h"
  57. #include "curl_memory.h"
  58. #include "memdebug.h"
  59. /* ------------------------------------------------------------------ */
  60. #ifdef ENABLE_IPV6
  61. /* Return the scope of the given address. */
  62. unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
  63. {
  64. if(sa->sa_family == AF_INET6) {
  65. const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa;
  66. const unsigned char *b = sa6->sin6_addr.s6_addr;
  67. unsigned short w = (unsigned short) ((b[0] << 8) | b[1]);
  68. if((b[0] & 0xFE) == 0xFC) /* Handle ULAs */
  69. return IPV6_SCOPE_UNIQUELOCAL;
  70. switch(w & 0xFFC0) {
  71. case 0xFE80:
  72. return IPV6_SCOPE_LINKLOCAL;
  73. case 0xFEC0:
  74. return IPV6_SCOPE_SITELOCAL;
  75. case 0x0000:
  76. w = b[1] | b[2] | b[3] | b[4] | b[5] | b[6] | b[7] | b[8] | b[9] |
  77. b[10] | b[11] | b[12] | b[13] | b[14];
  78. if(w || b[15] != 0x01)
  79. break;
  80. return IPV6_SCOPE_NODELOCAL;
  81. default:
  82. break;
  83. }
  84. }
  85. return IPV6_SCOPE_GLOBAL;
  86. }
  87. #endif
  88. #ifndef CURL_DISABLE_BINDLOCAL
  89. #if defined(HAVE_GETIFADDRS)
  90. if2ip_result_t Curl_if2ip(int af,
  91. #ifdef ENABLE_IPV6
  92. unsigned int remote_scope,
  93. unsigned int local_scope_id,
  94. #endif
  95. const char *interf,
  96. char *buf, int buf_size)
  97. {
  98. struct ifaddrs *iface, *head;
  99. if2ip_result_t res = IF2IP_NOT_FOUND;
  100. #if defined(ENABLE_IPV6) && \
  101. !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
  102. (void) local_scope_id;
  103. #endif
  104. if(getifaddrs(&head) >= 0) {
  105. for(iface = head; iface != NULL; iface = iface->ifa_next) {
  106. if(iface->ifa_addr) {
  107. if(iface->ifa_addr->sa_family == af) {
  108. if(strcasecompare(iface->ifa_name, interf)) {
  109. void *addr;
  110. const char *ip;
  111. char scope[12] = "";
  112. char ipstr[64];
  113. #ifdef ENABLE_IPV6
  114. if(af == AF_INET6) {
  115. #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
  116. unsigned int scopeid = 0;
  117. #endif
  118. unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr);
  119. if(ifscope != remote_scope) {
  120. /* We are interested only in interface addresses whose scope
  121. matches the remote address we want to connect to: global
  122. for global, link-local for link-local, etc... */
  123. if(res == IF2IP_NOT_FOUND)
  124. res = IF2IP_AF_NOT_SUPPORTED;
  125. continue;
  126. }
  127. addr =
  128. &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr;
  129. #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
  130. /* Include the scope of this interface as part of the address */
  131. scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr)
  132. ->sin6_scope_id;
  133. /* If given, scope id should match. */
  134. if(local_scope_id && scopeid != local_scope_id) {
  135. if(res == IF2IP_NOT_FOUND)
  136. res = IF2IP_AF_NOT_SUPPORTED;
  137. continue;
  138. }
  139. if(scopeid)
  140. msnprintf(scope, sizeof(scope), "%%%u", scopeid);
  141. #endif
  142. }
  143. else
  144. #endif
  145. addr =
  146. &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
  147. res = IF2IP_FOUND;
  148. ip = Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
  149. msnprintf(buf, buf_size, "%s%s", ip, scope);
  150. break;
  151. }
  152. }
  153. else if((res == IF2IP_NOT_FOUND) &&
  154. strcasecompare(iface->ifa_name, interf)) {
  155. res = IF2IP_AF_NOT_SUPPORTED;
  156. }
  157. }
  158. }
  159. freeifaddrs(head);
  160. }
  161. return res;
  162. }
  163. #elif defined(HAVE_IOCTL_SIOCGIFADDR)
  164. if2ip_result_t Curl_if2ip(int af,
  165. #ifdef ENABLE_IPV6
  166. unsigned int remote_scope,
  167. unsigned int local_scope_id,
  168. #endif
  169. const char *interf,
  170. char *buf, int buf_size)
  171. {
  172. struct ifreq req;
  173. struct in_addr in;
  174. struct sockaddr_in *s;
  175. curl_socket_t dummy;
  176. size_t len;
  177. const char *r;
  178. #ifdef ENABLE_IPV6
  179. (void)remote_scope;
  180. (void)local_scope_id;
  181. #endif
  182. if(!interf || (af != AF_INET))
  183. return IF2IP_NOT_FOUND;
  184. len = strlen(interf);
  185. if(len >= sizeof(req.ifr_name))
  186. return IF2IP_NOT_FOUND;
  187. dummy = socket(AF_INET, SOCK_STREAM, 0);
  188. if(CURL_SOCKET_BAD == dummy)
  189. return IF2IP_NOT_FOUND;
  190. memset(&req, 0, sizeof(req));
  191. memcpy(req.ifr_name, interf, len + 1);
  192. req.ifr_addr.sa_family = AF_INET;
  193. if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
  194. sclose(dummy);
  195. /* With SIOCGIFADDR, we cannot tell the difference between an interface
  196. that does not exist and an interface that has no address of the
  197. correct family. Assume the interface does not exist */
  198. return IF2IP_NOT_FOUND;
  199. }
  200. s = (struct sockaddr_in *)(void *)&req.ifr_addr;
  201. memcpy(&in, &s->sin_addr, sizeof(in));
  202. r = Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
  203. sclose(dummy);
  204. if(!r)
  205. return IF2IP_NOT_FOUND;
  206. return IF2IP_FOUND;
  207. }
  208. #else
  209. if2ip_result_t Curl_if2ip(int af,
  210. #ifdef ENABLE_IPV6
  211. unsigned int remote_scope,
  212. unsigned int local_scope_id,
  213. #endif
  214. const char *interf,
  215. char *buf, int buf_size)
  216. {
  217. (void) af;
  218. #ifdef ENABLE_IPV6
  219. (void) remote_scope;
  220. (void) local_scope_id;
  221. #endif
  222. (void) interf;
  223. (void) buf;
  224. (void) buf_size;
  225. return IF2IP_NOT_FOUND;
  226. }
  227. #endif
  228. #endif /* CURL_DISABLE_BINDLOCAL */