Description
I did this
I consider following fragment using libcurl C API:
(this is great simplification to illustrate the issues)
CURLcode fetch(CURL *curl, char *ipv6, int scope)
{
char url[256];
snprintf(url, sizeof(url), "http://[%s]/", ipv6);
CURLcode ret;
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_ADDRESS_SCOPE, scope);
return curl_easy_perform(curl);
}
This was working as expected but it fails inside container running Alpine 3.9. (libcurl 7.64.0)
bash-4.4$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
129: eth0@if130: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
bash-4.4$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
129: eth0@if130: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fc00::242:ac11:4/64 scope global flags 02
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:4/64 scope link
valid_lft forever preferred_lft forever
The issue with docker is that it uses high interface index number and than:
https://github.com/curl/curl/blob/master/lib/setopt.c#L2302-L2312
case CURLOPT_ADDRESS_SCOPE:
/*
* We always get longs when passed plain numericals, but for this value we
* know that an unsigned int will always hold the value so we blindly
* typecast to this type
*/
arg = va_arg(param, long);
if((arg < 0) || (arg > 0xf))
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.scope_id = curlx_sltoui(arg);
break;
after some digging I found workaround where I can insert scope_id to URL and the code in url.c would take it out and set scope_id to proper value:
https://github.com/curl/curl/blob/master/lib/url.c#L2177
conn->scope_id = (unsigned int)scope;
...
if(data->set.scope_id)
/* Override any scope that was set above. */
conn->scope_id = data->set.scope_id;
I verified with strace
that we pass correct sockaddr_in6
to connect() call.
It seems like the argument check for CURLOPT_ADDRESS_SCOPE is incorrect and we should let OS decide if it is valid or not.
I verified that if removed, the code works ok. There should be no harm to existing use.
I'd be happy to craft PR.
I expected the following
I expect this to work consistently, docker or not.
curl/libcurl version
bash-4.4$ curl --version
curl 7.64.0 (x86_64-alpine-linux-musl) libcurl/7.64.0 OpenSSL/1.1.1a zlib/1.2.11 libssh2/1.8.2 nghttp2/1.35.1
Release-Date: 2019-02-06
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy
operating system
Alpine Linux 3.9