nsDNSService2.cpp 32 KB

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