From cf88b3057aa2f23d2a189db07800d98b524b5e17 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Mon, 26 Oct 2020 13:44:23 +0000
Subject: [PATCH] DoH: limit total time and max requests Better loop checking,
 force DoH off for request

---
 core/java/src/net/i2p/util/DNSOverHTTPS.java | 36 +++++++++++++++-----
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/core/java/src/net/i2p/util/DNSOverHTTPS.java b/core/java/src/net/i2p/util/DNSOverHTTPS.java
index 6b02742c3a..3d3167a765 100644
--- a/core/java/src/net/i2p/util/DNSOverHTTPS.java
+++ b/core/java/src/net/i2p/util/DNSOverHTTPS.java
@@ -43,9 +43,9 @@ public class DNSOverHTTPS implements EepGet.StatusListener {
     private static final Map<String, Result> v4Cache = new LHMCache<String, Result>(32);
     private static final Map<String, Result> v6Cache = new LHMCache<String, Result>(32);
     // v4 URLs to query, ending with '&'
-    private static final List<String> v4urls = new ArrayList<String>(4);
+    private static final List<String> v4urls = new ArrayList<String>(8);
     // v6 URLs to query, ending with '&'
-    private static final List<String> v6urls = new ArrayList<String>(4);
+    private static final List<String> v6urls = new ArrayList<String>(8);
     // consecutive failures
     private static final ObjectCounter<String> fails = new ObjectCounter<String>();
 
@@ -64,7 +64,11 @@ public class DNSOverHTTPS implements EepGet.StatusListener {
     } );
 
     static {
-        // Warning: All hostnames MUST be in loop check in lookup() below
+        // Public lists:
+        // https://dnscrypt.info/public-servers/
+        // https://github.com/curl/curl/wiki/DNS-over-HTTPS#publicly-available-servers
+        // https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Public+Resolvers#DNSPrivacyPublicResolvers-DNS-over-HTTPS(DoH)
+
         // Google
         // https://developers.google.com/speed/public-dns/docs/doh/
         // 8.8.8.8 and 8.8.4.4 now redirect to dns.google, but SSLEepGet doesn't support redirect
@@ -89,9 +93,13 @@ public class DNSOverHTTPS implements EepGet.StatusListener {
     // keep the timeout very short, as we try multiple addresses,
     // and will be falling back to regular DNS.
     private static final long TIMEOUT = 3*1000;
+    // total for v4 + v6
+    private static final long OVERALL_TIMEOUT = 10*1000;
     private static final int MAX_TTL = 24*60*60;
     // don't use a URL after this many consecutive failures
     private static final int MAX_FAILS = 3;
+    // each for v4 and v6
+    private static final int MAX_REQUESTS = 4;
     private static final int V4_CODE = 1;
     private static final int CNAME_CODE = 5;
     private static final int V6_CODE = 28;
@@ -203,21 +211,22 @@ public class DNSOverHTTPS implements EepGet.StatusListener {
     private String query(String host, Type type) {
         List<String> toQuery = new ArrayList<String>((type == Type.V6_ONLY) ? v6urls : v4urls);
         Collections.shuffle(toQuery);
+        final long timeout = System.currentTimeMillis() + OVERALL_TIMEOUT;
         if (type == Type.V4_ONLY || type == Type.V4_PREFERRED) {
             // v4 query
-            String rv = query(host, false, toQuery);
+            String rv = query(host, false, toQuery, timeout);
             if (rv != null)
                 return rv;
         }
         if (type != Type.V4_ONLY) {
             // v6 query
-            String rv = query(host, true, toQuery);
+            String rv = query(host, true, toQuery, timeout);
             if (rv != null)
                 return rv;
         }
         if (type == Type.V6_PREFERRED) {
             // v4 query after v6 query
-            String rv = query(host, false, toQuery);
+            String rv = query(host, false, toQuery, timeout);
             if (rv != null)
                 return rv;
         }
@@ -227,8 +236,16 @@ public class DNSOverHTTPS implements EepGet.StatusListener {
     /**
      *  @return null if not found
      */
-    private String query(String host, boolean isv6, List<String> toQuery) {
+    private String query(String host, boolean isv6, List<String> toQuery, long timeout) {
+        int requests = 0;
+        final String loopcheck = "https://" + host + '/';
         for (String url : toQuery) {
+            if (requests >= MAX_REQUESTS)
+                break;
+            if (System.currentTimeMillis() >= timeout)
+                break;
+            if (url.startsWith(loopcheck))
+                continue;
             if (fails.count(url) > MAX_FAILS)
                 continue;
             int tcode = isv6 ? V6_CODE : V4_CODE;
@@ -236,6 +253,7 @@ public class DNSOverHTTPS implements EepGet.StatusListener {
             log("Fetching " + furl);
             baos.reset();
             SSLEepGet eepget = new SSLEepGet(ctx, baos, furl, state);
+            eepget.forceDNSOverHTTPS(false);
             if (ctx.isRouterContext())
                 eepget.addStatusListener(this);
             else
@@ -248,9 +266,11 @@ public class DNSOverHTTPS implements EepGet.StatusListener {
             if (state == null)
                 state = eepget.getSSLState();
             // we treat all fails the same, whether server responded or not
+            requests++;
             fails.increment(url);
             log("No result from " + furl);
         }
+        log("No result after " + requests + " attempts");
         return null;
     }
 
@@ -343,7 +363,7 @@ public class DNSOverHTTPS implements EepGet.StatusListener {
             }
             log("Bad response:\n" + new String(b));
         } else {
-            log("Fail fetching");
+            log("Fail fetching, rc: " + eepget.getStatusCode());
         }
         return null;
     }
-- 
GitLab