Remove command invocations of "dig"
authorFelix Dörre <felix@dogcraft.de>
Wed, 27 Aug 2014 15:57:08 +0000 (17:57 +0200)
committerFelix Dörre <felix@dogcraft.de>
Thu, 28 Aug 2014 08:38:24 +0000 (10:38 +0200)
config/test.properties.template
src/org/cacert/gigi/email/EmailProvider.java
src/org/cacert/gigi/ping/DNSPinger.java
src/org/cacert/gigi/util/DNSUtil.java [new file with mode: 0644]
tests/org/cacert/gigi/ping/TestDNS.java

index 354b3f2..bc8d335 100644 (file)
@@ -26,4 +26,4 @@ sql.password=<password>
 
 domain.dnsmanage=http://you-installation-of-the/index.php
 domain.dnstest=the.dns.zone
-domain.dnsns=the.authorativ.ns.for.domain.dnstest
+domain.testns=the.authorativ.ns.for.domain.dnstest
index e82a44d..8e18813 100644 (file)
@@ -12,12 +12,14 @@ import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
-import java.util.LinkedList;
 import java.util.Properties;
 import java.util.regex.Pattern;
 
+import javax.naming.NamingException;
+
 import org.cacert.gigi.crypto.SMIME;
 import org.cacert.gigi.database.DatabaseConnection;
+import org.cacert.gigi.util.DNSUtil;
 
 public abstract class EmailProvider {
 
@@ -68,7 +70,12 @@ public abstract class EmailProvider {
             String[] parts = address.split("@", 2);
             String domain = parts[1];
 
-            LinkedList<String> mxhosts = getMxHosts(domain);
+            String[] mxhosts;
+            try {
+                mxhosts = DNSUtil.getMXEntries(domain);
+            } catch (NamingException e1) {
+                return "MX lookup for your hostname failed.";
+            }
 
             for (String host : mxhosts) {
                 try (Socket s = new Socket(host, 25); BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); PrintWriter pw = new PrintWriter(s.getOutputStream())) {
@@ -134,21 +141,4 @@ public abstract class EmailProvider {
         return FAIL;
     }
 
-    private static LinkedList<String> getMxHosts(String domain) throws IOException {
-        LinkedList<String> mxhosts = new LinkedList<String>();
-        Process dig = Runtime.getRuntime().exec(new String[] {
-                "dig", "+short", "MX", domain
-        });
-        try (BufferedReader br = new BufferedReader(new InputStreamReader(dig.getInputStream()))) {
-            String line;
-            while ((line = br.readLine()) != null) {
-                String[] mxparts = line.split(" ", 2);
-                if (mxparts.length != 2) {
-                    continue;
-                }
-                mxhosts.add(mxparts[1].substring(0, mxparts[1].length() - 1));
-            }
-        }
-        return mxhosts;
-    }
 }
index a611a23..5e735e0 100644 (file)
@@ -1,72 +1,56 @@
 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;
+import java.util.List;
+
+import javax.naming.NamingException;
 
 import org.cacert.gigi.Domain;
 import org.cacert.gigi.User;
+import org.cacert.gigi.util.DNSUtil;
 
 public class DNSPinger extends DomainPinger {
 
     @Override
     public String ping(Domain domain, String expToken, User u) {
+        String[] tokenParts = expToken.split(":", 2);
+        List<String> nameservers;
         try {
-            String[] tokenParts = expToken.split(":", 2);
-
-            Process p = Runtime.getRuntime().exec(new String[] {
-                    "dig", "+short", "NS", domain.getSuffix()
-            });
-            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", "@" + NS, "+short", "TXT", "cacert-" + tokenParts[0] + "." + domain.getSuffix()
-                };
-                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()) {
+            nameservers = Arrays.asList(DNSUtil.getNSNames(domain.getSuffix()));
+        } catch (NamingException e) {
+            return "No authorative nameserver found.";
+        }
+        StringBuffer result = new StringBuffer();
+        result.append("failed: ");
+        boolean failed = nameservers.isEmpty();
+        nameservers:
+        for (String NS : nameservers) {
+            boolean found = false;
+            try {
+                for (String token : DNSUtil.getTXTEntries("cacert-" + tokenParts[0] + "." + domain.getSuffix(), NS)) {
+                    if (token.isEmpty()) {
                         continue;
                     }
                     found = true;
-                    token = line.substring(1, line.length() - 1);
                     if (token.equals(tokenParts[1])) {
                         continue nameservers;
                     }
                 }
-                p.destroy();
-                result.append(NS);
-                if (found) {
-                    result.append(" DIFFER;");
-                } else {
-                    result.append(" EMPTY;");
-                }
-                failed = true;
-
+            } catch (NamingException e) {
+                found = false;
             }
-            if ( !failed) {
-                return PING_SUCCEDED;
+            result.append(NS);
+            if (found) {
+                result.append(" DIFFER;");
+            } else {
+                result.append(" EMPTY;");
             }
-            return result.toString();
-        } catch (IOException e) {
-            e.printStackTrace();
-            return "Connection closed";
+            failed = true;
+
         }
+        if ( !failed) {
+            return PING_SUCCEDED;
+        }
+        return result.toString();
     }
-
 }
diff --git a/src/org/cacert/gigi/util/DNSUtil.java b/src/org/cacert/gigi/util/DNSUtil.java
new file mode 100644 (file)
index 0000000..e8a3a40
--- /dev/null
@@ -0,0 +1,77 @@
+package org.cacert.gigi.util;
+
+import java.util.Arrays;
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.InitialDirContext;
+
+public class DNSUtil {
+
+    private static InitialDirContext context;
+    static {
+        Hashtable<String, String> env = new Hashtable<String, String>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
+        // env.put(Context.AUTHORITATIVE, "true");
+        // env.put(Context.PROVIDER_URL, "dns://ns.dyn.dogcraft.de");
+        try {
+            context = new InitialDirContext(env);
+        } catch (NamingException e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    public static String[] getNSNames(String name) throws NamingException {
+        Attributes dnsLookup = context.getAttributes(name, new String[] {
+            "NS"
+        });
+        return extractTextEntries(dnsLookup.get("NS"));
+    }
+
+    public static String[] getTXTEntries(String name, String server) throws NamingException {
+        Hashtable<String, String> env = new Hashtable<String, String>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
+        env.put(Context.AUTHORITATIVE, "true");
+        env.put(Context.PROVIDER_URL, "dns://" + server);
+        InitialDirContext context = new InitialDirContext(env);
+
+        Attributes dnsLookup = context.getAttributes(name, new String[] {
+            "TXT"
+        });
+
+        return extractTextEntries(dnsLookup.get("TXT"));
+    }
+
+    private static String[] extractTextEntries(Attribute nsRecords) throws NamingException {
+        if (nsRecords == null) {
+            return new String[] {};
+        }
+        String[] result = new String[nsRecords.size()];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = (String) nsRecords.get(i);
+        }
+        return result;
+    }
+
+    public static String[] getMXEntries(String domain) throws NamingException {
+        Attributes dnsLookup = context.getAttributes(domain, new String[] {
+            "MX"
+        });
+        return extractTextEntries(dnsLookup.get("MX"));
+    }
+
+    public static void main(String[] args) throws NamingException {
+        if (args[0].equals("MX")) {
+            System.out.println(Arrays.toString(getMXEntries(args[1])));
+        } else if (args[0].equals("NS")) {
+            System.out.println(Arrays.toString(getNSNames(args[1])));
+        } else if (args[0].equals("TXT")) {
+            System.out.println(Arrays.toString(getTXTEntries(args[1], args[2])));
+        }
+    }
+
+}
index 0a28491..e6c53f1 100644 (file)
@@ -14,32 +14,32 @@ import java.sql.SQLException;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import javax.naming.NamingException;
+
 import org.cacert.gigi.database.DatabaseConnection;
 import org.cacert.gigi.pages.account.DomainOverview;
 import org.cacert.gigi.testUtils.IOUtils;
 import org.cacert.gigi.testUtils.ManagedTest;
 import org.cacert.gigi.testUtils.TestEmailReciever.TestMail;
+import org.cacert.gigi.util.DNSUtil;
 import org.cacert.gigi.util.RandomToken;
 import org.junit.Test;
 
 public class TestDNS extends ManagedTest {
 
     @Test
-    public void testDNSSanity() throws IOException {
+    public void testDNSSanity() throws IOException, NamingException {
 
         String token = RandomToken.generateToken(16);
         String value = RandomToken.generateToken(16);
 
-        Process p = updateDNS(token, value);
-        String reRead = new String(IOUtils.readURL(p.getInputStream()));
-        reRead = reRead.trim();
-        reRead = reRead.substring(1, reRead.length() - 1);
+        String reRead = updateDNS(token, value);
         assertEquals(value, reRead);
 
     }
 
     @Test
-    public void testEmailAndDNS() throws IOException, InterruptedException, SQLException {
+    public void testEmailAndDNS() throws IOException, InterruptedException, SQLException, NamingException {
         String email = createUniqueName() + "@example.org";
         int uid = createVerifiedUser("a", "b", email, TEST_PASSWORD);
         String cookie = login(email, TEST_PASSWORD);
@@ -96,17 +96,14 @@ public class TestDNS extends ManagedTest {
         assertTrue(newcontent, pat.matcher(newcontent).find());
     }
 
-    private Process updateDNS(String token, String value) throws IOException, MalformedURLException {
+    private String updateDNS(String token, String value) throws IOException, MalformedURLException, NamingException {
         String test = getTestProps().getProperty("domain.dnstest");
         String targetDomain = "cacert-" + token + "." + test;
         String manage = getTestProps().getProperty("domain.dnsmanage");
         String url = manage + "t1=" + token + "&t2=" + value;
         assertEquals(200, ((HttpURLConnection) new URL(url).openConnection()).getResponseCode());
-
-        Process p = Runtime.getRuntime().exec(new String[] {
-                "dig", "@" + getTestProps().getProperty("domain.testns"), "+short", "TXT", targetDomain
-        });
-        return p;
+        String[] data = DNSUtil.getTXTEntries(targetDomain, getTestProps().getProperty("domain.testns"));
+        assertEquals(1, data.length);
+        return data[0];
     }
-
 }