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