Why is HttpUrlConnection throwing an SSLException while on a mobile data connection?

acj picture acj · Oct 14, 2012 · Viewed 17.2k times · Source

When using Android's HttpUrlConnection library to make an HTTPS request, I sometimes see the following exception being thrown:

javax.net.ssl.SSLException: SSL handshake aborted: ssl=0x5c1b18a0: I/O error during system call, Connection reset by peer
at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:395)
...

After digging into the issue a bit, I've learned that

  • Everything works fine on wifi
  • The exception is only thrown when the device is on a mobile data connection
  • After making an HTTPS over wifi first, connecting over mobile data tends to work fine for a while
  • The problem appears to happen on a small number of specific mobile carriers

What could be happening? Are some mobile carriers interfering with HTTPS traffic?

Answer

acj picture acj · Oct 14, 2012

Short answer:

It turns out that some mobile carriers will return an IP address for DNS lookups that should have failed as non-existent. The server that the app was connecting to would fail to resolve sometimes, and the carrier would try to assist by providing a page of similar sites.


Longer answer:

The hostname for the server that my app was connecting to would sometimes fail to resolve. This would normally throw an UnknownHostException to indicate the DNS failure. I expect this to happen occasionally, and the app handles it. The SSLException was an anomaly.

On carriers that intercept failed DNS lookups, navigating a Web browser to a non-existent host will show a page of "search results" that aim to help you find what you were looking for. (Some DLS/cable ISPs do this, too.) For an app making an HTTPS request, though, this breaks the SSL handshake because the remote host is different from what the app is expecting.

The root cause was a misbehaving DNS server that would return a non-existent host error for one of the servers that my app was using. Connecting over wifi seemed to be more reliable (due to another quirk of the same DNS server). Connecting over wifi would allow the DNS entry to be cached, thus temporarily masking the problem when we would subsequently connect over a mobile data connection. Most of the time, though, the mobile carrier would intercept the failed DNS lookup and redirect us to an unexpected hostname, which resulted in a failed SSL handshake.