From 2b4e34be37c64fefab5952064fa587d4c221e7d7 Mon Sep 17 00:00:00 2001
From: Robert Story <rstory@localhost>
Date: Tue, 16 Oct 2012 23:33:24 -0400
Subject: [PATCH 16/25] XULRUNNER use NSPRs new DNSSEC functionality

---
 netwerk/dns/nsDNSService2.cpp  | 25 ++++++++++++
 netwerk/dns/nsDNSService2.h    |  4 ++
 netwerk/dns/nsHostResolver.cpp | 88 +++++++++++++++++++++++++++++++++++++++---
 netwerk/dns/nsHostResolver.h   | 29 +++++++++++++-
 4 files changed, 138 insertions(+), 8 deletions(-)

diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp
index 3bc5b5e..5a1f11c 100644
--- a/netwerk/dns/nsDNSService2.cpp
+++ b/netwerk/dns/nsDNSService2.cpp
@@ -346,6 +346,12 @@ nsDNSSyncRequest::EqualsAsyncListener(nsIDNSListener *aListener)
 
 //-----------------------------------------------------------------------------
 
+#ifdef MOZ_DNSSEC
+
+val_context_t *nsDNSService::mValContext = nullptr;
+
+#endif
+
 nsDNSService::nsDNSService()
     : mLock("nsDNSServer.mLock")
     , mFirstTime(true)
@@ -423,6 +429,11 @@ nsDNSService::Init()
         }
     }
 
+#ifdef MOZ_DNSSEC
+    if (nullptr == mValContext)
+        val_create_context((char*)"mozilla-browser", &mValContext);
+#endif
+
     // we have to null out mIDN since we might be getting re-initialized
     // as a result of a pref change.
     nsCOMPtr<nsIIDNService> idn;
@@ -440,6 +451,9 @@ nsDNSService::Init()
     nsresult rv = nsHostResolver::Create(maxCacheEntries,
                                          maxCacheLifetime,
                                          lifetimeGracePeriod,
+#ifdef MOZ_DNSSEC
+                                         mValContext,
+#endif
                                          getter_AddRefs(res));
     if (NS_SUCCEEDED(rv)) {
         // now, set all of our member variables while holding the lock
@@ -471,14 +485,25 @@ nsDNSService::Init()
 NS_IMETHODIMP
 nsDNSService::Shutdown()
 {
+#ifdef MOZ_DNSSEC
+    val_context *ctx = nullptr;
+#endif
     nsRefPtr<nsHostResolver> res;
     {
         MutexAutoLock lock(mLock);
         res = mResolver;
         mResolver = nullptr;
+#ifdef MOZ_DNSSEC
+        ctx = mValContext;
+        mValContext = nullptr;
+#endif
     }
     if (res)
         res->Shutdown();
+#ifdef MOZ_DNSSEC
+    if (nullptr != ctx)
+        val_free_context(ctx);
+#endif
     return NS_OK;
 }
 
diff --git a/netwerk/dns/nsDNSService2.h b/netwerk/dns/nsDNSService2.h
index 6126dd2..1500ebc 100644
--- a/netwerk/dns/nsDNSService2.h
+++ b/netwerk/dns/nsDNSService2.h
@@ -37,6 +37,10 @@ private:
     // mLock protects access to mResolver and mIPv4OnlyDomains
     mozilla::Mutex            mLock;
 
+#ifdef MOZ_DNSSEC
+    static val_context_t     *mValContext;
+#endif
+
     // mIPv4OnlyDomains is a comma-separated list of domains for which only
     // IPv4 DNS lookups are performed. This allows the user to disable IPv6 on
     // a per-domain basis and work around broken DNS servers. See bug 68796.
diff --git a/netwerk/dns/nsHostResolver.cpp b/netwerk/dns/nsHostResolver.cpp
index db99b46..4a66b2d 100644
--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -24,6 +24,7 @@
 #include "nsAutoPtr.h"
 #include "pratom.h"
 #include "prthread.h"
+#include "prnetdb.h"
 #include "prerror.h"
 #include "prtime.h"
 #include "prlong.h"
@@ -145,7 +146,11 @@ private:
 // this macro filters out any flags that are not used when constructing the
 // host key.  the significant flags are those that would affect the resulting
 // host record (i.e., the flags that are passed down to PR_GetAddrInfoByName).
+#ifdef MOZ_DNSSEC
+#define RES_KEY_FLAGS(_f) ((_f) & (nsHostResolver::RES_CANON_NAME|nsHostResolver::RES_EXTENDED_ERRS))
+#else
 #define RES_KEY_FLAGS(_f) ((_f) & nsHostResolver::RES_CANON_NAME)
+#endif
 
 nsHostRecord::nsHostRecord(const nsHostKey *key)
     : addr_info_lock("nsHostRecord.addr_info_lock")
@@ -161,6 +166,10 @@ nsHostRecord::nsHostRecord(const nsHostKey *key)
     memcpy((char *) host, key->host, strlen(key->host) + 1);
     flags = key->flags;
     af = key->af;
+#ifdef MOZ_DNSSEC
+    saved_status = NS_OK;
+    security_status_flags = 0;
+#endif
 
     expiration = NowInMinutes();
 
@@ -335,10 +344,17 @@ HostDB_RemoveEntry(PLDHashTable *table,
 
 nsHostResolver::nsHostResolver(uint32_t maxCacheEntries,
                                uint32_t maxCacheLifetime,
-                               uint32_t lifetimeGracePeriod)
+                               uint32_t lifetimeGracePeriod
+#ifdef MOZ_DNSSEC
+                               , val_context_t *valContext
+#endif
+    )
     : mMaxCacheEntries(maxCacheEntries)
     , mMaxCacheLifetime(maxCacheLifetime)
     , mGracePeriod(lifetimeGracePeriod)
+#ifdef MOZ_DNSSEC
+    , mValContext(valContext)
+#endif
     , mLock("nsHostResolver.mLock")
     , mIdleThreadCV(mLock, "nsHostResolver.mIdleThreadCV")
     , mNumIdleThreads(0)
@@ -500,6 +516,10 @@ nsHostResolver::ResolveHost(const char            *host,
     if (!net_IsValidHostName(nsDependentCString(host)))
         return NS_ERROR_UNKNOWN_HOST;
 
+#ifdef MOZ_DNSSEC
+    flags = flags | RES_EXTENDED_ERRS;
+#endif
+
     // if result is set inside the lock, then we need to issue the
     // callback before returning.
     nsRefPtr<nsHostRecord> result;
@@ -561,7 +581,17 @@ nsHostResolver::ResolveHost(const char            *host,
                     Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
                                           METHOD_NEGATIVE_HIT);
                     status = NS_ERROR_UNKNOWN_HOST;
+                    if (!he->rec->resolving)
+                        // return the cached failure to the caller, but try
+                        // and refresh the record in the background
+                        IssueLookup(he->rec);
+                }
+#ifdef MOZ_DNSSEC
+                else {
+                    // use the cached status value
+                    status = he->rec->saved_status;
                 }
+#endif
             }
             // if the host name is an IP address literal and has been parsed,
             // go ahead and use it.
@@ -856,6 +886,9 @@ nsHostResolver::OnLookupComplete(nsHostRecord *rec, nsresult status, PRAddrInfo
             rec->expiration += 1;                 /* one minute for negative cache */
             rec->negative = true;
         }
+#ifdef MOZ_DNSSEC
+        rec->saved_status = status;
+#endif
         rec->resolving = false;
         
         if (rec->usingAnyThread) {
@@ -946,6 +979,25 @@ nsHostResolver::CancelAsyncRequest(const char            *host,
         }
     }
 }
+//  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
+#ifdef MOZ_DNSSEC
+static nsresult
+_ns_translate_dnssec_error(PRErrorCode err)
+{
+    switch(err) {
+        case PR_DNSSEC_VALIDATION_ERROR:
+            return NS_ERROR_DNSSEC_VALIDATION_ERROR;
+            break;
+
+        case PR_DNSSEC_DNE_ERROR:
+            return NS_ERROR_DNSSEC_DNE_ERROR;
+            break;
+    }
+
+    return NS_ERROR_UNKNOWN_HOST;
+}
+
+#endif // MOZ_DNSSEC
 
 //----------------------------------------------------------------------------
 
@@ -971,13 +1023,26 @@ nsHostResolver::ThreadFunc(void *arg)
             flags |= PR_AI_NOCANONNAME;
 
         TimeStamp startTime = TimeStamp::Now();
-
-        ai = PR_GetAddrInfoByName(rec->host, rec->af, flags);
+ 
+#ifdef MOZ_DNSSEC
+        if (rec->flags & RES_EXTENDED_ERRS) {
+            ai = PR_GetAddrInfoByNameExtended(rec->host, rec->af, flags,
+                                              &(rec->security_status_flags));
 #if defined(RES_RETRY_ON_FAILURE)
-        if (!ai && rs.Reset())
+            if (!ai && rs.Reset())
+                ai = PR_GetAddrInfoByNameExtended(rec->host, rec->af, flags,
+                                              &(rec->security_status_flags));
+#endif
+        } else
+#endif
+        {
             ai = PR_GetAddrInfoByName(rec->host, rec->af, flags);
+#if defined(RES_RETRY_ON_FAILURE)
+            if (!ai && rs.Reset())
+                ai = PR_GetAddrInfoByName(rec->host, rec->af, flags);
 #endif
-
+        }
+ 
         TimeDuration elapsed = TimeStamp::Now() - startTime;
         uint32_t millis = static_cast<uint32_t>(elapsed.ToMilliseconds());
 
@@ -992,7 +1057,11 @@ nsHostResolver::ThreadFunc(void *arg)
                                   millis);
         }
         else {
+#ifdef MOZ_DNSSEC
+            status = _ns_translate_dnssec_error(PR_GetError());
+#else
             status = NS_ERROR_UNKNOWN_HOST;
+#endif
             Telemetry::Accumulate(Telemetry::DNS_FAILED_LOOKUP_TIME, millis);
         }
         
@@ -1009,6 +1078,9 @@ nsresult
 nsHostResolver::Create(uint32_t         maxCacheEntries,
                        uint32_t         maxCacheLifetime,
                        uint32_t         lifetimeGracePeriod,
+#ifdef MOZ_DNSSEC
+                       val_context_t *valContext,
+#endif
                        nsHostResolver **result)
 {
 #if defined(PR_LOGGING)
@@ -1018,7 +1090,11 @@ nsHostResolver::Create(uint32_t         maxCacheEntries,
 
     nsHostResolver *res = new nsHostResolver(maxCacheEntries,
                                              maxCacheLifetime,
-                                             lifetimeGracePeriod);
+                                             lifetimeGracePeriod
+#ifdef MOZ_DNSSEC
+                                             , valContext
+#endif
+        );
     if (!res)
         return NS_ERROR_OUT_OF_MEMORY;
     NS_ADDREF(res);
diff --git a/netwerk/dns/nsHostResolver.h b/netwerk/dns/nsHostResolver.h
index 7a592f0..dfa08eb 100644
--- a/netwerk/dns/nsHostResolver.h
+++ b/netwerk/dns/nsHostResolver.h
@@ -11,6 +11,7 @@
 #include "prclist.h"
 #include "prnetdb.h"
 #include "pldhash.h"
+#include "prerror.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/Mutex.h"
 #include "nsISupportsImpl.h"
@@ -77,7 +78,16 @@ public:
 
     uint32_t     expiration; /* measured in minutes since epoch */
 
-    bool HasResult() const { return addr_info || addr || negative; }
+#ifdef MOZ_DNSSEC
+    uint16_t     security_status_flags; /* DNSSEC information (bitmask) */
+    nsresult     saved_status;
+#endif
+ 
+    bool HasResult() const { return addr_info || addr ||
+#ifdef MOZ_DNSSEC
+            security_status_flags ||
+#endif
+            negative; }
 
     // hold addr_info_lock when calling the blacklist functions
     bool Blacklisted(PRNetAddr *query);
@@ -87,6 +97,8 @@ public:
 private:
     friend class nsHostResolver;
 
+    PRIntervalTime start;
+
     PRCList callbacks; /* list of callbacks */
 
     bool    resolving; /* true if this record is being resolved, which means
@@ -168,6 +180,9 @@ public:
     static nsresult Create(uint32_t         maxCacheEntries,  // zero disables cache
                            uint32_t         maxCacheLifetime, // minutes
                            uint32_t         lifetimeGracePeriod, // minutes
+#ifdef MOZ_DNSSEC
+                           val_context_t    *valContext,
+#endif
                            nsHostResolver **resolver);
     
     /**
@@ -227,11 +242,18 @@ public:
         RES_SPECULATE     = 1 << 4,
         //RES_DISABLE_IPV6 = 1 << 5, // Not used
         RES_OFFLINE       = 1 << 6
+#ifdef MOZ_DNSSEC
+        , RES_EXTENDED_ERRS = 1 << 7
+#endif
     };
 
 private:
     nsHostResolver(uint32_t maxCacheEntries = 50, uint32_t maxCacheLifetime = 1,
-                   uint32_t lifetimeGracePeriod = 0);
+                   uint32_t lifetimeGracePeriod = 0
+#ifdef MOZ_DNSSEC
+                   , val_context_t *valContext = nullptr
+#endif
+        );
    ~nsHostResolver();
 
     nsresult Init();
@@ -259,6 +281,9 @@ private:
     uint32_t      mMaxCacheEntries;
     uint32_t      mMaxCacheLifetime;
     uint32_t      mGracePeriod;
+#ifdef MOZ_DNSSEC
+    val_context_t *mValContext;
+#endif
     Mutex         mLock;
     CondVar       mIdleThreadCV;
     uint32_t      mNumIdleThreads;
-- 
1.7.11.7

