Issue
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.
So using the IP address of the server is the only option, and you (or in my case, my customers) need to reconfigure the SSL certificate to handle requests being sent to the IP address in addition to the hostname. This is done by adding the IP address as a SAN (Subject Alternative Name) to the certificate.
For example:
SAN 1: DNS Name=pts
SAN 2: DNS Name=ptsserver
SAN 3: IP Address=97.188.239.34
SAN 4: IP Address=2604:2700:220:1:248:1893:25c8:1943
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?
Answered By - Psiloc
Answer Checked By - David Goodson (JavaFixing Volunteer)