Search code examples
javaandroidhttpurlconnectionhostname

Android cannot resolve hostname on internal network - but I can't use IP address


My Android application is used on customers internal networks, and part of the configuration involves them entering the URL to their web service.

Android from the start seems to be unable to see hostnames inside an internal network so until now I've been suggesting people use their server's IP address. An issue that's come up recently is that a customer has applied SSL to their server meaning the URL is only accessible over https, and the self-signed certificate of course matches the hostname and not the IP address. Requests to the URL via IP address no longer work, whether you specify http or https.

Googling for days suggest either rooting the device and modifying the hosts file, or supplying an internal DNS-over-TLS server, but both of these options are unavailable to me.

It surely cannot be this hard to resolve an internal hostname?

I'm not entirely sure this is a code issue as the problem is reproducible in Chrome, but here is my code:

protected JSONObject doInBackground(String... params) {
            try {
                URL url = new URL("http://officeserver/PTSWeb/PTSCommsServer.asmx");
                HttpURLConnection huc = (HttpURLConnection) url.openConnection();
                HttpURLConnection.setFollowRedirects(false);
                huc.setConnectTimeout(5 * 1000);
                huc.setRequestMethod("GET");
                huc.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)");
                huc.connect(); //FAILS HERE WITH UNABLE TO RESOLVE HOST
                BufferedReader in = new BufferedReader(new InputStreamReader(huc.getInputStream()));
                String result = "";
                StringBuilder total = new StringBuilder();
                for (String line; (line = in.readLine()) != null; ) {
                    total.append(line).append('\n');
                }
                in.close();
                result = total.toString();
                return new JSONObject(result);
            } catch (Exception e) {
                try {
                    JSONObject MyErrorJSON = new JSONObject();
                    MyErrorJSON.accumulate("WasError", "True");
                    MyErrorJSON.accumulate("ResponseText", e.toString());
                    return MyErrorJSON;
                } catch (Exception x) {
                    return null;
                }
            }
        }

Solution

  • This has received a number of views over the past 12 months so I thought I'd drop my "answer" here in case it's not just me facing this issue.

    I've danced around this problem for well over six years now, with it becoming a major headache over the last two. I've concluded that Android is indeed incapable of resolving hostnames on any simple internal network without rooting the device. It can however find servers by IP address or via the fully qualified domain name.

    Therefore you (or in my case, my customers) need to reconfigure the SSL certificate to handle requests being sent to the IP address or the FQDN in addition to the hostname. This is done by adding both as a SAN (Subject Alternative Name) to the certificate.

    For example:

    SAN 1: DNS Name=pts
    SAN 2: DNS Name=pts.local
    SAN 3: DNS Name=pts.domain.co.uk
    SAN 4: IP Address=93.184.216.34
    SAN 5: IP Address=2606:2800:220:1:248:1893:25c8:1946
    

    Note the difference between the "DNS Name" and "IP Address" headers. It's conceivable that adding the IP address as a DNS Name may help too in certain edge cases?