LCOV - code coverage report
Current view: top level - netwerk/dns - nsDNSService2.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 211 516 40.9 %
Date: 2017-07-14 16:53:18 Functions: 27 62 43.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: set sw=4 ts=8 et tw=80 : */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsDNSService2.h"
       8             : #include "nsIDNSRecord.h"
       9             : #include "nsIDNSListener.h"
      10             : #include "nsICancelable.h"
      11             : #include "nsIPrefService.h"
      12             : #include "nsIPrefBranch.h"
      13             : #include "nsIServiceManager.h"
      14             : #include "nsIXPConnect.h"
      15             : #include "nsProxyRelease.h"
      16             : #include "nsReadableUtils.h"
      17             : #include "nsString.h"
      18             : #include "nsAutoPtr.h"
      19             : #include "nsNetCID.h"
      20             : #include "nsError.h"
      21             : #include "nsDNSPrefetch.h"
      22             : #include "nsThreadUtils.h"
      23             : #include "nsIProtocolProxyService.h"
      24             : #include "prsystem.h"
      25             : #include "prnetdb.h"
      26             : #include "prmon.h"
      27             : #include "prio.h"
      28             : #include "plstr.h"
      29             : #include "nsIOService.h"
      30             : #include "nsCharSeparatedTokenizer.h"
      31             : #include "nsNetAddr.h"
      32             : #include "nsProxyRelease.h"
      33             : #include "nsIObserverService.h"
      34             : #include "nsINetworkLinkService.h"
      35             : 
      36             : #include "mozilla/Attributes.h"
      37             : #include "mozilla/net/NeckoCommon.h"
      38             : #include "mozilla/net/ChildDNSService.h"
      39             : #include "mozilla/net/DNSListenerProxy.h"
      40             : #include "mozilla/Services.h"
      41             : 
      42             : using namespace mozilla;
      43             : using namespace mozilla::net;
      44             : 
      45             : static const char kPrefDnsCacheEntries[]     = "network.dnsCacheEntries";
      46             : static const char kPrefDnsCacheExpiration[]  = "network.dnsCacheExpiration";
      47             : static const char kPrefDnsCacheGrace[]       = "network.dnsCacheExpirationGracePeriod";
      48             : static const char kPrefIPv4OnlyDomains[]     = "network.dns.ipv4OnlyDomains";
      49             : static const char kPrefDisableIPv6[]         = "network.dns.disableIPv6";
      50             : static const char kPrefDisablePrefetch[]     = "network.dns.disablePrefetch";
      51             : static const char kPrefBlockDotOnion[]       = "network.dns.blockDotOnion";
      52             : static const char kPrefDnsLocalDomains[]     = "network.dns.localDomains";
      53             : static const char kPrefDnsForceResolve[]     = "network.dns.forceResolve";
      54             : static const char kPrefDnsOfflineLocalhost[] = "network.dns.offline-localhost";
      55             : static const char kPrefDnsNotifyResolution[] = "network.dns.notifyResolution";
      56             : 
      57             : //-----------------------------------------------------------------------------
      58             : 
      59             : class nsDNSRecord : public nsIDNSRecord
      60             : {
      61             : public:
      62             :     NS_DECL_THREADSAFE_ISUPPORTS
      63             :     NS_DECL_NSIDNSRECORD
      64             : 
      65           3 :     explicit nsDNSRecord(nsHostRecord *hostRecord)
      66           3 :         : mHostRecord(hostRecord)
      67             :         , mIter(nullptr)
      68             :         , mIterGenCnt(-1)
      69           3 :         , mDone(false) {}
      70             : 
      71             : private:
      72           6 :     virtual ~nsDNSRecord() = default;
      73             : 
      74             :     RefPtr<nsHostRecord>  mHostRecord;
      75             :     NetAddrElement         *mIter;
      76             :     int                     mIterGenCnt; // the generation count of
      77             :                                          // mHostRecord->addr_info when we
      78             :                                          // start iterating
      79             :     bool                    mDone;
      80             : };
      81             : 
      82          35 : NS_IMPL_ISUPPORTS(nsDNSRecord, nsIDNSRecord)
      83             : 
      84             : NS_IMETHODIMP
      85           0 : nsDNSRecord::GetCanonicalName(nsACString &result)
      86             : {
      87             :     // this method should only be called if we have a CNAME
      88           0 :     NS_ENSURE_TRUE(mHostRecord->flags & nsHostResolver::RES_CANON_NAME,
      89             :                    NS_ERROR_NOT_AVAILABLE);
      90             : 
      91             :     // if the record is for an IP address literal, then the canonical
      92             :     // host name is the IP address literal.
      93             :     const char *cname;
      94             :     {
      95           0 :         MutexAutoLock lock(mHostRecord->addr_info_lock);
      96           0 :         if (mHostRecord->addr_info)
      97           0 :             cname = mHostRecord->addr_info->mCanonicalName ?
      98           0 :                 mHostRecord->addr_info->mCanonicalName :
      99           0 :                 mHostRecord->addr_info->mHostName;
     100             :         else
     101           0 :             cname = mHostRecord->host;
     102           0 :         result.Assign(cname);
     103             :     }
     104           0 :     return NS_OK;
     105             : }
     106             : 
     107             : NS_IMETHODIMP
     108           3 : nsDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr)
     109             : {
     110           3 :     if (mDone) {
     111           0 :         return NS_ERROR_NOT_AVAILABLE;
     112             :     }
     113             : 
     114           3 :     mHostRecord->addr_info_lock.Lock();
     115           3 :     if (mHostRecord->addr_info) {
     116           2 :         if (mIterGenCnt != mHostRecord->addr_info_gencnt) {
     117             :             // mHostRecord->addr_info has changed, restart the iteration.
     118           2 :             mIter = nullptr;
     119           2 :             mIterGenCnt = mHostRecord->addr_info_gencnt;
     120             :         }
     121             : 
     122           2 :         bool startedFresh = !mIter;
     123             : 
     124           2 :         do {
     125           2 :             if (!mIter) {
     126           2 :                 mIter = mHostRecord->addr_info->mAddresses.getFirst();
     127             :             } else {
     128           0 :                 mIter = mIter->getNext();
     129             :             }
     130             :         }
     131           2 :         while (mIter && mHostRecord->Blacklisted(&mIter->mAddress));
     132             : 
     133           2 :         if (!mIter && startedFresh) {
     134             :             // If everything was blacklisted we want to reset the blacklist (and
     135             :             // likely relearn it) and return the first address. That is better
     136             :             // than nothing.
     137           0 :             mHostRecord->ResetBlacklist();
     138           0 :             mIter = mHostRecord->addr_info->mAddresses.getFirst();
     139             :         }
     140             : 
     141           2 :         if (mIter) {
     142           2 :             memcpy(addr, &mIter->mAddress, sizeof(NetAddr));
     143             :         }
     144             : 
     145           2 :         mHostRecord->addr_info_lock.Unlock();
     146             : 
     147           2 :         if (!mIter) {
     148           0 :             mDone = true;
     149           0 :             return NS_ERROR_NOT_AVAILABLE;
     150             :         }
     151             :     } else {
     152           1 :         mHostRecord->addr_info_lock.Unlock();
     153             : 
     154           1 :         if (!mHostRecord->addr) {
     155             :             // Both mHostRecord->addr_info and mHostRecord->addr are null.
     156             :             // This can happen if mHostRecord->addr_info expired and the
     157             :             // attempt to reresolve it failed.
     158           0 :             return NS_ERROR_NOT_AVAILABLE;
     159             :         }
     160           1 :         memcpy(addr, mHostRecord->addr, sizeof(NetAddr));
     161           1 :         mDone = true;
     162             :     }
     163             : 
     164             :     // set given port
     165           3 :     port = htons(port);
     166           3 :     if (addr->raw.family == AF_INET) {
     167           3 :         addr->inet.port = port;
     168           0 :     } else if (addr->raw.family == AF_INET6) {
     169           0 :         addr->inet6.port = port;
     170             :     }
     171             : 
     172           3 :     return NS_OK;
     173             : }
     174             : 
     175             : NS_IMETHODIMP
     176           0 : nsDNSRecord::GetAddresses(nsTArray<NetAddr> & aAddressArray)
     177             : {
     178           0 :     if (mDone) {
     179           0 :         return NS_ERROR_NOT_AVAILABLE;
     180             :     }
     181             : 
     182           0 :     mHostRecord->addr_info_lock.Lock();
     183           0 :     if (mHostRecord->addr_info) {
     184           0 :         for (NetAddrElement *iter = mHostRecord->addr_info->mAddresses.getFirst();
     185           0 :              iter; iter = iter->getNext()) {
     186           0 :             if (mHostRecord->Blacklisted(&iter->mAddress)) {
     187           0 :                 continue;
     188             :             }
     189           0 :             NetAddr *addr = aAddressArray.AppendElement(NetAddr());
     190           0 :             memcpy(addr, &iter->mAddress, sizeof(NetAddr));
     191           0 :             if (addr->raw.family == AF_INET) {
     192           0 :                 addr->inet.port = 0;
     193           0 :             } else if (addr->raw.family == AF_INET6) {
     194           0 :                 addr->inet6.port = 0;
     195             :             }
     196             :         }
     197           0 :         mHostRecord->addr_info_lock.Unlock();
     198             :     } else {
     199           0 :         mHostRecord->addr_info_lock.Unlock();
     200             : 
     201           0 :         if (!mHostRecord->addr) {
     202           0 :             return NS_ERROR_NOT_AVAILABLE;
     203             :         }
     204           0 :         NetAddr *addr = aAddressArray.AppendElement(NetAddr());
     205           0 :         memcpy(addr, mHostRecord->addr, sizeof(NetAddr));
     206           0 :         if (addr->raw.family == AF_INET) {
     207           0 :             addr->inet.port = 0;
     208           0 :         } else if (addr->raw.family == AF_INET6) {
     209           0 :             addr->inet6.port = 0;
     210             :         }
     211             :     }
     212           0 :     return NS_OK;
     213             : }
     214             : 
     215             : NS_IMETHODIMP
     216           0 : nsDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr * *result)
     217             : {
     218             :     NetAddr addr;
     219           0 :     nsresult rv = GetNextAddr(port, &addr);
     220           0 :     if (NS_FAILED(rv)) return rv;
     221             : 
     222           0 :     NS_ADDREF(*result = new nsNetAddr(&addr));
     223             : 
     224           0 :     return NS_OK;
     225             : }
     226             : 
     227             : NS_IMETHODIMP
     228           0 : nsDNSRecord::GetNextAddrAsString(nsACString &result)
     229             : {
     230             :     NetAddr addr;
     231           0 :     nsresult rv = GetNextAddr(0, &addr);
     232           0 :     if (NS_FAILED(rv)) return rv;
     233             : 
     234             :     char buf[kIPv6CStrBufSize];
     235           0 :     if (NetAddrToString(&addr, buf, sizeof(buf))) {
     236           0 :         result.Assign(buf);
     237           0 :         return NS_OK;
     238             :     }
     239           0 :     NS_ERROR("NetAddrToString failed unexpectedly");
     240           0 :     return NS_ERROR_FAILURE; // conversion failed for some reason
     241             : }
     242             : 
     243             : NS_IMETHODIMP
     244           0 : nsDNSRecord::HasMore(bool *result)
     245             : {
     246           0 :     if (mDone) {
     247           0 :         *result = false;
     248           0 :         return NS_OK;
     249             :     }
     250             : 
     251           0 :     NetAddrElement *iterCopy = mIter;
     252           0 :     int iterGenCntCopy = mIterGenCnt;
     253             : 
     254             :     NetAddr addr;
     255           0 :     *result = NS_SUCCEEDED(GetNextAddr(0, &addr));
     256             : 
     257           0 :     mIter = iterCopy;
     258           0 :     mIterGenCnt = iterGenCntCopy;
     259           0 :     mDone = false;
     260             : 
     261           0 :     return NS_OK;
     262             : }
     263             : 
     264             : NS_IMETHODIMP
     265           0 : nsDNSRecord::Rewind()
     266             : {
     267           0 :     mIter = nullptr;
     268           0 :     mIterGenCnt = -1;
     269           0 :     mDone = false;
     270           0 :     return NS_OK;
     271             : }
     272             : 
     273             : NS_IMETHODIMP
     274           0 : nsDNSRecord::ReportUnusable(uint16_t aPort)
     275             : {
     276             :     // right now we don't use the port in the blacklist
     277             : 
     278           0 :     MutexAutoLock lock(mHostRecord->addr_info_lock);
     279             : 
     280             :     // Check that we are using a real addr_info (as opposed to a single
     281             :     // constant address), and that the generation count is valid. Otherwise,
     282             :     // ignore the report.
     283             : 
     284           0 :     if (mHostRecord->addr_info &&
     285           0 :         mIterGenCnt == mHostRecord->addr_info_gencnt &&
     286           0 :         mIter) {
     287           0 :         mHostRecord->ReportUnusable(&mIter->mAddress);
     288             :     }
     289             : 
     290           0 :     return NS_OK;
     291             : }
     292             : 
     293             : //-----------------------------------------------------------------------------
     294             : 
     295             : class nsDNSAsyncRequest final : public nsResolveHostCallback
     296             :                               , public nsICancelable
     297             : {
     298           3 :     ~nsDNSAsyncRequest() = default;
     299             : 
     300             : public:
     301             :     NS_DECL_THREADSAFE_ISUPPORTS
     302             :     NS_DECL_NSICANCELABLE
     303             : 
     304           3 :     nsDNSAsyncRequest(nsHostResolver   *res,
     305             :                       const nsACString &host,
     306             :                       const OriginAttributes &attrs,
     307             :                       nsIDNSListener   *listener,
     308             :                       uint16_t          flags,
     309             :                       uint16_t          af,
     310             :                       const nsACString &netInterface)
     311           3 :         : mResolver(res)
     312             :         , mHost(host)
     313             :         , mOriginAttributes(attrs)
     314             :         , mListener(listener)
     315             :         , mFlags(flags)
     316             :         , mAF(af)
     317           3 :         , mNetworkInterface(netInterface) {}
     318             : 
     319             :     void OnLookupComplete(nsHostResolver *, nsHostRecord *, nsresult) override;
     320             :     // Returns TRUE if the DNS listener arg is the same as the member listener
     321             :     // Used in Cancellations to remove DNS requests associated with a
     322             :     // particular hostname and nsIDNSListener
     323             :     bool EqualsAsyncListener(nsIDNSListener *aListener) override;
     324             : 
     325             :     size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const override;
     326             : 
     327             :     RefPtr<nsHostResolver> mResolver;
     328             :     nsCString                mHost; // hostname we're resolving
     329             :     const OriginAttributes   mOriginAttributes; // The originAttributes for this resolving
     330             :     nsCOMPtr<nsIDNSListener> mListener;
     331             :     uint16_t                 mFlags;
     332             :     uint16_t                 mAF;
     333             :     nsCString                mNetworkInterface;
     334             : };
     335             : 
     336             : void
     337           3 : nsDNSAsyncRequest::OnLookupComplete(nsHostResolver *resolver,
     338             :                                     nsHostRecord   *hostRecord,
     339             :                                     nsresult        status)
     340             : {
     341             :     // need to have an owning ref when we issue the callback to enable
     342             :     // the caller to be able to addref/release multiple times without
     343             :     // destroying the record prematurely.
     344           6 :     nsCOMPtr<nsIDNSRecord> rec;
     345           3 :     if (NS_SUCCEEDED(status)) {
     346           3 :         NS_ASSERTION(hostRecord, "no host record");
     347           3 :         rec = new nsDNSRecord(hostRecord);
     348             :     }
     349             : 
     350           3 :     mListener->OnLookupComplete(this, rec, status);
     351           3 :     mListener = nullptr;
     352             : 
     353             :     // release the reference to ourselves that was added before we were
     354             :     // handed off to the host resolver.
     355           3 :     NS_RELEASE_THIS();
     356           3 : }
     357             : 
     358             : bool
     359           0 : nsDNSAsyncRequest::EqualsAsyncListener(nsIDNSListener *aListener)
     360             : {
     361           0 :     nsCOMPtr<nsIDNSListenerProxy> wrapper = do_QueryInterface(mListener);
     362           0 :     if (wrapper) {
     363           0 :         nsCOMPtr<nsIDNSListener> originalListener;
     364           0 :         wrapper->GetOriginalListener(getter_AddRefs(originalListener));
     365           0 :         return aListener == originalListener;
     366             :     }
     367           0 :     return (aListener == mListener);
     368             : }
     369             : 
     370             : size_t
     371           0 : nsDNSAsyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
     372             : {
     373           0 :     size_t n = mallocSizeOf(this);
     374             : 
     375             :     // The following fields aren't measured.
     376             :     // - mHost, because it's a non-owning pointer
     377             :     // - mResolver, because it's a non-owning pointer
     378             :     // - mListener, because it's a non-owning pointer
     379             : 
     380           0 :     return n;
     381             : }
     382             : 
     383          24 : NS_IMPL_ISUPPORTS(nsDNSAsyncRequest, nsICancelable)
     384             : 
     385             : NS_IMETHODIMP
     386           0 : nsDNSAsyncRequest::Cancel(nsresult reason)
     387             : {
     388           0 :     NS_ENSURE_ARG(NS_FAILED(reason));
     389           0 :     mResolver->DetachCallback(mHost.get(), mOriginAttributes, mFlags, mAF,
     390           0 :                               mNetworkInterface.get(), this, reason);
     391           0 :     return NS_OK;
     392             : }
     393             : 
     394             : //-----------------------------------------------------------------------------
     395             : 
     396             : class nsDNSSyncRequest : public nsResolveHostCallback
     397             : {
     398             : public:
     399           0 :     explicit nsDNSSyncRequest(PRMonitor *mon)
     400           0 :         : mDone(false)
     401             :         , mStatus(NS_OK)
     402           0 :         , mMonitor(mon) {}
     403           0 :     virtual ~nsDNSSyncRequest() = default;
     404             : 
     405             :     void OnLookupComplete(nsHostResolver *, nsHostRecord *, nsresult) override;
     406             :     bool EqualsAsyncListener(nsIDNSListener *aListener) override;
     407             :     size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const override;
     408             : 
     409             :     bool                   mDone;
     410             :     nsresult               mStatus;
     411             :     RefPtr<nsHostRecord> mHostRecord;
     412             : 
     413             : private:
     414             :     PRMonitor             *mMonitor;
     415             : };
     416             : 
     417             : void
     418           0 : nsDNSSyncRequest::OnLookupComplete(nsHostResolver *resolver,
     419             :                                    nsHostRecord   *hostRecord,
     420             :                                    nsresult        status)
     421             : {
     422             :     // store results, and wake up nsDNSService::Resolve to process results.
     423           0 :     PR_EnterMonitor(mMonitor);
     424           0 :     mDone = true;
     425           0 :     mStatus = status;
     426           0 :     mHostRecord = hostRecord;
     427           0 :     PR_Notify(mMonitor);
     428           0 :     PR_ExitMonitor(mMonitor);
     429           0 : }
     430             : 
     431             : bool
     432           0 : nsDNSSyncRequest::EqualsAsyncListener(nsIDNSListener *aListener)
     433             : {
     434             :     // Sync request: no listener to compare
     435           0 :     return false;
     436             : }
     437             : 
     438             : size_t
     439           0 : nsDNSSyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
     440             : {
     441           0 :     size_t n = mallocSizeOf(this);
     442             : 
     443             :     // The following fields aren't measured.
     444             :     // - mHostRecord, because it's a non-owning pointer
     445             : 
     446             :     // Measurement of the following members may be added later if DMD finds it
     447             :     // is worthwhile:
     448             :     // - mMonitor
     449             : 
     450           0 :     return n;
     451             : }
     452             : 
     453           0 : class NotifyDNSResolution: public Runnable
     454             : {
     455             : public:
     456           0 :   explicit NotifyDNSResolution(const nsACString& aHostname)
     457           0 :     : mozilla::Runnable("NotifyDNSResolution")
     458           0 :     , mHostname(aHostname)
     459             :   {
     460           0 :     }
     461             : 
     462           0 :     NS_IMETHOD Run() override
     463             :     {
     464           0 :         MOZ_ASSERT(NS_IsMainThread());
     465           0 :         nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
     466           0 :         if (obs) {
     467           0 :             obs->NotifyObservers(nullptr,
     468             :                                  "dns-resolution-request",
     469           0 :                                  NS_ConvertUTF8toUTF16(mHostname).get());
     470             :         }
     471           0 :         return NS_OK;
     472             :     }
     473             : 
     474             : private:
     475             :     nsCString                                 mHostname;
     476             : };
     477             : 
     478             : //-----------------------------------------------------------------------------
     479             : 
     480           1 : nsDNSService::nsDNSService()
     481             :     : mLock("nsDNSServer.mLock")
     482             :     , mDisableIPv6(false)
     483             :     , mDisablePrefetch(false)
     484             :     , mFirstTime(true)
     485             :     , mNotifyResolution(false)
     486             :     , mOfflineLocalhost(false)
     487           1 :     , mForceResolveOn(false)
     488             : {
     489           1 : }
     490             : 
     491             : nsDNSService::~nsDNSService() = default;
     492             : 
     493         153 : NS_IMPL_ISUPPORTS(nsDNSService, nsIDNSService, nsPIDNSService, nsIObserver,
     494             :                   nsIMemoryReporter)
     495             : 
     496             : /******************************************************************************
     497             :  * nsDNSService impl:
     498             :  * singleton instance ctor/dtor methods
     499             :  ******************************************************************************/
     500             : static nsDNSService *gDNSService;
     501             : 
     502             : nsIDNSService*
     503           3 : nsDNSService::GetXPCOMSingleton()
     504             : {
     505           3 :     if (IsNeckoChild()) {
     506           2 :         return ChildDNSService::GetSingleton();
     507             :     }
     508             : 
     509           1 :     return GetSingleton();
     510             : }
     511             : 
     512             : nsDNSService*
     513           1 : nsDNSService::GetSingleton()
     514             : {
     515           1 :     NS_ASSERTION(!IsNeckoChild(), "not a parent process");
     516             : 
     517           1 :     if (gDNSService) {
     518           0 :         NS_ADDREF(gDNSService);
     519           0 :         return gDNSService;
     520             :     }
     521             : 
     522           1 :     gDNSService = new nsDNSService();
     523           1 :     if (gDNSService) {
     524           1 :         NS_ADDREF(gDNSService);
     525           1 :         if (NS_FAILED(gDNSService->Init())) {
     526           0 :               NS_RELEASE(gDNSService);
     527             :         }
     528             :     }
     529             : 
     530           1 :     return gDNSService;
     531             : }
     532             : 
     533             : NS_IMETHODIMP
     534           3 : nsDNSService::Init()
     535             : {
     536           3 :     if (mResolver)
     537           1 :         return NS_OK;
     538           2 :     NS_ENSURE_TRUE(!mResolver, NS_ERROR_ALREADY_INITIALIZED);
     539             :     // prefs
     540           2 :     uint32_t maxCacheEntries  = 400;
     541           2 :     uint32_t defaultCacheLifetime = 120; // seconds
     542           2 :     uint32_t defaultGracePeriod = 60; // seconds
     543           2 :     bool     disableIPv6      = false;
     544           2 :     bool     offlineLocalhost = true;
     545           2 :     bool     disablePrefetch  = false;
     546           2 :     bool     blockDotOnion    = true;
     547           2 :     int      proxyType        = nsIProtocolProxyService::PROXYCONFIG_DIRECT;
     548           2 :     bool     notifyResolution = false;
     549             : 
     550           4 :     nsAdoptingCString ipv4OnlyDomains;
     551           4 :     nsAdoptingCString localDomains;
     552           4 :     nsAdoptingCString forceResolve;
     553             : 
     554             :     // read prefs
     555           4 :     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     556           2 :     if (prefs) {
     557             :         int32_t val;
     558           2 :         if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheEntries, &val)))
     559           2 :             maxCacheEntries = (uint32_t) val;
     560           2 :         if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheExpiration, &val)))
     561           2 :             defaultCacheLifetime = val;
     562           2 :         if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheGrace, &val)))
     563           2 :             defaultGracePeriod = val;
     564             : 
     565             :         // ASSUMPTION: pref branch does not modify out params on failure
     566           2 :         prefs->GetBoolPref(kPrefDisableIPv6, &disableIPv6);
     567           2 :         prefs->GetCharPref(kPrefIPv4OnlyDomains, getter_Copies(ipv4OnlyDomains));
     568           2 :         prefs->GetCharPref(kPrefDnsLocalDomains, getter_Copies(localDomains));
     569           2 :         prefs->GetCharPref(kPrefDnsForceResolve, getter_Copies(forceResolve));
     570           2 :         prefs->GetBoolPref(kPrefDnsOfflineLocalhost, &offlineLocalhost);
     571           2 :         prefs->GetBoolPref(kPrefDisablePrefetch, &disablePrefetch);
     572           2 :         prefs->GetBoolPref(kPrefBlockDotOnion, &blockDotOnion);
     573             : 
     574             :         // If a manual proxy is in use, disable prefetch implicitly
     575           2 :         prefs->GetIntPref("network.proxy.type", &proxyType);
     576           2 :         prefs->GetBoolPref(kPrefDnsNotifyResolution, &notifyResolution);
     577             : 
     578           2 :         if (mFirstTime) {
     579           1 :             mFirstTime = false;
     580             : 
     581             :             // register as prefs observer
     582           1 :             prefs->AddObserver(kPrefDnsCacheEntries, this, false);
     583           1 :             prefs->AddObserver(kPrefDnsCacheExpiration, this, false);
     584           1 :             prefs->AddObserver(kPrefDnsCacheGrace, this, false);
     585           1 :             prefs->AddObserver(kPrefIPv4OnlyDomains, this, false);
     586           1 :             prefs->AddObserver(kPrefDnsLocalDomains, this, false);
     587           1 :             prefs->AddObserver(kPrefDnsForceResolve, this, false);
     588           1 :             prefs->AddObserver(kPrefDisableIPv6, this, false);
     589           1 :             prefs->AddObserver(kPrefDnsOfflineLocalhost, this, false);
     590           1 :             prefs->AddObserver(kPrefDisablePrefetch, this, false);
     591           1 :             prefs->AddObserver(kPrefBlockDotOnion, this, false);
     592           1 :             prefs->AddObserver(kPrefDnsNotifyResolution, this, false);
     593             : 
     594             :             // Monitor these to see if there is a change in proxy configuration
     595             :             // If a manual proxy is in use, disable prefetch implicitly
     596           1 :             prefs->AddObserver("network.proxy.type", this, false);
     597             :         }
     598             :     }
     599             : 
     600             :     nsCOMPtr<nsIObserverService> observerService =
     601           4 :         mozilla::services::GetObserverService();
     602           2 :     if (observerService) {
     603           2 :         observerService->AddObserver(this, "last-pb-context-exited", false);
     604           2 :         observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, false);
     605             :     }
     606             : 
     607           2 :     nsDNSPrefetch::Initialize(this);
     608             : 
     609           4 :     nsCOMPtr<nsIIDNService> idn = do_GetService(NS_IDNSERVICE_CONTRACTID);
     610             : 
     611           4 :     RefPtr<nsHostResolver> res;
     612           2 :     nsresult rv = nsHostResolver::Create(maxCacheEntries,
     613             :                                          defaultCacheLifetime,
     614             :                                          defaultGracePeriod,
     615           4 :                                          getter_AddRefs(res));
     616           2 :     if (NS_SUCCEEDED(rv)) {
     617             :         // now, set all of our member variables while holding the lock
     618           4 :         MutexAutoLock lock(mLock);
     619           2 :         mResolver = res;
     620           2 :         mIDN = idn;
     621           2 :         mIPv4OnlyDomains = ipv4OnlyDomains; // exchanges buffer ownership
     622           2 :         mOfflineLocalhost = offlineLocalhost;
     623           2 :         mDisableIPv6 = disableIPv6;
     624           2 :         mBlockDotOnion = blockDotOnion;
     625           2 :         mForceResolve = forceResolve;
     626           2 :         mForceResolveOn = !mForceResolve.IsEmpty();
     627             : 
     628             :         // Disable prefetching either by explicit preference or if a manual proxy is configured
     629           2 :         mDisablePrefetch = disablePrefetch || (proxyType == nsIProtocolProxyService::PROXYCONFIG_MANUAL);
     630             : 
     631           2 :         mLocalDomains.Clear();
     632           2 :         if (localDomains) {
     633             :             nsCCharSeparatedTokenizer tokenizer(localDomains, ',',
     634           2 :                                                 nsCCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
     635             : 
     636           2 :             while (tokenizer.hasMoreTokens()) {
     637           0 :                 mLocalDomains.PutEntry(tokenizer.nextToken());
     638             :             }
     639             :         }
     640           2 :         mNotifyResolution = notifyResolution;
     641             :     }
     642             : 
     643           2 :     RegisterWeakMemoryReporter(this);
     644             : 
     645           2 :     return rv;
     646             : }
     647             : 
     648             : NS_IMETHODIMP
     649           1 : nsDNSService::Shutdown()
     650             : {
     651           1 :     UnregisterWeakMemoryReporter(this);
     652             : 
     653           2 :     RefPtr<nsHostResolver> res;
     654             :     {
     655           2 :         MutexAutoLock lock(mLock);
     656           1 :         res = mResolver;
     657           1 :         mResolver = nullptr;
     658             :     }
     659           1 :     if (res) {
     660           1 :         res->Shutdown();
     661             :     }
     662             : 
     663             :     nsCOMPtr<nsIObserverService> observerService =
     664           2 :         mozilla::services::GetObserverService();
     665           1 :     if (observerService) {
     666           1 :         observerService->RemoveObserver(this, NS_NETWORK_LINK_TOPIC);
     667           1 :         observerService->RemoveObserver(this, "last-pb-context-exited");
     668             :     }
     669             : 
     670           2 :     return NS_OK;
     671             : }
     672             : 
     673             : bool
     674           3 : nsDNSService::GetOffline() const
     675             : {
     676           3 :     bool offline = false;
     677           6 :     nsCOMPtr<nsIIOService> io = do_GetService(NS_IOSERVICE_CONTRACTID);
     678           3 :     if (io) {
     679           3 :         io->GetOffline(&offline);
     680             :     }
     681           6 :     return offline;
     682             : }
     683             : 
     684             : NS_IMETHODIMP
     685           0 : nsDNSService::GetPrefetchEnabled(bool *outVal)
     686             : {
     687           0 :     MutexAutoLock lock(mLock);
     688           0 :     *outVal = !mDisablePrefetch;
     689           0 :     return NS_OK;
     690             : }
     691             : 
     692             : NS_IMETHODIMP
     693           0 : nsDNSService::SetPrefetchEnabled(bool inVal)
     694             : {
     695           0 :     MutexAutoLock lock(mLock);
     696           0 :     mDisablePrefetch = !inVal;
     697           0 :     return NS_OK;
     698             : }
     699             : 
     700             : nsresult
     701           3 : nsDNSService::PreprocessHostname(bool              aLocalDomain,
     702             :                                  const nsACString &aInput,
     703             :                                  nsIIDNService    *aIDN,
     704             :                                  nsACString       &aACE)
     705             : {
     706             :     // Enforce RFC 7686
     707          12 :     if (mBlockDotOnion &&
     708          12 :         StringEndsWith(aInput, NS_LITERAL_CSTRING(".onion"))) {
     709           0 :         return NS_ERROR_UNKNOWN_HOST;
     710             :     }
     711             : 
     712           3 :     if (aLocalDomain) {
     713           0 :         aACE.AssignLiteral("localhost");
     714           0 :         return NS_OK;
     715             :     }
     716             : 
     717           3 :     if (mForceResolveOn) {
     718           0 :         MutexAutoLock lock(mLock);
     719           0 :         if (!aInput.LowerCaseEqualsASCII("localhost") &&
     720           0 :             !aInput.LowerCaseEqualsASCII("127.0.0.1")) {
     721           0 :             aACE.Assign(mForceResolve);
     722           0 :             return NS_OK;
     723             :         }
     724             :     }
     725             : 
     726           3 :     if (!aIDN || IsASCII(aInput)) {
     727           3 :         aACE = aInput;
     728           3 :         return NS_OK;
     729             :     }
     730             : 
     731           0 :     if (!(IsUTF8(aInput) && NS_SUCCEEDED(aIDN->ConvertUTF8toACE(aInput, aACE)))) {
     732           0 :         return NS_ERROR_FAILURE;
     733             :     }
     734           0 :     return NS_OK;
     735             : }
     736             : 
     737             : NS_IMETHODIMP
     738           0 : nsDNSService::AsyncResolve(const nsACString  &aHostname,
     739             :                            uint32_t           flags,
     740             :                            nsIDNSListener    *listener,
     741             :                            nsIEventTarget    *target_,
     742             :                            JS::HandleValue    aOriginAttributes,
     743             :                            JSContext         *aCx,
     744             :                            uint8_t            aArgc,
     745             :                            nsICancelable    **result)
     746             : {
     747           0 :     OriginAttributes attrs;
     748             : 
     749           0 :     if (aArgc == 1) {
     750           0 :         if (!aOriginAttributes.isObject() ||
     751           0 :             !attrs.Init(aCx, aOriginAttributes)) {
     752           0 :             return NS_ERROR_INVALID_ARG;
     753             :         }
     754             :     }
     755             : 
     756           0 :     return AsyncResolveExtendedNative(aHostname, flags, EmptyCString(),
     757             :                                       listener, target_, attrs,
     758           0 :                                       result);
     759             : }
     760             : 
     761             : NS_IMETHODIMP
     762           4 : nsDNSService::AsyncResolveNative(const nsACString        &aHostname,
     763             :                                  uint32_t                 flags,
     764             :                                  nsIDNSListener          *listener,
     765             :                                  nsIEventTarget          *target_,
     766             :                                  const OriginAttributes  &aOriginAttributes,
     767             :                                  nsICancelable          **result)
     768             : {
     769           4 :     return AsyncResolveExtendedNative(aHostname, flags, EmptyCString(),
     770             :                                       listener, target_, aOriginAttributes,
     771           4 :                                       result);
     772             : }
     773             : 
     774             : NS_IMETHODIMP
     775           0 : nsDNSService::AsyncResolveExtended(const nsACString  &aHostname,
     776             :                                    uint32_t           flags,
     777             :                                    const nsACString  &aNetworkInterface,
     778             :                                    nsIDNSListener    *listener,
     779             :                                    nsIEventTarget    *target_,
     780             :                                    JS::HandleValue    aOriginAttributes,
     781             :                                    JSContext         *aCx,
     782             :                                    uint8_t           aArgc,
     783             :                                    nsICancelable    **result)
     784             : {
     785           0 :     OriginAttributes attrs;
     786             : 
     787           0 :     if (aArgc == 1) {
     788           0 :         if (!aOriginAttributes.isObject() ||
     789           0 :             !attrs.Init(aCx, aOriginAttributes)) {
     790           0 :             return NS_ERROR_INVALID_ARG;
     791             :         }
     792             :     }
     793             : 
     794             :     return AsyncResolveExtendedNative(aHostname, flags, aNetworkInterface,
     795             :                                       listener, target_, attrs,
     796           0 :                                       result);
     797             : }
     798             : 
     799             : NS_IMETHODIMP
     800           7 : nsDNSService::AsyncResolveExtendedNative(const nsACString        &aHostname,
     801             :                                          uint32_t                 flags,
     802             :                                          const nsACString        &aNetworkInterface,
     803             :                                          nsIDNSListener          *listener,
     804             :                                          nsIEventTarget          *target_,
     805             :                                          const OriginAttributes  &aOriginAttributes,
     806             :                                          nsICancelable          **result)
     807             : {
     808             :     // grab reference to global host resolver and IDN service.  beware
     809             :     // simultaneous shutdown!!
     810          14 :     RefPtr<nsHostResolver> res;
     811          14 :     nsCOMPtr<nsIIDNService> idn;
     812          14 :     nsCOMPtr<nsIEventTarget> target = target_;
     813           7 :     bool localDomain = false;
     814             :     {
     815          10 :         MutexAutoLock lock(mLock);
     816             : 
     817           7 :         if (mDisablePrefetch && (flags & RESOLVE_SPECULATE))
     818           4 :             return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
     819             : 
     820           3 :         res = mResolver;
     821           3 :         idn = mIDN;
     822           3 :         localDomain = mLocalDomains.GetEntry(aHostname);
     823             :     }
     824             : 
     825           3 :     if (mNotifyResolution) {
     826           0 :         NS_DispatchToMainThread(new NotifyDNSResolution(aHostname));
     827             :     }
     828             : 
     829           3 :     if (!res)
     830           0 :         return NS_ERROR_OFFLINE;
     831             : 
     832           6 :     nsCString hostname;
     833           3 :     nsresult rv = PreprocessHostname(localDomain, aHostname, idn, hostname);
     834           3 :     if (NS_FAILED(rv)) {
     835           0 :         return rv;
     836             :     }
     837             : 
     838           3 :     if (GetOffline() &&
     839           0 :         (!mOfflineLocalhost || !hostname.LowerCaseEqualsASCII("localhost"))) {
     840           0 :         flags |= RESOLVE_OFFLINE;
     841             :     }
     842             : 
     843             :     // make sure JS callers get notification on the main thread
     844           6 :     nsCOMPtr<nsIXPConnectWrappedJS> wrappedListener = do_QueryInterface(listener);
     845           3 :     if (wrappedListener && !target) {
     846           0 :         target = GetMainThreadEventTarget();
     847             :     }
     848             : 
     849           3 :     if (target) {
     850           0 :         listener = new DNSListenerProxy(listener, target);
     851             :     }
     852             : 
     853           3 :     uint16_t af = GetAFForLookup(hostname, flags);
     854             : 
     855             :     auto *req =
     856             :         new nsDNSAsyncRequest(res, hostname, aOriginAttributes, listener, flags, af,
     857           6 :                               aNetworkInterface);
     858           3 :     if (!req)
     859           0 :         return NS_ERROR_OUT_OF_MEMORY;
     860           3 :     NS_ADDREF(*result = req);
     861             : 
     862             :     // addref for resolver; will be released when OnLookupComplete is called.
     863           3 :     NS_ADDREF(req);
     864           3 :     rv = res->ResolveHost(req->mHost.get(), req->mOriginAttributes, flags, af,
     865           3 :                           req->mNetworkInterface.get(), req);
     866           3 :     if (NS_FAILED(rv)) {
     867           0 :         NS_RELEASE(req);
     868           0 :         NS_RELEASE(*result);
     869             :     }
     870           3 :     return rv;
     871             : }
     872             : 
     873             : NS_IMETHODIMP
     874           0 : nsDNSService::CancelAsyncResolve(const nsACString &aHostname,
     875             :                                  uint32_t          aFlags,
     876             :                                  nsIDNSListener   *aListener,
     877             :                                  nsresult          aReason,
     878             :                                  JS::HandleValue   aOriginAttributes,
     879             :                                  JSContext        *aCx,
     880             :                                  uint8_t           aArgc)
     881             : {
     882           0 :     OriginAttributes attrs;
     883             : 
     884           0 :     if (aArgc == 1) {
     885           0 :         if (!aOriginAttributes.isObject() ||
     886           0 :             !attrs.Init(aCx, aOriginAttributes)) {
     887           0 :             return NS_ERROR_INVALID_ARG;
     888             :         }
     889             :     }
     890             : 
     891           0 :     return CancelAsyncResolveExtendedNative(aHostname, aFlags, EmptyCString(),
     892           0 :                                             aListener, aReason, attrs);
     893             : }
     894             : 
     895             : NS_IMETHODIMP
     896           0 : nsDNSService::CancelAsyncResolveNative(const nsACString       &aHostname,
     897             :                                        uint32_t                aFlags,
     898             :                                        nsIDNSListener         *aListener,
     899             :                                        nsresult                aReason,
     900             :                                        const OriginAttributes &aOriginAttributes)
     901             : {
     902           0 :     return CancelAsyncResolveExtendedNative(aHostname, aFlags, EmptyCString(),
     903           0 :                                             aListener, aReason, aOriginAttributes);
     904             : }
     905             : 
     906             : NS_IMETHODIMP
     907           0 : nsDNSService::CancelAsyncResolveExtended(const nsACString &aHostname,
     908             :                                          uint32_t          aFlags,
     909             :                                          const nsACString &aNetworkInterface,
     910             :                                          nsIDNSListener   *aListener,
     911             :                                          nsresult          aReason,
     912             :                                          JS::HandleValue   aOriginAttributes,
     913             :                                          JSContext        *aCx,
     914             :                                          uint8_t           aArgc)
     915             : {
     916           0 :     OriginAttributes attrs;
     917             : 
     918           0 :     if (aArgc == 1) {
     919           0 :         if (!aOriginAttributes.isObject() ||
     920           0 :             !attrs.Init(aCx, aOriginAttributes)) {
     921           0 :             return NS_ERROR_INVALID_ARG;
     922             :         }
     923             :     }
     924             : 
     925             :     return CancelAsyncResolveExtendedNative(aHostname, aFlags, aNetworkInterface,
     926           0 :                                             aListener, aReason, attrs);
     927             : }
     928             : 
     929             : NS_IMETHODIMP
     930           0 : nsDNSService::CancelAsyncResolveExtendedNative(const nsACString       &aHostname,
     931             :                                                uint32_t                aFlags,
     932             :                                                const nsACString       &aNetworkInterface,
     933             :                                                nsIDNSListener         *aListener,
     934             :                                                nsresult                aReason,
     935             :                                                const OriginAttributes &aOriginAttributes)
     936             : {
     937             :     // grab reference to global host resolver and IDN service.  beware
     938             :     // simultaneous shutdown!!
     939           0 :     RefPtr<nsHostResolver> res;
     940           0 :     nsCOMPtr<nsIIDNService> idn;
     941           0 :     bool localDomain = false;
     942             :     {
     943           0 :         MutexAutoLock lock(mLock);
     944             : 
     945           0 :         if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE))
     946           0 :             return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
     947             : 
     948           0 :         res = mResolver;
     949           0 :         idn = mIDN;
     950           0 :         localDomain = mLocalDomains.GetEntry(aHostname);
     951             :     }
     952           0 :     if (!res)
     953           0 :         return NS_ERROR_OFFLINE;
     954             : 
     955           0 :     nsCString hostname;
     956           0 :     nsresult rv = PreprocessHostname(localDomain, aHostname, idn, hostname);
     957           0 :     if (NS_FAILED(rv)) {
     958           0 :         return rv;
     959             :     }
     960             : 
     961           0 :     uint16_t af = GetAFForLookup(hostname, aFlags);
     962             : 
     963           0 :     res->CancelAsyncRequest(hostname.get(), aOriginAttributes, aFlags, af,
     964           0 :                             nsPromiseFlatCString(aNetworkInterface).get(), aListener,
     965           0 :                             aReason);
     966           0 :     return NS_OK;
     967             : }
     968             : 
     969             : NS_IMETHODIMP
     970           0 : nsDNSService::Resolve(const nsACString  &aHostname,
     971             :                       uint32_t           flags,
     972             :                       JS::HandleValue    aOriginAttributes,
     973             :                       JSContext         *aCx,
     974             :                       uint8_t            aArgc,
     975             :                       nsIDNSRecord     **result)
     976             : {
     977           0 :     OriginAttributes attrs;
     978             : 
     979           0 :     if (aArgc == 1) {
     980           0 :         if (!aOriginAttributes.isObject() ||
     981           0 :             !attrs.Init(aCx, aOriginAttributes)) {
     982           0 :             return NS_ERROR_INVALID_ARG;
     983             :         }
     984             :     }
     985             : 
     986           0 :     return ResolveNative(aHostname, flags, attrs, result);
     987             : }
     988             : 
     989             : NS_IMETHODIMP
     990           0 : nsDNSService::ResolveNative(const nsACString        &aHostname,
     991             :                             uint32_t                 flags,
     992             :                             const OriginAttributes  &aOriginAttributes,
     993             :                             nsIDNSRecord           **result)
     994             : {
     995             :     // grab reference to global host resolver and IDN service.  beware
     996             :     // simultaneous shutdown!!
     997           0 :     RefPtr<nsHostResolver> res;
     998           0 :     nsCOMPtr<nsIIDNService> idn;
     999           0 :     bool localDomain = false;
    1000             :     {
    1001           0 :         MutexAutoLock lock(mLock);
    1002           0 :         res = mResolver;
    1003           0 :         idn = mIDN;
    1004           0 :         localDomain = mLocalDomains.GetEntry(aHostname);
    1005             :     }
    1006             : 
    1007           0 :     if (mNotifyResolution) {
    1008           0 :         NS_DispatchToMainThread(new NotifyDNSResolution(aHostname));
    1009             :     }
    1010             : 
    1011           0 :     NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE);
    1012             : 
    1013           0 :     nsCString hostname;
    1014           0 :     nsresult rv = PreprocessHostname(localDomain, aHostname, idn, hostname);
    1015           0 :     if (NS_FAILED(rv)) {
    1016           0 :         return rv;
    1017             :     }
    1018             : 
    1019           0 :     if (GetOffline() &&
    1020           0 :         (!mOfflineLocalhost || !hostname.LowerCaseEqualsASCII("localhost"))) {
    1021           0 :         flags |= RESOLVE_OFFLINE;
    1022             :     }
    1023             : 
    1024             :     //
    1025             :     // sync resolve: since the host resolver only works asynchronously, we need
    1026             :     // to use a mutex and a condvar to wait for the result.  however, since the
    1027             :     // result may be in the resolvers cache, we might get called back recursively
    1028             :     // on the same thread.  so, our mutex needs to be re-entrant.  in other words,
    1029             :     // we need to use a monitor! ;-)
    1030             :     //
    1031             : 
    1032           0 :     PRMonitor *mon = PR_NewMonitor();
    1033           0 :     if (!mon)
    1034           0 :         return NS_ERROR_OUT_OF_MEMORY;
    1035             : 
    1036           0 :     PR_EnterMonitor(mon);
    1037           0 :     nsDNSSyncRequest syncReq(mon);
    1038             : 
    1039           0 :     uint16_t af = GetAFForLookup(hostname, flags);
    1040             : 
    1041           0 :     rv = res->ResolveHost(hostname.get(), aOriginAttributes, flags, af, "", &syncReq);
    1042           0 :     if (NS_SUCCEEDED(rv)) {
    1043             :         // wait for result
    1044           0 :         while (!syncReq.mDone)
    1045           0 :             PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
    1046             : 
    1047           0 :         if (NS_FAILED(syncReq.mStatus))
    1048           0 :             rv = syncReq.mStatus;
    1049             :         else {
    1050           0 :             NS_ASSERTION(syncReq.mHostRecord, "no host record");
    1051           0 :             auto *rec = new nsDNSRecord(syncReq.mHostRecord);
    1052           0 :             if (!rec)
    1053           0 :                 rv = NS_ERROR_OUT_OF_MEMORY;
    1054             :             else
    1055           0 :                 NS_ADDREF(*result = rec);
    1056             :         }
    1057             :     }
    1058             : 
    1059           0 :     PR_ExitMonitor(mon);
    1060           0 :     PR_DestroyMonitor(mon);
    1061           0 :     return rv;
    1062             : }
    1063             : 
    1064             : NS_IMETHODIMP
    1065           0 : nsDNSService::GetMyHostName(nsACString &result)
    1066             : {
    1067             :     char name[100];
    1068           0 :     if (PR_GetSystemInfo(PR_SI_HOSTNAME, name, sizeof(name)) == PR_SUCCESS) {
    1069           0 :         result = name;
    1070           0 :         return NS_OK;
    1071             :     }
    1072           0 :     return NS_ERROR_FAILURE;
    1073             : }
    1074             : 
    1075             : NS_IMETHODIMP
    1076           1 : nsDNSService::Observe(nsISupports *subject, const char *topic, const char16_t *data)
    1077             : {
    1078             :     // We are only getting called if a preference has changed or there's a
    1079             :     // network link event.
    1080           1 :     NS_ASSERTION(strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0 ||
    1081             :                  strcmp(topic, "last-pb-context-exited") == 0 ||
    1082             :                  strcmp(topic, NS_NETWORK_LINK_TOPIC) == 0,
    1083             :                  "unexpected observe call");
    1084             : 
    1085           1 :     bool flushCache = false;
    1086           1 :     if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
    1087           0 :         nsAutoCString converted = NS_ConvertUTF16toUTF8(data);
    1088           0 :         if (mResolver && !strcmp(converted.get(), NS_NETWORK_LINK_DATA_CHANGED)) {
    1089           0 :             flushCache = true;
    1090             :         }
    1091           1 :     } else if (!strcmp(topic, "last-pb-context-exited")) {
    1092           0 :         flushCache = true;
    1093             :     }
    1094           1 :     if (flushCache) {
    1095           0 :         mResolver->FlushCache();
    1096           0 :         return NS_OK;
    1097             :     }
    1098             : 
    1099             :     //
    1100             :     // Shutdown and this function are both only called on the UI thread, so we don't
    1101             :     // have to worry about mResolver being cleared out from under us.
    1102             :     //
    1103             :     // NOTE Shutting down and reinitializing the service like this is obviously
    1104             :     // suboptimal if Observe gets called several times in a row, but we don't
    1105             :     // expect that to be the case.
    1106             :     //
    1107             : 
    1108           1 :     if (mResolver) {
    1109           1 :         Shutdown();
    1110             :     }
    1111           1 :     Init();
    1112           1 :     return NS_OK;
    1113             : }
    1114             : 
    1115             : uint16_t
    1116           3 : nsDNSService::GetAFForLookup(const nsACString &host, uint32_t flags)
    1117             : {
    1118           3 :     if (mDisableIPv6 || (flags & RESOLVE_DISABLE_IPV6))
    1119           1 :         return PR_AF_INET;
    1120             : 
    1121           4 :     MutexAutoLock lock(mLock);
    1122             : 
    1123           2 :     uint16_t af = PR_AF_UNSPEC;
    1124             : 
    1125           2 :     if (!mIPv4OnlyDomains.IsEmpty()) {
    1126             :         const char *domain, *domainEnd, *end;
    1127             :         uint32_t hostLen, domainLen;
    1128             : 
    1129             :         // see if host is in one of the IPv4-only domains
    1130           0 :         domain = mIPv4OnlyDomains.BeginReading();
    1131           0 :         domainEnd = mIPv4OnlyDomains.EndReading();
    1132             : 
    1133           0 :         nsACString::const_iterator hostStart;
    1134           0 :         host.BeginReading(hostStart);
    1135           0 :         hostLen = host.Length();
    1136             : 
    1137           0 :         do {
    1138             :             // skip any whitespace
    1139           0 :             while (*domain == ' ' || *domain == '\t')
    1140           0 :                 ++domain;
    1141             : 
    1142             :             // find end of this domain in the string
    1143           0 :             end = strchr(domain, ',');
    1144           0 :             if (!end)
    1145           0 :                 end = domainEnd;
    1146             : 
    1147             :             // to see if the hostname is in the domain, check if the domain
    1148             :             // matches the end of the hostname.
    1149           0 :             domainLen = end - domain;
    1150           0 :             if (domainLen && hostLen >= domainLen) {
    1151           0 :                 const char *hostTail = hostStart.get() + hostLen - domainLen;
    1152           0 :                 if (PL_strncasecmp(domain, hostTail, domainLen) == 0) {
    1153             :                     // now, make sure either that the hostname is a direct match or
    1154             :                     // that the hostname begins with a dot.
    1155           0 :                     if (hostLen == domainLen ||
    1156           0 :                             *hostTail == '.' || *(hostTail - 1) == '.') {
    1157           0 :                         af = PR_AF_INET;
    1158           0 :                         break;
    1159             :                     }
    1160             :                 }
    1161             :             }
    1162             : 
    1163           0 :             domain = end + 1;
    1164           0 :         } while (*end);
    1165             :     }
    1166             : 
    1167           2 :     if ((af != PR_AF_INET) && (flags & RESOLVE_DISABLE_IPV4))
    1168           0 :         af = PR_AF_INET6;
    1169             : 
    1170           2 :     return af;
    1171             : }
    1172             : 
    1173             : NS_IMETHODIMP
    1174           0 : nsDNSService::GetDNSCacheEntries(nsTArray<mozilla::net::DNSCacheEntries> *args)
    1175             : {
    1176           0 :     NS_ENSURE_TRUE(mResolver, NS_ERROR_NOT_INITIALIZED);
    1177           0 :     mResolver->GetDNSCacheEntries(args);
    1178           0 :     return NS_OK;
    1179             : }
    1180             : 
    1181             : size_t
    1182           0 : nsDNSService::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
    1183             : {
    1184             :     // Measurement of the following members may be added later if DMD finds it
    1185             :     // is worthwhile:
    1186             :     // - mIDN
    1187             :     // - mLock
    1188             : 
    1189           0 :     size_t n = mallocSizeOf(this);
    1190           0 :     n += mResolver ? mResolver->SizeOfIncludingThis(mallocSizeOf) : 0;
    1191           0 :     n += mIPv4OnlyDomains.SizeOfExcludingThisIfUnshared(mallocSizeOf);
    1192           0 :     n += mLocalDomains.SizeOfExcludingThis(mallocSizeOf);
    1193           0 :     return n;
    1194             : }
    1195             : 
    1196           0 : MOZ_DEFINE_MALLOC_SIZE_OF(DNSServiceMallocSizeOf)
    1197             : 
    1198             : NS_IMETHODIMP
    1199           0 : nsDNSService::CollectReports(nsIHandleReportCallback* aHandleReport,
    1200             :                              nsISupports* aData, bool aAnonymize)
    1201             : {
    1202           0 :     MOZ_COLLECT_REPORT(
    1203             :         "explicit/network/dns-service", KIND_HEAP, UNITS_BYTES,
    1204             :         SizeOfIncludingThis(DNSServiceMallocSizeOf),
    1205           0 :         "Memory used for the DNS service.");
    1206             : 
    1207           0 :     return NS_OK;
    1208             : }
    1209             : 

Generated by: LCOV version 1.13