Coverage Report

Created: 2018-09-25 14:53

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