Created
January 8, 2018 00:44
-
-
Save philipwhiuk/bbf761b1090de72e83a3064f16a22b38 to your computer and use it in GitHub Desktop.
Socket that supports DNS-SEC lookup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
import java.net.InetAddress; | |
import java.net.InetSocketAddress; | |
import java.security.KeyManagementException; | |
import java.security.NoSuchAlgorithmException; | |
import java.util.Set; | |
import android.util.Log; | |
import de.measite.minidns.dnssec.DNSSECValidationFailedException; | |
import de.measite.minidns.hla.DnssecResolverApi; | |
import de.measite.minidns.hla.ResolverResult; | |
import de.measite.minidns.record.A; | |
import de.measite.minidns.record.AAAA; | |
import de.measite.minidns.record.Data; | |
import javax.net.ssl.SSLContext; | |
import javax.net.ssl.SSLSocket; | |
import javax.net.ssl.SSLSocketFactory; | |
public class Socket extends java.net.Socket { | |
private static final int READ_TIMEOUT = 10000; | |
private static final int CONNECT_TIMEOUT = 30000; | |
private final String hostname; | |
public Socket(String hostname, int port, boolean dnssecRequired, DNSCache dnsCache) throws IOException { | |
super(); | |
this.hostname = hostname; | |
byte[] address = dnsCache.getAddress(hostname); | |
if (address != null) { | |
connect(new InetSocketAddress(InetAddress.getByAddress(address), port), CONNECT_TIMEOUT); | |
} else if (dnssecRequired) { | |
createDnsSecSocket(hostname, port); | |
} else { | |
//Just use the normal resolver which makes use of the Android cache | |
connect(new InetSocketAddress(InetAddress.getByName(hostname), port), CONNECT_TIMEOUT); | |
} | |
setSoTimeout(READ_TIMEOUT); | |
dnsCache.storeAddress(hostname, getInetAddress().getAddress()); | |
} | |
/** | |
* Create a socket to a host using a specific IP address | |
*/ | |
public Socket(String hostname, byte[] address, int port) throws IOException { | |
super(); | |
this.hostname = hostname; | |
connect(new InetSocketAddress(InetAddress.getByAddress(address), port), CONNECT_TIMEOUT); | |
} | |
/** | |
* Use MiniDNS for a DNSSec Aware Resolver | |
*/ | |
private void createDnsSecSocket(String hostname, int port) throws IOException { | |
IOException exception = new IOException("No records available"); | |
try { | |
for (AAAA record : resolveInetAddresses(hostname, AAAA.class)) { | |
try { | |
connect(new InetSocketAddress(record.getInetAddress(), port), CONNECT_TIMEOUT); | |
return; | |
} catch (IOException lastException) { | |
exception = lastException; | |
} | |
} | |
} catch (DNSSECValidationFailedException e) { | |
Log.v("K9", "DNS-SEC IPv6 validation failure - will try IPv4", e); | |
e.printStackTrace(); | |
} | |
for (A record : resolveInetAddresses(hostname, A.class)) { | |
try { | |
connect(new InetSocketAddress(record.getInetAddress(), port), CONNECT_TIMEOUT); | |
return; | |
} catch (IOException lastException) { | |
exception = lastException; | |
} | |
} | |
throw exception; | |
} | |
/** | |
* Fetch the A records | |
*/ | |
private <D extends Data> Set<D> resolveInetAddresses(String hostname, Class<D> clazz) throws IOException { | |
ResolverResult<D> result = DnssecResolverApi.INSTANCE.resolve(hostname, clazz); | |
if (!result.wasSuccessful()) { | |
throw new IOException("DNS lookup failed:" + result.getResponseCode()); | |
} | |
if (!result.isAuthenticData()) { | |
throw new IOException("DNS-SEC not available for host", result.getDnssecResultNotAuthenticException()); | |
} | |
return result.getAnswers(); | |
} | |
public SSLSocket upgradeToTLS(int tlsPort) throws KeyManagementException, NoSuchAlgorithmException, IOException { | |
SSLContext sslContext = SSLContext.getInstance("TLS"); | |
sslContext.init(null, null, null); | |
SSLSocketFactory sf = sslContext.getSocketFactory(); | |
return (SSLSocket) sf.createSocket(this, hostname, tlsPort, true); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment