Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/dns/TRRService.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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
6
#include "nsICaptivePortalService.h"
7
#include "nsIObserverService.h"
8
#include "nsIURIMutator.h"
9
#include "nsNetUtil.h"
10
#include "nsStandardURL.h"
11
#include "TRR.h"
12
#include "TRRService.h"
13
14
#include "mozilla/Preferences.h"
15
#include "mozilla/Tokenizer.h"
16
17
static const char kOpenCaptivePortalLoginEvent[] = "captive-portal-login";
18
static const char kClearPrivateData[] = "clear-private-data";
19
static const char kPurge[] = "browser:purge-session-history";
20
static const char kDisableIpv6Pref[] = "network.dns.disableIPv6";
21
22
15
#define TRR_PREF_PREFIX           "network.trr."
23
12
#define TRR_PREF(x)               TRR_PREF_PREFIX x
24
25
namespace mozilla {
26
namespace net {
27
28
#undef LOG
29
extern mozilla::LazyLogModule gHostResolverLog;
30
6
#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args)
31
32
TRRService *gTRRService = nullptr;
33
34
NS_IMPL_ISUPPORTS(TRRService, nsIObserver, nsISupportsWeakReference)
35
36
TRRService::TRRService()
37
  : mInitialized(false)
38
  , mMode(0)
39
  , mTRRBlacklistExpireTime(72 * 3600)
40
  , mTRRTimeout(3000)
41
  , mLock("trrservice")
42
  , mConfirmationNS(NS_LITERAL_CSTRING("example.com"))
43
  , mWaitForCaptive(true)
44
  , mRfc1918(false)
45
  , mCaptiveIsPassed(false)
46
  , mUseGET(false)
47
  , mDisableECS(true)
48
  , mClearTRRBLStorage(false)
49
  , mConfirmationState(CONFIRM_INIT)
50
  , mRetryConfirmInterval(1000)
51
3
{
52
3
  MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
53
3
}
54
55
nsresult
56
TRRService::Init()
57
3
{
58
3
  MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
59
3
  if (mInitialized) {
60
0
    return NS_OK;
61
0
  }
62
3
  mInitialized = true;
63
3
64
3
  nsCOMPtr<nsIObserverService> observerService =
65
3
    mozilla::services::GetObserverService();
66
3
  if (observerService) {
67
3
    observerService->AddObserver(this, NS_CAPTIVE_PORTAL_CONNECTIVITY, true);
68
3
    observerService->AddObserver(this, kOpenCaptivePortalLoginEvent, true);
69
3
    observerService->AddObserver(this, kClearPrivateData, true);
70
3
    observerService->AddObserver(this, kPurge, true);
71
3
  }
72
3
  nsCOMPtr<nsIPrefBranch> prefBranch;
73
3
  GetPrefBranch(getter_AddRefs(prefBranch));
74
3
  if (prefBranch) {
75
3
    prefBranch->AddObserver(TRR_PREF_PREFIX, this, true);
76
3
    prefBranch->AddObserver(kDisableIpv6Pref, this, true);
77
3
  }
78
3
  nsCOMPtr<nsICaptivePortalService> captivePortalService =
79
3
    do_GetService(NS_CAPTIVEPORTAL_CID);
80
3
  if (captivePortalService) {
81
3
    int32_t captiveState;
82
3
    MOZ_ALWAYS_SUCCEEDS(captivePortalService->GetState(&captiveState));
83
3
84
3
    if ((captiveState == nsICaptivePortalService::UNLOCKED_PORTAL) ||
85
3
        (captiveState == nsICaptivePortalService::NOT_CAPTIVE)) {
86
0
      mCaptiveIsPassed = true;
87
0
    }
88
3
    LOG(("TRRService::Init mCaptiveState=%d mCaptiveIsPassed=%d\n",
89
3
         captiveState, (int)mCaptiveIsPassed));
90
3
  }
91
3
92
3
  ReadPrefs(nullptr);
93
3
94
3
  gTRRService = this;
95
3
96
3
  LOG(("Initialized TRRService\n"));
97
3
  return NS_OK;
98
3
}
99
100
bool
101
TRRService::Enabled()
102
0
{
103
0
  if (mConfirmationState == CONFIRM_INIT &&
104
0
      (!mWaitForCaptive || mCaptiveIsPassed || (mMode == MODE_TRRONLY))) {
105
0
    LOG(("TRRService::Enabled => CONFIRM_TRYING\n"));
106
0
    mConfirmationState = CONFIRM_TRYING;
107
0
  }
108
0
109
0
  if (mConfirmationState == CONFIRM_TRYING) {
110
0
    LOG(("TRRService::Enabled MaybeConfirm()\n"));
111
0
    MaybeConfirm();
112
0
  }
113
0
114
0
  if (mConfirmationState != CONFIRM_OK) {
115
0
    LOG(("TRRService::Enabled mConfirmationState=%d mCaptiveIsPassed=%d\n",
116
0
         (int)mConfirmationState,
117
0
         (int)mCaptiveIsPassed));
118
0
  }
119
0
120
0
  return (mConfirmationState == CONFIRM_OK);
121
0
}
122
123
void
124
TRRService::GetPrefBranch(nsIPrefBranch **result)
125
3
{
126
3
  MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
127
3
  *result = nullptr;
128
3
  CallGetService(NS_PREFSERVICE_CONTRACTID, result);
129
3
}
130
131
nsresult
132
TRRService::ReadPrefs(const char *name)
133
3
{
134
3
  MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
135
3
  if (!name || !strcmp(name, TRR_PREF("mode"))) {
136
3
    // 0 - off, 1 - parallel, 2 - TRR first, 3 - TRR only, 4 - shadow,
137
3
    // 5 - explicit off
138
3
    uint32_t tmp;
139
3
    if (NS_SUCCEEDED(Preferences::GetUint(TRR_PREF("mode"), &tmp))) {
140
3
      if (tmp > MODE_TRROFF) {
141
0
        tmp = MODE_TRROFF;
142
0
      }
143
3
      mMode = tmp;
144
3
    }
145
3
  }
146
3
  if (!name || !strcmp(name, TRR_PREF("uri"))) {
147
3
    // URI Template, RFC 6570.
148
3
    MutexAutoLock lock(mLock);
149
3
    nsAutoCString old(mPrivateURI);
150
3
    Preferences::GetCString(TRR_PREF("uri"), mPrivateURI);
151
3
    nsAutoCString scheme;
152
3
    if (!mPrivateURI.IsEmpty()) {
153
0
      nsCOMPtr<nsIIOService> ios(do_GetIOService());
154
0
      if (ios) {
155
0
        ios->ExtractScheme(mPrivateURI, scheme);
156
0
      }
157
0
    }
158
3
    if (!mPrivateURI.IsEmpty() && !scheme.Equals("https")) {
159
0
      LOG(("TRRService TRR URI %s is not https. Not used.\n",
160
0
           mPrivateURI.get()));
161
0
      mPrivateURI.Truncate();
162
0
    }
163
3
    if (!mPrivateURI.IsEmpty()) {
164
0
      // cut off everything from "{" to "}" sequences (potentially multiple),
165
0
      // as a crude conversion from template into URI.
166
0
      nsAutoCString uri(mPrivateURI);
167
0
168
0
      do {
169
0
        nsCCharSeparatedTokenizer openBrace(uri, '{');
170
0
        if (openBrace.hasMoreTokens()) {
171
0
          // the 'nextToken' is the left side of the open brace (or full uri)
172
0
          nsAutoCString prefix(openBrace.nextToken());
173
0
174
0
          // if there is an open brace, there's another token
175
0
          const nsACString& endBrace = openBrace.nextToken();
176
0
          nsCCharSeparatedTokenizer closeBrace(endBrace, '}');
177
0
          if (closeBrace.hasMoreTokens()) {
178
0
            // there is a close brace as well, make a URI out of the prefix
179
0
            // and the suffix
180
0
            closeBrace.nextToken();
181
0
            nsAutoCString suffix(closeBrace.nextToken());
182
0
            uri = prefix + suffix;
183
0
          } else {
184
0
            // no (more) close brace
185
0
            break;
186
0
          }
187
0
        } else {
188
0
          // no (more) open brace
189
0
          break;
190
0
        }
191
0
      } while (true);
192
0
      mPrivateURI = uri;
193
0
    }
194
3
    if (!old.IsEmpty() && !mPrivateURI.Equals(old)) {
195
0
      mClearTRRBLStorage = true;
196
0
      LOG(("TRRService clearing blacklist because of change is uri service\n"));
197
0
    }
198
3
  }
199
3
  if (!name || !strcmp(name, TRR_PREF("credentials"))) {
200
3
    MutexAutoLock lock(mLock);
201
3
    Preferences::GetCString(TRR_PREF("credentials"), mPrivateCred);
202
3
  }
203
3
  if (!name || !strcmp(name, TRR_PREF("confirmationNS"))) {
204
3
    MutexAutoLock lock(mLock);
205
3
    nsAutoCString old(mConfirmationNS);
206
3
    Preferences::GetCString(TRR_PREF("confirmationNS"), mConfirmationNS);
207
3
    if (name && !old.IsEmpty() && !mConfirmationNS.Equals(old) &&
208
3
        (mConfirmationState > CONFIRM_TRYING)) {
209
0
      LOG(("TRR::ReadPrefs: restart confirmationNS state\n"));
210
0
      mConfirmationState = CONFIRM_TRYING;
211
0
    }
212
3
  }
213
3
  if (!name || !strcmp(name, TRR_PREF("bootstrapAddress"))) {
214
3
    MutexAutoLock lock(mLock);
215
3
    Preferences::GetCString(TRR_PREF("bootstrapAddress"), mBootstrapAddr);
216
3
  }
217
3
  if (!name || !strcmp(name, TRR_PREF("wait-for-portal"))) {
218
3
    // Wait for captive portal?
219
3
    bool tmp;
220
3
    if (NS_SUCCEEDED(Preferences::GetBool(TRR_PREF("wait-for-portal"), &tmp))) {
221
3
      mWaitForCaptive = tmp;
222
3
    }
223
3
  }
224
3
  if (!name || !strcmp(name, TRR_PREF("allow-rfc1918"))) {
225
3
    bool tmp;
226
3
    if (NS_SUCCEEDED(Preferences::GetBool(TRR_PREF("allow-rfc1918"), &tmp))) {
227
3
      mRfc1918 = tmp;
228
3
    }
229
3
  }
230
3
  if (!name || !strcmp(name, TRR_PREF("useGET"))) {
231
3
    bool tmp;
232
3
    if (NS_SUCCEEDED(Preferences::GetBool(TRR_PREF("useGET"), &tmp))) {
233
3
      mUseGET = tmp;
234
3
    }
235
3
  }
236
3
  if (!name || !strcmp(name, TRR_PREF("blacklist-duration"))) {
237
3
    // prefs is given in number of seconds
238
3
    uint32_t secs;
239
3
    if (NS_SUCCEEDED(Preferences::GetUint(TRR_PREF("blacklist-duration"), &secs))) {
240
3
      mTRRBlacklistExpireTime = secs;
241
3
    }
242
3
  }
243
3
  if (!name || !strcmp(name, TRR_PREF("request-timeout"))) {
244
3
    // number of milliseconds
245
3
    uint32_t ms;
246
3
    if (NS_SUCCEEDED(Preferences::GetUint(TRR_PREF("request-timeout"), &ms))) {
247
3
      mTRRTimeout = ms;
248
3
    }
249
3
  }
250
3
  if (!name || !strcmp(name, TRR_PREF("early-AAAA"))) {
251
3
    bool tmp;
252
3
    if (NS_SUCCEEDED(Preferences::GetBool(TRR_PREF("early-AAAA"), &tmp))) {
253
3
      mEarlyAAAA = tmp;
254
3
    }
255
3
  }
256
3
  if (!name || !strcmp(name, kDisableIpv6Pref)) {
257
3
    bool tmp;
258
3
    if (NS_SUCCEEDED(Preferences::GetBool(kDisableIpv6Pref, &tmp))) {
259
3
      mDisableIPv6 = tmp;
260
3
    }
261
3
  }
262
3
  if (!name || !strcmp(name, TRR_PREF("disable-ECS"))) {
263
3
    bool tmp;
264
3
    if (NS_SUCCEEDED(Preferences::GetBool(TRR_PREF("disable-ECS"), &tmp))) {
265
3
      mDisableECS = tmp;
266
3
    }
267
3
  }
268
3
269
3
  return NS_OK;
270
3
}
271
272
nsresult
273
TRRService::GetURI(nsCString &result)
274
0
{
275
0
  MutexAutoLock lock(mLock);
276
0
  result = mPrivateURI;
277
0
  return NS_OK;
278
0
}
279
280
nsresult
281
TRRService::GetCredentials(nsCString &result)
282
0
{
283
0
  MutexAutoLock lock(mLock);
284
0
  result = mPrivateCred;
285
0
  return NS_OK;
286
0
}
287
288
nsresult
289
TRRService::Start()
290
0
{
291
0
  MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
292
0
  if (!mInitialized) {
293
0
    return NS_ERROR_NOT_INITIALIZED;
294
0
  }
295
0
  return NS_OK;
296
0
}
297
298
TRRService::~TRRService()
299
0
{
300
0
  MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
301
0
  LOG(("Exiting TRRService\n"));
302
0
  gTRRService = nullptr;
303
0
}
304
305
NS_IMETHODIMP
306
TRRService::Observe(nsISupports *aSubject,
307
                    const char * aTopic,
308
                    const char16_t * aData)
309
0
{
310
0
  MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
311
0
  LOG(("TRR::Observe() topic=%s\n", aTopic));
312
0
  if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
313
0
    ReadPrefs(NS_ConvertUTF16toUTF8(aData).get());
314
0
315
0
    if (((mConfirmationState == CONFIRM_INIT) &&
316
0
         !mBootstrapAddr.IsEmpty() &&
317
0
         (mMode == MODE_TRRONLY))  ||
318
0
        (mConfirmationState == CONFIRM_FAILED)) {
319
0
      mConfirmationState = CONFIRM_TRYING;
320
0
      MaybeConfirm();
321
0
    }
322
0
323
0
  } else if (!strcmp(aTopic, kOpenCaptivePortalLoginEvent)) {
324
0
    // We are in a captive portal
325
0
    LOG(("TRRservice in captive portal\n"));
326
0
    mCaptiveIsPassed = false;
327
0
  } else if (!strcmp(aTopic, NS_CAPTIVE_PORTAL_CONNECTIVITY)) {
328
0
    nsAutoCString data = NS_ConvertUTF16toUTF8(aData);
329
0
    LOG(("TRRservice captive portal was %s\n", data.get()));
330
0
    if (!mTRRBLStorage) {
331
0
      mTRRBLStorage = DataStorage::Get(DataStorageClass::TRRBlacklist);
332
0
      if (mTRRBLStorage) {
333
0
        bool storageWillPersist = true;
334
0
        if (NS_FAILED(mTRRBLStorage->Init(storageWillPersist))) {
335
0
          mTRRBLStorage = nullptr;
336
0
        }
337
0
        if (mClearTRRBLStorage) {
338
0
          if (mTRRBLStorage) {
339
0
            mTRRBLStorage->Clear();
340
0
          }
341
0
          mClearTRRBLStorage = false;
342
0
        }
343
0
      }
344
0
    }
345
0
346
0
    if (!mCaptiveIsPassed) {
347
0
      if (mConfirmationState != CONFIRM_OK) {
348
0
        mConfirmationState = CONFIRM_TRYING;
349
0
        MaybeConfirm();
350
0
      }
351
0
    } else {
352
0
      LOG(("TRRservice CP clear when already up!\n"));
353
0
    }
354
0
355
0
    mCaptiveIsPassed = true;
356
0
357
0
  } else if (!strcmp(aTopic, kClearPrivateData) ||
358
0
             !strcmp(aTopic, kPurge)) {
359
0
    // flush the TRR blacklist, both in-memory and on-disk
360
0
    if (mTRRBLStorage) {
361
0
      mTRRBLStorage->Clear();
362
0
    }
363
0
  }
364
0
  return NS_OK;
365
0
}
366
367
void
368
TRRService::MaybeConfirm()
369
0
{
370
0
  if (TRR_DISABLED(mMode) || mConfirmer ||
371
0
      mConfirmationState != CONFIRM_TRYING) {
372
0
    LOG(("TRRService:MaybeConfirm mode=%d, mConfirmer=%p mConfirmationState=%d\n",
373
0
         (int)mMode, (void *)mConfirmer, (int)mConfirmationState));
374
0
    return;
375
0
  }
376
0
  nsAutoCString host;
377
0
  {
378
0
    MutexAutoLock lock(mLock);
379
0
    host = mConfirmationNS;
380
0
  }
381
0
  if (host.Equals("skip")) {
382
0
    LOG(("TRRService starting confirmation test %s SKIPPED\n",
383
0
         mPrivateURI.get()));
384
0
    mConfirmationState = CONFIRM_OK;
385
0
  } else {
386
0
    LOG(("TRRService starting confirmation test %s %s\n",
387
0
         mPrivateURI.get(), host.get()));
388
0
    mConfirmer = new TRR(this, host, TRRTYPE_NS, false);
389
0
    NS_DispatchToMainThread(mConfirmer);
390
0
  }
391
0
}
392
393
bool
394
TRRService::MaybeBootstrap(const nsACString &aPossible, nsACString &aResult)
395
0
{
396
0
  MutexAutoLock lock(mLock);
397
0
  if (TRR_DISABLED(mMode) || mBootstrapAddr.IsEmpty()) {
398
0
    return false;
399
0
  }
400
0
401
0
  nsCOMPtr<nsIURI> url;
402
0
  nsresult rv = NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
403
0
    .Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
404
0
                            nsIStandardURL::URLTYPE_STANDARD, 443,
405
0
                            mPrivateURI, nullptr, nullptr, nullptr))
406
0
    .Finalize(url);
407
0
  if (NS_FAILED(rv)) {
408
0
    LOG(("TRRService::MaybeBootstrap failed to create URI!\n"));
409
0
    return false;
410
0
  }
411
0
412
0
  nsAutoCString host;
413
0
  url->GetHost(host);
414
0
  if (!aPossible.Equals(host)) {
415
0
    return false;
416
0
  }
417
0
  LOG(("TRRService::MaybeBootstrap: use %s instead of %s\n",
418
0
       mBootstrapAddr.get(), host.get()));
419
0
  aResult = mBootstrapAddr;
420
0
  return true;
421
0
}
422
423
// When running in TRR-only mode, the blacklist is not used and it will also
424
// try resolving the localhost / .local names.
425
bool
426
TRRService::IsTRRBlacklisted(const nsACString &aHost, bool privateBrowsing,
427
                             bool aParentsToo) // false if domain
428
0
{
429
0
  if (mMode == MODE_TRRONLY) {
430
0
    return false; // might as well try
431
0
  }
432
0
433
0
  // hardcode these so as to not worry about expiration
434
0
  if (StringEndsWith(aHost, NS_LITERAL_CSTRING(".local")) ||
435
0
      aHost.Equals(NS_LITERAL_CSTRING("localhost"))) {
436
0
    return true;
437
0
  }
438
0
439
0
  if (!Enabled()) {
440
0
    return true;
441
0
  }
442
0
  if (!mTRRBLStorage) {
443
0
    return false;
444
0
  }
445
0
446
0
  // Only use the Storage API in the main thread
447
0
  MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
448
0
449
0
  if (mClearTRRBLStorage) {
450
0
    mTRRBLStorage->Clear();
451
0
    mClearTRRBLStorage = false;
452
0
    return false; // just cleared!
453
0
  }
454
0
455
0
  int32_t dot = aHost.FindChar('.');
456
0
  if ((dot == kNotFound) && aParentsToo) {
457
0
    // Only if a full host name. Domains can be dotless to be able to
458
0
    // blacklist entire TLDs
459
0
    return true;
460
0
  } else if(dot != kNotFound) {
461
0
    // there was a dot, check the parent first
462
0
    dot++;
463
0
    nsDependentCSubstring domain = Substring(aHost, dot, aHost.Length() - dot);
464
0
    nsAutoCString check(domain);
465
0
466
0
    // recursively check the domain part of this name
467
0
    if (IsTRRBlacklisted(check, privateBrowsing, false)) {
468
0
      // the domain name of this name is already TRR blacklisted
469
0
      return true;
470
0
    }
471
0
  }
472
0
473
0
  MutexAutoLock lock(mLock);
474
0
  // use a unified casing for the hashkey
475
0
  nsAutoCString hashkey(aHost);
476
0
  nsCString val(mTRRBLStorage->Get(hashkey, privateBrowsing ?
477
0
                                   DataStorage_Private : DataStorage_Persistent));
478
0
479
0
  if (!val.IsEmpty()) {
480
0
    nsresult code;
481
0
    int32_t until = val.ToInteger(&code) + mTRRBlacklistExpireTime;
482
0
    int32_t expire = NowInSeconds();
483
0
    if (NS_SUCCEEDED(code) && (until > expire)) {
484
0
      LOG(("Host [%s] is TRR blacklisted\n", nsCString(aHost).get()));
485
0
      return true;
486
0
    }
487
0
    // the blacklisted entry has expired
488
0
    RefPtr<DataStorage> storage = mTRRBLStorage;
489
0
    nsCOMPtr<nsIRunnable> runnable =
490
0
      NS_NewRunnableFunction("proxyStorageRemove",
491
0
                              [storage, hashkey, privateBrowsing]() {
492
0
                                storage->Remove(hashkey, privateBrowsing ?
493
0
                                                DataStorage_Private :
494
0
                                                DataStorage_Persistent);
495
0
                              });
496
0
    if (!NS_IsMainThread()) {
497
0
      NS_DispatchToMainThread(runnable);
498
0
    } else {
499
0
      runnable->Run();
500
0
    }
501
0
  }
502
0
  return false;
503
0
}
504
505
class ProxyBlacklist : public Runnable
506
{
507
public:
508
  ProxyBlacklist(TRRService *service, const nsACString &aHost, bool pb, bool aParentsToo)
509
    : mozilla::Runnable("proxyBlackList")
510
    , mService(service), mHost(aHost), mPB(pb), mParentsToo(aParentsToo)
511
0
  { }
512
513
  NS_IMETHOD Run() override
514
0
  {
515
0
    mService->TRRBlacklist(mHost, mPB, mParentsToo);
516
0
    mService = nullptr;
517
0
    return NS_OK;
518
0
  }
519
520
private:
521
  RefPtr<TRRService> mService;
522
  nsCString mHost;
523
  bool      mPB;
524
  bool      mParentsToo;
525
};
526
527
void
528
TRRService::TRRBlacklist(const nsACString &aHost, bool privateBrowsing, bool aParentsToo)
529
0
{
530
0
  if (!mTRRBLStorage) {
531
0
    return;
532
0
  }
533
0
534
0
  if (!NS_IsMainThread()) {
535
0
    NS_DispatchToMainThread(new ProxyBlacklist(this, aHost,
536
0
                                               privateBrowsing, aParentsToo));
537
0
    return;
538
0
  }
539
0
540
0
  LOG(("TRR blacklist %s\n", nsCString(aHost).get()));
541
0
  nsAutoCString hashkey(aHost);
542
0
  nsAutoCString val;
543
0
  val.AppendInt( NowInSeconds() ); // creation time
544
0
545
0
  // this overwrites any existing entry
546
0
  {
547
0
    MutexAutoLock lock(mLock);
548
0
    mTRRBLStorage->Put(hashkey, val, privateBrowsing ?
549
0
                       DataStorage_Private : DataStorage_Persistent);
550
0
  }
551
0
552
0
  if (aParentsToo) {
553
0
    // when given a full host name, verify its domain as well
554
0
    int32_t dot = aHost.FindChar('.');
555
0
    if (dot != kNotFound) {
556
0
      // this has a domain to be checked
557
0
      dot++;
558
0
      nsDependentCSubstring domain = Substring(aHost, dot, aHost.Length() - dot);
559
0
      nsAutoCString check(domain);
560
0
      if (IsTRRBlacklisted(check, privateBrowsing, false)) {
561
0
        // the domain part is already blacklisted, no need to add this entry
562
0
        return;
563
0
      }
564
0
      // verify 'check' over TRR
565
0
      LOG(("TRR: verify if '%s' resolves as NS\n", check.get()));
566
0
567
0
      // check if there's an NS entry for this name
568
0
      RefPtr<TRR> trr = new TRR(this, check, TRRTYPE_NS, privateBrowsing);
569
0
      NS_DispatchToMainThread(trr);
570
0
    }
571
0
  }
572
0
}
573
574
NS_IMETHODIMP
575
TRRService::Notify(nsITimer *aTimer)
576
0
{
577
0
  if (aTimer == mRetryConfirmTimer) {
578
0
    mRetryConfirmTimer = nullptr;
579
0
    if (mConfirmationState == CONFIRM_FAILED) {
580
0
      LOG(("TRRService retry NS of %s\n", mConfirmationNS.get()));
581
0
      mConfirmationState = CONFIRM_TRYING;
582
0
      MaybeConfirm();
583
0
    }
584
0
  } else {
585
0
    MOZ_CRASH("Unknown timer");
586
0
  }
587
0
588
0
  return NS_OK;
589
0
}
590
591
592
AHostResolver::LookupStatus
593
TRRService::CompleteLookup(nsHostRecord *rec, nsresult status, AddrInfo *aNewRRSet, bool pb)
594
0
{
595
0
  // this is an NS check for the TRR blacklist or confirmationNS check
596
0
597
0
  MOZ_ASSERT(NS_IsMainThread());
598
0
  MOZ_ASSERT(!rec);
599
0
600
0
  nsAutoPtr<AddrInfo> newRRSet(aNewRRSet);
601
0
  MOZ_ASSERT(newRRSet && newRRSet->IsTRR() == TRRTYPE_NS);
602
0
603
0
  MOZ_ASSERT(!mConfirmer || (mConfirmationState == CONFIRM_TRYING));
604
0
  if (mConfirmationState == CONFIRM_TRYING) {
605
0
    MOZ_ASSERT(mConfirmer);
606
0
    mConfirmationState = NS_SUCCEEDED(status) ? CONFIRM_OK : CONFIRM_FAILED;
607
0
    LOG(("TRRService finishing confirmation test %s %d %X\n",
608
0
         mPrivateURI.get(), (int)mConfirmationState, (unsigned int)status));
609
0
    mConfirmer = nullptr;
610
0
    if ((mConfirmationState == CONFIRM_FAILED) && (mMode == MODE_TRRONLY)) {
611
0
      // in TRR-only mode; retry failed confirmations
612
0
      NS_NewTimerWithCallback(getter_AddRefs(mRetryConfirmTimer),
613
0
                              this, mRetryConfirmInterval,
614
0
                              nsITimer::TYPE_ONE_SHOT);
615
0
      if (mRetryConfirmInterval < 64000) {
616
0
        // double the interval up to this point
617
0
        mRetryConfirmInterval *= 2;
618
0
      }
619
0
    } else {
620
0
      if (mMode != MODE_TRRONLY) {
621
0
        // don't accumulate trronly data here since trronly failures are
622
0
        // handled above by trying again, so counting the successes here would
623
0
        // skew the numbers
624
0
        Telemetry::Accumulate(Telemetry::DNS_TRR_NS_VERFIFIED,
625
0
                              (mConfirmationState == CONFIRM_OK));
626
0
      }
627
0
      mRetryConfirmInterval = 1000;
628
0
    }
629
0
    return LOOKUP_OK;
630
0
  }
631
0
632
0
  // when called without a host record, this is a domain name check response.
633
0
  if (NS_SUCCEEDED(status)) {
634
0
    LOG(("TRR verified %s to be fine!\n", newRRSet->mHostName.get()));
635
0
  } else {
636
0
    LOG(("TRR says %s doesn't resolve as NS!\n", newRRSet->mHostName.get()));
637
0
    TRRBlacklist(newRRSet->mHostName, pb, false);
638
0
  }
639
0
  return LOOKUP_OK;
640
0
}
641
642
AHostResolver::LookupStatus
643
TRRService::CompleteLookupByType(nsHostRecord *, nsresult,
644
                                 const nsTArray<nsCString> *aResult,
645
                                 uint32_t aTtl,
646
                                 bool aPb)
647
0
{
648
0
  return LOOKUP_OK;
649
0
}
650
651
#undef LOG
652
653
} // namespace net
654
} // namespace mozilla