Implement basic Ping mechanisms Startssl, http and dns-txt
authorFelix Dörre <felix@dogcraft.de>
Mon, 30 Jun 2014 18:07:07 +0000 (20:07 +0200)
committerFelix Dörre <felix@dogcraft.de>
Fri, 4 Jul 2014 13:58:20 +0000 (15:58 +0200)
src/org/cacert/gigi/ping/DNSPinger.java [new file with mode: 0644]
src/org/cacert/gigi/ping/DomainPinger.java [new file with mode: 0644]
src/org/cacert/gigi/ping/HTTPFetch.java [new file with mode: 0644]
src/org/cacert/gigi/ping/SSLPinger.java [new file with mode: 0644]

diff --git a/src/org/cacert/gigi/ping/DNSPinger.java b/src/org/cacert/gigi/ping/DNSPinger.java
new file mode 100644 (file)
index 0000000..e4373c5
--- /dev/null
@@ -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<String> nameservers = new LinkedList<String>();
+                       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 (file)
index 0000000..8be4c2b
--- /dev/null
@@ -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 (file)
index 0000000..de5ec0d
--- /dev/null
@@ -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 (file)
index 0000000..1cf4a3f
--- /dev/null
@@ -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(("<stream:stream to=\"" + domain + "\" xmlns=\"jabber:"
+                               + (server ? "server" : "client") + "\"" + " xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">")
+                               .getBytes());
+               os.flush();
+               os.write("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>"
+                               .getBytes());
+               os.flush();
+               scanFor(is, "<proceed");
+               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.<SNIServerName> 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", "");
+       }
+}