if2ip.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2022, 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. #if defined(HAVE_GETIFADDRS)
  89. if2ip_result_t Curl_if2ip(int af,
  90. #ifdef ENABLE_IPV6
  91. unsigned int remote_scope,
  92. unsigned int local_scope_id,
  93. #endif
  94. const char *interf,
  95. char *buf, int buf_size)
  96. {
  97. struct ifaddrs *iface, *head;
  98. if2ip_result_t res = IF2IP_NOT_FOUND;
  99. #if defined(ENABLE_IPV6) && \
  100. !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
  101. (void) local_scope_id;
  102. #endif
  103. if(getifaddrs(&head) >= 0) {
  104. for(iface = head; iface != NULL; iface = iface->ifa_next) {
  105. if(iface->ifa_addr) {
  106. if(iface->ifa_addr->sa_family == af) {
  107. if(strcasecompare(iface->ifa_name, interf)) {
  108. void *addr;
  109. const char *ip;
  110. char scope[12] = "";
  111. char ipstr[64];
  112. #ifdef ENABLE_IPV6
  113. if(af == AF_INET6) {
  114. #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
  115. unsigned int scopeid = 0;
  116. #endif
  117. unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr);
  118. if(ifscope != remote_scope) {
  119. /* We are interested only in interface addresses whose scope
  120. matches the remote address we want to connect to: global
  121. for global, link-local for link-local, etc... */
  122. if(res == IF2IP_NOT_FOUND)
  123. res = IF2IP_AF_NOT_SUPPORTED;
  124. continue;
  125. }
  126. addr =
  127. &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr;
  128. #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
  129. /* Include the scope of this interface as part of the address */
  130. scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr)
  131. ->sin6_scope_id;
  132. /* If given, scope id should match. */
  133. if(local_scope_id && scopeid != local_scope_id) {
  134. if(res == IF2IP_NOT_FOUND)
  135. res = IF2IP_AF_NOT_SUPPORTED;
  136. continue;
  137. }
  138. if(scopeid)
  139. msnprintf(scope, sizeof(scope), "%%%u", scopeid);
  140. #endif
  141. }
  142. else
  143. #endif
  144. addr =
  145. &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
  146. res = IF2IP_FOUND;
  147. ip = Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
  148. msnprintf(buf, buf_size, "%s%s", ip, scope);
  149. break;
  150. }
  151. }
  152. else if((res == IF2IP_NOT_FOUND) &&
  153. strcasecompare(iface->ifa_name, interf)) {
  154. res = IF2IP_AF_NOT_SUPPORTED;
  155. }
  156. }
  157. }
  158. freeifaddrs(head);
  159. }
  160. return res;
  161. }
  162. #elif defined(HAVE_IOCTL_SIOCGIFADDR)
  163. if2ip_result_t Curl_if2ip(int af,
  164. #ifdef ENABLE_IPV6
  165. unsigned int remote_scope,
  166. unsigned int local_scope_id,
  167. #endif
  168. const char *interf,
  169. char *buf, int buf_size)
  170. {
  171. struct ifreq req;
  172. struct in_addr in;
  173. struct sockaddr_in *s;
  174. curl_socket_t dummy;
  175. size_t len;
  176. const char *r;
  177. #ifdef ENABLE_IPV6
  178. (void)remote_scope;
  179. (void)local_scope_id;
  180. #endif
  181. if(!interf || (af != AF_INET))
  182. return IF2IP_NOT_FOUND;
  183. len = strlen(interf);
  184. if(len >= sizeof(req.ifr_name))
  185. return IF2IP_NOT_FOUND;
  186. dummy = socket(AF_INET, SOCK_STREAM, 0);
  187. if(CURL_SOCKET_BAD == dummy)
  188. return IF2IP_NOT_FOUND;
  189. memset(&req, 0, sizeof(req));
  190. memcpy(req.ifr_name, interf, len + 1);
  191. req.ifr_addr.sa_family = AF_INET;
  192. if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
  193. sclose(dummy);
  194. /* With SIOCGIFADDR, we cannot tell the difference between an interface
  195. that does not exist and an interface that has no address of the
  196. correct family. Assume the interface does not exist */
  197. return IF2IP_NOT_FOUND;
  198. }
  199. s = (struct sockaddr_in *)(void *)&req.ifr_addr;
  200. memcpy(&in, &s->sin_addr, sizeof(in));
  201. r = Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
  202. sclose(dummy);
  203. if(!r)
  204. return IF2IP_NOT_FOUND;
  205. return IF2IP_FOUND;
  206. }
  207. #else
  208. if2ip_result_t Curl_if2ip(int af,
  209. #ifdef ENABLE_IPV6
  210. unsigned int remote_scope,
  211. unsigned int local_scope_id,
  212. #endif
  213. const char *interf,
  214. char *buf, int buf_size)
  215. {
  216. (void) af;
  217. #ifdef ENABLE_IPV6
  218. (void) remote_scope;
  219. (void) local_scope_id;
  220. #endif
  221. (void) interf;
  222. (void) buf;
  223. (void) buf_size;
  224. return IF2IP_NOT_FOUND;
  225. }
  226. #endif