113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci 2713498266Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 2813498266Sopenharmony_ci# include <netinet/in.h> 2913498266Sopenharmony_ci#endif 3013498266Sopenharmony_ci#ifdef HAVE_ARPA_INET_H 3113498266Sopenharmony_ci# include <arpa/inet.h> 3213498266Sopenharmony_ci#endif 3313498266Sopenharmony_ci#ifdef HAVE_NET_IF_H 3413498266Sopenharmony_ci# include <net/if.h> 3513498266Sopenharmony_ci#endif 3613498266Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H 3713498266Sopenharmony_ci# include <sys/ioctl.h> 3813498266Sopenharmony_ci#endif 3913498266Sopenharmony_ci#ifdef HAVE_NETDB_H 4013498266Sopenharmony_ci# include <netdb.h> 4113498266Sopenharmony_ci#endif 4213498266Sopenharmony_ci#ifdef HAVE_SYS_SOCKIO_H 4313498266Sopenharmony_ci# include <sys/sockio.h> 4413498266Sopenharmony_ci#endif 4513498266Sopenharmony_ci#ifdef HAVE_IFADDRS_H 4613498266Sopenharmony_ci# include <ifaddrs.h> 4713498266Sopenharmony_ci#endif 4813498266Sopenharmony_ci#ifdef HAVE_STROPTS_H 4913498266Sopenharmony_ci# include <stropts.h> 5013498266Sopenharmony_ci#endif 5113498266Sopenharmony_ci#ifdef __VMS 5213498266Sopenharmony_ci# include <inet.h> 5313498266Sopenharmony_ci#endif 5413498266Sopenharmony_ci 5513498266Sopenharmony_ci#include "inet_ntop.h" 5613498266Sopenharmony_ci#include "strcase.h" 5713498266Sopenharmony_ci#include "if2ip.h" 5813498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 5913498266Sopenharmony_ci#include "curl_printf.h" 6013498266Sopenharmony_ci#include "curl_memory.h" 6113498266Sopenharmony_ci#include "memdebug.h" 6213498266Sopenharmony_ci 6313498266Sopenharmony_ci/* ------------------------------------------------------------------ */ 6413498266Sopenharmony_ci 6513498266Sopenharmony_ci#ifdef ENABLE_IPV6 6613498266Sopenharmony_ci/* Return the scope of the given address. */ 6713498266Sopenharmony_ciunsigned int Curl_ipv6_scope(const struct sockaddr *sa) 6813498266Sopenharmony_ci{ 6913498266Sopenharmony_ci if(sa->sa_family == AF_INET6) { 7013498266Sopenharmony_ci const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa; 7113498266Sopenharmony_ci const unsigned char *b = sa6->sin6_addr.s6_addr; 7213498266Sopenharmony_ci unsigned short w = (unsigned short) ((b[0] << 8) | b[1]); 7313498266Sopenharmony_ci 7413498266Sopenharmony_ci if((b[0] & 0xFE) == 0xFC) /* Handle ULAs */ 7513498266Sopenharmony_ci return IPV6_SCOPE_UNIQUELOCAL; 7613498266Sopenharmony_ci switch(w & 0xFFC0) { 7713498266Sopenharmony_ci case 0xFE80: 7813498266Sopenharmony_ci return IPV6_SCOPE_LINKLOCAL; 7913498266Sopenharmony_ci case 0xFEC0: 8013498266Sopenharmony_ci return IPV6_SCOPE_SITELOCAL; 8113498266Sopenharmony_ci case 0x0000: 8213498266Sopenharmony_ci w = b[1] | b[2] | b[3] | b[4] | b[5] | b[6] | b[7] | b[8] | b[9] | 8313498266Sopenharmony_ci b[10] | b[11] | b[12] | b[13] | b[14]; 8413498266Sopenharmony_ci if(w || b[15] != 0x01) 8513498266Sopenharmony_ci break; 8613498266Sopenharmony_ci return IPV6_SCOPE_NODELOCAL; 8713498266Sopenharmony_ci default: 8813498266Sopenharmony_ci break; 8913498266Sopenharmony_ci } 9013498266Sopenharmony_ci } 9113498266Sopenharmony_ci return IPV6_SCOPE_GLOBAL; 9213498266Sopenharmony_ci} 9313498266Sopenharmony_ci#endif 9413498266Sopenharmony_ci 9513498266Sopenharmony_ci#ifndef CURL_DISABLE_BINDLOCAL 9613498266Sopenharmony_ci 9713498266Sopenharmony_ci#if defined(HAVE_GETIFADDRS) 9813498266Sopenharmony_ci 9913498266Sopenharmony_ciif2ip_result_t Curl_if2ip(int af, 10013498266Sopenharmony_ci#ifdef ENABLE_IPV6 10113498266Sopenharmony_ci unsigned int remote_scope, 10213498266Sopenharmony_ci unsigned int local_scope_id, 10313498266Sopenharmony_ci#endif 10413498266Sopenharmony_ci const char *interf, 10513498266Sopenharmony_ci char *buf, int buf_size) 10613498266Sopenharmony_ci{ 10713498266Sopenharmony_ci struct ifaddrs *iface, *head; 10813498266Sopenharmony_ci if2ip_result_t res = IF2IP_NOT_FOUND; 10913498266Sopenharmony_ci 11013498266Sopenharmony_ci#if defined(ENABLE_IPV6) && \ 11113498266Sopenharmony_ci !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) 11213498266Sopenharmony_ci (void) local_scope_id; 11313498266Sopenharmony_ci#endif 11413498266Sopenharmony_ci 11513498266Sopenharmony_ci if(getifaddrs(&head) >= 0) { 11613498266Sopenharmony_ci for(iface = head; iface != NULL; iface = iface->ifa_next) { 11713498266Sopenharmony_ci if(iface->ifa_addr) { 11813498266Sopenharmony_ci if(iface->ifa_addr->sa_family == af) { 11913498266Sopenharmony_ci if(strcasecompare(iface->ifa_name, interf)) { 12013498266Sopenharmony_ci void *addr; 12113498266Sopenharmony_ci const char *ip; 12213498266Sopenharmony_ci char scope[12] = ""; 12313498266Sopenharmony_ci char ipstr[64]; 12413498266Sopenharmony_ci#ifdef ENABLE_IPV6 12513498266Sopenharmony_ci if(af == AF_INET6) { 12613498266Sopenharmony_ci#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 12713498266Sopenharmony_ci unsigned int scopeid = 0; 12813498266Sopenharmony_ci#endif 12913498266Sopenharmony_ci unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr); 13013498266Sopenharmony_ci 13113498266Sopenharmony_ci if(ifscope != remote_scope) { 13213498266Sopenharmony_ci /* We are interested only in interface addresses whose scope 13313498266Sopenharmony_ci matches the remote address we want to connect to: global 13413498266Sopenharmony_ci for global, link-local for link-local, etc... */ 13513498266Sopenharmony_ci if(res == IF2IP_NOT_FOUND) 13613498266Sopenharmony_ci res = IF2IP_AF_NOT_SUPPORTED; 13713498266Sopenharmony_ci continue; 13813498266Sopenharmony_ci } 13913498266Sopenharmony_ci 14013498266Sopenharmony_ci addr = 14113498266Sopenharmony_ci &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr; 14213498266Sopenharmony_ci#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 14313498266Sopenharmony_ci /* Include the scope of this interface as part of the address */ 14413498266Sopenharmony_ci scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr) 14513498266Sopenharmony_ci ->sin6_scope_id; 14613498266Sopenharmony_ci 14713498266Sopenharmony_ci /* If given, scope id should match. */ 14813498266Sopenharmony_ci if(local_scope_id && scopeid != local_scope_id) { 14913498266Sopenharmony_ci if(res == IF2IP_NOT_FOUND) 15013498266Sopenharmony_ci res = IF2IP_AF_NOT_SUPPORTED; 15113498266Sopenharmony_ci 15213498266Sopenharmony_ci continue; 15313498266Sopenharmony_ci } 15413498266Sopenharmony_ci 15513498266Sopenharmony_ci if(scopeid) 15613498266Sopenharmony_ci msnprintf(scope, sizeof(scope), "%%%u", scopeid); 15713498266Sopenharmony_ci#endif 15813498266Sopenharmony_ci } 15913498266Sopenharmony_ci else 16013498266Sopenharmony_ci#endif 16113498266Sopenharmony_ci addr = 16213498266Sopenharmony_ci &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr; 16313498266Sopenharmony_ci res = IF2IP_FOUND; 16413498266Sopenharmony_ci ip = Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr)); 16513498266Sopenharmony_ci msnprintf(buf, buf_size, "%s%s", ip, scope); 16613498266Sopenharmony_ci break; 16713498266Sopenharmony_ci } 16813498266Sopenharmony_ci } 16913498266Sopenharmony_ci else if((res == IF2IP_NOT_FOUND) && 17013498266Sopenharmony_ci strcasecompare(iface->ifa_name, interf)) { 17113498266Sopenharmony_ci res = IF2IP_AF_NOT_SUPPORTED; 17213498266Sopenharmony_ci } 17313498266Sopenharmony_ci } 17413498266Sopenharmony_ci } 17513498266Sopenharmony_ci 17613498266Sopenharmony_ci freeifaddrs(head); 17713498266Sopenharmony_ci } 17813498266Sopenharmony_ci 17913498266Sopenharmony_ci return res; 18013498266Sopenharmony_ci} 18113498266Sopenharmony_ci 18213498266Sopenharmony_ci#elif defined(HAVE_IOCTL_SIOCGIFADDR) 18313498266Sopenharmony_ci 18413498266Sopenharmony_ciif2ip_result_t Curl_if2ip(int af, 18513498266Sopenharmony_ci#ifdef ENABLE_IPV6 18613498266Sopenharmony_ci unsigned int remote_scope, 18713498266Sopenharmony_ci unsigned int local_scope_id, 18813498266Sopenharmony_ci#endif 18913498266Sopenharmony_ci const char *interf, 19013498266Sopenharmony_ci char *buf, int buf_size) 19113498266Sopenharmony_ci{ 19213498266Sopenharmony_ci struct ifreq req; 19313498266Sopenharmony_ci struct in_addr in; 19413498266Sopenharmony_ci struct sockaddr_in *s; 19513498266Sopenharmony_ci curl_socket_t dummy; 19613498266Sopenharmony_ci size_t len; 19713498266Sopenharmony_ci const char *r; 19813498266Sopenharmony_ci 19913498266Sopenharmony_ci#ifdef ENABLE_IPV6 20013498266Sopenharmony_ci (void)remote_scope; 20113498266Sopenharmony_ci (void)local_scope_id; 20213498266Sopenharmony_ci#endif 20313498266Sopenharmony_ci 20413498266Sopenharmony_ci if(!interf || (af != AF_INET)) 20513498266Sopenharmony_ci return IF2IP_NOT_FOUND; 20613498266Sopenharmony_ci 20713498266Sopenharmony_ci len = strlen(interf); 20813498266Sopenharmony_ci if(len >= sizeof(req.ifr_name)) 20913498266Sopenharmony_ci return IF2IP_NOT_FOUND; 21013498266Sopenharmony_ci 21113498266Sopenharmony_ci dummy = socket(AF_INET, SOCK_STREAM, 0); 21213498266Sopenharmony_ci if(CURL_SOCKET_BAD == dummy) 21313498266Sopenharmony_ci return IF2IP_NOT_FOUND; 21413498266Sopenharmony_ci 21513498266Sopenharmony_ci memset(&req, 0, sizeof(req)); 21613498266Sopenharmony_ci memcpy(req.ifr_name, interf, len + 1); 21713498266Sopenharmony_ci req.ifr_addr.sa_family = AF_INET; 21813498266Sopenharmony_ci 21913498266Sopenharmony_ci if(ioctl(dummy, SIOCGIFADDR, &req) < 0) { 22013498266Sopenharmony_ci sclose(dummy); 22113498266Sopenharmony_ci /* With SIOCGIFADDR, we cannot tell the difference between an interface 22213498266Sopenharmony_ci that does not exist and an interface that has no address of the 22313498266Sopenharmony_ci correct family. Assume the interface does not exist */ 22413498266Sopenharmony_ci return IF2IP_NOT_FOUND; 22513498266Sopenharmony_ci } 22613498266Sopenharmony_ci 22713498266Sopenharmony_ci s = (struct sockaddr_in *)(void *)&req.ifr_addr; 22813498266Sopenharmony_ci memcpy(&in, &s->sin_addr, sizeof(in)); 22913498266Sopenharmony_ci r = Curl_inet_ntop(s->sin_family, &in, buf, buf_size); 23013498266Sopenharmony_ci 23113498266Sopenharmony_ci sclose(dummy); 23213498266Sopenharmony_ci if(!r) 23313498266Sopenharmony_ci return IF2IP_NOT_FOUND; 23413498266Sopenharmony_ci return IF2IP_FOUND; 23513498266Sopenharmony_ci} 23613498266Sopenharmony_ci 23713498266Sopenharmony_ci#else 23813498266Sopenharmony_ci 23913498266Sopenharmony_ciif2ip_result_t Curl_if2ip(int af, 24013498266Sopenharmony_ci#ifdef ENABLE_IPV6 24113498266Sopenharmony_ci unsigned int remote_scope, 24213498266Sopenharmony_ci unsigned int local_scope_id, 24313498266Sopenharmony_ci#endif 24413498266Sopenharmony_ci const char *interf, 24513498266Sopenharmony_ci char *buf, int buf_size) 24613498266Sopenharmony_ci{ 24713498266Sopenharmony_ci (void) af; 24813498266Sopenharmony_ci#ifdef ENABLE_IPV6 24913498266Sopenharmony_ci (void) remote_scope; 25013498266Sopenharmony_ci (void) local_scope_id; 25113498266Sopenharmony_ci#endif 25213498266Sopenharmony_ci (void) interf; 25313498266Sopenharmony_ci (void) buf; 25413498266Sopenharmony_ci (void) buf_size; 25513498266Sopenharmony_ci return IF2IP_NOT_FOUND; 25613498266Sopenharmony_ci} 25713498266Sopenharmony_ci 25813498266Sopenharmony_ci#endif 25913498266Sopenharmony_ci 26013498266Sopenharmony_ci#endif /* CURL_DISABLE_BINDLOCAL */ 261