Coverage Report

Created: 2025-12-30 08:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/src/cares_wrap.cc
Line
Count
Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "cares_wrap.h"
23
#include "ada.h"
24
#include "async_wrap-inl.h"
25
#include "base_object-inl.h"
26
#include "env-inl.h"
27
#include "memory_tracker-inl.h"
28
#include "nbytes.h"
29
#include "node.h"
30
#include "node_errors.h"
31
#include "node_external_reference.h"
32
#include "req_wrap-inl.h"
33
#include "util-inl.h"
34
#include "uv.h"
35
#include "v8.h"
36
37
#include <cerrno>
38
#include <cstring>
39
#include <memory>
40
#include <vector>
41
#include <unordered_set>
42
43
#ifndef T_TLSA
44
#define T_TLSA 52 /* TLSA certificate association */
45
#endif
46
47
#ifndef T_CAA
48
# define T_CAA    257 /* Certification Authority Authorization */
49
#endif
50
51
// OpenBSD does not define these
52
#ifndef AI_ALL
53
# define AI_ALL 0
54
#endif
55
#ifndef AI_V4MAPPED
56
# define AI_V4MAPPED 0
57
#endif
58
59
60
namespace node {
61
namespace cares_wrap {
62
63
using v8::Array;
64
using v8::ArrayBuffer;
65
using v8::Context;
66
using v8::DictionaryTemplate;
67
using v8::EscapableHandleScope;
68
using v8::Exception;
69
using v8::FunctionCallbackInfo;
70
using v8::FunctionTemplate;
71
using v8::HandleScope;
72
using v8::Int32;
73
using v8::Integer;
74
using v8::Isolate;
75
using v8::Just;
76
using v8::JustVoid;
77
using v8::Local;
78
using v8::LocalVector;
79
using v8::Maybe;
80
using v8::MaybeLocal;
81
using v8::Nothing;
82
using v8::Null;
83
using v8::Object;
84
using v8::String;
85
using v8::Uint32;
86
using v8::Undefined;
87
using v8::Value;
88
89
namespace {
90
91
Mutex ares_library_mutex;
92
93
0
inline uint16_t cares_get_16bit(const unsigned char* p) {
94
0
  return static_cast<uint32_t>(p[0] << 8U) | (static_cast<uint32_t>(p[1]));
95
0
}
96
97
0
void ares_poll_cb(uv_poll_t* watcher, int status, int events) {
98
0
  NodeAresTask* task = ContainerOf(&NodeAresTask::poll_watcher, watcher);
99
0
  ChannelWrap* channel = task->channel;
100
101
  /* Reset the idle timer */
102
0
  uv_timer_again(channel->timer_handle());
103
104
0
  if (status < 0) {
105
    /* An error happened. Just pretend that the socket is both readable and */
106
    /* writable. */
107
0
    ares_process_fd(channel->cares_channel(), task->sock, task->sock);
108
0
    return;
109
0
  }
110
111
  /* Process DNS responses */
112
0
  ares_process_fd(channel->cares_channel(),
113
0
                  events & UV_READABLE ? task->sock : ARES_SOCKET_BAD,
114
0
                  events & UV_WRITABLE ? task->sock : ARES_SOCKET_BAD);
115
0
}
116
117
118
0
void ares_poll_close_cb(uv_poll_t* watcher) {
119
0
  std::unique_ptr<NodeAresTask> free_me(
120
0
        ContainerOf(&NodeAresTask::poll_watcher, watcher));
121
0
}
122
123
124
/* Callback from ares when socket operation is started */
125
0
void ares_sockstate_cb(void* data, ares_socket_t sock, int read, int write) {
126
0
  ChannelWrap* channel = static_cast<ChannelWrap*>(data);
127
0
  NodeAresTask* task;
128
129
0
  NodeAresTask lookup_task;
130
0
  lookup_task.sock = sock;
131
0
  auto it = channel->task_list()->find(&lookup_task);
132
133
0
  task = (it == channel->task_list()->end()) ? nullptr : *it;
134
135
0
  if (read || write) {
136
0
    if (!task) {
137
      /* New socket */
138
0
      channel->StartTimer();
139
140
0
      task = NodeAresTask::Create(channel, sock);
141
0
      if (task == nullptr) {
142
        /* This should never happen unless we're out of memory or something */
143
        /* is seriously wrong. The socket won't be polled, but the query will */
144
        /* eventually time out. */
145
0
        return;
146
0
      }
147
148
0
      channel->task_list()->insert(task);
149
0
    }
150
151
    /* This should never fail. If it fails anyway, the query will eventually */
152
    /* time out. */
153
0
    uv_poll_start(&task->poll_watcher,
154
0
                  (read ? UV_READABLE : 0) | (write ? UV_WRITABLE : 0),
155
0
                  ares_poll_cb);
156
157
0
  } else {
158
0
    if (task != nullptr) {
159
0
      channel->task_list()->erase(it);
160
0
      channel->env()->CloseHandle(&task->poll_watcher, ares_poll_close_cb);
161
0
    }
162
163
0
    if (channel->task_list()->empty()) {
164
0
      channel->CloseTimer();
165
0
    }
166
0
  }
167
0
}
168
169
0
MaybeLocal<Array> HostentToNames(Environment* env, struct hostent* host) {
170
0
  EscapableHandleScope scope(env->isolate());
171
172
0
  LocalVector<Value> names(env->isolate());
173
174
0
  for (uint32_t i = 0; host->h_aliases[i] != nullptr; ++i) {
175
0
    names.emplace_back(OneByteString(env->isolate(), host->h_aliases[i]));
176
0
  }
177
178
0
  return scope.Escape(Array::New(env->isolate(), names.data(), names.size()));
179
0
}
180
181
MaybeLocal<Array> HostentToNames(Environment* env,
182
                                 struct hostent* host,
183
0
                                 Local<Array> names) {
184
0
  size_t offset = names->Length();
185
186
0
  for (uint32_t i = 0; host->h_aliases[i] != nullptr; ++i) {
187
0
    if (names
188
0
            ->Set(env->context(),
189
0
                  i + offset,
190
0
                  OneByteString(env->isolate(), host->h_aliases[i]))
191
0
            .IsNothing()) {
192
0
      return {};
193
0
    }
194
0
  }
195
196
0
  return names;
197
0
}
198
199
template <typename T>
200
Local<Array> AddrTTLToArray(
201
    Environment* env,
202
    const T* addrttls,
203
0
    size_t naddrttls) {
204
0
  MaybeStackBuffer<Local<Value>, 8> ttls(naddrttls);
205
0
  for (size_t i = 0; i < naddrttls; i++) {
206
0
    ttls[i] = Integer::NewFromUnsigned(env->isolate(), addrttls[i].ttl);
207
0
  }
208
209
0
  return Array::New(env->isolate(), ttls.out(), naddrttls);
210
0
}
Unexecuted instantiation: cares_wrap.cc:v8::Local<v8::Array> node::cares_wrap::(anonymous namespace)::AddrTTLToArray<ares_addrttl>(node::Environment*, ares_addrttl const*, unsigned long)
Unexecuted instantiation: cares_wrap.cc:v8::Local<v8::Array> node::cares_wrap::(anonymous namespace)::AddrTTLToArray<ares_addr6ttl>(node::Environment*, ares_addr6ttl const*, unsigned long)
211
212
Maybe<int> ParseGeneralReply(Environment* env,
213
                             const unsigned char* buf,
214
                             int len,
215
                             int* type,
216
                             Local<Array> ret,
217
                             void* addrttls = nullptr,
218
0
                             int* naddrttls = nullptr) {
219
0
  HandleScope handle_scope(env->isolate());
220
0
  hostent* host;
221
222
0
  int status;
223
0
  switch (*type) {
224
0
    case ns_t_a:
225
0
    case ns_t_cname:
226
0
    case ns_t_cname_or_a:
227
0
      status = ares_parse_a_reply(buf,
228
0
                                  len,
229
0
                                  &host,
230
0
                                  static_cast<ares_addrttl*>(addrttls),
231
0
                                  naddrttls);
232
0
      break;
233
0
    case ns_t_aaaa:
234
0
      status = ares_parse_aaaa_reply(buf,
235
0
                                     len,
236
0
                                     &host,
237
0
                                     static_cast<ares_addr6ttl*>(addrttls),
238
0
                                     naddrttls);
239
0
      break;
240
0
    case ns_t_ns:
241
0
      status = ares_parse_ns_reply(buf, len, &host);
242
0
      break;
243
0
    case ns_t_ptr:
244
0
      status = ares_parse_ptr_reply(buf, len, nullptr, 0, AF_INET, &host);
245
0
      break;
246
0
    default:
247
0
      UNREACHABLE("Bad NS type");
248
0
  }
249
250
0
  if (status != ARES_SUCCESS) return Just<int>(status);
251
252
0
  CHECK_NOT_NULL(host);
253
0
  HostEntPointer ptr(host);
254
255
  /* If it's `CNAME`, return the CNAME value;
256
   * And if it's `CNAME_OR_A` and it has value in `h_name` and `h_aliases[0]`,
257
   * we consider it's a CNAME record, otherwise we consider it's an A record. */
258
0
  if ((*type == ns_t_cname_or_a && ptr->h_name && ptr->h_aliases[0]) ||
259
0
      *type == ns_t_cname) {
260
    // A cname lookup always returns a single record but we follow the
261
    // common API here.
262
0
    *type = ns_t_cname;
263
0
    if (ret->Set(env->context(),
264
0
                 ret->Length(),
265
0
                 OneByteString(env->isolate(), ptr->h_name))
266
0
            .IsNothing()) {
267
0
      return Nothing<int>();
268
0
    }
269
0
    return Just<int>(ARES_SUCCESS);
270
0
  }
271
272
0
  if (*type == ns_t_cname_or_a)
273
0
    *type = ns_t_a;
274
275
0
  if (*type == ns_t_ns) {
276
0
    if (HostentToNames(env, ptr.get(), ret).IsEmpty()) {
277
0
      return Nothing<int>();
278
0
    }
279
0
  } else if (*type == ns_t_ptr) {
280
0
    uint32_t offset = ret->Length();
281
0
    for (uint32_t i = 0; ptr->h_aliases[i] != nullptr; i++) {
282
0
      auto alias = OneByteString(env->isolate(), ptr->h_aliases[i]);
283
0
      if (ret->Set(env->context(), i + offset, alias).IsNothing()) {
284
0
        return Nothing<int>();
285
0
      }
286
0
    }
287
0
  } else {
288
0
    uint32_t offset = ret->Length();
289
0
    char ip[INET6_ADDRSTRLEN];
290
0
    for (uint32_t i = 0; ptr->h_addr_list[i] != nullptr; ++i) {
291
0
      uv_inet_ntop(ptr->h_addrtype, ptr->h_addr_list[i], ip, sizeof(ip));
292
0
      auto address = OneByteString(env->isolate(), ip);
293
0
      if (ret->Set(env->context(), i + offset, address).IsNothing()) {
294
0
        return Nothing<int>();
295
0
      }
296
0
    }
297
0
  }
298
299
0
  return Just<int>(ARES_SUCCESS);
300
0
}
301
Maybe<int> ParseMxReply(Environment* env,
302
                        const unsigned char* buf,
303
                        int len,
304
                        Local<Array> ret,
305
0
                        bool need_type = false) {
306
0
  HandleScope handle_scope(env->isolate());
307
308
0
  auto tmpl = env->mx_record_template();
309
0
  if (tmpl.IsEmpty()) {
310
0
    static constexpr std::string_view names[] = {
311
0
        "exchange",
312
0
        "priority",
313
0
        "type",
314
0
    };
315
0
    tmpl = DictionaryTemplate::New(env->isolate(), names);
316
0
    env->set_mx_record_template(tmpl);
317
0
  }
318
319
0
  struct ares_mx_reply* mx_start;
320
0
  int status = ares_parse_mx_reply(buf, len, &mx_start);
321
0
  if (status != ARES_SUCCESS) return Just<int>(status);
322
323
0
  DeleteFnPtr<void, ares_free_data> free_me(mx_start);
324
325
0
  uint32_t offset = ret->Length();
326
0
  ares_mx_reply* current = mx_start;
327
328
0
  MaybeLocal<Value> values[] = {
329
0
      Undefined(env->isolate()),  // exchange
330
0
      Undefined(env->isolate()),  // priority
331
0
      Undefined(env->isolate()),  // type
332
0
  };
333
334
0
  for (uint32_t i = 0; current != nullptr; ++i, current = current->next) {
335
0
    values[0] = OneByteString(env->isolate(), current->host);
336
0
    values[1] = Integer::New(env->isolate(), current->priority);
337
0
    values[2] = env->dns_mx_string();
338
0
    Local<Value> record;
339
0
    if (!NewDictionaryInstance(env->context(), tmpl, values).ToLocal(&record) ||
340
0
        ret->Set(env->context(), i + offset, record).IsNothing()) {
341
0
      return Nothing<int>();
342
0
    }
343
0
  }
344
345
0
  return Just<int>(ARES_SUCCESS);
346
0
}
347
348
Maybe<int> ParseCaaReply(Environment* env,
349
                         const unsigned char* buf,
350
                         int len,
351
                         Local<Array> ret,
352
0
                         bool need_type = false) {
353
0
  HandleScope handle_scope(env->isolate());
354
355
0
  auto tmpl = env->caa_record_template();
356
0
  if (tmpl.IsEmpty()) {
357
0
    static constexpr std::string_view names[] = {
358
0
        "critical",
359
0
        "type",
360
0
    };
361
0
    tmpl = DictionaryTemplate::New(env->isolate(), names);
362
0
    env->set_caa_record_template(tmpl);
363
0
  }
364
365
0
  struct ares_caa_reply* caa_start;
366
0
  int status = ares_parse_caa_reply(buf, len, &caa_start);
367
0
  if (status != ARES_SUCCESS) return Just<int>(status);
368
0
  DeleteFnPtr<void, ares_free_data> free_me(caa_start);
369
370
0
  MaybeLocal<Value> values[] = {
371
0
      Undefined(env->isolate()),  // critical
372
0
      Undefined(env->isolate()),  // type
373
0
  };
374
375
0
  uint32_t offset = ret->Length();
376
0
  ares_caa_reply* current = caa_start;
377
0
  for (uint32_t i = 0; current != nullptr; ++i, current = current->next) {
378
0
    values[0] = Integer::New(env->isolate(), current->critical);
379
0
    values[1] = env->dns_caa_string();
380
0
    Local<Object> caa_record;
381
0
    if (!NewDictionaryInstance(env->context(), tmpl, values)
382
0
             .ToLocal(&caa_record)) {
383
0
      return Nothing<int>();
384
0
    }
385
386
    // This additional property is not part of the template as it is
387
    // variable based on the record.
388
0
    if (caa_record
389
0
            ->Set(env->context(),
390
0
                  OneByteString(env->isolate(), current->property),
391
0
                  OneByteString(env->isolate(), current->value))
392
0
            .IsNothing()) {
393
0
      return Nothing<int>();
394
0
    }
395
396
0
    if (ret->Set(env->context(), i + offset, caa_record).IsNothing()) {
397
0
      return Nothing<int>();
398
0
    }
399
0
  }
400
401
0
  return Just<int>(ARES_SUCCESS);
402
0
}
403
404
Maybe<int> ParseTlsaReply(Environment* env,
405
                          unsigned char* buf,
406
                          int len,
407
0
                          Local<Array> ret) {
408
0
  EscapableHandleScope handle_scope(env->isolate());
409
410
0
  auto tmpl = env->tlsa_record_template();
411
0
  if (tmpl.IsEmpty()) {
412
0
    static constexpr std::string_view names[] = {
413
0
        "certUsage",
414
0
        "selector",
415
0
        "match",
416
0
        "data",
417
0
    };
418
0
    tmpl = DictionaryTemplate::New(env->isolate(), names);
419
0
    env->set_tlsa_record_template(tmpl);
420
0
  }
421
422
0
  ares_dns_record_t* dnsrec = nullptr;
423
424
0
  int status = ares_dns_parse(buf, len, 0, &dnsrec);
425
0
  if (status != ARES_SUCCESS) {
426
0
    ares_dns_record_destroy(dnsrec);
427
0
    return Just<int>(status);
428
0
  }
429
430
0
  DeleteFnPtr<ares_dns_record_t, ares_dns_record_destroy> free_me(dnsrec);
431
432
0
  uint32_t offset = ret->Length();
433
0
  size_t rr_count = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER);
434
435
0
  MaybeLocal<Value> values[] = {
436
0
      Undefined(env->isolate()),  // certUsage
437
0
      Undefined(env->isolate()),  // selector
438
0
      Undefined(env->isolate()),  // match
439
0
      Undefined(env->isolate()),  // data
440
0
  };
441
442
0
  for (size_t i = 0; i < rr_count; i++) {
443
0
    const ares_dns_rr_t* rr =
444
0
        ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, i);
445
446
0
    if (ares_dns_rr_get_type(rr) != ARES_REC_TYPE_TLSA) continue;
447
448
0
    unsigned char certusage = ares_dns_rr_get_u8(rr, ARES_RR_TLSA_CERT_USAGE);
449
0
    unsigned char selector = ares_dns_rr_get_u8(rr, ARES_RR_TLSA_SELECTOR);
450
0
    unsigned char match = ares_dns_rr_get_u8(rr, ARES_RR_TLSA_MATCH);
451
0
    size_t data_len;
452
0
    const unsigned char* data =
453
0
        ares_dns_rr_get_bin(rr, ARES_RR_TLSA_DATA, &data_len);
454
0
    if (!data || data_len == 0) continue;
455
456
0
    Local<ArrayBuffer> data_ab = ArrayBuffer::New(env->isolate(), data_len);
457
0
    memcpy(data_ab->Data(), data, data_len);
458
459
0
    values[0] = Integer::NewFromUnsigned(env->isolate(), certusage);
460
0
    values[1] = Integer::NewFromUnsigned(env->isolate(), selector);
461
0
    values[2] = Integer::NewFromUnsigned(env->isolate(), match);
462
0
    values[3] = data_ab;
463
464
0
    Local<Object> tlsa_rec;
465
0
    if (!NewDictionaryInstance(env->context(), tmpl, values)
466
0
             .ToLocal(&tlsa_rec) ||
467
0
        ret->Set(env->context(), offset + i, tlsa_rec).IsNothing()) {
468
0
      return Nothing<int>();
469
0
    }
470
0
  }
471
472
0
  return Just<int>(ARES_SUCCESS);
473
0
}
474
475
Maybe<int> ParseTxtReply(Environment* env,
476
                         const unsigned char* buf,
477
                         int len,
478
                         Local<Array> ret,
479
0
                         bool need_type = false) {
480
0
  HandleScope handle_scope(env->isolate());
481
482
0
  auto tmpl = env->txt_record_template();
483
0
  if (tmpl.IsEmpty()) {
484
0
    static constexpr std::string_view names[] = {
485
0
        "entries",
486
0
        "type",
487
0
    };
488
0
    tmpl = DictionaryTemplate::New(env->isolate(), names);
489
0
    env->set_txt_record_template(tmpl);
490
0
  }
491
492
0
  struct ares_txt_ext* txt_out;
493
494
0
  int status = ares_parse_txt_reply_ext(buf, len, &txt_out);
495
0
  if (status != ARES_SUCCESS) return Just<int>(status);
496
0
  DeleteFnPtr<void, ares_free_data> free_me(txt_out);
497
498
0
  Local<Array> txt_chunk;
499
0
  LocalVector<Value> chunks(env->isolate());
500
501
0
  struct ares_txt_ext* current = txt_out;
502
0
  uint32_t i = 0;
503
0
  uint32_t offset = ret->Length();
504
505
0
  MaybeLocal<Value> values[] = {
506
0
      Undefined(env->isolate()),  // entries
507
0
      Undefined(env->isolate()),  // type
508
0
  };
509
510
0
  for (; current != nullptr; current = current->next) {
511
0
    Local<String> txt =
512
0
        OneByteString(env->isolate(), current->txt, current->length);
513
514
    // New record found - write out the current chunk
515
0
    if (current->record_start) {
516
0
      if (!chunks.empty()) {
517
0
        auto txt_chunk =
518
0
            Array::New(env->isolate(), chunks.data(), chunks.size());
519
0
        chunks.clear();
520
0
        if (need_type) {
521
0
          values[0] = txt_chunk;
522
0
          values[1] = env->dns_txt_string();
523
0
          Local<Object> elem;
524
0
          if (!NewDictionaryInstance(env->context(), tmpl, values)
525
0
                   .ToLocal(&elem) ||
526
0
              ret->Set(env->context(), offset + i++, elem).IsNothing()) {
527
0
            return Nothing<int>();
528
0
          }
529
0
        } else if (ret->Set(env->context(), offset + i++, txt_chunk)
530
0
                       .IsNothing()) {
531
0
          return Nothing<int>();
532
0
        }
533
0
      }
534
535
0
      txt_chunk = Array::New(env->isolate());
536
0
    }
537
538
0
    chunks.push_back(txt);
539
0
  }
540
541
  // Push last chunk if it isn't empty
542
0
  if (!chunks.empty()) {
543
0
    txt_chunk = Array::New(env->isolate(), chunks.data(), chunks.size());
544
0
    if (need_type) {
545
0
      values[0] = txt_chunk;
546
0
      values[1] = env->dns_txt_string();
547
0
      Local<Object> elem;
548
0
      if (!NewDictionaryInstance(env->context(), tmpl, values).ToLocal(&elem) ||
549
0
          ret->Set(env->context(), offset + i, elem).IsNothing()) {
550
0
        return Nothing<int>();
551
0
      }
552
0
    } else if (ret->Set(env->context(), offset + i, txt_chunk).IsNothing()) {
553
0
      return Nothing<int>();
554
0
    }
555
0
  }
556
557
0
  return Just<int>(ARES_SUCCESS);
558
0
}
559
560
Maybe<int> ParseSrvReply(Environment* env,
561
                         const unsigned char* buf,
562
                         int len,
563
                         Local<Array> ret,
564
0
                         bool need_type = false) {
565
0
  HandleScope handle_scope(env->isolate());
566
567
0
  auto tmpl = env->srv_record_template();
568
0
  if (tmpl.IsEmpty()) {
569
0
    static constexpr std::string_view names[] = {
570
0
        "name",
571
0
        "port",
572
0
        "priority",
573
0
        "weight",
574
0
        "type",
575
0
    };
576
0
    tmpl = DictionaryTemplate::New(env->isolate(), names);
577
0
    env->set_srv_record_template(tmpl);
578
0
  }
579
580
0
  struct ares_srv_reply* srv_start;
581
0
  int status = ares_parse_srv_reply(buf, len, &srv_start);
582
0
  if (status != ARES_SUCCESS) return Just<int>(status);
583
0
  DeleteFnPtr<void, ares_free_data> free_me(srv_start);
584
585
0
  MaybeLocal<Value> values[] = {
586
0
      Undefined(env->isolate()),  // name
587
0
      Undefined(env->isolate()),  // port
588
0
      Undefined(env->isolate()),  // priority
589
0
      Undefined(env->isolate()),  // weight
590
0
      Undefined(env->isolate()),  // type
591
0
  };
592
593
0
  ares_srv_reply* current = srv_start;
594
0
  int offset = ret->Length();
595
0
  for (uint32_t i = 0; current != nullptr; ++i, current = current->next) {
596
0
    values[0] = OneByteString(env->isolate(), current->host);
597
0
    values[1] = Integer::New(env->isolate(), current->port);
598
0
    values[2] = Integer::New(env->isolate(), current->priority);
599
0
    values[3] = Integer::New(env->isolate(), current->weight);
600
0
    values[4] = env->dns_srv_string();
601
602
0
    Local<Object> srv_record;
603
0
    if (!NewDictionaryInstance(env->context(), tmpl, values)
604
0
             .ToLocal(&srv_record) ||
605
0
        ret->Set(env->context(), i + offset, srv_record).IsNothing()) {
606
0
      return Nothing<int>();
607
0
    }
608
0
  }
609
610
0
  return Just<int>(ARES_SUCCESS);
611
0
}
612
613
Maybe<int> ParseNaptrReply(Environment* env,
614
                           const unsigned char* buf,
615
                           int len,
616
                           Local<Array> ret,
617
0
                           bool need_type = false) {
618
0
  HandleScope handle_scope(env->isolate());
619
620
0
  auto tmpl = env->naptr_record_template();
621
0
  if (tmpl.IsEmpty()) {
622
0
    static constexpr std::string_view names[] = {
623
0
        "flags",
624
0
        "service",
625
0
        "regexp",
626
0
        "replacement",
627
0
        "order",
628
0
        "preference",
629
0
        "type",
630
0
    };
631
0
    tmpl = DictionaryTemplate::New(env->isolate(), names);
632
0
    env->set_naptr_record_template(tmpl);
633
0
  }
634
635
0
  ares_naptr_reply* naptr_start;
636
0
  int status = ares_parse_naptr_reply(buf, len, &naptr_start);
637
0
  if (status != ARES_SUCCESS) return Just<int>(status);
638
0
  DeleteFnPtr<void, ares_free_data> free_me(naptr_start);
639
640
0
  MaybeLocal<Value> values[] = {
641
0
      Undefined(env->isolate()),  // flags
642
0
      Undefined(env->isolate()),  // service
643
0
      Undefined(env->isolate()),  // regexp
644
0
      Undefined(env->isolate()),  // replacement
645
0
      Undefined(env->isolate()),  // order
646
0
      Undefined(env->isolate()),  // preference
647
0
      Undefined(env->isolate()),  // type
648
0
  };
649
650
0
  ares_naptr_reply* current = naptr_start;
651
0
  int offset = ret->Length();
652
0
  for (uint32_t i = 0; current != nullptr; ++i, current = current->next) {
653
0
    values[0] = OneByteString(env->isolate(), current->flags);
654
0
    values[1] = OneByteString(env->isolate(), current->service);
655
0
    values[2] = OneByteString(env->isolate(), current->regexp);
656
0
    values[3] = OneByteString(env->isolate(), current->replacement);
657
0
    values[4] = Integer::New(env->isolate(), current->order);
658
0
    values[5] = Integer::New(env->isolate(), current->preference);
659
0
    if (need_type) {
660
0
      values[6] = env->dns_naptr_string();
661
0
    }
662
663
0
    Local<Object> naptr_record;
664
0
    if (!NewDictionaryInstance(env->context(), tmpl, values)
665
0
             .ToLocal(&naptr_record) ||
666
0
        ret->Set(env->context(), i + offset, naptr_record).IsNothing()) {
667
0
      return Nothing<int>();
668
0
    }
669
0
  }
670
671
0
  return Just<int>(ARES_SUCCESS);
672
0
}
673
674
0
Local<DictionaryTemplate> getSoaRecordTemplate(Environment* env) {
675
0
  auto tmpl = env->soa_record_template();
676
0
  if (tmpl.IsEmpty()) {
677
0
    static constexpr std::string_view names[] = {
678
0
        "nsname",
679
0
        "hostmaster",
680
0
        "serial",
681
0
        "refresh",
682
0
        "retry",
683
0
        "expire",
684
0
        "minttl",
685
0
        "type",
686
0
    };
687
0
    tmpl = DictionaryTemplate::New(env->isolate(), names);
688
0
    env->set_soa_record_template(tmpl);
689
0
  }
690
0
  return tmpl;
691
0
}
692
693
Maybe<int> ParseSoaReply(Environment* env,
694
                         unsigned char* buf,
695
                         int len,
696
0
                         Local<Object>* ret) {
697
0
  EscapableHandleScope handle_scope(env->isolate());
698
699
0
  auto tmpl = getSoaRecordTemplate(env);
700
701
  // Manage memory using standardard smart pointer std::unique_tr
702
0
  struct AresDeleter {
703
0
    void operator()(char* ptr) const noexcept { ares_free_string(ptr); }
704
0
  };
705
0
  using ares_unique_ptr = std::unique_ptr<char[], AresDeleter>;
706
707
  // Can't use ares_parse_soa_reply() here which can only parse single record
708
0
  const unsigned int ancount = cares_get_16bit(buf + 6);
709
0
  unsigned char* ptr = buf + NS_HFIXEDSZ;
710
0
  char* name_temp = nullptr;
711
0
  long temp_len;  // NOLINT(runtime/int)
712
0
  int status = ares_expand_name(ptr, buf, len, &name_temp, &temp_len);
713
0
  if (status != ARES_SUCCESS) {
714
    // returns EBADRESP in case of invalid input
715
0
    return Just<int>(status == ARES_EBADNAME ? ARES_EBADRESP : status);
716
0
  }
717
718
0
  const ares_unique_ptr name(name_temp);
719
720
0
  if (ptr + temp_len + NS_QFIXEDSZ > buf + len) {
721
0
    return Just<int>(ARES_EBADRESP);
722
0
  }
723
0
  ptr += temp_len + NS_QFIXEDSZ;
724
725
0
  MaybeLocal<Value> values[] = {
726
0
      Undefined(env->isolate()),  // nsname
727
0
      Undefined(env->isolate()),  // hostmaster
728
0
      Undefined(env->isolate()),  // serial
729
0
      Undefined(env->isolate()),  // refresh
730
0
      Undefined(env->isolate()),  // retry
731
0
      Undefined(env->isolate()),  // expire
732
0
      Undefined(env->isolate()),  // minttl
733
0
      Undefined(env->isolate()),  // type
734
0
  };
735
736
0
  for (unsigned int i = 0; i < ancount; i++) {
737
0
    char* rr_name_temp = nullptr;
738
0
    long rr_temp_len;  // NOLINT(runtime/int)
739
0
    int status2 = ares_expand_name(ptr, buf, len, &rr_name_temp, &rr_temp_len);
740
741
0
    if (status2 != ARES_SUCCESS)
742
0
      return Just<int>(status2 == ARES_EBADNAME ? ARES_EBADRESP : status2);
743
744
0
    const ares_unique_ptr rr_name(rr_name_temp);
745
746
0
    ptr += rr_temp_len;
747
0
    if (ptr + NS_RRFIXEDSZ > buf + len) {
748
0
      return Just<int>(ARES_EBADRESP);
749
0
    }
750
751
0
    const int rr_type = cares_get_16bit(ptr);
752
0
    const int rr_len = cares_get_16bit(ptr + 8);
753
0
    ptr += NS_RRFIXEDSZ;
754
755
    // only need SOA
756
0
    if (rr_type == ns_t_soa) {
757
0
      char* nsname_temp = nullptr;
758
0
      long nsname_temp_len;  // NOLINT(runtime/int)
759
760
0
      int status3 = ares_expand_name(ptr, buf, len,
761
0
                                     &nsname_temp,
762
0
                                     &nsname_temp_len);
763
0
      if (status3 != ARES_SUCCESS) {
764
0
        return Just<int>(status3 == ARES_EBADNAME ? ARES_EBADRESP : status3);
765
0
      }
766
0
      const ares_unique_ptr nsname(nsname_temp);
767
0
      ptr += nsname_temp_len;
768
769
0
      char* hostmaster_temp = nullptr;
770
0
      long hostmaster_temp_len;  // NOLINT(runtime/int)
771
0
      int status4 = ares_expand_name(ptr, buf, len,
772
0
                                     &hostmaster_temp,
773
0
                                     &hostmaster_temp_len);
774
0
      if (status4 != ARES_SUCCESS) {
775
0
        return Just<int>(status4 == ARES_EBADNAME ? ARES_EBADRESP : status4);
776
0
      }
777
0
      const ares_unique_ptr hostmaster(hostmaster_temp);
778
0
      ptr += hostmaster_temp_len;
779
780
0
      if (ptr + 5 * 4 > buf + len) {
781
0
        return Just<int>(ARES_EBADRESP);
782
0
      }
783
784
0
      const unsigned int serial = nbytes::ReadUint32BE(ptr + 0 * 4);
785
0
      const unsigned int refresh = nbytes::ReadUint32BE(ptr + 1 * 4);
786
0
      const unsigned int retry = nbytes::ReadUint32BE(ptr + 2 * 4);
787
0
      const unsigned int expire = nbytes::ReadUint32BE(ptr + 3 * 4);
788
0
      const unsigned int minttl = nbytes::ReadUint32BE(ptr + 4 * 4);
789
790
0
      values[0] = OneByteString(env->isolate(), nsname.get());
791
0
      values[1] = OneByteString(env->isolate(), hostmaster.get());
792
0
      values[2] = Integer::NewFromUnsigned(env->isolate(), serial);
793
0
      values[3] = Integer::New(env->isolate(), refresh);
794
0
      values[4] = Integer::New(env->isolate(), retry);
795
0
      values[5] = Integer::New(env->isolate(), expire);
796
0
      values[6] = Integer::NewFromUnsigned(env->isolate(), minttl);
797
0
      values[7] = env->dns_soa_string();
798
0
      Local<Object> soa_record;
799
0
      if (!NewDictionaryInstance(env->context(), tmpl, values)
800
0
               .ToLocal(&soa_record)) {
801
0
        return Nothing<int>();
802
0
      }
803
804
0
      *ret = handle_scope.Escape(soa_record);
805
0
      break;
806
0
    }
807
808
0
    ptr += rr_len;
809
0
  }
810
811
0
  return Just<int>(ARES_SUCCESS);
812
0
}
813
}  // anonymous namespace
814
815
ChannelWrap::ChannelWrap(Environment* env,
816
                         Local<Object> object,
817
                         int timeout,
818
                         int tries,
819
                         int max_timeout)
820
0
    : AsyncWrap(env, object, PROVIDER_DNSCHANNEL),
821
0
      timeout_(timeout),
822
0
      tries_(tries),
823
0
      max_timeout_(max_timeout) {
824
0
  MakeWeak();
825
826
0
  Setup();
827
0
}
828
829
0
void ChannelWrap::MemoryInfo(MemoryTracker* tracker) const {
830
0
  if (timer_handle_ != nullptr)
831
0
    tracker->TrackField("timer_handle", *timer_handle_);
832
0
  tracker->TrackField("task_list", task_list_, "NodeAresTask::List");
833
0
}
834
835
0
void ChannelWrap::New(const FunctionCallbackInfo<Value>& args) {
836
0
  CHECK(args.IsConstructCall());
837
0
  CHECK_EQ(args.Length(), 3);
838
0
  CHECK(args[0]->IsInt32());
839
0
  CHECK(args[1]->IsInt32());
840
0
  CHECK(args[2]->IsInt32());
841
0
  const int timeout = args[0].As<Int32>()->Value();
842
0
  const int tries = args[1].As<Int32>()->Value();
843
0
  const int max_timeout = args[2].As<Int32>()->Value();
844
0
  Environment* env = Environment::GetCurrent(args);
845
0
  new ChannelWrap(env, args.This(), timeout, tries, max_timeout);
846
0
}
847
848
GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env,
849
                                       Local<Object> req_wrap_obj,
850
                                       uint8_t order)
851
0
    : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP),
852
0
      order_(order) {}
853
854
GetNameInfoReqWrap::GetNameInfoReqWrap(
855
    Environment* env,
856
    Local<Object> req_wrap_obj)
857
0
    : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETNAMEINFOREQWRAP) {}
858
859
/* This is called once per second by loop->timer. It is used to constantly */
860
/* call back into c-ares for possibly processing timeouts. */
861
0
void ChannelWrap::AresTimeout(uv_timer_t* handle) {
862
0
  ChannelWrap* channel = static_cast<ChannelWrap*>(handle->data);
863
0
  CHECK_EQ(channel->timer_handle(), handle);
864
0
  ares_process_fd(channel->cares_channel(), ARES_SOCKET_BAD, ARES_SOCKET_BAD);
865
0
}
866
867
868
0
void NodeAresTask::MemoryInfo(MemoryTracker* tracker) const {
869
0
  tracker->TrackField("channel", channel);
870
0
}
871
872
/* Allocates and returns a new NodeAresTask */
873
0
NodeAresTask* NodeAresTask::Create(ChannelWrap* channel, ares_socket_t sock) {
874
0
  auto task = new NodeAresTask();
875
876
0
  task->channel = channel;
877
0
  task->sock = sock;
878
879
0
  if (uv_poll_init_socket(channel->env()->event_loop(),
880
0
                          &task->poll_watcher, sock) < 0) {
881
    /* This should never happen. */
882
0
    delete task;
883
0
    return nullptr;
884
0
  }
885
886
0
  return task;
887
0
}
888
889
0
void ChannelWrap::Setup() {
890
0
  struct ares_options options;
891
0
  memset(&options, 0, sizeof(options));
892
0
  options.flags = ARES_FLAG_NOCHECKRESP;
893
0
  options.sock_state_cb = ares_sockstate_cb;
894
0
  options.sock_state_cb_data = this;
895
0
  options.timeout = timeout_;
896
0
  options.tries = tries_;
897
0
  options.qcache_max_ttl = 0;
898
899
0
  int r;
900
0
  if (!library_inited_) {
901
0
    Mutex::ScopedLock lock(ares_library_mutex);
902
    // Multiple calls to ares_library_init() increase a reference counter,
903
    // so this is a no-op except for the first call to it.
904
0
    r = ares_library_init(ARES_LIB_INIT_ALL);
905
0
    if (r != ARES_SUCCESS)
906
0
      return env()->ThrowError(ToErrorCodeString(r));
907
0
  }
908
909
  /* We do the call to ares_init_option for caller. */
910
0
  int optmask = ARES_OPT_FLAGS | ARES_OPT_TIMEOUTMS | ARES_OPT_SOCK_STATE_CB |
911
0
                ARES_OPT_TRIES | ARES_OPT_QUERY_CACHE;
912
913
0
  if (max_timeout_ > 0) {
914
0
    options.maxtimeout = max_timeout_;
915
0
    optmask |= ARES_OPT_MAXTIMEOUTMS;
916
0
  }
917
918
0
  r = ares_init_options(&channel_, &options, optmask);
919
920
0
  if (r != ARES_SUCCESS) {
921
0
    Mutex::ScopedLock lock(ares_library_mutex);
922
0
    ares_library_cleanup();
923
0
    return env()->ThrowError(ToErrorCodeString(r));
924
0
  }
925
926
0
  library_inited_ = true;
927
0
}
928
929
0
void ChannelWrap::StartTimer() {
930
0
  if (timer_handle_ == nullptr) {
931
0
    timer_handle_ = new uv_timer_t();
932
0
    timer_handle_->data = static_cast<void*>(this);
933
0
    uv_timer_init(env()->event_loop(), timer_handle_);
934
0
  } else if (uv_is_active(reinterpret_cast<uv_handle_t*>(timer_handle_))) {
935
0
    return;
936
0
  }
937
0
  int timeout = timeout_;
938
0
  if (timeout <= 0 || timeout > 1000) timeout = 1000;
939
0
  uv_timer_start(timer_handle_, AresTimeout, timeout, timeout);
940
0
}
941
942
0
void ChannelWrap::CloseTimer() {
943
0
  if (timer_handle_ == nullptr)
944
0
    return;
945
946
0
  env()->CloseHandle(timer_handle_, [](uv_timer_t* handle) { delete handle; });
947
0
  timer_handle_ = nullptr;
948
0
}
949
950
0
ChannelWrap::~ChannelWrap() {
951
0
  ares_destroy(channel_);
952
953
0
  if (library_inited_) {
954
0
    Mutex::ScopedLock lock(ares_library_mutex);
955
    // This decreases the reference counter increased by ares_library_init().
956
0
    ares_library_cleanup();
957
0
  }
958
959
0
  CloseTimer();
960
0
}
961
962
963
0
void ChannelWrap::ModifyActivityQueryCount(int count) {
964
0
  active_query_count_ += count;
965
0
  CHECK_GE(active_query_count_, 0);
966
0
}
967
968
969
/**
970
 * This function is to check whether current servers are fallback servers
971
 * when cares initialized.
972
 *
973
 * The fallback servers of cares is [ "127.0.0.1" ] with no user additional
974
 * setting.
975
 */
976
0
void ChannelWrap::EnsureServers() {
977
  /* if last query is OK or servers are set by user self, do not check */
978
0
  if (query_last_ok_ || !is_servers_default_) {
979
0
    return;
980
0
  }
981
982
0
  ares_addr_port_node* servers = nullptr;
983
984
0
  ares_get_servers_ports(channel_, &servers);
985
986
  /* if no server or multi-servers, ignore */
987
0
  if (servers == nullptr) return;
988
0
  if (servers->next != nullptr) {
989
0
    ares_free_data(servers);
990
0
    is_servers_default_ = false;
991
0
    return;
992
0
  }
993
994
  /* if the only server is not 127.0.0.1, ignore */
995
0
  if (servers[0].family != AF_INET ||
996
0
      servers[0].addr.addr4.s_addr != htonl(INADDR_LOOPBACK) ||
997
0
      servers[0].tcp_port != 0 ||
998
0
      servers[0].udp_port != 0) {
999
0
    ares_free_data(servers);
1000
0
    is_servers_default_ = false;
1001
0
    return;
1002
0
  }
1003
1004
0
  ares_free_data(servers);
1005
0
  servers = nullptr;
1006
1007
  /* destroy channel and reset channel */
1008
0
  ares_destroy(channel_);
1009
1010
0
  CloseTimer();
1011
0
  Setup();
1012
0
}
1013
1014
0
int AnyTraits::Send(QueryWrap<AnyTraits>* wrap, const char* name) {
1015
0
  wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_ANY);
1016
0
  return ARES_SUCCESS;
1017
0
}
1018
1019
0
int ATraits::Send(QueryWrap<ATraits>* wrap, const char* name) {
1020
0
  wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_A);
1021
0
  return ARES_SUCCESS;
1022
0
}
1023
1024
0
int AaaaTraits::Send(QueryWrap<AaaaTraits>* wrap, const char* name) {
1025
0
  wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_AAAA);
1026
0
  return ARES_SUCCESS;
1027
0
}
1028
1029
0
int CaaTraits::Send(QueryWrap<CaaTraits>* wrap, const char* name) {
1030
0
  wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_CAA);
1031
0
  return ARES_SUCCESS;
1032
0
}
1033
1034
0
int CnameTraits::Send(QueryWrap<CnameTraits>* wrap, const char* name) {
1035
0
  wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_CNAME);
1036
0
  return ARES_SUCCESS;
1037
0
}
1038
1039
0
int MxTraits::Send(QueryWrap<MxTraits>* wrap, const char* name) {
1040
0
  wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_MX);
1041
0
  return ARES_SUCCESS;
1042
0
}
1043
1044
0
int NsTraits::Send(QueryWrap<NsTraits>* wrap, const char* name) {
1045
0
  wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_NS);
1046
0
  return ARES_SUCCESS;
1047
0
}
1048
1049
0
int TlsaTraits::Send(QueryWrap<TlsaTraits>* wrap, const char* name) {
1050
0
  wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_TLSA);
1051
0
  return ARES_SUCCESS;
1052
0
}
1053
1054
0
int TxtTraits::Send(QueryWrap<TxtTraits>* wrap, const char* name) {
1055
0
  wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_TXT);
1056
0
  return ARES_SUCCESS;
1057
0
}
1058
1059
0
int SrvTraits::Send(QueryWrap<SrvTraits>* wrap, const char* name) {
1060
0
  wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_SRV);
1061
0
  return ARES_SUCCESS;
1062
0
}
1063
1064
0
int PtrTraits::Send(QueryWrap<PtrTraits>* wrap, const char* name) {
1065
0
  wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_PTR);
1066
0
  return ARES_SUCCESS;
1067
0
}
1068
1069
0
int NaptrTraits::Send(QueryWrap<NaptrTraits>* wrap, const char* name) {
1070
0
  wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_NAPTR);
1071
0
  return ARES_SUCCESS;
1072
0
}
1073
1074
0
int SoaTraits::Send(QueryWrap<SoaTraits>* wrap, const char* name) {
1075
0
  wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_SOA);
1076
0
  return ARES_SUCCESS;
1077
0
}
1078
1079
Maybe<int> AnyTraits::Parse(QueryAnyWrap* wrap,
1080
0
                            const std::unique_ptr<ResponseData>& response) {
1081
0
  if (response->is_host) [[unlikely]] {
1082
0
    return Just<int>(ARES_EBADRESP);
1083
0
  }
1084
1085
0
  unsigned char* buf = response->buf.data;
1086
0
  int len = response->buf.size;
1087
1088
0
  Environment* env = wrap->env();
1089
0
  HandleScope handle_scope(env->isolate());
1090
0
  Context::Scope context_scope(env->context());
1091
1092
0
  Local<Array> ret = Array::New(env->isolate());
1093
0
  int type, status, old_count;
1094
1095
  /* Parse A records or CNAME records */
1096
0
  ares_addrttl addrttls[256];
1097
0
  int naddrttls = arraysize(addrttls);
1098
1099
0
  type = ns_t_cname_or_a;
1100
0
  if (!ParseGeneralReply(env, buf, len, &type, ret, addrttls, &naddrttls)
1101
0
           .To(&status)) {
1102
0
    return Nothing<int>();
1103
0
  }
1104
0
  uint32_t a_count = ret->Length();
1105
0
  if (status != ARES_SUCCESS && status != ARES_ENODATA) {
1106
0
    return Just<int>(status);
1107
0
  }
1108
1109
0
  if (type == ns_t_a) {
1110
0
    CHECK_EQ(static_cast<uint32_t>(naddrttls), a_count);
1111
1112
0
    auto tmpl = env->a_record_template();
1113
0
    if (tmpl.IsEmpty()) {
1114
0
      static constexpr std::string_view names[] = {
1115
0
          "address",
1116
0
          "ttl",
1117
0
          "type",
1118
0
      };
1119
0
      tmpl = DictionaryTemplate::New(env->isolate(), names);
1120
0
      env->set_a_record_template(tmpl);
1121
0
    }
1122
0
    MaybeLocal<Value> values[] = {
1123
0
        Undefined(env->isolate()),  // address
1124
0
        Undefined(env->isolate()),  // ttl
1125
0
        Undefined(env->isolate()),  // type
1126
0
    };
1127
1128
0
    for (uint32_t i = 0; i < a_count; i++) {
1129
0
      Local<Value> address;
1130
0
      if (!ret->Get(env->context(), i).ToLocal(&address)) {
1131
0
        return Nothing<int>();
1132
0
      }
1133
0
      values[0] = address;
1134
0
      values[1] = Integer::NewFromUnsigned(env->isolate(), addrttls[i].ttl);
1135
0
      values[2] = env->dns_a_string();
1136
1137
0
      Local<Object> obj;
1138
0
      if (!NewDictionaryInstance(env->context(), tmpl, values).ToLocal(&obj) ||
1139
0
          ret->Set(env->context(), i, obj).IsNothing()) {
1140
0
        return Nothing<int>();
1141
0
      }
1142
0
    }
1143
0
  } else {
1144
0
    auto tmpl = env->cname_record_template();
1145
0
    if (tmpl.IsEmpty()) {
1146
0
      static constexpr std::string_view names[] = {
1147
0
          "value",
1148
0
          "type",
1149
0
      };
1150
0
      tmpl = DictionaryTemplate::New(env->isolate(), names);
1151
0
      env->set_cname_record_template(tmpl);
1152
0
    }
1153
0
    MaybeLocal<Value> values[] = {
1154
0
        Undefined(env->isolate()),  // value
1155
0
        Undefined(env->isolate()),  // type
1156
0
    };
1157
0
    for (uint32_t i = 0; i < a_count; i++) {
1158
0
      Local<Value> value;
1159
0
      if (!ret->Get(env->context(), i).ToLocal(&value)) {
1160
0
        return Nothing<int>();
1161
0
      }
1162
0
      values[0] = value;
1163
0
      values[1] = env->dns_cname_string();
1164
0
      Local<Object> obj;
1165
0
      if (!NewDictionaryInstance(env->context(), tmpl, values).ToLocal(&obj) ||
1166
0
          ret->Set(env->context(), i, obj).IsNothing()) {
1167
0
        return Nothing<int>();
1168
0
      }
1169
0
    }
1170
0
  }
1171
1172
  /* Parse AAAA records */
1173
0
  ares_addr6ttl addr6ttls[256];
1174
0
  int naddr6ttls = arraysize(addr6ttls);
1175
1176
0
  type = ns_t_aaaa;
1177
0
  if (!ParseGeneralReply(env, buf, len, &type, ret, addr6ttls, &naddr6ttls)
1178
0
           .To(&status)) {
1179
0
    return Nothing<int>();
1180
0
  }
1181
0
  uint32_t aaaa_count = ret->Length() - a_count;
1182
0
  if (status != ARES_SUCCESS && status != ARES_ENODATA)
1183
0
    return Just<int>(status);
1184
1185
0
  CHECK_EQ(aaaa_count, static_cast<uint32_t>(naddr6ttls));
1186
0
  CHECK_EQ(ret->Length(), a_count + aaaa_count);
1187
1188
0
  auto tmpl = env->aaaa_record_template();
1189
0
  if (tmpl.IsEmpty()) {
1190
0
    static constexpr std::string_view names[] = {
1191
0
        "address",
1192
0
        "ttl",
1193
0
        "type",
1194
0
    };
1195
0
    tmpl = DictionaryTemplate::New(env->isolate(), names);
1196
0
    env->set_aaaa_record_template(tmpl);
1197
0
  }
1198
1199
0
  MaybeLocal<Value> values[] = {
1200
0
      Undefined(env->isolate()),  // address
1201
0
      Undefined(env->isolate()),  // ttl
1202
0
      Undefined(env->isolate()),  // type
1203
0
  };
1204
1205
0
  for (uint32_t i = a_count; i < ret->Length(); i++) {
1206
0
    Local<Value> address;
1207
0
    if (!ret->Get(env->context(), i).ToLocal(&address)) {
1208
0
      return Nothing<int>();
1209
0
    }
1210
0
    values[0] = address;
1211
0
    values[1] =
1212
0
        Integer::NewFromUnsigned(env->isolate(), addr6ttls[i - a_count].ttl);
1213
0
    values[2] = env->dns_aaaa_string();
1214
0
    Local<Object> obj;
1215
0
    if (!NewDictionaryInstance(env->context(), tmpl, values).ToLocal(&obj) ||
1216
0
        ret->Set(env->context(), i, obj).IsNothing()) {
1217
0
      return Nothing<int>();
1218
0
    }
1219
0
  }
1220
1221
  /* Parse MX records */
1222
0
  if (!ParseMxReply(env, buf, len, ret, true).To(&status)) {
1223
0
    return Nothing<int>();
1224
0
  }
1225
0
  if (status != ARES_SUCCESS && status != ARES_ENODATA) {
1226
0
    return Just<int>(status);
1227
0
  }
1228
1229
  /* Parse NS records */
1230
0
  type = ns_t_ns;
1231
0
  old_count = ret->Length();
1232
0
  if (!ParseGeneralReply(env, buf, len, &type, ret).To(&status)) {
1233
0
    return Nothing<int>();
1234
0
  }
1235
0
  if (status != ARES_SUCCESS && status != ARES_ENODATA) {
1236
0
    return Just<int>(status);
1237
0
  }
1238
1239
0
  auto dns_ns_tmpl = env->dns_ns_record_template();
1240
0
  if (dns_ns_tmpl.IsEmpty()) {
1241
0
    static constexpr std::string_view names[] = {
1242
0
        "value",
1243
0
        "type",
1244
0
    };
1245
0
    dns_ns_tmpl = DictionaryTemplate::New(env->isolate(), names);
1246
0
    env->set_dns_ns_record_template(dns_ns_tmpl);
1247
0
  }
1248
1249
0
  MaybeLocal<Value> values_ns[] = {
1250
0
      Undefined(env->isolate()),  // value
1251
0
      Undefined(env->isolate()),  // type
1252
0
  };
1253
1254
0
  for (uint32_t i = old_count; i < ret->Length(); i++) {
1255
0
    Local<Value> value;
1256
0
    if (!ret->Get(env->context(), i).ToLocal(&value)) {
1257
0
      return Nothing<int>();
1258
0
    }
1259
0
    values_ns[0] = value;
1260
0
    values_ns[1] = env->dns_ns_string();
1261
0
    Local<Object> obj;
1262
0
    if (!NewDictionaryInstance(env->context(), dns_ns_tmpl, values_ns)
1263
0
             .ToLocal(&obj) ||
1264
0
        ret->Set(env->context(), i, obj).IsNothing()) {
1265
0
      return Nothing<int>();
1266
0
    }
1267
0
  }
1268
1269
  /* Parse TXT records */
1270
0
  if (!ParseTxtReply(env, buf, len, ret, true).To(&status)) {
1271
0
    return Nothing<int>();
1272
0
  }
1273
0
  if (status != ARES_SUCCESS && status != ARES_ENODATA) {
1274
0
    return Just<int>(status);
1275
0
  }
1276
1277
  /* Parse SRV records */
1278
0
  if (!ParseSrvReply(env, buf, len, ret, true).To(&status)) {
1279
0
    return Nothing<int>();
1280
0
  }
1281
0
  if (status != ARES_SUCCESS && status != ARES_ENODATA) {
1282
0
    return Just<int>(status);
1283
0
  }
1284
1285
  /* Parse PTR records */
1286
0
  type = ns_t_ptr;
1287
0
  old_count = ret->Length();
1288
0
  if (!ParseGeneralReply(env, buf, len, &type, ret).To(&status)) {
1289
0
    return Nothing<int>();
1290
0
  }
1291
0
  if (status != ARES_SUCCESS && status != ARES_ENODATA)
1292
0
    return Just<int>(status);
1293
1294
0
  for (uint32_t i = old_count; i < ret->Length(); i++) {
1295
0
    Local<Value> value;
1296
0
    if (!ret->Get(env->context(), i).ToLocal(&value)) {
1297
0
      return Nothing<int>();
1298
0
    }
1299
0
    values_ns[0] = value;
1300
0
    values_ns[1] = env->dns_ptr_string();
1301
0
    Local<Object> obj;
1302
0
    if (!NewDictionaryInstance(env->context(), dns_ns_tmpl, values_ns)
1303
0
             .ToLocal(&obj) ||
1304
0
        ret->Set(env->context(), i, obj).IsNothing()) {
1305
0
      return Nothing<int>();
1306
0
    }
1307
0
  }
1308
1309
  /* Parse NAPTR records */
1310
0
  if (!ParseNaptrReply(env, buf, len, ret, true).To(&status)) {
1311
0
    return Nothing<int>();
1312
0
  }
1313
0
  if (status != ARES_SUCCESS && status != ARES_ENODATA) {
1314
0
    return Just<int>(status);
1315
0
  }
1316
1317
  /* Parse SOA records */
1318
0
  Local<Object> soa_record = Local<Object>();
1319
0
  if (!ParseSoaReply(env, buf, len, &soa_record).To(&status)) {
1320
0
    return Nothing<int>();
1321
0
  }
1322
0
  if (status != ARES_SUCCESS && status != ARES_ENODATA) {
1323
0
    return Just<int>(status);
1324
0
  }
1325
1326
0
  if (!soa_record.IsEmpty()) {
1327
0
    if (ret->Set(env->context(), ret->Length(), soa_record).IsNothing()) {
1328
0
      return Just<int>(ARES_ENOMEM);
1329
0
    }
1330
0
  }
1331
1332
  /* Parse TLSA records */
1333
0
  if (!ParseTlsaReply(env, buf, len, ret).To(&status)) {
1334
0
    return Nothing<int>();
1335
0
  }
1336
0
  if (status != ARES_SUCCESS && status != ARES_ENODATA) {
1337
0
    return Just<int>(status);
1338
0
  }
1339
1340
  /* Parse CAA records */
1341
0
  if (!ParseCaaReply(env, buf, len, ret, true).To(&status)) {
1342
0
    return Nothing<int>();
1343
0
  }
1344
0
  if (status != ARES_SUCCESS && status != ARES_ENODATA) {
1345
0
    return Just<int>(status);
1346
0
  }
1347
1348
0
  wrap->CallOnComplete(ret);
1349
0
  return Just<int>(ARES_SUCCESS);
1350
0
}
1351
1352
Maybe<int> ATraits::Parse(QueryAWrap* wrap,
1353
0
                          const std::unique_ptr<ResponseData>& response) {
1354
0
  if (response->is_host) [[unlikely]] {
1355
0
    return Just<int>(ARES_EBADRESP);
1356
0
  }
1357
1358
0
  unsigned char* buf = response->buf.data;
1359
0
  int len = response->buf.size;
1360
1361
0
  Environment* env = wrap->env();
1362
0
  HandleScope handle_scope(env->isolate());
1363
0
  Context::Scope context_scope(env->context());
1364
1365
0
  ares_addrttl addrttls[256];
1366
0
  int naddrttls = arraysize(addrttls), status;
1367
0
  Local<Array> ret = Array::New(env->isolate());
1368
1369
0
  int type = ns_t_a;
1370
0
  if (!ParseGeneralReply(env, buf, len, &type, ret, addrttls, &naddrttls)
1371
0
           .To(&status)) {
1372
0
    return Nothing<int>();
1373
0
  }
1374
0
  if (status != ARES_SUCCESS) {
1375
0
    return Just<int>(status);
1376
0
  }
1377
1378
0
  Local<Array> ttls = AddrTTLToArray<ares_addrttl>(env, addrttls, naddrttls);
1379
1380
0
  wrap->CallOnComplete(ret, ttls);
1381
0
  return Just<int>(ARES_SUCCESS);
1382
0
}
1383
1384
Maybe<int> AaaaTraits::Parse(QueryAaaaWrap* wrap,
1385
0
                             const std::unique_ptr<ResponseData>& response) {
1386
0
  if (response->is_host) [[unlikely]] {
1387
0
    return Just<int>(ARES_EBADRESP);
1388
0
  }
1389
1390
0
  unsigned char* buf = response->buf.data;
1391
0
  int len = response->buf.size;
1392
1393
0
  Environment* env = wrap->env();
1394
0
  HandleScope handle_scope(env->isolate());
1395
0
  Context::Scope context_scope(env->context());
1396
1397
0
  ares_addr6ttl addrttls[256];
1398
0
  int naddrttls = arraysize(addrttls), status;
1399
0
  Local<Array> ret = Array::New(env->isolate());
1400
1401
0
  int type = ns_t_aaaa;
1402
0
  if (!ParseGeneralReply(env, buf, len, &type, ret, addrttls, &naddrttls)
1403
0
           .To(&status)) {
1404
0
    return Nothing<int>();
1405
0
  }
1406
0
  if (status != ARES_SUCCESS) {
1407
0
    return Just<int>(status);
1408
0
  }
1409
1410
0
  Local<Array> ttls = AddrTTLToArray<ares_addr6ttl>(env, addrttls, naddrttls);
1411
1412
0
  wrap->CallOnComplete(ret, ttls);
1413
0
  return Just<int>(ARES_SUCCESS);
1414
0
}
1415
1416
Maybe<int> CaaTraits::Parse(QueryCaaWrap* wrap,
1417
0
                            const std::unique_ptr<ResponseData>& response) {
1418
0
  if (response->is_host) [[unlikely]] {
1419
0
    return Just<int>(ARES_EBADRESP);
1420
0
  }
1421
1422
0
  unsigned char* buf = response->buf.data;
1423
0
  int len = response->buf.size;
1424
1425
0
  Environment* env = wrap->env();
1426
0
  HandleScope handle_scope(env->isolate());
1427
0
  Context::Scope context_scope(env->context());
1428
1429
0
  Local<Array> ret = Array::New(env->isolate());
1430
0
  int status;
1431
0
  if (!ParseCaaReply(env, buf, len, ret).To(&status)) {
1432
0
    return Nothing<int>();
1433
0
  }
1434
0
  if (status != ARES_SUCCESS) {
1435
0
    return Just<int>(status);
1436
0
  }
1437
1438
0
  wrap->CallOnComplete(ret);
1439
0
  return Just<int>(ARES_SUCCESS);
1440
0
}
1441
1442
Maybe<int> CnameTraits::Parse(QueryCnameWrap* wrap,
1443
0
                              const std::unique_ptr<ResponseData>& response) {
1444
0
  if (response->is_host) [[unlikely]] {
1445
0
    return Just<int>(ARES_EBADRESP);
1446
0
  }
1447
1448
0
  unsigned char* buf = response->buf.data;
1449
0
  int len = response->buf.size;
1450
1451
0
  Environment* env = wrap->env();
1452
0
  HandleScope handle_scope(env->isolate());
1453
0
  Context::Scope context_scope(env->context());
1454
1455
0
  Local<Array> ret = Array::New(env->isolate());
1456
0
  int type = ns_t_cname;
1457
0
  int status;
1458
0
  if (!ParseGeneralReply(env, buf, len, &type, ret).To(&status)) {
1459
0
    return Nothing<int>();
1460
0
  }
1461
0
  if (status != ARES_SUCCESS) {
1462
0
    return Just<int>(status);
1463
0
  }
1464
1465
0
  wrap->CallOnComplete(ret);
1466
0
  return Just<int>(ARES_SUCCESS);
1467
0
}
1468
1469
Maybe<int> MxTraits::Parse(QueryMxWrap* wrap,
1470
0
                           const std::unique_ptr<ResponseData>& response) {
1471
0
  if (response->is_host) [[unlikely]] {
1472
0
    return Just<int>(ARES_EBADRESP);
1473
0
  }
1474
1475
0
  unsigned char* buf = response->buf.data;
1476
0
  int len = response->buf.size;
1477
1478
0
  Environment* env = wrap->env();
1479
0
  HandleScope handle_scope(env->isolate());
1480
0
  Context::Scope context_scope(env->context());
1481
1482
0
  Local<Array> mx_records = Array::New(env->isolate());
1483
0
  int status;
1484
0
  if (!ParseMxReply(env, buf, len, mx_records).To(&status)) {
1485
0
    return Nothing<int>();
1486
0
  }
1487
1488
0
  if (status != ARES_SUCCESS) {
1489
0
    return Just<int>(status);
1490
0
  }
1491
1492
0
  wrap->CallOnComplete(mx_records);
1493
0
  return Just<int>(ARES_SUCCESS);
1494
0
}
1495
1496
Maybe<int> NsTraits::Parse(QueryNsWrap* wrap,
1497
0
                           const std::unique_ptr<ResponseData>& response) {
1498
0
  if (response->is_host) [[unlikely]] {
1499
0
    return Just<int>(ARES_EBADRESP);
1500
0
  }
1501
1502
0
  unsigned char* buf = response->buf.data;
1503
0
  int len = response->buf.size;
1504
1505
0
  Environment* env = wrap->env();
1506
0
  HandleScope handle_scope(env->isolate());
1507
0
  Context::Scope context_scope(env->context());
1508
1509
0
  int type = ns_t_ns;
1510
0
  Local<Array> names = Array::New(env->isolate());
1511
0
  int status;
1512
0
  if (!ParseGeneralReply(env, buf, len, &type, names).To(&status)) {
1513
0
    return Nothing<int>();
1514
0
  }
1515
0
  if (status != ARES_SUCCESS) {
1516
0
    return Just<int>(status);
1517
0
  }
1518
1519
0
  wrap->CallOnComplete(names);
1520
0
  return Just<int>(ARES_SUCCESS);
1521
0
}
1522
1523
Maybe<int> TlsaTraits::Parse(QueryTlsaWrap* wrap,
1524
0
                             const std::unique_ptr<ResponseData>& response) {
1525
0
  if (response->is_host) [[unlikely]] {
1526
0
    return Just<int>(ARES_EBADRESP);
1527
0
  }
1528
1529
0
  unsigned char* buf = response->buf.data;
1530
0
  int len = response->buf.size;
1531
1532
0
  Environment* env = wrap->env();
1533
0
  HandleScope handle_scope(env->isolate());
1534
0
  Context::Scope context_scope(env->context());
1535
1536
0
  Local<Array> tlsa_records = Array::New(env->isolate());
1537
0
  int status;
1538
0
  if (!ParseTlsaReply(env, buf, len, tlsa_records).To(&status)) {
1539
0
    return Nothing<int>();
1540
0
  }
1541
0
  if (status != ARES_SUCCESS) {
1542
0
    return Just<int>(status);
1543
0
  }
1544
1545
0
  wrap->CallOnComplete(tlsa_records);
1546
0
  return Just<int>(ARES_SUCCESS);
1547
0
}
1548
1549
Maybe<int> TxtTraits::Parse(QueryTxtWrap* wrap,
1550
0
                            const std::unique_ptr<ResponseData>& response) {
1551
0
  if (response->is_host) [[unlikely]] {
1552
0
    return Just<int>(ARES_EBADRESP);
1553
0
  }
1554
1555
0
  unsigned char* buf = response->buf.data;
1556
0
  int len = response->buf.size;
1557
1558
0
  Environment* env = wrap->env();
1559
0
  HandleScope handle_scope(env->isolate());
1560
0
  Context::Scope context_scope(env->context());
1561
1562
0
  Local<Array> txt_records = Array::New(env->isolate());
1563
0
  int status;
1564
0
  if (!ParseTxtReply(env, buf, len, txt_records).To(&status)) {
1565
0
    return Nothing<int>();
1566
0
  }
1567
0
  if (status != ARES_SUCCESS) {
1568
0
    return Just<int>(status);
1569
0
  }
1570
1571
0
  wrap->CallOnComplete(txt_records);
1572
0
  return Just<int>(ARES_SUCCESS);
1573
0
}
1574
1575
Maybe<int> SrvTraits::Parse(QuerySrvWrap* wrap,
1576
0
                            const std::unique_ptr<ResponseData>& response) {
1577
0
  if (response->is_host) [[unlikely]] {
1578
0
    return Just<int>(ARES_EBADRESP);
1579
0
  }
1580
1581
0
  unsigned char* buf = response->buf.data;
1582
0
  int len = response->buf.size;
1583
1584
0
  Environment* env = wrap->env();
1585
0
  HandleScope handle_scope(env->isolate());
1586
0
  Context::Scope context_scope(env->context());
1587
1588
0
  Local<Array> srv_records = Array::New(env->isolate());
1589
0
  int status;
1590
0
  if (!ParseSrvReply(env, buf, len, srv_records).To(&status)) {
1591
0
    return Nothing<int>();
1592
0
  }
1593
0
  if (status != ARES_SUCCESS) return Just<int>(status);
1594
1595
0
  wrap->CallOnComplete(srv_records);
1596
0
  return Just<int>(ARES_SUCCESS);
1597
0
}
1598
1599
Maybe<int> PtrTraits::Parse(QueryPtrWrap* wrap,
1600
0
                            const std::unique_ptr<ResponseData>& response) {
1601
0
  if (response->is_host) [[unlikely]] {
1602
0
    return Just<int>(ARES_EBADRESP);
1603
0
  }
1604
0
  unsigned char* buf = response->buf.data;
1605
0
  int len = response->buf.size;
1606
1607
0
  Environment* env = wrap->env();
1608
0
  HandleScope handle_scope(env->isolate());
1609
0
  Context::Scope context_scope(env->context());
1610
1611
0
  int type = ns_t_ptr;
1612
0
  Local<Array> aliases = Array::New(env->isolate());
1613
1614
0
  int status;
1615
0
  if (!ParseGeneralReply(env, buf, len, &type, aliases).To(&status)) {
1616
0
    return Nothing<int>();
1617
0
  }
1618
0
  if (status != ARES_SUCCESS) {
1619
0
    return Just<int>(status);
1620
0
  }
1621
1622
0
  wrap->CallOnComplete(aliases);
1623
0
  return Just<int>(ARES_SUCCESS);
1624
0
}
1625
1626
Maybe<int> NaptrTraits::Parse(QueryNaptrWrap* wrap,
1627
0
                              const std::unique_ptr<ResponseData>& response) {
1628
0
  if (response->is_host) [[unlikely]] {
1629
0
    return Just<int>(ARES_EBADRESP);
1630
0
  }
1631
0
  unsigned char* buf = response->buf.data;
1632
0
  int len = response->buf.size;
1633
1634
0
  Environment* env = wrap->env();
1635
0
  HandleScope handle_scope(env->isolate());
1636
0
  Context::Scope context_scope(env->context());
1637
1638
0
  Local<Array> naptr_records = Array::New(env->isolate());
1639
0
  int status;
1640
0
  if (!ParseNaptrReply(env, buf, len, naptr_records).To(&status)) {
1641
0
    return Nothing<int>();
1642
0
  }
1643
0
  if (status != ARES_SUCCESS) {
1644
0
    return Just<int>(status);
1645
0
  }
1646
1647
0
  wrap->CallOnComplete(naptr_records);
1648
0
  return Just<int>(ARES_SUCCESS);
1649
0
}
1650
1651
Maybe<int> SoaTraits::Parse(QuerySoaWrap* wrap,
1652
0
                            const std::unique_ptr<ResponseData>& response) {
1653
0
  if (response->is_host) [[unlikely]] {
1654
0
    return Just<int>(ARES_EBADRESP);
1655
0
  }
1656
0
  unsigned char* buf = response->buf.data;
1657
0
  int len = response->buf.size;
1658
1659
0
  Environment* env = wrap->env();
1660
0
  HandleScope handle_scope(env->isolate());
1661
0
  Context::Scope context_scope(env->context());
1662
1663
0
  auto tmpl = getSoaRecordTemplate(env);
1664
0
  MaybeLocal<Value> values[] = {
1665
0
      Undefined(env->isolate()),  // nsname
1666
0
      Undefined(env->isolate()),  // hostmaster
1667
0
      Undefined(env->isolate()),  // serial
1668
0
      Undefined(env->isolate()),  // refresh
1669
0
      Undefined(env->isolate()),  // retry
1670
0
      Undefined(env->isolate()),  // expire
1671
0
      Undefined(env->isolate()),  // minttl
1672
0
      Undefined(env->isolate()),  // type
1673
0
  };
1674
1675
0
  ares_soa_reply* soa_out;
1676
0
  int status = ares_parse_soa_reply(buf, len, &soa_out);
1677
1678
0
  if (status != ARES_SUCCESS) return Just<int>(status);
1679
1680
0
  auto cleanup = OnScopeLeave([&]() { ares_free_data(soa_out); });
1681
1682
0
  values[0] = OneByteString(env->isolate(), soa_out->nsname);
1683
0
  values[1] = OneByteString(env->isolate(), soa_out->hostmaster);
1684
0
  values[2] = Integer::NewFromUnsigned(env->isolate(), soa_out->serial);
1685
0
  values[3] = Integer::New(env->isolate(), soa_out->refresh);
1686
0
  values[4] = Integer::New(env->isolate(), soa_out->retry);
1687
0
  values[5] = Integer::New(env->isolate(), soa_out->expire);
1688
0
  values[6] = Integer::NewFromUnsigned(env->isolate(), soa_out->minttl);
1689
0
  Local<Object> soa_record;
1690
0
  if (!NewDictionaryInstance(env->context(), tmpl, values)
1691
0
           .ToLocal(&soa_record)) {
1692
0
    return Nothing<int>();
1693
0
  }
1694
1695
0
  wrap->CallOnComplete(soa_record);
1696
0
  return Just<int>(ARES_SUCCESS);
1697
0
}
1698
1699
0
int ReverseTraits::Send(QueryReverseWrap* wrap, const char* name) {
1700
0
  permission::PermissionScope scope = permission::PermissionScope::kNet;
1701
0
  Environment* env_holder = wrap->env();
1702
1703
0
  if (!env_holder->permission()->is_granted(env_holder, scope, name))
1704
0
      [[unlikely]] {
1705
0
    wrap->QueuePermissionModelResponseCallback(name);
1706
    // Error will be returned in the callback
1707
0
    return ARES_SUCCESS;
1708
0
  }
1709
1710
0
  int length, family;
1711
0
  char address_buffer[sizeof(struct in6_addr)];
1712
1713
0
  if (uv_inet_pton(AF_INET, name, &address_buffer) == 0) {
1714
0
    length = sizeof(struct in_addr);
1715
0
    family = AF_INET;
1716
0
  } else if (uv_inet_pton(AF_INET6, name, &address_buffer) == 0) {
1717
0
    length = sizeof(struct in6_addr);
1718
0
    family = AF_INET6;
1719
0
  } else {
1720
0
    return UV_EINVAL;  // So errnoException() reports a proper error.
1721
0
  }
1722
1723
0
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(
1724
0
      TRACING_CATEGORY_NODE2(dns, native), "reverse", wrap,
1725
0
      "name", TRACE_STR_COPY(name),
1726
0
      "family", family == AF_INET ? "ipv4" : "ipv6");
1727
1728
0
  ares_gethostbyaddr(wrap->channel()->cares_channel(),
1729
0
                     address_buffer,
1730
0
                     length,
1731
0
                     family,
1732
0
                     QueryReverseWrap::Callback,
1733
0
                     wrap->MakeCallbackPointer());
1734
0
  return ARES_SUCCESS;
1735
0
}
1736
1737
Maybe<int> ReverseTraits::Parse(QueryReverseWrap* wrap,
1738
0
                                const std::unique_ptr<ResponseData>& response) {
1739
0
  if (!response->is_host) [[unlikely]] {
1740
0
    return Just<int>(ARES_EBADRESP);
1741
0
  }
1742
0
  struct hostent* host = response->host.get();
1743
1744
0
  Environment* env = wrap->env();
1745
0
  HandleScope handle_scope(env->isolate());
1746
0
  Context::Scope context_scope(env->context());
1747
0
  Local<Array> names;
1748
0
  if (!HostentToNames(env, host).ToLocal(&names)) {
1749
0
    return Nothing<int>();
1750
0
  }
1751
0
  wrap->CallOnComplete(names);
1752
0
  return Just<int>(ARES_SUCCESS);
1753
0
}
1754
1755
namespace {
1756
template <class Wrap>
1757
0
static void Query(const FunctionCallbackInfo<Value>& args) {
1758
0
  ChannelWrap* channel;
1759
0
  ASSIGN_OR_RETURN_UNWRAP(&channel, args.This());
1760
1761
0
  CHECK_EQ(false, args.IsConstructCall());
1762
0
  CHECK(args[0]->IsObject());
1763
0
  CHECK(args[1]->IsString());
1764
1765
0
  Local<Object> req_wrap_obj = args[0].As<Object>();
1766
0
  Local<String> string = args[1].As<String>();
1767
0
  auto wrap = std::make_unique<Wrap>(channel, req_wrap_obj);
1768
1769
0
  node::Utf8Value utf8name(args.GetIsolate(), string);
1770
0
  auto plain_name = utf8name.ToStringView();
1771
0
  std::string name = ada::idna::to_ascii(plain_name);
1772
0
  channel->ModifyActivityQueryCount(1);
1773
0
  int err = wrap->Send(name.c_str());
1774
0
  if (err) {
1775
0
    channel->ModifyActivityQueryCount(-1);
1776
0
  } else {
1777
    // Release ownership of the pointer allowing the ownership to be transferred
1778
0
    USE(wrap.release());
1779
0
  }
1780
1781
0
  args.GetReturnValue().Set(err);
1782
0
}
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::ReverseTraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::ATraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::AnyTraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::AaaaTraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::CaaTraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::CnameTraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::MxTraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::NaptrTraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::NsTraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::PtrTraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::SrvTraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::SoaTraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::TlsaTraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
Unexecuted instantiation: cares_wrap.cc:void node::cares_wrap::(anonymous namespace)::Query<node::cares_wrap::QueryWrap<node::cares_wrap::TxtTraits> >(v8::FunctionCallbackInfo<v8::Value> const&)
1783
1784
0
void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
1785
0
  auto cleanup = OnScopeLeave([&]() { uv_freeaddrinfo(res); });
1786
0
  BaseObjectPtr<GetAddrInfoReqWrap> req_wrap{
1787
0
      static_cast<GetAddrInfoReqWrap*>(req->data)};
1788
0
  Environment* env = req_wrap->env();
1789
1790
0
  HandleScope handle_scope(env->isolate());
1791
0
  Context::Scope context_scope(env->context());
1792
1793
0
  Local<Value> argv[] = {
1794
0
    Integer::New(env->isolate(), status),
1795
0
    Null(env->isolate())
1796
0
  };
1797
1798
0
  uint32_t n = 0;
1799
0
  const uint8_t order = req_wrap->order();
1800
1801
0
  if (status == 0) {
1802
0
    Local<Array> results = Array::New(env->isolate());
1803
1804
0
    auto add = [&](bool want_ipv4, bool want_ipv6) -> Maybe<void> {
1805
0
      for (auto p = res; p != nullptr; p = p->ai_next) {
1806
0
        CHECK_EQ(p->ai_socktype, SOCK_STREAM);
1807
1808
0
        const char* addr;
1809
0
        if (want_ipv4 && p->ai_family == AF_INET) {
1810
0
          addr = reinterpret_cast<char*>(
1811
0
              &(reinterpret_cast<struct sockaddr_in*>(p->ai_addr)->sin_addr));
1812
0
        } else if (want_ipv6 && p->ai_family == AF_INET6) {
1813
0
          addr = reinterpret_cast<char*>(
1814
0
              &(reinterpret_cast<struct sockaddr_in6*>(p->ai_addr)->sin6_addr));
1815
0
        } else {
1816
0
          continue;
1817
0
        }
1818
1819
0
        char ip[INET6_ADDRSTRLEN];
1820
0
        if (uv_inet_ntop(p->ai_family, addr, ip, sizeof(ip)))
1821
0
          continue;
1822
1823
0
        Local<String> s = OneByteString(env->isolate(), ip);
1824
0
        if (results->Set(env->context(), n, s).IsNothing())
1825
0
          return Nothing<void>();
1826
0
        n++;
1827
0
      }
1828
0
      return JustVoid();
1829
0
    };
1830
1831
0
    switch (order) {
1832
0
      case DNS_ORDER_IPV4_FIRST:
1833
0
        if (add(true, false).IsNothing() || add(false, true).IsNothing())
1834
0
          return;
1835
1836
0
        break;
1837
0
      case DNS_ORDER_IPV6_FIRST:
1838
0
        if (add(false, true).IsNothing() || add(true, false).IsNothing())
1839
0
          return;
1840
1841
0
        break;
1842
0
      default:
1843
0
        if (add(true, true).IsNothing()) return;
1844
1845
0
        break;
1846
0
    }
1847
1848
    // No responses were found to return
1849
0
    if (n == 0) {
1850
0
      argv[0] = Integer::New(env->isolate(), UV_EAI_NODATA);
1851
0
    }
1852
1853
0
    argv[1] = results;
1854
0
  }
1855
1856
0
  TRACE_EVENT_NESTABLE_ASYNC_END2(TRACING_CATEGORY_NODE2(dns, native),
1857
0
                                  "lookup",
1858
0
                                  req_wrap.get(),
1859
0
                                  "count",
1860
0
                                  n,
1861
0
                                  "order",
1862
0
                                  order);
1863
1864
  // Make the callback into JavaScript
1865
0
  req_wrap->MakeCallback(env->oncomplete_string(), arraysize(argv), argv);
1866
0
}
1867
1868
1869
void AfterGetNameInfo(uv_getnameinfo_t* req,
1870
                      int status,
1871
                      const char* hostname,
1872
0
                      const char* service) {
1873
0
  BaseObjectPtr<GetNameInfoReqWrap> req_wrap{
1874
0
      static_cast<GetNameInfoReqWrap*>(req->data)};
1875
0
  Environment* env = req_wrap->env();
1876
1877
0
  HandleScope handle_scope(env->isolate());
1878
0
  Context::Scope context_scope(env->context());
1879
1880
0
  Local<Value> argv[] = {
1881
0
    Integer::New(env->isolate(), status),
1882
0
    Null(env->isolate()),
1883
0
    Null(env->isolate())
1884
0
  };
1885
1886
0
  if (status == 0) {
1887
    // Success
1888
0
    Local<String> js_hostname = OneByteString(env->isolate(), hostname);
1889
0
    Local<String> js_service = OneByteString(env->isolate(), service);
1890
0
    argv[1] = js_hostname;
1891
0
    argv[2] = js_service;
1892
0
  }
1893
1894
0
  TRACE_EVENT_NESTABLE_ASYNC_END2(
1895
0
      TRACING_CATEGORY_NODE2(dns, native), "lookupService", req_wrap.get(),
1896
0
      "hostname", TRACE_STR_COPY(hostname),
1897
0
      "service", TRACE_STR_COPY(service));
1898
1899
  // Make the callback into JavaScript
1900
0
  req_wrap->MakeCallback(env->oncomplete_string(), arraysize(argv), argv);
1901
0
}
1902
1903
0
void CanonicalizeIP(const FunctionCallbackInfo<Value>& args) {
1904
0
  Isolate* isolate = args.GetIsolate();
1905
0
  node::Utf8Value ip(isolate, args[0]);
1906
1907
0
  int af;
1908
0
  unsigned char result[sizeof(ares_addr_port_node::addr)];
1909
0
  if (uv_inet_pton(af = AF_INET, *ip, result) != 0 &&
1910
0
      uv_inet_pton(af = AF_INET6, *ip, result) != 0)
1911
0
    return;
1912
1913
0
  char canonical_ip[INET6_ADDRSTRLEN]{};
1914
0
  CHECK_EQ(0, uv_inet_ntop(af, result, canonical_ip, sizeof(canonical_ip)));
1915
0
  args.GetReturnValue().Set(OneByteString(isolate, canonical_ip));
1916
0
}
1917
1918
0
void ConvertIpv6StringToBuffer(const FunctionCallbackInfo<Value>& args) {
1919
0
  Isolate* isolate = args.GetIsolate();
1920
0
  node::Utf8Value ip(isolate, args[0]);
1921
0
  unsigned char dst[16];  // IPv6 addresses are 128 bits (16 bytes)
1922
1923
0
  if (uv_inet_pton(AF_INET6, *ip, dst) != 0) {
1924
0
    isolate->ThrowException(Exception::Error(
1925
0
        FIXED_ONE_BYTE_STRING(isolate, "Invalid IPv6 address")));
1926
0
    return;
1927
0
  }
1928
1929
0
  Local<Object> buffer;
1930
0
  if (node::Buffer::Copy(
1931
0
          isolate, reinterpret_cast<const char*>(dst), sizeof(dst))
1932
0
          .ToLocal(&buffer)) {
1933
0
    args.GetReturnValue().Set(buffer);
1934
0
  }
1935
0
}
1936
1937
0
void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
1938
0
  Environment* env = Environment::GetCurrent(args);
1939
1940
0
  CHECK(args[0]->IsObject());
1941
0
  CHECK(args[1]->IsString());
1942
0
  CHECK(args[2]->IsInt32());
1943
0
  CHECK(args[4]->IsUint32());
1944
0
  Local<Object> req_wrap_obj = args[0].As<Object>();
1945
0
  node::Utf8Value hostname(env->isolate(), args[1]);
1946
1947
0
  ERR_ACCESS_DENIED_IF_INSUFFICIENT_PERMISSIONS(
1948
0
      env, permission::PermissionScope::kNet, hostname.ToStringView(), args);
1949
1950
0
  std::string ascii_hostname = ada::idna::to_ascii(hostname.ToStringView());
1951
1952
0
  int32_t flags = 0;
1953
0
  if (args[3]->IsInt32()) {
1954
0
    flags = args[3].As<Int32>()->Value();
1955
0
  }
1956
1957
0
  int family;
1958
1959
0
  switch (args[2].As<Int32>()->Value()) {
1960
0
    case 0:
1961
0
      family = AF_UNSPEC;
1962
0
      break;
1963
0
    case 4:
1964
0
      family = AF_INET;
1965
0
      break;
1966
0
    case 6:
1967
0
      family = AF_INET6;
1968
0
      break;
1969
0
    default:
1970
0
      UNREACHABLE("bad address family");
1971
0
  }
1972
1973
0
  Local<Uint32> order = args[4].As<Uint32>();
1974
1975
0
  auto req_wrap =
1976
0
      std::make_unique<GetAddrInfoReqWrap>(env, req_wrap_obj, order->Value());
1977
1978
0
  struct addrinfo hints;
1979
0
  memset(&hints, 0, sizeof(hints));
1980
0
  hints.ai_family = family;
1981
0
  hints.ai_socktype = SOCK_STREAM;
1982
0
  hints.ai_flags = flags;
1983
1984
0
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(TRACING_CATEGORY_NODE2(dns, native),
1985
0
                                    "lookup",
1986
0
                                    req_wrap.get(),
1987
0
                                    "hostname",
1988
0
                                    TRACE_STR_COPY(ascii_hostname.data()),
1989
0
                                    "family",
1990
0
                                    family == AF_INET    ? "ipv4"
1991
0
                                    : family == AF_INET6 ? "ipv6"
1992
0
                                                         : "unspec");
1993
1994
0
  int err = req_wrap->Dispatch(
1995
0
      uv_getaddrinfo, AfterGetAddrInfo, ascii_hostname.data(), nullptr, &hints);
1996
0
  if (err == 0)
1997
    // Release ownership of the pointer allowing the ownership to be transferred
1998
0
    USE(req_wrap.release());
1999
2000
0
  args.GetReturnValue().Set(err);
2001
0
}
2002
2003
2004
0
void GetNameInfo(const FunctionCallbackInfo<Value>& args) {
2005
0
  Environment* env = Environment::GetCurrent(args);
2006
2007
0
  CHECK(args[0]->IsObject());
2008
0
  CHECK(args[1]->IsString());
2009
0
  CHECK(args[2]->IsUint32());
2010
0
  Local<Object> req_wrap_obj = args[0].As<Object>();
2011
0
  node::Utf8Value ip(env->isolate(), args[1]);
2012
0
  const unsigned port = args[2]->Uint32Value(env->context()).FromJust();
2013
0
  struct sockaddr_storage addr;
2014
2015
0
  CHECK(uv_ip4_addr(*ip, port, reinterpret_cast<sockaddr_in*>(&addr)) == 0 ||
2016
0
        uv_ip6_addr(*ip, port, reinterpret_cast<sockaddr_in6*>(&addr)) == 0);
2017
2018
0
  auto req_wrap = std::make_unique<GetNameInfoReqWrap>(env, req_wrap_obj);
2019
2020
0
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(
2021
0
      TRACING_CATEGORY_NODE2(dns, native), "lookupService", req_wrap.get(),
2022
0
      "ip", TRACE_STR_COPY(*ip), "port", port);
2023
2024
0
  int err = 0;
2025
0
  if (!env->permission()->is_granted(
2026
0
          env, permission::PermissionScope::kNet, ip.ToStringView()))
2027
0
      [[unlikely]] {
2028
0
    req_wrap->InsufficientPermissionError(*ip);
2029
0
  } else {
2030
0
    err = req_wrap->Dispatch(uv_getnameinfo,
2031
0
                             AfterGetNameInfo,
2032
0
                             reinterpret_cast<struct sockaddr*>(&addr),
2033
0
                             NI_NAMEREQD);
2034
0
  }
2035
2036
0
  if (err == 0)
2037
    // Release ownership of the pointer allowing the ownership to be transferred
2038
0
    USE(req_wrap.release());
2039
2040
0
  args.GetReturnValue().Set(err);
2041
0
}
2042
2043
2044
0
void GetServers(const FunctionCallbackInfo<Value>& args) {
2045
0
  Environment* env = Environment::GetCurrent(args);
2046
0
  ChannelWrap* channel;
2047
0
  ASSIGN_OR_RETURN_UNWRAP(&channel, args.This());
2048
2049
0
  Local<Array> server_array = Array::New(env->isolate());
2050
2051
0
  ares_addr_port_node* servers;
2052
2053
0
  int r = ares_get_servers_ports(channel->cares_channel(), &servers);
2054
0
  CHECK_EQ(r, ARES_SUCCESS);
2055
0
  auto cleanup = OnScopeLeave([&]() { ares_free_data(servers); });
2056
2057
0
  ares_addr_port_node* cur = servers;
2058
2059
0
  for (uint32_t i = 0; cur != nullptr; ++i, cur = cur->next) {
2060
0
    char ip[INET6_ADDRSTRLEN];
2061
2062
0
    const void* caddr = static_cast<const void*>(&cur->addr);
2063
0
    int err = uv_inet_ntop(cur->family, caddr, ip, sizeof(ip));
2064
0
    CHECK_EQ(err, 0);
2065
2066
0
    Local<Value> ret[] = {
2067
0
      OneByteString(env->isolate(), ip),
2068
0
      Integer::New(env->isolate(), cur->udp_port)
2069
0
    };
2070
2071
0
    if (server_array->Set(env->context(), i,
2072
0
                          Array::New(env->isolate(), ret, arraysize(ret)))
2073
0
          .IsNothing()) {
2074
0
      return;
2075
0
    }
2076
0
  }
2077
2078
0
  args.GetReturnValue().Set(server_array);
2079
0
}
2080
2081
2082
0
void SetServers(const FunctionCallbackInfo<Value>& args) {
2083
0
  Environment* env = Environment::GetCurrent(args);
2084
0
  ChannelWrap* channel;
2085
0
  ASSIGN_OR_RETURN_UNWRAP(&channel, args.This());
2086
2087
0
  if (channel->active_query_count()) {
2088
0
    return args.GetReturnValue().Set(DNS_ESETSRVPENDING);
2089
0
  }
2090
2091
0
  CHECK(args[0]->IsArray());
2092
2093
0
  Local<Array> arr = args[0].As<Array>();
2094
2095
0
  uint32_t len = arr->Length();
2096
2097
0
  if (len == 0) {
2098
0
    int rv = ares_set_servers(channel->cares_channel(), nullptr);
2099
0
    return args.GetReturnValue().Set(rv);
2100
0
  }
2101
2102
0
  std::vector<ares_addr_port_node> servers(len);
2103
0
  ares_addr_port_node* last = nullptr;
2104
2105
0
  int err;
2106
2107
0
  for (uint32_t i = 0; i < len; i++) {
2108
0
    Local<Value> val;
2109
0
    if (!arr->Get(env->context(), i).ToLocal(&val)) return;
2110
0
    CHECK(val->IsArray());
2111
2112
0
    Local<Array> elm = val.As<Array>();
2113
2114
0
    Local<Value> familyValue;
2115
0
    Local<Value> ipValue;
2116
0
    Local<Value> portValue;
2117
2118
0
    if (!elm->Get(env->context(), 0).ToLocal(&familyValue)) return;
2119
0
    if (!elm->Get(env->context(), 1).ToLocal(&ipValue)) return;
2120
0
    if (!elm->Get(env->context(), 2).ToLocal(&portValue)) return;
2121
2122
0
    CHECK(familyValue->Int32Value(env->context()).FromJust());
2123
0
    CHECK(ipValue->IsString());
2124
0
    CHECK(portValue->Int32Value(env->context()).FromJust());
2125
2126
0
    int fam = familyValue->Int32Value(env->context()).FromJust();
2127
0
    node::Utf8Value ip(env->isolate(), ipValue);
2128
0
    int port = portValue->Int32Value(env->context()).FromJust();
2129
2130
0
    ares_addr_port_node* cur = &servers[i];
2131
2132
0
    cur->tcp_port = cur->udp_port = port;
2133
0
    switch (fam) {
2134
0
      case 4:
2135
0
        cur->family = AF_INET;
2136
0
        err = uv_inet_pton(AF_INET, *ip, &cur->addr);
2137
0
        break;
2138
0
      case 6:
2139
0
        cur->family = AF_INET6;
2140
0
        err = uv_inet_pton(AF_INET6, *ip, &cur->addr);
2141
0
        break;
2142
0
      default:
2143
0
        UNREACHABLE("Bad address family");
2144
0
    }
2145
2146
0
    if (err)
2147
0
      break;
2148
2149
0
    cur->next = nullptr;
2150
2151
0
    if (last != nullptr)
2152
0
      last->next = cur;
2153
2154
0
    last = cur;
2155
0
  }
2156
2157
0
  if (err == 0)
2158
0
    err = ares_set_servers_ports(channel->cares_channel(), servers.data());
2159
0
  else
2160
0
    err = ARES_EBADSTR;
2161
2162
0
  if (err == ARES_SUCCESS)
2163
0
    channel->set_is_servers_default(false);
2164
2165
0
  args.GetReturnValue().Set(err);
2166
0
}
2167
2168
0
void SetLocalAddress(const FunctionCallbackInfo<Value>& args) {
2169
0
  Environment* env = Environment::GetCurrent(args);
2170
0
  ChannelWrap* channel;
2171
0
  ASSIGN_OR_RETURN_UNWRAP(&channel, args.This());
2172
2173
0
  CHECK_EQ(args.Length(), 2);
2174
0
  CHECK(args[0]->IsString());
2175
2176
0
  Isolate* isolate = args.GetIsolate();
2177
0
  node::Utf8Value ip0(isolate, args[0]);
2178
2179
0
  unsigned char addr0[sizeof(struct in6_addr)];
2180
0
  unsigned char addr1[sizeof(struct in6_addr)];
2181
0
  int type0 = 0;
2182
2183
  // This function accepts 2 arguments.  The first may be either an IPv4
2184
  // address or an IPv6 address.  If present, the second argument must be the
2185
  // other type of address.  Otherwise, the unspecified type of IP is set
2186
  // to 0 (any).
2187
2188
0
  if (uv_inet_pton(AF_INET, *ip0, &addr0) == 0) {
2189
0
    ares_set_local_ip4(channel->cares_channel(), nbytes::ReadUint32BE(addr0));
2190
0
    type0 = 4;
2191
0
  } else if (uv_inet_pton(AF_INET6, *ip0, &addr0) == 0) {
2192
0
    ares_set_local_ip6(channel->cares_channel(), addr0);
2193
0
    type0 = 6;
2194
0
  } else {
2195
0
    THROW_ERR_INVALID_ARG_VALUE(env, "Invalid IP address.");
2196
0
    return;
2197
0
  }
2198
2199
0
  if (!args[1]->IsUndefined()) {
2200
0
    CHECK(args[1]->IsString());
2201
0
    node::Utf8Value ip1(isolate, args[1]);
2202
2203
0
    if (uv_inet_pton(AF_INET, *ip1, &addr1) == 0) {
2204
0
      if (type0 == 4) {
2205
0
        THROW_ERR_INVALID_ARG_VALUE(env, "Cannot specify two IPv4 addresses.");
2206
0
        return;
2207
0
      } else {
2208
0
        ares_set_local_ip4(channel->cares_channel(),
2209
0
                           nbytes::ReadUint32BE(addr1));
2210
0
      }
2211
0
    } else if (uv_inet_pton(AF_INET6, *ip1, &addr1) == 0) {
2212
0
      if (type0 == 6) {
2213
0
        THROW_ERR_INVALID_ARG_VALUE(env, "Cannot specify two IPv6 addresses.");
2214
0
        return;
2215
0
      } else {
2216
0
        ares_set_local_ip6(channel->cares_channel(), addr1);
2217
0
      }
2218
0
    } else {
2219
0
      THROW_ERR_INVALID_ARG_VALUE(env, "Invalid IP address.");
2220
0
      return;
2221
0
    }
2222
0
  } else {
2223
    // No second arg specified
2224
0
    if (type0 == 4) {
2225
0
      memset(&addr1, 0, sizeof(addr1));
2226
0
      ares_set_local_ip6(channel->cares_channel(), addr1);
2227
0
    } else {
2228
0
      ares_set_local_ip4(channel->cares_channel(), 0);
2229
0
    }
2230
0
  }
2231
0
}
2232
2233
0
void Cancel(const FunctionCallbackInfo<Value>& args) {
2234
0
  ChannelWrap* channel;
2235
0
  ASSIGN_OR_RETURN_UNWRAP(&channel, args.This());
2236
2237
0
  TRACE_EVENT_INSTANT0(TRACING_CATEGORY_NODE2(dns, native),
2238
0
      "cancel", TRACE_EVENT_SCOPE_THREAD);
2239
2240
0
  ares_cancel(channel->cares_channel());
2241
0
}
2242
2243
const char EMSG_ESETSRVPENDING[] = "There are pending queries.";
2244
0
void StrError(const FunctionCallbackInfo<Value>& args) {
2245
0
  Environment* env = Environment::GetCurrent(args);
2246
0
  int code = args[0]->Int32Value(env->context()).FromJust();
2247
0
  const char* errmsg = (code == DNS_ESETSRVPENDING) ?
2248
0
    EMSG_ESETSRVPENDING :
2249
0
    ares_strerror(code);
2250
0
  args.GetReturnValue().Set(OneByteString(env->isolate(), errmsg));
2251
0
}
2252
2253
}  // namespace
2254
2255
0
inline void safe_free_hostent(struct hostent* host) {
2256
0
  int idx;
2257
2258
0
  if (host->h_addr_list != nullptr) {
2259
0
    idx = 0;
2260
0
    while (host->h_addr_list[idx]) {
2261
0
      free(host->h_addr_list[idx++]);
2262
0
    }
2263
0
    free(host->h_addr_list);
2264
0
    host->h_addr_list = nullptr;
2265
0
  }
2266
2267
0
  if (host->h_aliases != nullptr) {
2268
0
    idx = 0;
2269
0
    while (host->h_aliases[idx]) {
2270
0
      free(host->h_aliases[idx++]);
2271
0
    }
2272
0
    free(host->h_aliases);
2273
0
    host->h_aliases = nullptr;
2274
0
  }
2275
2276
0
  free(host->h_name);
2277
0
  free(host);
2278
0
}
2279
2280
void Initialize(Local<Object> target,
2281
                Local<Value> unused,
2282
                Local<Context> context,
2283
0
                void* priv) {
2284
0
  Environment* env = Environment::GetCurrent(context);
2285
0
  Isolate* isolate = env->isolate();
2286
2287
0
  SetMethod(context, target, "getaddrinfo", GetAddrInfo);
2288
0
  SetMethod(context, target, "getnameinfo", GetNameInfo);
2289
0
  SetMethodNoSideEffect(context, target, "canonicalizeIP", CanonicalizeIP);
2290
0
  SetMethodNoSideEffect(
2291
0
      context, target, "convertIpv6StringToBuffer", ConvertIpv6StringToBuffer);
2292
2293
0
  SetMethod(context, target, "strerror", StrError);
2294
2295
0
  NODE_DEFINE_CONSTANT(target, AF_INET);
2296
0
  NODE_DEFINE_CONSTANT(target, AF_INET6);
2297
0
  NODE_DEFINE_CONSTANT(target, AF_UNSPEC);
2298
0
  NODE_DEFINE_CONSTANT(target, AI_ADDRCONFIG);
2299
0
  NODE_DEFINE_CONSTANT(target, AI_ALL);
2300
0
  NODE_DEFINE_CONSTANT(target, AI_V4MAPPED);
2301
0
  NODE_DEFINE_CONSTANT(target, DNS_ORDER_VERBATIM);
2302
0
  NODE_DEFINE_CONSTANT(target, DNS_ORDER_IPV4_FIRST);
2303
0
  NODE_DEFINE_CONSTANT(target, DNS_ORDER_IPV6_FIRST);
2304
2305
0
  Local<FunctionTemplate> aiw =
2306
0
      BaseObject::MakeLazilyInitializedJSTemplate(env);
2307
0
  aiw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2308
0
  SetConstructorFunction(context, target, "GetAddrInfoReqWrap", aiw);
2309
2310
0
  Local<FunctionTemplate> niw =
2311
0
      BaseObject::MakeLazilyInitializedJSTemplate(env);
2312
0
  niw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2313
0
  SetConstructorFunction(context, target, "GetNameInfoReqWrap", niw);
2314
2315
0
  Local<FunctionTemplate> qrw =
2316
0
      BaseObject::MakeLazilyInitializedJSTemplate(env);
2317
0
  qrw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2318
0
  SetConstructorFunction(context, target, "QueryReqWrap", qrw);
2319
2320
0
  Local<FunctionTemplate> channel_wrap =
2321
0
      NewFunctionTemplate(isolate, ChannelWrap::New);
2322
0
  channel_wrap->InstanceTemplate()->SetInternalFieldCount(
2323
0
      ChannelWrap::kInternalFieldCount);
2324
0
  channel_wrap->Inherit(AsyncWrap::GetConstructorTemplate(env));
2325
2326
0
#define V(Name, _, JS)                                                         \
2327
0
  SetProtoMethod(isolate, channel_wrap, #JS, Query<Query##Name##Wrap>);
2328
0
  QUERY_TYPES(V)
2329
0
#undef V
2330
2331
0
  SetProtoMethodNoSideEffect(isolate, channel_wrap, "getServers", GetServers);
2332
0
  SetProtoMethod(isolate, channel_wrap, "setServers", SetServers);
2333
0
  SetProtoMethod(isolate, channel_wrap, "setLocalAddress", SetLocalAddress);
2334
0
  SetProtoMethod(isolate, channel_wrap, "cancel", Cancel);
2335
2336
0
  SetConstructorFunction(context, target, "ChannelWrap", channel_wrap);
2337
0
}
2338
2339
0
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
2340
0
  registry->Register(GetAddrInfo);
2341
0
  registry->Register(GetNameInfo);
2342
0
  registry->Register(CanonicalizeIP);
2343
0
  registry->Register(ConvertIpv6StringToBuffer);
2344
0
  registry->Register(StrError);
2345
0
  registry->Register(ChannelWrap::New);
2346
2347
0
#define V(Name, _, __) registry->Register(Query<Query##Name##Wrap>);
2348
0
  QUERY_TYPES(V)
2349
0
#undef V
2350
2351
0
  registry->Register(GetServers);
2352
0
  registry->Register(SetServers);
2353
0
  registry->Register(SetLocalAddress);
2354
0
  registry->Register(Cancel);
2355
0
}
2356
2357
}  // namespace cares_wrap
2358
}  // namespace node
2359
2360
NODE_BINDING_CONTEXT_AWARE_INTERNAL(cares_wrap, node::cares_wrap::Initialize)
2361
NODE_BINDING_EXTERNAL_REFERENCE(cares_wrap,
2362
                                node::cares_wrap::RegisterExternalReferences)