• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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