From f09e6d3da3f51938c76eac7fa354206acb00406a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Felix=20D=C3=B6rre?= Date: Mon, 30 Jun 2014 20:07:07 +0200 Subject: [PATCH] Implement basic Ping mechanisms Startssl, http and dns-txt --- src/org/cacert/gigi/ping/DNSPinger.java | 71 +++++++ src/org/cacert/gigi/ping/DomainPinger.java | 5 + src/org/cacert/gigi/ping/HTTPFetch.java | 30 +++ src/org/cacert/gigi/ping/SSLPinger.java | 205 +++++++++++++++++++++ 4 files changed, 311 insertions(+) create mode 100644 src/org/cacert/gigi/ping/DNSPinger.java create mode 100644 src/org/cacert/gigi/ping/DomainPinger.java create mode 100644 src/org/cacert/gigi/ping/HTTPFetch.java create mode 100644 src/org/cacert/gigi/ping/SSLPinger.java diff --git a/src/org/cacert/gigi/ping/DNSPinger.java b/src/org/cacert/gigi/ping/DNSPinger.java new file mode 100644 index 00000000..e4373c58 --- /dev/null +++ b/src/org/cacert/gigi/ping/DNSPinger.java @@ -0,0 +1,71 @@ +package org.cacert.gigi.ping; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.LinkedList; + +public class DNSPinger extends DomainPinger { + + @Override + public void ping(String domain, String configuration, String expToken) { + try { + Process p = Runtime.getRuntime().exec( + new String[]{"dig", "+short", "NS", domain}); + BufferedReader br = new BufferedReader(new InputStreamReader( + p.getInputStream())); + String line; + LinkedList nameservers = new LinkedList(); + while ((line = br.readLine()) != null) { + nameservers.add(line); + } + p.destroy(); + StringBuffer result = new StringBuffer(); + result.append("failed: "); + boolean failed = nameservers.isEmpty(); + nameservers : for (String NS : nameservers) { + String[] call = new String[]{"dig", "+short", "TXT", + "cacert." + domain, NS}; + System.out.println(Arrays.toString(call)); + p = Runtime.getRuntime().exec(call); + br = new BufferedReader(new InputStreamReader( + p.getInputStream())); + String token = null; + boolean found = false; + while ((line = br.readLine()) != null) { + if (line.isEmpty()) { + continue; + } + found = true; + token = line.substring(1, line.length() - 1); + if (token.equals(expToken)) { + continue nameservers; + } + } + p.destroy(); + result.append(NS); + if (found) { + result.append(" DIFFER;"); + } else { + result.append(" EMPTY;"); + } + failed = true; + + } + if (!failed) { + // Success + return; + } + System.out.println(result.toString()); + } catch (IOException e) { + e.printStackTrace(); + // FAIL + } + // FAIL + } + public static void main(String[] args) { + new DNSPinger().ping("dyn.dogcraft.de", "", "salat"); + } + +} diff --git a/src/org/cacert/gigi/ping/DomainPinger.java b/src/org/cacert/gigi/ping/DomainPinger.java new file mode 100644 index 00000000..8be4c2bf --- /dev/null +++ b/src/org/cacert/gigi/ping/DomainPinger.java @@ -0,0 +1,5 @@ +package org.cacert.gigi.ping; + +public abstract class DomainPinger { + public abstract void ping(String domain, String configuration, String token); +} diff --git a/src/org/cacert/gigi/ping/HTTPFetch.java b/src/org/cacert/gigi/ping/HTTPFetch.java new file mode 100644 index 00000000..de5ec0da --- /dev/null +++ b/src/org/cacert/gigi/ping/HTTPFetch.java @@ -0,0 +1,30 @@ +package org.cacert.gigi.ping; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; + +public class HTTPFetch extends DomainPinger { + + @Override + public void ping(String domain, String configuration, String expToken) { + try { + URL u = new URL("http://" + domain + "/cacert_rai.txt"); + BufferedReader br = new BufferedReader(new InputStreamReader( + u.openStream(), "UTF-8")); + String line = br.readLine(); + if (line == null) { + // empty + return; + } + if (line.equals(expToken)) { + // found + } + // differ + } catch (IOException e) { + e.printStackTrace(); + // error + } + } +} diff --git a/src/org/cacert/gigi/ping/SSLPinger.java b/src/org/cacert/gigi/ping/SSLPinger.java new file mode 100644 index 00000000..1cf4a3f8 --- /dev/null +++ b/src/org/cacert/gigi/ping/SSLPinger.java @@ -0,0 +1,205 @@ +package org.cacert.gigi.ping; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +import javax.net.ssl.SNIHostName; +import javax.net.ssl.SNIServerName; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult.Status; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLParameters; +import javax.security.cert.X509Certificate; + +public class SSLPinger extends DomainPinger { + + @Override + public void ping(String domain, String configuration, String expToken) { + try { + SocketChannel sch = SocketChannel.open(); + String[] parts = configuration.split(":", 2); + sch.connect(new InetSocketAddress(domain, Integer + .parseInt(parts[0]))); + if (parts.length == 2) { + switch (parts[1]) { + case "xmpp" : + startXMPP(sch, false, domain); + break; + case "server-xmpp" : + startXMPP(sch, true, domain); + break; + case "smtp" : + startSMTP(sch); + break; + case "imap" : + startIMAP(sch); + break; + + } + } + test(sch, domain); + } catch (IOException e) { + e.printStackTrace(); + } + + } + private void startIMAP(SocketChannel sch) throws IOException { + Socket s = sch.socket(); + InputStream is = s.getInputStream(); + OutputStream os = s.getOutputStream(); + scanFor(is, "\n"); + os.write("ENABLE STARTTLS\r\n".getBytes()); + os.flush(); + scanFor(is, "\n"); + } + private void startXMPP(SocketChannel sch, boolean server, String domain) + throws IOException { + Socket s = sch.socket(); + InputStream is = s.getInputStream(); + OutputStream os = s.getOutputStream(); + os.write(("") + .getBytes()); + os.flush(); + os.write("" + .getBytes()); + os.flush(); + scanFor(is, ""); + + } + private void scanFor(InputStream is, String scanFor) throws IOException { + int pos = 0; + while (pos < scanFor.length()) { + if (is.read() == scanFor.charAt(pos)) { + pos++; + } else { + pos = 0; + } + } + } + private void startSMTP(SocketChannel sch) throws IOException { + Socket s = sch.socket(); + InputStream is = s.getInputStream(); + readSMTP(is); + s.getOutputStream().write("EHLO ssl.pinger\r\n".getBytes()); + s.getOutputStream().flush(); + readSMTP(is); + s.getOutputStream().write("HELP\r\n".getBytes()); + s.getOutputStream().flush(); + readSMTP(is); + s.getOutputStream().write("STARTTLS\r\n".getBytes()); + s.getOutputStream().flush(); + readSMTP(is); + } + private void readSMTP(InputStream is) throws IOException { + int counter = 0; + boolean finish = true; + while (true) { + char c = (char) is.read(); + if (counter == 3) { + if (c == ' ') { + finish = true; + } else if (c == '-') { + finish = false; + } else { + throw new Error("Invalid smtp: " + c); + } + } + if (c == '\n') { + if (finish) { + return; + } + counter = 0; + } else { + counter++; + } + } + } + private void test(SocketChannel sch, String domain) { + try { + SSLContext sc = SSLContext.getDefault(); + SSLEngine se = sc.createSSLEngine(); + ByteBuffer enc_in = ByteBuffer.allocate(se.getSession() + .getPacketBufferSize()); + ByteBuffer enc_out = ByteBuffer.allocate(se.getSession() + .getPacketBufferSize()); + ByteBuffer dec_in = ByteBuffer.allocate(se.getSession() + .getApplicationBufferSize()); + ByteBuffer dec_out = ByteBuffer.allocate(se.getSession() + .getApplicationBufferSize()); + se.setUseClientMode(true); + SSLParameters sp = se.getSSLParameters(); + sp.setServerNames(Arrays. asList(new SNIHostName( + domain))); + se.setSSLParameters(sp); + se.beginHandshake(); + enc_in.limit(0); + while (se.getHandshakeStatus() != HandshakeStatus.FINISHED + && se.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) { + switch (se.getHandshakeStatus()) { + case NEED_WRAP : + dec_out.limit(0); + se.wrap(dec_out, enc_out); + enc_out.flip(); + while (enc_out.remaining() > 0) { + sch.write(enc_out); + } + enc_out.clear(); + break; + case NEED_UNWRAP : + if (enc_in.remaining() == 0) { + enc_in.clear(); + sch.read(enc_in); + enc_in.flip(); + } + while (se.unwrap(enc_in, dec_in).getStatus() == Status.BUFFER_UNDERFLOW) { + enc_in.position(enc_in.limit()); + enc_in.limit(enc_in.capacity()); + sch.read(enc_in); + enc_in.flip(); + } + enc_in.compact(); + enc_in.flip(); + break; + case NEED_TASK : + se.getDelegatedTask().run(); + break; + case NOT_HANDSHAKING : + case FINISHED : + + } + + } + System.out.println("completed"); + System.out.println(se.getSession().getCipherSuite()); + X509Certificate[] peerCertificateChain = se.getSession() + .getPeerCertificateChain(); + for (X509Certificate x509Certificate : peerCertificateChain) { + System.out.println(x509Certificate.getSubjectDN().getName()); + } + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (SSLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + public static void main(String[] args) { + new SSLPinger().ping("dogcraft.de", "443", ""); + new SSLPinger().ping("dogcraft.de", "587:smtp", ""); + new SSLPinger().ping("dogcraft.de", "5222:xmpp", ""); + new SSLPinger().ping("dogcraft.de", "5269:server-xmpp", ""); + new SSLPinger().ping("dogcraft.de", "143:imap", ""); + } +} -- 2.39.2