cf-socket: set scope_id for IPv6 link-local addresses
No binary (build failed)
—
(log yok)
| @@ -44,6 +44,12 @@ | |
| #include <arpa/inet.h> | |
| #endif | |
| + | #ifdef HAVE_IFADDRS_H |
| + | #include <ifaddrs.h> |
| + | #endif |
| + | #ifdef HAVE_NET_IF_H |
| + | #include <net/if.h> |
| + | #endif |
| #ifdef __VMS | |
| #include <in.h> | |
| #include <inet.h> | |
| @@ -297,6 +303,49 @@ int Curl_sock_nosigpipe(curl_socket_t sockfd) | |
| } | |
| #endif /* USE_SO_NOSIGPIPE */ | |
| + | #if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) |
| + | static uint32_t get_scope_id(struct Curl_easy *data, |
| + | struct sockaddr_in6 *sa6) |
| + | { |
| + | uint32_t scope_id = 0; |
| + | if(data->conn->scope_id) |
| + | return data->conn->scope_id; |
| + | /* NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Assign) */ |
| + | scope_id = sa6->sin6_scope_id; |
| + | if(!scope_id && IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { |
| + | /* The resolver did not set scope_id for this link-local address. |
| + | * Try to determine it from the system's network interfaces. |
| + | * Without a scope_id, connect() to a link-local address fails |
| + | * with EINVAL on Linux. |
| + | * NOTE: On multi-homed hosts with several interfaces having |
| + | * link-local addresses, this picks the first one found, which |
| + | * may not be the correct outgoing interface. */ |
| + | #if defined(HAVE_GETIFADDRS) && defined(HAVE_NET_IF_H) |
| + | struct ifaddrs *ifa, *ifa_list; |
| + | if(getifaddrs(&ifa_list) == 0) { |
| + | for(ifa = ifa_list; ifa; ifa = ifa->ifa_next) { |
| + | if(ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6 && |
| + | (ifa->ifa_flags & IFF_UP) && |
| + | !(ifa->ifa_flags & IFF_LOOPBACK)) { |
| + | struct sockaddr_in6 *s6 = (void *)ifa->ifa_addr; |
| + | if(IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) && s6->sin6_scope_id) { |
| + | scope_id = s6->sin6_scope_id; |
| + | infof(data, |
| + | "determined scope_id=%lu for link-local address " |
| + | "from local interface", |
| + | (unsigned long)scope_id); |
| + | break; |
| + | } |
| + | } |
| + | } |
| + | freeifaddrs(ifa_list); |
| + | } |
| + | #endif /* HAVE_GETIFADDRS && HAVE_NET_IF_H */ |
| + | } |
| + | return scope_id; |
| + | } |
| + | #endif |
| + | |
| static CURLcode socket_open(struct Curl_easy *data, | |
| struct Curl_sockaddr_ex *addr, | |
| curl_socket_t *sockfd) | |
| @@ -366,9 +415,9 @@ static CURLcode socket_open(struct Curl_easy *data, | |
| #endif | |
| #if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) | |
| - | if(data->conn->scope_id && (addr->family == AF_INET6)) { |
| + | if(addr->family == AF_INET6) { |
| struct sockaddr_in6 * const sa6 = (void *)&addr->curl_sa_addr; | |
| - | sa6->sin6_scope_id = data->conn->scope_id; |
| + | sa6->sin6_scope_id = get_scope_id(data, sa6); |
| } | |
| #endif | |
| return CURLE_OK; | |
| @@ -1085,7 +1134,20 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf, | |
| (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_V6ONLY, | |
| (void *)&on, sizeof(on)); | |
| #endif | |
| - | infof(data, " Trying [%s]:%d...", ctx->ip.remote_ip, ctx->ip.remote_port); |
| + | #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID |
| + | { |
| + | struct sockaddr_in6 *sa6 = (void *)&ctx->addr.curl_sa_addr; |
| + | if(sa6->sin6_scope_id) |
| + | infof(data, " Trying [%s]:%d scope_id=%lu...", |
| + | ctx->ip.remote_ip, ctx->ip.remote_port, |
| + | (unsigned long)sa6->sin6_scope_id); |
| + | else |
| + | #endif |
| + | infof(data, " Trying [%s]:%d...", |
| + | ctx->ip.remote_ip, ctx->ip.remote_port); |
| + | #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID |
| + | } |
| + | #endif |
| } | |
| else | |
| #endif | |