1 #ifndef SRC_CARES_WRAP_H_
2 #define SRC_CARES_WRAP_H_
3
4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6 #define CARES_STATICLIB
7
8 #include "async_wrap.h"
9 #include "base_object.h"
10 #include "env.h"
11 #include "memory_tracker.h"
12 #include "node.h"
13 #include "node_internals.h"
14 #include "util.h"
15
16 #include "ares.h"
17 #include "v8.h"
18 #include "uv.h"
19
20 #include <unordered_set>
21
22 #ifdef __POSIX__
23 # include <netdb.h>
24 #endif // __POSIX__
25
26 # include <ares_nameser.h>
27
28 namespace node {
29 namespace cares_wrap {
30
31 constexpr int ns_t_cname_or_a = -1;
32 constexpr int DNS_ESETSRVPENDING = -1000;
33
34 class ChannelWrap;
35
36 inline void safe_free_hostent(struct hostent* host);
37
38 using HostEntPointer = DeleteFnPtr<hostent, ares_free_hostent>;
39 using SafeHostEntPointer = DeleteFnPtr<hostent, safe_free_hostent>;
40
ToErrorCodeString(int status)41 inline const char* ToErrorCodeString(int status) {
42 switch (status) {
43 #define V(code) case ARES_##code: return #code;
44 V(EADDRGETNETWORKPARAMS)
45 V(EBADFAMILY)
46 V(EBADFLAGS)
47 V(EBADHINTS)
48 V(EBADNAME)
49 V(EBADQUERY)
50 V(EBADRESP)
51 V(EBADSTR)
52 V(ECANCELLED)
53 V(ECONNREFUSED)
54 V(EDESTRUCTION)
55 V(EFILE)
56 V(EFORMERR)
57 V(ELOADIPHLPAPI)
58 V(ENODATA)
59 V(ENOMEM)
60 V(ENONAME)
61 V(ENOTFOUND)
62 V(ENOTIMP)
63 V(ENOTINITIALIZED)
64 V(EOF)
65 V(EREFUSED)
66 V(ESERVFAIL)
67 V(ETIMEOUT)
68 #undef V
69 }
70
71 return "UNKNOWN_ARES_ERROR";
72 }
73
cares_wrap_hostent_cpy(struct hostent * dest,const struct hostent * src)74 inline void cares_wrap_hostent_cpy(
75 struct hostent* dest,
76 const struct hostent* src) {
77 dest->h_addr_list = nullptr;
78 dest->h_addrtype = 0;
79 dest->h_aliases = nullptr;
80 dest->h_length = 0;
81 dest->h_name = nullptr;
82
83 /* copy `h_name` */
84 size_t name_size = strlen(src->h_name) + 1;
85 dest->h_name = node::Malloc<char>(name_size);
86 memcpy(dest->h_name, src->h_name, name_size);
87
88 /* copy `h_aliases` */
89 size_t alias_count;
90 for (alias_count = 0;
91 src->h_aliases[alias_count] != nullptr;
92 alias_count++) {
93 }
94
95 dest->h_aliases = node::Malloc<char*>(alias_count + 1);
96 for (size_t i = 0; i < alias_count; i++) {
97 const size_t cur_alias_size = strlen(src->h_aliases[i]) + 1;
98 dest->h_aliases[i] = node::Malloc(cur_alias_size);
99 memcpy(dest->h_aliases[i], src->h_aliases[i], cur_alias_size);
100 }
101 dest->h_aliases[alias_count] = nullptr;
102
103 /* copy `h_addr_list` */
104 size_t list_count;
105 for (list_count = 0;
106 src->h_addr_list[list_count] != nullptr;
107 list_count++) {
108 }
109
110 dest->h_addr_list = node::Malloc<char*>(list_count + 1);
111 for (size_t i = 0; i < list_count; i++) {
112 dest->h_addr_list[i] = node::Malloc(src->h_length);
113 memcpy(dest->h_addr_list[i], src->h_addr_list[i], src->h_length);
114 }
115 dest->h_addr_list[list_count] = nullptr;
116
117 /* work after work */
118 dest->h_length = src->h_length;
119 dest->h_addrtype = src->h_addrtype;
120 }
121
122
123 struct NodeAresTask final : public MemoryRetainer {
124 ChannelWrap* channel;
125 ares_socket_t sock;
126 uv_poll_t poll_watcher;
127
128 inline void MemoryInfo(MemoryTracker* trakcer) const override;
129 SET_MEMORY_INFO_NAME(NodeAresTask)
130 SET_SELF_SIZE(NodeAresTask)
131
132 struct Hash {
operatorfinal::Hash133 inline size_t operator()(NodeAresTask* a) const {
134 return std::hash<ares_socket_t>()(a->sock);
135 }
136 };
137
138 struct Equal {
operatorfinal::Equal139 inline bool operator()(NodeAresTask* a, NodeAresTask* b) const {
140 return a->sock == b->sock;
141 }
142 };
143
144 static NodeAresTask* Create(ChannelWrap* channel, ares_socket_t sock);
145
146 using List = std::unordered_set<NodeAresTask*, Hash, Equal>;
147 };
148
149 class ChannelWrap final : public AsyncWrap {
150 public:
151 ChannelWrap(
152 Environment* env,
153 v8::Local<v8::Object> object,
154 int timeout,
155 int tries);
156 ~ChannelWrap() override;
157
158 static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
159
160 void Setup();
161 void EnsureServers();
162 void StartTimer();
163 void CloseTimer();
164
165 void ModifyActivityQueryCount(int count);
166
timer_handle()167 inline uv_timer_t* timer_handle() { return timer_handle_; }
cares_channel()168 inline ares_channel cares_channel() { return channel_; }
set_query_last_ok(bool ok)169 inline void set_query_last_ok(bool ok) { query_last_ok_ = ok; }
set_is_servers_default(bool is_default)170 inline void set_is_servers_default(bool is_default) {
171 is_servers_default_ = is_default;
172 }
active_query_count()173 inline int active_query_count() { return active_query_count_; }
task_list()174 inline NodeAresTask::List* task_list() { return &task_list_; }
175
176 void MemoryInfo(MemoryTracker* tracker) const override;
177 SET_MEMORY_INFO_NAME(ChannelWrap)
178 SET_SELF_SIZE(ChannelWrap)
179
180 static void AresTimeout(uv_timer_t* handle);
181
182 private:
183 uv_timer_t* timer_handle_ = nullptr;
184 ares_channel channel_ = nullptr;
185 bool query_last_ok_ = true;
186 bool is_servers_default_ = true;
187 bool library_inited_ = false;
188 int timeout_;
189 int tries_;
190 int active_query_count_ = 0;
191 NodeAresTask::List task_list_;
192 };
193
194 class GetAddrInfoReqWrap final : public ReqWrap<uv_getaddrinfo_t> {
195 public:
196 GetAddrInfoReqWrap(Environment* env,
197 v8::Local<v8::Object> req_wrap_obj,
198 bool verbatim);
199
200 SET_NO_MEMORY_INFO()
SET_MEMORY_INFO_NAME(GetAddrInfoReqWrap)201 SET_MEMORY_INFO_NAME(GetAddrInfoReqWrap)
202 SET_SELF_SIZE(GetAddrInfoReqWrap)
203
204 bool verbatim() const { return verbatim_; }
205
206 private:
207 const bool verbatim_;
208 };
209
210 class GetNameInfoReqWrap final : public ReqWrap<uv_getnameinfo_t> {
211 public:
212 GetNameInfoReqWrap(Environment* env, v8::Local<v8::Object> req_wrap_obj);
213
214 SET_NO_MEMORY_INFO()
215 SET_MEMORY_INFO_NAME(GetNameInfoReqWrap)
216 SET_SELF_SIZE(GetNameInfoReqWrap)
217 };
218
219 struct ResponseData final {
220 int status;
221 bool is_host;
222 SafeHostEntPointer host;
223 MallocedBuffer<unsigned char> buf;
224 };
225
226 template <typename Traits>
227 class QueryWrap final : public AsyncWrap {
228 public:
QueryWrap(ChannelWrap * channel,v8::Local<v8::Object> req_wrap_obj)229 QueryWrap(ChannelWrap* channel, v8::Local<v8::Object> req_wrap_obj)
230 : AsyncWrap(channel->env(), req_wrap_obj, AsyncWrap::PROVIDER_QUERYWRAP),
231 channel_(channel),
232 trace_name_(Traits::name) {}
233
~QueryWrap()234 ~QueryWrap() {
235 CHECK_EQ(false, persistent().IsEmpty());
236
237 // Let Callback() know that this object no longer exists.
238 if (callback_ptr_ != nullptr)
239 *callback_ptr_ = nullptr;
240 }
241
Send(const char * name)242 int Send(const char* name) {
243 return Traits::Send(this, name);
244 }
245
AresQuery(const char * name,int dnsclass,int type)246 void AresQuery(const char* name, int dnsclass, int type) {
247 channel_->EnsureServers();
248 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
249 TRACING_CATEGORY_NODE2(dns, native), trace_name_, this,
250 "name", TRACE_STR_COPY(name));
251 ares_query(
252 channel_->cares_channel(),
253 name,
254 dnsclass,
255 type,
256 Callback,
257 MakeCallbackPointer());
258 }
259
ParseError(int status)260 void ParseError(int status) {
261 CHECK_NE(status, ARES_SUCCESS);
262 v8::HandleScope handle_scope(env()->isolate());
263 v8::Context::Scope context_scope(env()->context());
264 const char* code = ToErrorCodeString(status);
265 v8::Local<v8::Value> arg = OneByteString(env()->isolate(), code);
266 TRACE_EVENT_NESTABLE_ASYNC_END1(
267 TRACING_CATEGORY_NODE2(dns, native), trace_name_, this,
268 "error", status);
269 MakeCallback(env()->oncomplete_string(), 1, &arg);
270 }
271
channel()272 const BaseObjectPtr<ChannelWrap>& channel() const { return channel_; }
273
AfterResponse()274 void AfterResponse() {
275 CHECK(response_data_);
276
277 int status = response_data_->status;
278
279 if (status != ARES_SUCCESS)
280 return ParseError(status);
281
282 status = Traits::Parse(this, response_data_);
283
284 if (status != ARES_SUCCESS)
285 ParseError(status);
286 }
287
MakeCallbackPointer()288 void* MakeCallbackPointer() {
289 CHECK_NULL(callback_ptr_);
290 callback_ptr_ = new QueryWrap<Traits>*(this);
291 return callback_ptr_;
292 }
293
FromCallbackPointer(void * arg)294 static QueryWrap<Traits>* FromCallbackPointer(void* arg) {
295 std::unique_ptr<QueryWrap<Traits>*> wrap_ptr {
296 static_cast<QueryWrap<Traits>**>(arg)
297 };
298 QueryWrap<Traits>* wrap = *wrap_ptr.get();
299 if (wrap == nullptr) return nullptr;
300 wrap->callback_ptr_ = nullptr;
301 return wrap;
302 }
303
Callback(void * arg,int status,int timeouts,unsigned char * answer_buf,int answer_len)304 static void Callback(
305 void* arg,
306 int status,
307 int timeouts,
308 unsigned char* answer_buf,
309 int answer_len) {
310 QueryWrap<Traits>* wrap = FromCallbackPointer(arg);
311 if (wrap == nullptr) return;
312
313 unsigned char* buf_copy = nullptr;
314 if (status == ARES_SUCCESS) {
315 buf_copy = node::Malloc<unsigned char>(answer_len);
316 memcpy(buf_copy, answer_buf, answer_len);
317 }
318
319 wrap->response_data_ = std::make_unique<ResponseData>();
320 ResponseData* data = wrap->response_data_.get();
321 data->status = status;
322 data->is_host = false;
323 data->buf = MallocedBuffer<unsigned char>(buf_copy, answer_len);
324
325 wrap->QueueResponseCallback(status);
326 }
327
Callback(void * arg,int status,int timeouts,struct hostent * host)328 static void Callback(
329 void* arg,
330 int status,
331 int timeouts,
332 struct hostent* host) {
333 QueryWrap<Traits>* wrap = FromCallbackPointer(arg);
334 if (wrap == nullptr) return;
335
336 struct hostent* host_copy = nullptr;
337 if (status == ARES_SUCCESS) {
338 host_copy = node::Malloc<hostent>(1);
339 cares_wrap_hostent_cpy(host_copy, host);
340 }
341
342 wrap->response_data_ = std::make_unique<ResponseData>();
343 ResponseData* data = wrap->response_data_.get();
344 data->status = status;
345 data->host.reset(host_copy);
346 data->is_host = true;
347
348 wrap->QueueResponseCallback(status);
349 }
350
QueueResponseCallback(int status)351 void QueueResponseCallback(int status) {
352 BaseObjectPtr<QueryWrap<Traits>> strong_ref{this};
353 env()->SetImmediate([this, strong_ref](Environment*) {
354 AfterResponse();
355
356 // Delete once strong_ref goes out of scope.
357 Detach();
358 });
359
360 channel_->set_query_last_ok(status != ARES_ECONNREFUSED);
361 channel_->ModifyActivityQueryCount(-1);
362 }
363
364 void CallOnComplete(
365 v8::Local<v8::Value> answer,
366 v8::Local<v8::Value> extra = v8::Local<v8::Value>()) {
367 v8::HandleScope handle_scope(env()->isolate());
368 v8::Context::Scope context_scope(env()->context());
369 v8::Local<v8::Value> argv[] = {
370 v8::Integer::New(env()->isolate(), 0),
371 answer,
372 extra
373 };
374 const int argc = arraysize(argv) - extra.IsEmpty();
375 TRACE_EVENT_NESTABLE_ASYNC_END0(
376 TRACING_CATEGORY_NODE2(dns, native), trace_name_, this);
377
378 MakeCallback(env()->oncomplete_string(), argc, argv);
379 }
380
MemoryInfo(MemoryTracker * tracker)381 void MemoryInfo(MemoryTracker* tracker) const override {
382 tracker->TrackField("channel", channel_);
383 if (response_data_) {
384 tracker->TrackFieldWithSize("response", response_data_->buf.size);
385 }
386 }
387
388 SET_MEMORY_INFO_NAME(QueryWrap)
389 SET_SELF_SIZE(QueryWrap<Traits>)
390
391 private:
392 BaseObjectPtr<ChannelWrap> channel_;
393
394 std::unique_ptr<ResponseData> response_data_;
395 const char* trace_name_;
396 // Pointer to pointer to 'this' that can be reset from the destructor,
397 // in order to let Callback() know that 'this' no longer exists.
398 QueryWrap<Traits>** callback_ptr_ = nullptr;
399 };
400
401 struct AnyTraits final {
402 static constexpr const char* name = "resolveAny";
403 static int Send(QueryWrap<AnyTraits>* wrap, const char* name);
404 static int Parse(
405 QueryWrap<AnyTraits>* wrap,
406 const std::unique_ptr<ResponseData>& response);
407 };
408
409 struct ATraits final {
410 static constexpr const char* name = "resolve4";
411 static int Send(QueryWrap<ATraits>* wrap, const char* name);
412 static int Parse(
413 QueryWrap<ATraits>* wrap,
414 const std::unique_ptr<ResponseData>& response);
415 };
416
417 struct AaaaTraits final {
418 static constexpr const char* name = "resolve6";
419 static int Send(QueryWrap<AaaaTraits>* wrap, const char* name);
420 static int Parse(
421 QueryWrap<AaaaTraits>* wrap,
422 const std::unique_ptr<ResponseData>& response);
423 };
424
425 struct CaaTraits final {
426 static constexpr const char* name = "resolveCaa";
427 static int Send(QueryWrap<CaaTraits>* wrap, const char* name);
428 static int Parse(
429 QueryWrap<CaaTraits>* wrap,
430 const std::unique_ptr<ResponseData>& response);
431 };
432
433 struct CnameTraits final {
434 static constexpr const char* name = "resolveCname";
435 static int Send(QueryWrap<CnameTraits>* wrap, const char* name);
436 static int Parse(
437 QueryWrap<CnameTraits>* wrap,
438 const std::unique_ptr<ResponseData>& response);
439 };
440
441 struct MxTraits final {
442 static constexpr const char* name = "resolveMx";
443 static int Send(QueryWrap<MxTraits>* wrap, const char* name);
444 static int Parse(
445 QueryWrap<MxTraits>* wrap,
446 const std::unique_ptr<ResponseData>& response);
447 };
448
449 struct NsTraits final {
450 static constexpr const char* name = "resolveNs";
451 static int Send(QueryWrap<NsTraits>* wrap, const char* name);
452 static int Parse(
453 QueryWrap<NsTraits>* wrap,
454 const std::unique_ptr<ResponseData>& response);
455 };
456
457 struct TxtTraits final {
458 static constexpr const char* name = "resolveTxt";
459 static int Send(QueryWrap<TxtTraits>* wrap, const char* name);
460 static int Parse(
461 QueryWrap<TxtTraits>* wrap,
462 const std::unique_ptr<ResponseData>& response);
463 };
464
465 struct SrvTraits final {
466 static constexpr const char* name = "resolveSrv";
467 static int Send(QueryWrap<SrvTraits>* wrap, const char* name);
468 static int Parse(
469 QueryWrap<SrvTraits>* wrap,
470 const std::unique_ptr<ResponseData>& response);
471 };
472
473 struct PtrTraits final {
474 static constexpr const char* name = "resolvePtr";
475 static int Send(QueryWrap<PtrTraits>* wrap, const char* name);
476 static int Parse(
477 QueryWrap<PtrTraits>* wrap,
478 const std::unique_ptr<ResponseData>& response);
479 };
480
481 struct NaptrTraits final {
482 static constexpr const char* name = "resolveNaptr";
483 static int Send(QueryWrap<NaptrTraits>* wrap, const char* name);
484 static int Parse(
485 QueryWrap<NaptrTraits>* wrap,
486 const std::unique_ptr<ResponseData>& response);
487 };
488
489 struct SoaTraits final {
490 static constexpr const char* name = "resolveSoa";
491 static int Send(QueryWrap<SoaTraits>* wrap, const char* name);
492 static int Parse(
493 QueryWrap<SoaTraits>* wrap,
494 const std::unique_ptr<ResponseData>& response);
495 };
496
497 struct ReverseTraits final {
498 static constexpr const char* name = "reverse";
499 static int Send(QueryWrap<ReverseTraits>* wrap, const char* name);
500 static int Parse(
501 QueryWrap<ReverseTraits>* wrap,
502 const std::unique_ptr<ResponseData>& response);
503 };
504
505 using QueryAnyWrap = QueryWrap<AnyTraits>;
506 using QueryAWrap = QueryWrap<ATraits>;
507 using QueryAaaaWrap = QueryWrap<AaaaTraits>;
508 using QueryCaaWrap = QueryWrap<CaaTraits>;
509 using QueryCnameWrap = QueryWrap<CnameTraits>;
510 using QueryMxWrap = QueryWrap<MxTraits>;
511 using QueryNsWrap = QueryWrap<NsTraits>;
512 using QueryTxtWrap = QueryWrap<TxtTraits>;
513 using QuerySrvWrap = QueryWrap<SrvTraits>;
514 using QueryPtrWrap = QueryWrap<PtrTraits>;
515 using QueryNaptrWrap = QueryWrap<NaptrTraits>;
516 using QuerySoaWrap = QueryWrap<SoaTraits>;
517 using GetHostByAddrWrap = QueryWrap<ReverseTraits>;
518
519 } // namespace cares_wrap
520 } // namespace node
521
522 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
523
524 #endif // SRC_CARES_WRAP_H_
525