• 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 "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