Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/dns/TRR.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim:set ts=4 sw=4 sts=4 et cin: */
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 "DNS.h"
8
#include "nsCharSeparatedTokenizer.h"
9
#include "nsContentUtils.h"
10
#include "nsHostResolver.h"
11
#include "nsIHttpChannel.h"
12
#include "nsIHttpChannelInternal.h"
13
#include "nsIIOService.h"
14
#include "nsIInputStream.h"
15
#include "nsISupportsBase.h"
16
#include "nsISupportsUtils.h"
17
#include "nsIUploadChannel2.h"
18
#include "nsNetUtil.h"
19
#include "nsStringStream.h"
20
#include "nsThreadUtils.h"
21
#include "nsURLHelper.h"
22
#include "TRR.h"
23
#include "TRRService.h"
24
25
#include "mozilla/Base64.h"
26
#include "mozilla/DebugOnly.h"
27
#include "mozilla/Logging.h"
28
#include "mozilla/Preferences.h"
29
#include "mozilla/Telemetry.h"
30
#include "mozilla/TimeStamp.h"
31
#include "mozilla/Tokenizer.h"
32
33
namespace mozilla {
34
namespace net {
35
36
#undef LOG
37
extern mozilla::LazyLogModule gHostResolverLog;
38
0
#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args)
39
0
#define LOG_ENABLED() MOZ_LOG_TEST(mozilla::net::gHostResolverLog, mozilla::LogLevel::Debug)
40
41
NS_IMPL_ISUPPORTS(TRR, nsIHttpPushListener, nsIInterfaceRequestor, nsIStreamListener, nsIRunnable)
42
43
const uint8_t kDNS_CLASS_IN = 1;
44
45
NS_IMETHODIMP
46
TRR::Notify(nsITimer *aTimer)
47
0
{
48
0
  if (aTimer == mTimeout) {
49
0
    mTimeout = nullptr;
50
0
    Cancel();
51
0
  } else {
52
0
    MOZ_CRASH("Unknown timer");
53
0
  }
54
0
55
0
  return NS_OK;
56
0
}
57
58
// convert a given host request to a DOH 'body'
59
//
60
nsresult
61
TRR::DohEncode(nsCString &aBody, bool aDisableECS)
62
0
{
63
0
  aBody.Truncate();
64
0
  // Header
65
0
  aBody += '\0';
66
0
  aBody += '\0'; // 16 bit id
67
0
  aBody += 0x01; // |QR|   Opcode  |AA|TC|RD| Set the RD bit
68
0
  aBody += '\0'; // |RA|   Z    |   RCODE   |
69
0
  aBody += '\0';
70
0
  aBody += 1;    // QDCOUNT (number of entries in the question section)
71
0
  aBody += '\0';
72
0
  aBody += '\0'; // ANCOUNT
73
0
  aBody += '\0';
74
0
  aBody += '\0'; // NSCOUNT
75
0
76
0
  aBody += '\0'; // ARCOUNT
77
0
  aBody += aDisableECS ? 1 : '\0';   // ARCOUNT low byte for EDNS(0)
78
0
79
0
  // Question
80
0
81
0
  // The input host name should be converted to a sequence of labels, where
82
0
  // each label consists of a length octet followed by that number of
83
0
  // octets.  The domain name terminates with the zero length octet for the
84
0
  // null label of the root.
85
0
  // Followed by 16 bit QTYPE and 16 bit QCLASS
86
0
87
0
  int32_t index = 0;
88
0
  int32_t offset = 0;
89
0
  do {
90
0
    bool dotFound = false;
91
0
    int32_t labelLength;
92
0
    index = mHost.FindChar('.', offset);
93
0
    if (kNotFound != index) {
94
0
      dotFound = true;
95
0
      labelLength = index - offset;
96
0
    } else {
97
0
      labelLength = mHost.Length() - offset;
98
0
    }
99
0
    if (labelLength > 63) {
100
0
      // too long label!
101
0
      return NS_ERROR_ILLEGAL_VALUE;
102
0
    }
103
0
    aBody += static_cast<unsigned char>(labelLength);
104
0
    nsDependentCSubstring label = Substring(mHost, offset, labelLength);
105
0
    aBody.Append(label);
106
0
    if(!dotFound) {
107
0
      aBody += '\0'; // terminate with a final zero
108
0
      break;
109
0
    }
110
0
    offset += labelLength + 1; // move over label and dot
111
0
  } while(true);
112
0
113
0
  aBody += '\0'; // upper 8 bit TYPE
114
0
  aBody += static_cast<uint8_t>(mType);
115
0
  aBody += '\0'; // upper 8 bit CLASS
116
0
  aBody += kDNS_CLASS_IN;  // IN - "the Internet"
117
0
118
0
  if (aDisableECS) {
119
0
    // EDNS(0) is RFC 6891, ECS is RFC 7871
120
0
    aBody += '\0'; // NAME       | domain name  | MUST be 0 (root domain)      |
121
0
    aBody += '\0';
122
0
    aBody += 41;   // TYPE       | u_int16_t    | OPT (41)                     |
123
0
    aBody += 16;   // CLASS      | u_int16_t    | requestor's UDP payload size |
124
0
    aBody += '\0'; // advertise 4K (high-byte: 16 | low-byte: 0), ignored by DoH
125
0
    aBody += '\0'; // TTL        | u_int32_t    | extended RCODE and flags     |
126
0
    aBody += '\0';
127
0
    aBody += '\0';
128
0
    aBody += '\0';
129
0
130
0
    aBody += '\0'; // upper 8 bit RDLEN
131
0
    aBody += 8;    // RDLEN      | u_int16_t    | length of all RDATA          |
132
0
133
0
    // RDATA      | octet stream | {attribute,value} pairs      |
134
0
    // The RDATA is just the ECS option setting zero subnet prefix
135
0
136
0
    aBody += '\0'; // upper 8 bit OPTION-CODE ECS
137
0
    aBody += 8;    // OPTION-CODE, 2 octets, for ECS is 8
138
0
139
0
    aBody += '\0'; // upper 8 bit OPTION-LENGTH
140
0
    aBody += 4;    // OPTION-LENGTH, 2 octets, contains the length of the payload
141
0
                   // after OPTION-LENGTH
142
0
    aBody += '\0'; // upper 8 bit FAMILY. IANA Address Family Numbers registry, not the
143
0
                   // AF_* constants!
144
0
    aBody += 1;    // FAMILY (Ipv4), 2 octets
145
0
146
0
    aBody += '\0'; // SOURCE PREFIX-LENGTH      |     SCOPE PREFIX-LENGTH       |
147
0
    aBody += '\0';
148
0
149
0
    // ADDRESS, minimum number of octets == nothing because zero bits
150
0
  }
151
0
  return NS_OK;
152
0
}
153
154
NS_IMETHODIMP
155
TRR::Run()
156
0
{
157
0
  MOZ_ASSERT(NS_IsMainThread());
158
0
  if ((gTRRService == nullptr) || NS_FAILED(SendHTTPRequest())) {
159
0
    FailData(NS_ERROR_FAILURE);
160
0
    // The dtor will now be run
161
0
  }
162
0
  return NS_OK;
163
0
}
164
165
nsresult
166
TRR::SendHTTPRequest()
167
0
{
168
0
  // This is essentially the "run" method - created from nsHostResolver
169
0
  MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
170
0
171
0
  if ((mType != TRRTYPE_A) && (mType != TRRTYPE_AAAA) && (mType != TRRTYPE_NS) &&
172
0
      (mType != TRRTYPE_TXT)) {
173
0
    // limit the calling interface because nsHostResolver has explicit slots for
174
0
    // these types
175
0
    return NS_ERROR_FAILURE;
176
0
  }
177
0
178
0
  if ((mType == TRRTYPE_A) || (mType == TRRTYPE_AAAA)) {
179
0
    // let NS resolves skip the blacklist check
180
0
    if (gTRRService->IsTRRBlacklisted(mHost, mPB, true)) {
181
0
      if (mType == TRRTYPE_A) {
182
0
        // count only blacklist for A records to avoid double counts
183
0
        Telemetry::Accumulate(Telemetry::DNS_TRR_BLACKLISTED, true);
184
0
      }
185
0
      // not really an error but no TRR is issued
186
0
      return NS_ERROR_UNKNOWN_HOST;
187
0
    } else {
188
0
      if (mType == TRRTYPE_A) {
189
0
        Telemetry::Accumulate(Telemetry::DNS_TRR_BLACKLISTED, false);
190
0
      }
191
0
    }
192
0
  }
193
0
194
0
  nsresult rv;
195
0
  nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
196
0
  NS_ENSURE_SUCCESS(rv, rv);
197
0
198
0
  bool useGet = gTRRService->UseGET();
199
0
  nsAutoCString body;
200
0
  nsCOMPtr<nsIURI> dnsURI;
201
0
  bool disableECS = gTRRService->DisableECS();
202
0
203
0
  LOG(("TRR::SendHTTPRequest resolve %s type %u\n", mHost.get(), mType));
204
0
205
0
  if (useGet) {
206
0
    nsAutoCString tmp;
207
0
    rv = DohEncode(tmp, disableECS);
208
0
    NS_ENSURE_SUCCESS(rv, rv);
209
0
210
0
    /* For GET requests, the outgoing packet needs to be Base64url-encoded and
211
0
       then appended to the end of the URI. */
212
0
    rv = Base64URLEncode(tmp.Length(), reinterpret_cast<const unsigned char *>(tmp.get()),
213
0
                         Base64URLEncodePaddingPolicy::Omit, body);
214
0
    NS_ENSURE_SUCCESS(rv, rv);
215
0
216
0
    nsAutoCString uri;
217
0
    gTRRService->GetURI(uri);
218
0
    uri.Append(NS_LITERAL_CSTRING("?dns="));
219
0
    uri.Append(body);
220
0
    LOG(("TRR::SendHTTPRequest GET dns=%s\n", body.get()));
221
0
    rv = NS_NewURI(getter_AddRefs(dnsURI), uri);
222
0
  } else {
223
0
    rv = DohEncode(body, disableECS);
224
0
    NS_ENSURE_SUCCESS(rv, rv);
225
0
226
0
    nsAutoCString uri;
227
0
    gTRRService->GetURI(uri);
228
0
    rv = NS_NewURI(getter_AddRefs(dnsURI), uri);
229
0
  }
230
0
  if (NS_FAILED(rv)) {
231
0
    LOG(("TRR:SendHTTPRequest: NewURI failed!\n"));
232
0
    return rv;
233
0
  }
234
0
235
0
  rv = NS_NewChannel(getter_AddRefs(mChannel),
236
0
                     dnsURI,
237
0
                     nsContentUtils::GetSystemPrincipal(),
238
0
                     nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
239
0
                     nsIContentPolicy::TYPE_OTHER,
240
0
                     nullptr,   // PerformanceStorage
241
0
                     nullptr, // aLoadGroup
242
0
                     this,
243
0
                     nsIRequest::LOAD_ANONYMOUS |
244
0
                     (mPB ? nsIRequest::INHIBIT_CACHING: 0), ios);
245
0
  if (NS_FAILED(rv)) {
246
0
    LOG(("TRR:SendHTTPRequest: NewChannel failed!\n"));
247
0
    return rv;
248
0
  }
249
0
250
0
  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
251
0
  if (!httpChannel) {
252
0
    return NS_ERROR_UNEXPECTED;
253
0
  }
254
0
255
0
  rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
256
0
                                     NS_LITERAL_CSTRING("application/dns-message"),
257
0
                                     false);
258
0
  NS_ENSURE_SUCCESS(rv, rv);
259
0
260
0
  nsAutoCString cred;
261
0
  gTRRService->GetCredentials(cred);
262
0
  if (!cred.IsEmpty()){
263
0
    rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Authorization"), cred, false);
264
0
    NS_ENSURE_SUCCESS(rv, rv);
265
0
  }
266
0
267
0
  nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(mChannel);
268
0
  if (!internalChannel) {
269
0
    return NS_ERROR_UNEXPECTED;
270
0
  }
271
0
272
0
  // setting a small stream window means the h2 stack won't pipeline a window update
273
0
  // with each HEADERS or reply to a DATA with a WINDOW UPDATE
274
0
  rv = internalChannel->SetInitialRwin(127 * 1024);
275
0
  NS_ENSURE_SUCCESS(rv, rv);
276
0
  rv = internalChannel->SetTrr(true);
277
0
  NS_ENSURE_SUCCESS(rv, rv);
278
0
279
0
  mAllowRFC1918 = gTRRService->AllowRFC1918();
280
0
281
0
  if (useGet) {
282
0
    rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("GET"));
283
0
    NS_ENSURE_SUCCESS(rv, rv);
284
0
  } else {
285
0
    rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Cache-Control"),
286
0
                                       NS_LITERAL_CSTRING("no-store"), false);
287
0
    NS_ENSURE_SUCCESS(rv, rv);
288
0
    nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(httpChannel);
289
0
    if (!uploadChannel) {
290
0
      return NS_ERROR_UNEXPECTED;
291
0
    }
292
0
    uint32_t streamLength = body.Length();
293
0
    nsCOMPtr<nsIInputStream> uploadStream;
294
0
    rv = NS_NewCStringInputStream(getter_AddRefs(uploadStream), std::move(body));
295
0
    NS_ENSURE_SUCCESS(rv, rv);
296
0
297
0
    rv = uploadChannel->ExplicitSetUploadStream(uploadStream,
298
0
                                                NS_LITERAL_CSTRING("application/dns-message"),
299
0
                                                streamLength,
300
0
                                                NS_LITERAL_CSTRING("POST"), false);
301
0
    NS_ENSURE_SUCCESS(rv, rv);
302
0
  }
303
0
304
0
  // set the *default* response content type
305
0
  if (NS_FAILED(httpChannel->SetContentType(NS_LITERAL_CSTRING("application/dns-message")))) {
306
0
    LOG(("TRR::SendHTTPRequest: couldn't set content-type!\n"));
307
0
  }
308
0
  if (NS_SUCCEEDED(httpChannel->AsyncOpen2(this))) {
309
0
    NS_NewTimerWithCallback(getter_AddRefs(mTimeout),
310
0
                            this, gTRRService->GetRequestTimeout(),
311
0
                            nsITimer::TYPE_ONE_SHOT);
312
0
    return NS_OK;
313
0
  }
314
0
  mChannel = nullptr;
315
0
  return NS_ERROR_UNEXPECTED;
316
0
}
317
318
NS_IMETHODIMP
319
TRR::GetInterface(const nsIID &iid, void **result)
320
0
{
321
0
  if (!iid.Equals(NS_GET_IID(nsIHttpPushListener))) {
322
0
    return NS_ERROR_NO_INTERFACE;
323
0
  }
324
0
325
0
  nsCOMPtr<nsIHttpPushListener> copy(this);
326
0
  *result = copy.forget().take();
327
0
  return NS_OK;
328
0
}
329
330
nsresult
331
TRR::DohDecodeQuery(const nsCString &query, nsCString &host, enum TrrType &type)
332
0
{
333
0
  FallibleTArray<uint8_t> binary;
334
0
  bool found_dns = false;
335
0
  LOG(("TRR::DohDecodeQuery %s!\n", query.get()));
336
0
337
0
  // extract "dns=" from the query string
338
0
  nsCCharSeparatedTokenizer tokenizer(query, '&');
339
0
  nsAutoCString data;
340
0
  while (tokenizer.hasMoreTokens()) {
341
0
    const nsACString& token = tokenizer.nextToken();
342
0
    nsDependentCSubstring dns = Substring(token, 0, 4);
343
0
    nsAutoCString check(dns);
344
0
    if (check.Equals("dns=")) {
345
0
      nsDependentCSubstring q = Substring(token, 4, -1);
346
0
      data = q;
347
0
      found_dns = true;
348
0
      break;
349
0
    }
350
0
  }
351
0
  if (!found_dns) {
352
0
    LOG(("TRR::DohDecodeQuery no dns= in pushed URI query string\n"));
353
0
    return NS_ERROR_ILLEGAL_VALUE;
354
0
  }
355
0
356
0
  nsresult rv = Base64URLDecode(data,
357
0
                                Base64URLDecodePaddingPolicy::Ignore, binary);
358
0
  NS_ENSURE_SUCCESS(rv, rv);
359
0
  uint32_t avail = binary.Length();
360
0
  if (avail < 12) {
361
0
    return NS_ERROR_FAILURE;
362
0
  }
363
0
  // check the query bit and the opcode
364
0
  if ((binary[2] & 0xf8) != 0) {
365
0
    return NS_ERROR_FAILURE;
366
0
  }
367
0
  uint32_t qdcount = (binary[4] << 8) + binary[5];
368
0
  if (!qdcount) {
369
0
    return NS_ERROR_FAILURE;
370
0
  }
371
0
372
0
  uint32_t index = 12;
373
0
  uint32_t length = 0;
374
0
  host.Truncate();
375
0
  do {
376
0
    if (avail < (index + 1)) {
377
0
      return NS_ERROR_UNEXPECTED;
378
0
    }
379
0
380
0
    length = binary[index];
381
0
    if (length) {
382
0
      if (host.Length()) {
383
0
        host.Append(".");
384
0
      }
385
0
      if (avail < (index + 1 + length)) {
386
0
        return NS_ERROR_UNEXPECTED;
387
0
      }
388
0
      host.Append((const char *)(&binary[0]) + index + 1, length);
389
0
    }
390
0
    index += 1 + length; // skip length byte + label
391
0
  } while (length);
392
0
393
0
  LOG(("TRR::DohDecodeQuery host %s\n", host.get()));
394
0
395
0
  if (avail < (index + 2)) {
396
0
    return NS_ERROR_UNEXPECTED;
397
0
  }
398
0
  uint16_t i16 = 0;
399
0
  i16 += binary[index] << 8;
400
0
  i16 += binary[index + 1];
401
0
  index += 4; // skip question's type, class
402
0
  type = (enum TrrType)i16;
403
0
404
0
  LOG(("TRR::DohDecodeQuery type %d\n", (int)type));
405
0
406
0
  return NS_OK;
407
0
}
408
409
nsresult
410
TRR::ReceivePush(nsIHttpChannel *pushed, nsHostRecord *pushedRec)
411
0
{
412
0
  if (!mHostResolver) {
413
0
    return NS_ERROR_UNEXPECTED;
414
0
  }
415
0
416
0
  LOG(("TRR::ReceivePush: PUSH incoming!\n"));
417
0
418
0
  nsCOMPtr<nsIURI> uri;
419
0
  pushed->GetURI(getter_AddRefs(uri));
420
0
  nsAutoCString query;
421
0
  if (uri) {
422
0
    uri->GetQuery(query);
423
0
  }
424
0
425
0
  PRNetAddr tempAddr;
426
0
  if (NS_FAILED(DohDecodeQuery(query, mHost, mType)) ||
427
0
      (PR_StringToNetAddr(mHost.get(), &tempAddr) == PR_SUCCESS)) { // literal
428
0
    LOG(("TRR::ReceivePush failed to decode %s\n", mHost.get()));
429
0
    return NS_ERROR_UNEXPECTED;
430
0
  }
431
0
432
0
  RefPtr<nsHostRecord> hostRecord;
433
0
  nsresult rv;
434
0
  rv = mHostResolver->GetHostRecord(mHost,
435
0
                                    pushedRec->flags, pushedRec->af,
436
0
                                    pushedRec->pb,
437
0
                                    pushedRec->originSuffix,
438
0
                                    getter_AddRefs(hostRecord));
439
0
  if (NS_FAILED(rv)) {
440
0
    return rv;
441
0
  }
442
0
443
0
  rv = mHostResolver->TrrLookup_unlocked(hostRecord, this);
444
0
  if (NS_FAILED(rv)) {
445
0
    return rv;
446
0
  }
447
0
448
0
  rv = pushed->AsyncOpen2(this);
449
0
  if (NS_FAILED(rv)) {
450
0
    return rv;
451
0
  }
452
0
453
0
  // OK!
454
0
  mChannel = pushed;
455
0
  mRec.swap(hostRecord);
456
0
457
0
  return NS_OK;
458
0
}
459
460
NS_IMETHODIMP
461
TRR::OnPush(nsIHttpChannel *associated, nsIHttpChannel *pushed)
462
0
{
463
0
  LOG(("TRR::OnPush entry\n"));
464
0
  MOZ_ASSERT(associated == mChannel);
465
0
  if (!mRec) {
466
0
    return NS_ERROR_FAILURE;
467
0
  }
468
0
469
0
  RefPtr<TRR> trr = new TRR(mHostResolver, mPB);
470
0
  return trr->ReceivePush(pushed, mRec);
471
0
}
472
473
NS_IMETHODIMP
474
TRR::OnStartRequest(nsIRequest *aRequest,
475
                    nsISupports *aContext)
476
0
{
477
0
  LOG(("TRR::OnStartRequest %p %s %d\n", this, mHost.get(), mType));
478
0
  mStartTime = TimeStamp::Now();
479
0
  return NS_OK;
480
0
}
481
482
static uint16_t get16bit(unsigned char *aData, int index)
483
0
{
484
0
  return ((aData[index] << 8) | aData[index + 1]);
485
0
}
486
487
static uint32_t get32bit(unsigned char *aData, int index)
488
0
{
489
0
  return (aData[index] << 24) | (aData[index+1] << 16) |
490
0
    (aData[index+2] << 8) | aData[index+3];
491
0
}
492
493
nsresult
494
TRR::PassQName(unsigned int &index)
495
0
{
496
0
  uint8_t length;
497
0
  do {
498
0
    if (mBodySize < (index + 1)) {
499
0
      LOG(("TRR: PassQName:%d fail at index %d\n", __LINE__, index));
500
0
      return NS_ERROR_ILLEGAL_VALUE;
501
0
    }
502
0
    length = static_cast<uint8_t>(mResponse[index]);
503
0
    if ((length & 0xc0) == 0xc0) {
504
0
      // name pointer, advance over it and be done
505
0
      if (mBodySize < (index + 2)) {
506
0
        return NS_ERROR_ILLEGAL_VALUE;
507
0
      }
508
0
      index += 2;
509
0
      break;
510
0
    }
511
0
    if (length & 0xc0) {
512
0
      LOG(("TRR: illegal label length byte (%x) at index %d\n", length, index));
513
0
      return NS_ERROR_ILLEGAL_VALUE;
514
0
    }
515
0
    // pass label
516
0
    if (mBodySize < (index + 1 + length)) {
517
0
      LOG(("TRR: PassQName:%d fail at index %d\n", __LINE__, index));
518
0
      return NS_ERROR_ILLEGAL_VALUE;
519
0
    }
520
0
    index += 1 + length;
521
0
  } while (length);
522
0
  return NS_OK;
523
0
}
524
525
// GetQname: retrieves the qname (stores in 'aQname') and stores the index
526
// after qname was parsed into the 'aIndex'.
527
528
nsresult
529
TRR::GetQname(nsAutoCString &aQname, unsigned int &aIndex)
530
0
{
531
0
  uint8_t clength = 0;
532
0
  unsigned int cindex = aIndex;
533
0
  unsigned int loop = 128; // a valid DNS name can never loop this much
534
0
  unsigned int endindex = 0; // index position after this data
535
0
  do {
536
0
    if (cindex >= mBodySize) {
537
0
      LOG(("TRR: bad cname packet\n"));
538
0
      return NS_ERROR_ILLEGAL_VALUE;
539
0
    }
540
0
    clength = static_cast<uint8_t>(mResponse[cindex]);
541
0
    if ((clength & 0xc0) == 0xc0) {
542
0
      // name pointer, get the new offset (14 bits)
543
0
      if ((cindex +1) >= mBodySize) {
544
0
        return NS_ERROR_ILLEGAL_VALUE;
545
0
      }
546
0
      // extract the new index position for the next label
547
0
      uint16_t newpos = (clength & 0x3f) << 8 | mResponse[cindex+1];
548
0
      if (!endindex) {
549
0
        // only update on the first "jump"
550
0
        endindex = cindex + 2;
551
0
      }
552
0
      cindex = newpos;
553
0
      continue;
554
0
    } else if (clength & 0xc0) {
555
0
      // any of those bits set individually is an error
556
0
      LOG(("TRR: bad cname packet\n"));
557
0
      return NS_ERROR_ILLEGAL_VALUE;
558
0
    } else {
559
0
      cindex++;
560
0
    }
561
0
    if (clength) {
562
0
      if (!aQname.IsEmpty()) {
563
0
        aQname.Append(".");
564
0
      }
565
0
      if ((cindex + clength) > mBodySize) {
566
0
        return NS_ERROR_ILLEGAL_VALUE;
567
0
      }
568
0
      aQname.Append((const char *)(&mResponse[cindex]), clength);
569
0
      cindex += clength; // skip label
570
0
    }
571
0
  } while (clength && --loop);
572
0
573
0
  if (!loop) {
574
0
    LOG(("TRR::DohDecode pointer loop error\n"));
575
0
    return NS_ERROR_ILLEGAL_VALUE;
576
0
  }
577
0
  if (!endindex) {
578
0
    // there was no "jump"
579
0
    endindex = cindex;
580
0
  }
581
0
  aIndex = endindex;
582
0
  return NS_OK;
583
0
}
584
585
//
586
// DohDecode() collects the TTL and the IP addresses in the response
587
//
588
nsresult
589
TRR::DohDecode(nsCString &aHost)
590
0
{
591
0
  // The response has a 12 byte header followed by the question (returned)
592
0
  // and then the answer. The answer section itself contains the name, type
593
0
  // and class again and THEN the record data.
594
0
595
0
  // www.example.com response:
596
0
  // header:
597
0
  // abcd 8180 0001 0001 0000 0000
598
0
  // the question:
599
0
  // 0377 7777 0765 7861 6d70 6c65 0363 6f6d 0000 0100 01
600
0
  // the answer:
601
0
  // 03 7777 7707 6578 616d 706c 6503 636f 6d00 0001 0001
602
0
  // 0000 0080 0004 5db8 d822
603
0
604
0
  unsigned int index = 12;
605
0
  uint8_t length;
606
0
  nsAutoCString host;
607
0
  nsresult rv;
608
0
609
0
  LOG(("doh decode %s %d bytes\n", aHost.get(), mBodySize));
610
0
611
0
  mCname.Truncate();
612
0
613
0
  if (mBodySize < 12 || mResponse[0] || mResponse[1]) {
614
0
    LOG(("TRR bad incoming DOH, eject!\n"));
615
0
    return NS_ERROR_ILLEGAL_VALUE;
616
0
  }
617
0
  uint8_t rcode = mResponse[3] & 0x0F;
618
0
  if (rcode) {
619
0
    LOG(("TRR Decode %s RCODE %d\n", aHost.get(), rcode));
620
0
    return NS_ERROR_FAILURE;
621
0
  }
622
0
623
0
  uint16_t questionRecords = get16bit(mResponse, 4); // qdcount
624
0
  // iterate over the single(?) host name in question
625
0
  while (questionRecords) {
626
0
    do {
627
0
      if (mBodySize < (index + 1)) {
628
0
        return NS_ERROR_ILLEGAL_VALUE;
629
0
      }
630
0
      length = static_cast<uint8_t>(mResponse[index]);
631
0
      if (length) {
632
0
        if (host.Length()) {
633
0
          host.Append(".");
634
0
        }
635
0
        if (mBodySize < (index + 1 + length)) {
636
0
          return NS_ERROR_ILLEGAL_VALUE;
637
0
        }
638
0
        host.Append(((char *)mResponse) + index + 1, length);
639
0
      }
640
0
      index += 1 + length; // skip length byte + label
641
0
    } while (length);
642
0
    if (mBodySize < (index + 4)) {
643
0
      return NS_ERROR_ILLEGAL_VALUE;
644
0
    }
645
0
    index += 4; // skip question's type, class
646
0
    questionRecords--;
647
0
  }
648
0
649
0
  // Figure out the number of answer records from ANCOUNT
650
0
  uint16_t answerRecords = get16bit(mResponse, 6);
651
0
652
0
  LOG(("TRR Decode: %d answer records (%u bytes body) %s index=%u\n",
653
0
       answerRecords, mBodySize, host.get(), index));
654
0
655
0
  while (answerRecords) {
656
0
    nsAutoCString qname;
657
0
    rv = GetQname(qname, index);
658
0
    if (NS_FAILED(rv)) {
659
0
      return rv;
660
0
    }
661
0
    // 16 bit TYPE
662
0
    if (mBodySize < (index + 2)) {
663
0
      LOG(("TRR: Dohdecode:%d fail at index %d\n", __LINE__, index + 2));
664
0
      return NS_ERROR_ILLEGAL_VALUE;
665
0
    }
666
0
    uint16_t TYPE = get16bit(mResponse, index);
667
0
668
0
    if ((TYPE != TRRTYPE_CNAME) &&
669
0
        (TYPE != static_cast<uint16_t>(mType))) {
670
0
      // Not the same type as was asked for nor CNAME
671
0
      LOG(("TRR: Dohdecode:%d asked for type %d got %d\n", __LINE__,
672
0
           mType, TYPE));
673
0
      return NS_ERROR_UNEXPECTED;
674
0
    }
675
0
    index += 2;
676
0
677
0
    // 16 bit class
678
0
    if (mBodySize < (index + 2)) {
679
0
      LOG(("TRR: Dohdecode:%d fail at index %d\n", __LINE__, index + 2));
680
0
      return NS_ERROR_ILLEGAL_VALUE;
681
0
    }
682
0
    uint16_t CLASS = get16bit(mResponse, index);
683
0
    if (kDNS_CLASS_IN != CLASS) {
684
0
      LOG(("TRR bad CLASS (%u) at index %d\n", CLASS, index));
685
0
      return NS_ERROR_UNEXPECTED;
686
0
    }
687
0
    index += 2;
688
0
689
0
    // 32 bit TTL (seconds)
690
0
    if (mBodySize < (index + 4)) {
691
0
      LOG(("TRR: Dohdecode:%d fail at index %d\n", __LINE__, index));
692
0
      return NS_ERROR_ILLEGAL_VALUE;
693
0
    }
694
0
    uint32_t TTL = get32bit(mResponse, index);
695
0
    index += 4;
696
0
697
0
    // 16 bit RDLENGTH
698
0
    if (mBodySize < (index + 2)) {
699
0
      LOG(("TRR: Dohdecode:%d fail at index %d\n", __LINE__, index));
700
0
      return NS_ERROR_ILLEGAL_VALUE;
701
0
    }
702
0
    uint16_t RDLENGTH = get16bit(mResponse, index);
703
0
    index += 2;
704
0
705
0
    if (mBodySize < (index + RDLENGTH)) {
706
0
      LOG(("TRR: Dohdecode:%d fail RDLENGTH=%d at index %d\n", __LINE__,
707
0
           RDLENGTH, index));
708
0
      return NS_ERROR_ILLEGAL_VALUE;
709
0
    }
710
0
711
0
    if (qname.Equals(aHost)) {
712
0
713
0
      // RDATA
714
0
      // - A (TYPE 1):  4 bytes
715
0
      // - AAAA (TYPE 28): 16 bytes
716
0
      // - NS (TYPE 2): N bytes
717
0
718
0
      switch(TYPE) {
719
0
      case TRRTYPE_A:
720
0
        if (RDLENGTH != 4) {
721
0
          LOG(("TRR bad length for A (%u)\n", RDLENGTH));
722
0
          return NS_ERROR_UNEXPECTED;
723
0
        }
724
0
        rv = mDNS.Add(TTL, mResponse, index, RDLENGTH,
725
0
                      mAllowRFC1918);
726
0
        if (NS_FAILED(rv)) {
727
0
          LOG(("TRR:DohDecode failed: local IP addresses or unknown IP family\n"));
728
0
          return rv;
729
0
        }
730
0
        break;
731
0
      case TRRTYPE_AAAA:
732
0
        if (RDLENGTH != 16) {
733
0
          LOG(("TRR bad length for AAAA (%u)\n", RDLENGTH));
734
0
          return NS_ERROR_UNEXPECTED;
735
0
        }
736
0
        rv = mDNS.Add(TTL, mResponse, index, RDLENGTH,
737
0
                      mAllowRFC1918);
738
0
        if (NS_FAILED(rv)) {
739
0
          LOG(("TRR got unique/local IPv6 address!\n"));
740
0
          return rv;
741
0
        }
742
0
        break;
743
0
744
0
      case TRRTYPE_NS:
745
0
        break;
746
0
      case TRRTYPE_CNAME:
747
0
        if (mCname.IsEmpty()) {
748
0
          nsAutoCString qname;
749
0
          unsigned int qnameindex = index;
750
0
          rv = GetQname(qname, qnameindex);
751
0
          if (NS_FAILED(rv)) {
752
0
            return rv;
753
0
          }
754
0
          if(!qname.IsEmpty()) {
755
0
            mCname = qname;
756
0
            LOG(("TRR::DohDecode CNAME host %s => %s\n",
757
0
                 host.get(), mCname.get()));
758
0
          } else {
759
0
            LOG(("TRR::DohDecode empty CNAME for host %s!\n",
760
0
                 host.get()));
761
0
          }
762
0
        }
763
0
        else {
764
0
          LOG(("TRR::DohDecode CNAME - ignoring another entry\n"));
765
0
        }
766
0
        break;
767
0
      case TRRTYPE_TXT:
768
0
      {
769
0
        // TXT record RRDATA sections are a series of character-strings
770
0
        // each character string is a length byte followed by that many data bytes
771
0
        nsAutoCString txt;
772
0
        unsigned int txtIndex = index;
773
0
        uint16_t available = RDLENGTH;
774
0
775
0
        while (available > 0) {
776
0
          uint8_t characterStringLen = mResponse[txtIndex++];
777
0
          available--;
778
0
          if (characterStringLen > available) {
779
0
            LOG(("TRR::DohDecode MALFORMED TXT RECORD\n"));
780
0
            break;
781
0
          }
782
0
          txt.Append((const char *)(&mResponse[txtIndex]), characterStringLen);
783
0
          txtIndex += characterStringLen;
784
0
          available -= characterStringLen;
785
0
        }
786
0
787
0
        mTxt.AppendElement(txt);
788
0
        if (mTxtTtl > TTL) {
789
0
          mTxtTtl = TTL;
790
0
        }
791
0
        LOG(("TRR::DohDecode TXT host %s => %s\n",
792
0
             host.get(), txt.get()));
793
0
        break;
794
0
      }
795
0
      default:
796
0
        // skip unknown record types
797
0
        LOG(("TRR unsupported TYPE (%u) RDLENGTH %u\n", TYPE, RDLENGTH));
798
0
        break;
799
0
      }
800
0
    }
801
0
    else {
802
0
      LOG(("TRR asked for %s data but got %s\n", aHost.get(), qname.get()));
803
0
    }
804
0
805
0
    index += RDLENGTH;
806
0
    LOG(("done with record type %u len %u index now %u of %u\n",
807
0
         TYPE, RDLENGTH, index, mBodySize));
808
0
    answerRecords--;
809
0
  }
810
0
811
0
  // NSCOUNT
812
0
  uint16_t nsRecords = get16bit(mResponse, 8);
813
0
  LOG(("TRR Decode: %d ns records (%u bytes body)\n", nsRecords, mBodySize));
814
0
  while (nsRecords) {
815
0
    rv = PassQName(index);
816
0
    if (NS_FAILED(rv)) {
817
0
      return rv;
818
0
    }
819
0
820
0
    if (mBodySize < (index + 8)) {
821
0
      return NS_ERROR_ILLEGAL_VALUE;
822
0
    }
823
0
    index += 2; // type
824
0
    index += 2; // class
825
0
    index += 4; // ttl
826
0
827
0
    // 16 bit RDLENGTH
828
0
    if (mBodySize < (index + 2)) {
829
0
      return NS_ERROR_ILLEGAL_VALUE;
830
0
    }
831
0
    uint16_t RDLENGTH = get16bit(mResponse, index);
832
0
    index += 2;
833
0
    if (mBodySize < (index + RDLENGTH)) {
834
0
      return NS_ERROR_ILLEGAL_VALUE;
835
0
    }
836
0
    index += RDLENGTH;
837
0
    LOG(("done with nsRecord now %u of %u\n", index, mBodySize));
838
0
    nsRecords--;
839
0
  }
840
0
841
0
  // additional resource records
842
0
  uint16_t arRecords = get16bit(mResponse, 10);
843
0
  LOG(("TRR Decode: %d additional resource records (%u bytes body)\n",
844
0
       arRecords, mBodySize));
845
0
  while (arRecords) {
846
0
    rv = PassQName(index);
847
0
    if (NS_FAILED(rv)) {
848
0
      return rv;
849
0
    }
850
0
851
0
    if (mBodySize < (index + 8)) {
852
0
      return NS_ERROR_ILLEGAL_VALUE;
853
0
    }
854
0
    index += 2; // type
855
0
    index += 2; // class
856
0
    index += 4; // ttl
857
0
858
0
    // 16 bit RDLENGTH
859
0
    if (mBodySize < (index + 2)) {
860
0
      return NS_ERROR_ILLEGAL_VALUE;
861
0
    }
862
0
    uint16_t RDLENGTH = get16bit(mResponse, index);
863
0
    index += 2;
864
0
    if (mBodySize < (index + RDLENGTH)) {
865
0
      return NS_ERROR_ILLEGAL_VALUE;
866
0
    }
867
0
    index += RDLENGTH;
868
0
    LOG(("done with additional rr now %u of %u\n", index, mBodySize));
869
0
    arRecords--;
870
0
  }
871
0
872
0
  if (index != mBodySize) {
873
0
    LOG(("DohDecode failed to parse entire response body, %u out of %u bytes\n",
874
0
         index, mBodySize));
875
0
    // failed to parse 100%, do not continue
876
0
    return NS_ERROR_ILLEGAL_VALUE;
877
0
  }
878
0
879
0
  if ((mType != TRRTYPE_NS) && mCname.IsEmpty() &&
880
0
      !mDNS.mAddresses.getFirst() &&
881
0
      mTxt.IsEmpty()) {
882
0
    // no entries were stored!
883
0
    LOG(("TRR: No entries were stored!\n"));
884
0
    return NS_ERROR_FAILURE;
885
0
  }
886
0
  return NS_OK;
887
0
}
888
889
nsresult
890
TRR::ReturnData()
891
0
{
892
0
  if (mType != TRRTYPE_TXT) {
893
0
    // create and populate an AddrInfo instance to pass on
894
0
    nsAutoPtr<AddrInfo> ai(new AddrInfo(mHost, mType));
895
0
    DOHaddr *item;
896
0
    uint32_t ttl = AddrInfo::NO_TTL_DATA;
897
0
    while ((item = static_cast<DOHaddr*>(mDNS.mAddresses.popFirst()))) {
898
0
      PRNetAddr prAddr;
899
0
      NetAddrToPRNetAddr(&item->mNet, &prAddr);
900
0
      auto *addrElement = new NetAddrElement(&prAddr);
901
0
      ai->AddAddress(addrElement);
902
0
      if (item->mTtl < ttl) {
903
0
        // While the DNS packet might return individual TTLs for each address,
904
0
        // we can only return one value in the AddrInfo class so pick the
905
0
        // lowest number.
906
0
        ttl = item->mTtl;
907
0
      }
908
0
    }
909
0
    ai->ttl = ttl;
910
0
    if (!mHostResolver) {
911
0
      return NS_ERROR_FAILURE;
912
0
    }
913
0
    (void)mHostResolver->CompleteLookup(mRec, NS_OK, ai.forget(), mPB);
914
0
    mHostResolver = nullptr;
915
0
    mRec = nullptr;
916
0
  } else {
917
0
    (void)mHostResolver->CompleteLookupByType(mRec, NS_OK, &mTxt, mTxtTtl, mPB);
918
0
  }
919
0
  return NS_OK;
920
0
}
921
922
nsresult
923
TRR::FailData(nsresult error)
924
0
{
925
0
  if (!mHostResolver) {
926
0
    return NS_ERROR_FAILURE;
927
0
  }
928
0
929
0
  if (mType == TRRTYPE_TXT) {
930
0
    (void)mHostResolver->CompleteLookupByType(mRec, error,
931
0
                                              nullptr, 0, mPB);
932
0
  } else {
933
0
    // create and populate an TRR AddrInfo instance to pass on to signal that
934
0
    // this comes from TRR
935
0
    AddrInfo *ai = new AddrInfo(mHost, mType);
936
0
937
0
    (void)mHostResolver->CompleteLookup(mRec, error, ai, mPB);
938
0
  }
939
0
940
0
  mHostResolver = nullptr;
941
0
  mRec = nullptr;
942
0
  return NS_OK;
943
0
}
944
945
nsresult
946
TRR::On200Response()
947
0
{
948
0
  // decode body and create an AddrInfo struct for the response
949
0
  nsresult rv = DohDecode(mHost);
950
0
951
0
  if (NS_SUCCEEDED(rv)) {
952
0
    if (!mDNS.mAddresses.getFirst() && !mCname.IsEmpty() &&
953
0
        mType != TRRTYPE_TXT) {
954
0
      nsCString cname = mCname;
955
0
      LOG(("TRR: check for CNAME record for %s within previous response\n",
956
0
           cname.get()));
957
0
      rv = DohDecode(cname);
958
0
      if (NS_SUCCEEDED(rv) && mDNS.mAddresses.getFirst()) {
959
0
        LOG(("TRR: Got the CNAME record without asking for it\n"));
960
0
        ReturnData();
961
0
        return NS_OK;
962
0
      }
963
0
      // restore mCname as DohDecode() change it
964
0
      mCname = cname;
965
0
      if (!--mCnameLoop) {
966
0
        LOG(("TRR::On200Response CNAME loop, eject!\n"));
967
0
      } else  {
968
0
        LOG(("TRR::On200Response CNAME %s => %s (%u)\n", mHost.get(), mCname.get(),
969
0
             mCnameLoop));
970
0
        RefPtr<TRR> trr = new TRR(mHostResolver, mRec, mCname,
971
0
                                  mType, mCnameLoop, mPB);
972
0
        rv = NS_DispatchToMainThread(trr);
973
0
        if (NS_SUCCEEDED(rv)) {
974
0
          return rv;
975
0
        }
976
0
      }
977
0
    } else {
978
0
      // pass back the response data
979
0
      ReturnData();
980
0
      return NS_OK;
981
0
    }
982
0
  } else {
983
0
    LOG(("TRR::On200Response DohDecode %x\n", (int)rv));
984
0
  }
985
0
  return NS_ERROR_FAILURE;
986
0
}
987
988
989
NS_IMETHODIMP
990
TRR::OnStopRequest(nsIRequest *aRequest,
991
                   nsISupports *aContext,
992
                   nsresult aStatusCode)
993
0
{
994
0
  // The dtor will be run after the function returns
995
0
  LOG(("TRR:OnStopRequest %p %s %d failed=%d code=%X\n",
996
0
       this, mHost.get(), mType, mFailed, (unsigned int)aStatusCode));
997
0
  nsCOMPtr<nsIChannel> channel;
998
0
  channel.swap(mChannel);
999
0
1000
0
  // if status was "fine", parse the response and pass on the answer
1001
0
  if (!mFailed && NS_SUCCEEDED(aStatusCode)) {
1002
0
    nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
1003
0
    if (!httpChannel) {
1004
0
      return NS_ERROR_UNEXPECTED;
1005
0
    }
1006
0
    nsresult rv = NS_OK;
1007
0
    nsAutoCString contentType;
1008
0
    httpChannel->GetContentType(contentType);
1009
0
    if (contentType.Length() &&
1010
0
        !contentType.LowerCaseEqualsLiteral("application/dns-message")) {
1011
0
      LOG(("TRR:OnStopRequest %p %s %d wrong content type %s\n",
1012
0
           this, mHost.get(), mType, contentType.get()));
1013
0
      FailData(NS_ERROR_UNEXPECTED);
1014
0
      return NS_OK;
1015
0
    }
1016
0
1017
0
    uint32_t httpStatus;
1018
0
    rv = httpChannel->GetResponseStatus(&httpStatus);
1019
0
    if (NS_SUCCEEDED(rv) && httpStatus == 200) {
1020
0
      rv = On200Response();
1021
0
      if (NS_SUCCEEDED(rv)) {
1022
0
        return rv;
1023
0
      }
1024
0
    } else {
1025
0
      LOG(("TRR:OnStopRequest:%d %p rv %x httpStatus %d\n", __LINE__,
1026
0
           this, (int)rv, httpStatus));
1027
0
    }
1028
0
  }
1029
0
1030
0
  LOG(("TRR:OnStopRequest %p status %x mFailed %d\n",
1031
0
       this, (int)aStatusCode, mFailed));
1032
0
  FailData(NS_ERROR_UNKNOWN_HOST);
1033
0
  return NS_OK;
1034
0
}
1035
1036
NS_IMETHODIMP
1037
TRR::OnDataAvailable(nsIRequest *aRequest,
1038
                     nsISupports *aContext,
1039
                     nsIInputStream *aInputStream,
1040
                     uint64_t aOffset,
1041
                     const uint32_t aCount)
1042
0
{
1043
0
  LOG(("TRR:OnDataAvailable %p %s %d failed=%d aCount=%u\n",
1044
0
       this, mHost.get(), mType, mFailed, (unsigned int)aCount));
1045
0
  // receive DNS response into the local buffer
1046
0
  if (mFailed) {
1047
0
    return NS_ERROR_FAILURE;
1048
0
  }
1049
0
1050
0
  if (aCount + mBodySize > kMaxSize) {
1051
0
    LOG(("TRR::OnDataAvailable:%d fail\n",  __LINE__));
1052
0
    mFailed = true;
1053
0
    return NS_ERROR_FAILURE;
1054
0
  }
1055
0
1056
0
  uint32_t count;
1057
0
  nsresult rv = aInputStream->Read((char *)mResponse + mBodySize, aCount, &count);
1058
0
  if (NS_FAILED(rv)) {
1059
0
    LOG(("TRR::OnDataAvailable:%d fail\n",  __LINE__));
1060
0
    mFailed = true;
1061
0
    return rv;
1062
0
  }
1063
0
  MOZ_ASSERT(count == aCount);
1064
0
  mBodySize += aCount;
1065
0
  return NS_OK;
1066
0
}
1067
1068
nsresult
1069
DOHresp::Add(uint32_t TTL, unsigned char *dns, int index, uint16_t len,
1070
             bool aLocalAllowed)
1071
0
{
1072
0
  nsAutoPtr<DOHaddr> doh(new DOHaddr);
1073
0
  NetAddr *addr = &doh->mNet;
1074
0
  if (4 == len) {
1075
0
    // IPv4
1076
0
    addr->inet.family = AF_INET;
1077
0
    addr->inet.port = 0; // unknown
1078
0
    addr->inet.ip = ntohl(get32bit(dns, index));
1079
0
  } else if (16 == len) {
1080
0
    // IPv6
1081
0
    addr->inet6.family = AF_INET6;
1082
0
    addr->inet6.port = 0;     // unknown
1083
0
    addr->inet6.flowinfo = 0; // unknown
1084
0
    addr->inet6.scope_id = 0; // unknown
1085
0
    for(int i = 0; i < 16; i++, index++) {
1086
0
      addr->inet6.ip.u8[i] = dns[index];
1087
0
    }
1088
0
  } else {
1089
0
    return NS_ERROR_UNEXPECTED;
1090
0
  }
1091
0
1092
0
  if (IsIPAddrLocal(addr) && !aLocalAllowed) {
1093
0
    return NS_ERROR_FAILURE;
1094
0
  }
1095
0
  doh->mTtl = TTL;
1096
0
1097
0
  if (LOG_ENABLED()) {
1098
0
    char buf[128];
1099
0
    NetAddrToString(addr, buf, sizeof(buf));
1100
0
    LOG(("DOHresp:Add %s\n", buf));
1101
0
  }
1102
0
  mAddresses.insertBack(doh.forget());
1103
0
  return NS_OK;
1104
0
}
1105
1106
class ProxyCancel : public Runnable
1107
{
1108
public:
1109
  explicit ProxyCancel(TRR *aTRR)
1110
    : Runnable("proxyTrrCancel")
1111
    , mTRR(aTRR)
1112
0
  { }
1113
1114
  NS_IMETHOD Run() override
1115
0
  {
1116
0
    mTRR->Cancel();
1117
0
    mTRR = nullptr;
1118
0
    return NS_OK;
1119
0
  }
1120
1121
private:
1122
  RefPtr<TRR> mTRR;
1123
};
1124
1125
void
1126
TRR::Cancel()
1127
0
{
1128
0
  if (!NS_IsMainThread()) {
1129
0
    NS_DispatchToMainThread(new ProxyCancel(this));
1130
0
    return;
1131
0
  }
1132
0
  if (mChannel) {
1133
0
    LOG(("TRR: %p canceling Channel %p %s %d\n", this,
1134
0
         mChannel.get(), mHost.get(), mType));
1135
0
    mChannel->Cancel(NS_ERROR_ABORT);
1136
0
  }
1137
0
}
1138
1139
#undef LOG
1140
1141
// namespace
1142
}
1143
}