Skip to content

Commit 6518932

Browse files
XadillaXMylesBorins
authored andcommitted
dns: fix resolve failed starts without network
Fix the bug that you start process without network at first, but it connected lately, `dns.resolve` will stay failed with ECONNREFUSED because c-ares servers fallback to 127.0.0.1 at the very beginning. If c-ares servers "127.0.0.1" is detected and its not set by user self, and last query is not OK, recreating `ares_channel` operation will be triggered to reload servers. Fixes: #1644 Backport-PR-URL: #14434 PR-URL: #13076 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
1 parent a1cef1f commit 6518932

File tree

3 files changed

+110
-74
lines changed

3 files changed

+110
-74
lines changed

src/cares_wrap.cc

+86-74
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,69 @@ struct CaresAsyncData {
372372
uv_async_t async_handle;
373373
};
374374

375+
void SetupCaresChannel(Environment* env) {
376+
struct ares_options options;
377+
memset(&options, 0, sizeof(options));
378+
options.flags = ARES_FLAG_NOCHECKRESP;
379+
options.sock_state_cb = ares_sockstate_cb;
380+
options.sock_state_cb_data = env;
381+
382+
/* We do the call to ares_init_option for caller. */
383+
int r = ares_init_options(env->cares_channel_ptr(),
384+
&options,
385+
ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);
386+
387+
if (r != ARES_SUCCESS) {
388+
ares_library_cleanup();
389+
return env->ThrowError(ToErrorCodeString(r));
390+
}
391+
}
392+
393+
394+
/**
395+
* This function is to check whether current servers are fallback servers
396+
* when cares initialized.
397+
*
398+
* The fallback servers of cares is [ "127.0.0.1" ] with no user additional
399+
* setting.
400+
*/
401+
void AresEnsureServers(Environment* env) {
402+
/* if last query is OK or servers are set by user self, do not check */
403+
if (env->cares_query_last_ok() || !env->cares_is_servers_default()) {
404+
return;
405+
}
406+
407+
ares_channel channel = env->cares_channel();
408+
ares_addr_node* servers = nullptr;
409+
410+
ares_get_servers(channel, &servers);
411+
412+
/* if no server or multi-servers, ignore */
413+
if (servers == nullptr) return;
414+
if (servers->next != nullptr) {
415+
ares_free_data(servers);
416+
env->set_cares_is_servers_default(false);
417+
return;
418+
}
419+
420+
/* if the only server is not 127.0.0.1, ignore */
421+
if (servers[0].family != AF_INET ||
422+
servers[0].addr.addr4.s_addr != htonl(INADDR_LOOPBACK)) {
423+
ares_free_data(servers);
424+
env->set_cares_is_servers_default(false);
425+
return;
426+
}
427+
428+
ares_free_data(servers);
429+
servers = nullptr;
430+
431+
/* destroy channel and reset channel */
432+
ares_destroy(channel);
433+
434+
SetupCaresChannel(env);
435+
}
436+
437+
375438
class QueryWrap : public AsyncWrap {
376439
public:
377440
QueryWrap(Environment* env, Local<Object> req_wrap_obj)
@@ -402,6 +465,13 @@ class QueryWrap : public AsyncWrap {
402465
return static_cast<void*>(this);
403466
}
404467

468+
static void AresQuery(Environment* env, const char* name,
469+
int dnsclass, int type, ares_callback callback,
470+
void* arg) {
471+
AresEnsureServers(env);
472+
ares_query(env->cares_channel(), name, dnsclass, type, callback, arg);
473+
}
474+
405475
static void CaresAsyncClose(uv_handle_t* handle) {
406476
uv_async_t* async = reinterpret_cast<uv_async_t*>(handle);
407477
auto data = static_cast<struct CaresAsyncData*>(async->data);
@@ -453,6 +523,7 @@ class QueryWrap : public AsyncWrap {
453523
async_handle,
454524
CaresAsyncCb));
455525

526+
wrap->env()->set_cares_query_last_ok(status != ARES_ECONNREFUSED);
456527
async_handle->data = data;
457528
uv_async_send(async_handle);
458529
}
@@ -478,6 +549,7 @@ class QueryWrap : public AsyncWrap {
478549
async_handle,
479550
CaresAsyncCb));
480551

552+
wrap->env()->set_cares_query_last_ok(status != ARES_ECONNREFUSED);
481553
async_handle->data = data;
482554
uv_async_send(async_handle);
483555
}
@@ -522,12 +594,7 @@ class QueryAWrap: public QueryWrap {
522594
}
523595

524596
int Send(const char* name) override {
525-
ares_query(env()->cares_channel(),
526-
name,
527-
ns_c_in,
528-
ns_t_a,
529-
Callback,
530-
GetQueryArg());
597+
AresQuery(env(), name, ns_c_in, ns_t_a, Callback, GetQueryArg());
531598
return 0;
532599
}
533600

@@ -570,12 +637,7 @@ class QueryAaaaWrap: public QueryWrap {
570637
}
571638

572639
int Send(const char* name) override {
573-
ares_query(env()->cares_channel(),
574-
name,
575-
ns_c_in,
576-
ns_t_aaaa,
577-
Callback,
578-
GetQueryArg());
640+
AresQuery(env(), name, ns_c_in, ns_t_aaaa, Callback, GetQueryArg());
579641
return 0;
580642
}
581643

@@ -618,12 +680,7 @@ class QueryCnameWrap: public QueryWrap {
618680
}
619681

620682
int Send(const char* name) override {
621-
ares_query(env()->cares_channel(),
622-
name,
623-
ns_c_in,
624-
ns_t_cname,
625-
Callback,
626-
GetQueryArg());
683+
AresQuery(env(), name, ns_c_in, ns_t_cname, Callback, GetQueryArg());
627684
return 0;
628685
}
629686

@@ -659,12 +716,7 @@ class QueryMxWrap: public QueryWrap {
659716
}
660717

661718
int Send(const char* name) override {
662-
ares_query(env()->cares_channel(),
663-
name,
664-
ns_c_in,
665-
ns_t_mx,
666-
Callback,
667-
GetQueryArg());
719+
AresQuery(env(), name, ns_c_in, ns_t_mx, Callback, GetQueryArg());
668720
return 0;
669721
}
670722

@@ -710,12 +762,7 @@ class QueryNsWrap: public QueryWrap {
710762
}
711763

712764
int Send(const char* name) override {
713-
ares_query(env()->cares_channel(),
714-
name,
715-
ns_c_in,
716-
ns_t_ns,
717-
Callback,
718-
GetQueryArg());
765+
AresQuery(env(), name, ns_c_in, ns_t_ns, Callback, GetQueryArg());
719766
return 0;
720767
}
721768

@@ -748,12 +795,7 @@ class QueryTxtWrap: public QueryWrap {
748795
}
749796

750797
int Send(const char* name) override {
751-
ares_query(env()->cares_channel(),
752-
name,
753-
ns_c_in,
754-
ns_t_txt,
755-
Callback,
756-
GetQueryArg());
798+
AresQuery(env(), name, ns_c_in, ns_t_txt, Callback, GetQueryArg());
757799
return 0;
758800
}
759801

@@ -805,12 +847,7 @@ class QuerySrvWrap: public QueryWrap {
805847
}
806848

807849
int Send(const char* name) override {
808-
ares_query(env()->cares_channel(),
809-
name,
810-
ns_c_in,
811-
ns_t_srv,
812-
Callback,
813-
GetQueryArg());
850+
AresQuery(env(), name, ns_c_in, ns_t_srv, Callback, GetQueryArg());
814851
return 0;
815852
}
816853

@@ -861,12 +898,7 @@ class QueryPtrWrap: public QueryWrap {
861898
}
862899

863900
int Send(const char* name) override {
864-
ares_query(env()->cares_channel(),
865-
name,
866-
ns_c_in,
867-
ns_t_ptr,
868-
Callback,
869-
GetQueryArg());
901+
AresQuery(env(), name, ns_c_in, ns_t_ptr, Callback, GetQueryArg());
870902
return 0;
871903
}
872904

@@ -904,12 +936,7 @@ class QueryNaptrWrap: public QueryWrap {
904936
}
905937

906938
int Send(const char* name) override {
907-
ares_query(env()->cares_channel(),
908-
name,
909-
ns_c_in,
910-
ns_t_naptr,
911-
Callback,
912-
GetQueryArg());
939+
AresQuery(env(), name, ns_c_in, ns_t_naptr, Callback, GetQueryArg());
913940
return 0;
914941
}
915942

@@ -968,12 +995,7 @@ class QuerySoaWrap: public QueryWrap {
968995
}
969996

970997
int Send(const char* name) override {
971-
ares_query(env()->cares_channel(),
972-
name,
973-
ns_c_in,
974-
ns_t_soa,
975-
Callback,
976-
GetQueryArg());
998+
AresQuery(env(), name, ns_c_in, ns_t_soa, Callback, GetQueryArg());
977999
return 0;
9781000
}
9791001

@@ -1434,6 +1456,9 @@ static void SetServers(const FunctionCallbackInfo<Value>& args) {
14341456

14351457
delete[] servers;
14361458

1459+
if (err == ARES_SUCCESS)
1460+
env->set_cares_is_servers_default(false);
1461+
14371462
args.GetReturnValue().Set(err);
14381463
}
14391464

@@ -1468,20 +1493,7 @@ static void Initialize(Local<Object> target,
14681493
if (r != ARES_SUCCESS)
14691494
return env->ThrowError(ToErrorCodeString(r));
14701495

1471-
struct ares_options options;
1472-
memset(&options, 0, sizeof(options));
1473-
options.flags = ARES_FLAG_NOCHECKRESP;
1474-
options.sock_state_cb = ares_sockstate_cb;
1475-
options.sock_state_cb_data = env;
1476-
1477-
/* We do the call to ares_init_option for caller. */
1478-
r = ares_init_options(env->cares_channel_ptr(),
1479-
&options,
1480-
ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);
1481-
if (r != ARES_SUCCESS) {
1482-
ares_library_cleanup();
1483-
return env->ThrowError(ToErrorCodeString(r));
1484-
}
1496+
SetupCaresChannel(env);
14851497

14861498
/* Initialize the timeout timer. The timer won't be started until the */
14871499
/* first socket is opened. */

src/env-inl.h

+18
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ inline Environment::Environment(v8::Local<v8::Context> context,
219219
: isolate_(context->GetIsolate()),
220220
isolate_data_(IsolateData::GetOrCreate(context->GetIsolate(), loop)),
221221
timer_base_(uv_now(loop)),
222+
cares_query_last_ok_(true),
223+
cares_is_servers_default_(true),
222224
using_domains_(false),
223225
printed_error_(false),
224226
trace_sync_io_(false),
@@ -453,6 +455,22 @@ inline ares_channel* Environment::cares_channel_ptr() {
453455
return &cares_channel_;
454456
}
455457

458+
inline bool Environment::cares_query_last_ok() {
459+
return cares_query_last_ok_;
460+
}
461+
462+
inline void Environment::set_cares_query_last_ok(bool ok) {
463+
cares_query_last_ok_ = ok;
464+
}
465+
466+
inline bool Environment::cares_is_servers_default() {
467+
return cares_is_servers_default_;
468+
}
469+
470+
inline void Environment::set_cares_is_servers_default(bool is_default) {
471+
cares_is_servers_default_ = is_default;
472+
}
473+
456474
inline node_ares_task_list* Environment::cares_task_list() {
457475
return &cares_task_list_;
458476
}

src/env.h

+6
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,10 @@ class Environment {
437437
inline uv_timer_t* cares_timer_handle();
438438
inline ares_channel cares_channel();
439439
inline ares_channel* cares_channel_ptr();
440+
inline bool cares_query_last_ok();
441+
inline void set_cares_query_last_ok(bool ok);
442+
inline bool cares_is_servers_default();
443+
inline void set_cares_is_servers_default(bool is_default);
440444
inline node_ares_task_list* cares_task_list();
441445

442446
inline bool using_domains() const;
@@ -555,6 +559,8 @@ class Environment {
555559
const uint64_t timer_base_;
556560
uv_timer_t cares_timer_handle_;
557561
ares_channel cares_channel_;
562+
bool cares_query_last_ok_;
563+
bool cares_is_servers_default_;
558564
node_ares_task_list cares_task_list_;
559565
bool using_domains_;
560566
bool printed_error_;

0 commit comments

Comments
 (0)