billfeller.github.io icon indicating copy to clipboard operation
billfeller.github.io copied to clipboard

curl 7.19.7 connect to ipv6 failed: Network is unreachable

Open billfeller opened this issue 8 years ago • 1 comments

Principle

i call it "IPv6 First, IPv4 Graceful degradation"

Background

the local curl version is:

$ curl -V
curl 7.19.7

when i use curl 7.19.7 to get the document that tha host is binded both ipv6 and ipv4, i just got the error incidentally below:

$ curl "http://www.desidime.com/"
curl: (7) Failed to connect to 2400:8901:1::8ba2:1a0a: Network is unreachable

remark: you can also find the dns config use Google Apps toolbox just below:

Questions

there are two questions here:

  1. why curl: (7) Failed to connect to 2400:8901:1::8ba2:1a0a: Network is unreachable?
  2. why it happened when bind both IPv6 and IPv4 accidently?

i will answer it one by one.

First, why curl: (7) Failed to connect to 2400:8901:1::8ba2:1a0a: Network is unreachable?

you know that it is not a problem with resolving IPv6 addresses. That name resolution is working fine because curl reports that it cannot reach network 2400:8901:1::8ba2:1a0a; this shows that the name translation did succeed. also you can find it in the strace log below:

$ strace -o /tmp/curl.7.19.7.log curl -6 "http://www.desidime.com/"
curl: (7) Failed to connect to 2400:8901:1::8ba2:1a0a: Network is unreachable
$ grep -n -E -A5 "connect|AF_INET" /tmp/curl.7.19.7.log 

image

so the reason is that in order to reach an IPv6 address, you need to have a route to the destination address and very few connections have any IPv6 connectivity at all. On the machine I'm writing this, I have almost no IPv6 routes at all:

$ route -n -A inet6 
Kernel IPv6 routing table
Destination  Next Hop  Flags Metric Ref    Use Iface
fe80::/64    ::        U     256    0        0 eth1
ff00::/8     ::        U     256    0        0 eth1

which you can compare with IPv4 routes below:

$ route -n -A inet
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.27.12.128   0.0.0.0         255.255.255.128 U     0      0        0 eth1
169.254.0.0     0.0.0.0         255.255.0.0     U     1003   0        0 eth1
192.168.0.0     172.27.12.129   255.255.0.0     UG    0      0        0 eth1
172.16.0.0      172.27.12.129   255.240.0.0     UG    0      0        0 eth1
100.64.0.0      172.27.12.129   255.192.0.0     UG    0      0        0 eth1
10.0.0.0        172.27.12.129   255.0.0.0       UG    0      0        0 eth1
0.0.0.0         0.0.0.0         0.0.0.0         U     0      0        0 tunnat

so it means you do need an IPv6 route to the destination network and too few places provide that facility yet.

second, why it happened accidently when bind both IPv6 and IPv4?

image

check the different iocalls in the fail and suc log, i found that when it failed, it directly connect to IPv6 and not connect to IPv4. and in our network IPv6 is not rounted as above. so i think it may be the network misconfiguration or maybe wrong dns cache lead to.

Solutions

now we need to give the solutions to solve it.

  1. you can ops Ipv6 network architecture to support ipv6 network.

  2. you can just resolve name to IPv4 address by the option -4 as below

    $ curl -h|grep 'Resolve name to IPv' 
     -4/--ipv4          Resolve name to IPv4 address
     -6/--ipv6          Resolve name to IPv6 address
    $ curl -4 -I "http://www.desidime.com"
    HTTP/1.1 200 OK
    

More Infomation About IPv6 and IPv4

ref from How does a device know when to use IPv4 or IPv6?

When a client wants to connect to a server (e.g., www.desidime.com), the client issues two DNS requests in parallel: one request for IPv4 addresses, and one request for IPv6 addresses. After receiving the responses, the client generally follows the process described in IETF standard RFC3484 ”Default Address Selection for IPv6” which leans towards an assumption that dual stack is a state of transitioning towards and IPv6-only network, and hence prefers IPv6 above IPv4 by design. When a client receives a response including both an IPv4 and IPv6 address then based upon RFC3484 the IPv6 address is the preferred address. If, for whatever reason, the usage of that address was non-successful, an alternate address will be used, potentially a valid IPv4 address to connect to the remote location.

rfc3484 10.3. Configuring Preference for IPv6 or IPv4

10.3. Configuring Preference for IPv6 or IPv4

The default policy table gives IPv6 addresses higher precedence than IPv4 addresses. This means that applications will use IPv6 in preference to IPv4 when the two are equally suitable.

in the figure below that curl 7.50.1 has implement new strategy called Happy Eyeballs: Success with Dual-Stack Hosts to open up a connection over BOTH IPv4 and IPv6 and use whichever one is fastest. so it can also solve the problem perfectly. It is up to the client to decide which address it will use to connect to the remote Internet resource more reliable, not just the preferred IPv6 in rfc3484.txt.

```bash
$ strace -o /tmp/curl.7.50.1.log /tmp/****/curl/bin/curl "http://www.desidime.com"
$ cat /tmp/curl.7.50.1.log |grep -n -P -A5 "connect|AF_INET"
```  
![image](https://cloud.githubusercontent.com/assets/998505/17473410/f48311e0-5d82-11e6-85ed-91bcdd23fc26.png)

Reference

billfeller avatar Aug 08 '16 07:08 billfeller

hi, how to curl php with proxy ipv6 ? thank

DuySexy avatar Sep 15 '20 14:09 DuySexy