Search code examples
javadns

Resolve the hostname in Java code and use it


I am connecting to a service through my Java code. Let's call FQDN or hostname of service as: abc.xyz.com.

My Java implementation returns exception:

java.net.UnknownHostException: dfour6gtsg5a.streaming.us-phoenix-1.oci.oraclecloud.com
    at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:567)
    at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
    at java.base/java.net.Socket.connect(Socket.java:633)
    at java.base/sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:304)
    at java.base/sun.security.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:174)
    at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:183)
    at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:532)
    at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:637)
    at java.base/sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:266)
    at java.base/sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:380)
    at 

Now, when I include entry of FQDN of service and IPAddress in /etc/hosts as below:

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
...
100.70.125.57 abc.xyz.com

Same Java implementation works correctly as service FQDN get resolved to IP address correctly.

If I try to run Java implementation with IPAddress, I get below error:

javax.net.ssl.SSLHandshakeException: No subject alternative names matching IP address 100.70.125.57 found
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:371)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:314)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:309)
    at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:654)
    at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:473)
    at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:369)
    at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:396)

In production environment, I will not have access to /etc/hosts for editing.

How can I resolve the Service FQDN to the IPAddress inside my Java implementation?


Solution

  • The simplest way I found is to provide value true to HttpsURLConnection.setHostnameVerifier()

    You need to override the method public boolean verify(String hostname, SSLSession session) for returning true everytime.

    Below is an example:

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.lang.Exception;
    import java.net.URL;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLSession;
    
    public class SkipVerification implements Runnable {
    
        private static final String TAG = SkipVerification.class.toString();
        private String server_port;
        private String serverIP;
    
        public SkipVerification(String serverIP, String server_port){
            this.serverIP = serverIP;
            this.server_port = server_port;
        }
    
        public void run() {
            try {
                HostnameVerifier hostnameVerifier = new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                };
    
                URL url = new URL("https://" + serverIP + ":" + server_port + "/json");
                InputStream inStream = null;
    
                try {
                    HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
                    urlConnection.setRequestProperty("Content-Type", "application/json");
                    urlConnection.setHostnameVerifier(hostnameVerifier);
                    inStream = urlConnection.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
                } catch (Exception e) {
                    Log.e(TAG, "error fetching data from server", e);
                } finally {
                    if (inStream != null) {
                        inStream.close();
                    }
                }
            } catch (Exception e) {
                Log.e(TAG, "error initializing SkipVerificationn thread", e);
            }
        }
    }
    

    This works when using HttpsURLConnection class. For other implementation, please refer to comment to question by @Elliott Frisch.