Skip to content

Commit 2b54147

Browse files
XadillaXaddaleax
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 PR-URL: #13076 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
1 parent 595e5e3 commit 2b54147

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
@@ -386,6 +386,69 @@ struct CaresAsyncData {
386386
uv_async_t async_handle;
387387
};
388388

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

483+
static void AresQuery(Environment* env, const char* name,
484+
int dnsclass, int type, ares_callback callback,
485+
void* arg) {
486+
AresEnsureServers(env);
487+
ares_query(env->cares_channel(), name, dnsclass, type, callback, arg);
488+
}
489+
420490
static void CaresAsyncClose(uv_handle_t* handle) {
421491
uv_async_t* async = reinterpret_cast<uv_async_t*>(handle);
422492
auto data = static_cast<struct CaresAsyncData*>(async->data);
@@ -466,6 +536,7 @@ class QueryWrap : public AsyncWrap {
466536
uv_async_t* async_handle = &data->async_handle;
467537
uv_async_init(wrap->env()->event_loop(), async_handle, CaresAsyncCb);
468538

539+
wrap->env()->set_cares_query_last_ok(status != ARES_ECONNREFUSED);
469540
async_handle->data = data;
470541
uv_async_send(async_handle);
471542
}
@@ -489,6 +560,7 @@ class QueryWrap : public AsyncWrap {
489560
uv_async_t* async_handle = &data->async_handle;
490561
uv_async_init(wrap->env()->event_loop(), async_handle, CaresAsyncCb);
491562

563+
wrap->env()->set_cares_query_last_ok(status != ARES_ECONNREFUSED);
492564
async_handle->data = data;
493565
uv_async_send(async_handle);
494566
}
@@ -533,12 +605,7 @@ class QueryAWrap: public QueryWrap {
533605
}
534606

535607
int Send(const char* name) override {
536-
ares_query(env()->cares_channel(),
537-
name,
538-
ns_c_in,
539-
ns_t_a,
540-
Callback,
541-
GetQueryArg());
608+
AresQuery(env(), name, ns_c_in, ns_t_a, Callback, GetQueryArg());
542609
return 0;
543610
}
544611

@@ -581,12 +648,7 @@ class QueryAaaaWrap: public QueryWrap {
581648
}
582649

583650
int Send(const char* name) override {
584-
ares_query(env()->cares_channel(),
585-
name,
586-
ns_c_in,
587-
ns_t_aaaa,
588-
Callback,
589-
GetQueryArg());
651+
AresQuery(env(), name, ns_c_in, ns_t_aaaa, Callback, GetQueryArg());
590652
return 0;
591653
}
592654

@@ -629,12 +691,7 @@ class QueryCnameWrap: public QueryWrap {
629691
}
630692

631693
int Send(const char* name) override {
632-
ares_query(env()->cares_channel(),
633-
name,
634-
ns_c_in,
635-
ns_t_cname,
636-
Callback,
637-
GetQueryArg());
694+
AresQuery(env(), name, ns_c_in, ns_t_cname, Callback, GetQueryArg());
638695
return 0;
639696
}
640697

@@ -670,12 +727,7 @@ class QueryMxWrap: public QueryWrap {
670727
}
671728

672729
int Send(const char* name) override {
673-
ares_query(env()->cares_channel(),
674-
name,
675-
ns_c_in,
676-
ns_t_mx,
677-
Callback,
678-
GetQueryArg());
730+
AresQuery(env(), name, ns_c_in, ns_t_mx, Callback, GetQueryArg());
679731
return 0;
680732
}
681733

@@ -721,12 +773,7 @@ class QueryNsWrap: public QueryWrap {
721773
}
722774

723775
int Send(const char* name) override {
724-
ares_query(env()->cares_channel(),
725-
name,
726-
ns_c_in,
727-
ns_t_ns,
728-
Callback,
729-
GetQueryArg());
776+
AresQuery(env(), name, ns_c_in, ns_t_ns, Callback, GetQueryArg());
730777
return 0;
731778
}
732779

@@ -759,12 +806,7 @@ class QueryTxtWrap: public QueryWrap {
759806
}
760807

761808
int Send(const char* name) override {
762-
ares_query(env()->cares_channel(),
763-
name,
764-
ns_c_in,
765-
ns_t_txt,
766-
Callback,
767-
GetQueryArg());
809+
AresQuery(env(), name, ns_c_in, ns_t_txt, Callback, GetQueryArg());
768810
return 0;
769811
}
770812

@@ -816,12 +858,7 @@ class QuerySrvWrap: public QueryWrap {
816858
}
817859

818860
int Send(const char* name) override {
819-
ares_query(env()->cares_channel(),
820-
name,
821-
ns_c_in,
822-
ns_t_srv,
823-
Callback,
824-
GetQueryArg());
861+
AresQuery(env(), name, ns_c_in, ns_t_srv, Callback, GetQueryArg());
825862
return 0;
826863
}
827864

@@ -872,12 +909,7 @@ class QueryPtrWrap: public QueryWrap {
872909
}
873910

874911
int Send(const char* name) override {
875-
ares_query(env()->cares_channel(),
876-
name,
877-
ns_c_in,
878-
ns_t_ptr,
879-
Callback,
880-
GetQueryArg());
912+
AresQuery(env(), name, ns_c_in, ns_t_ptr, Callback, GetQueryArg());
881913
return 0;
882914
}
883915

@@ -915,12 +947,7 @@ class QueryNaptrWrap: public QueryWrap {
915947
}
916948

917949
int Send(const char* name) override {
918-
ares_query(env()->cares_channel(),
919-
name,
920-
ns_c_in,
921-
ns_t_naptr,
922-
Callback,
923-
GetQueryArg());
950+
AresQuery(env(), name, ns_c_in, ns_t_naptr, Callback, GetQueryArg());
924951
return 0;
925952
}
926953

@@ -979,12 +1006,7 @@ class QuerySoaWrap: public QueryWrap {
9791006
}
9801007

9811008
int Send(const char* name) override {
982-
ares_query(env()->cares_channel(),
983-
name,
984-
ns_c_in,
985-
ns_t_soa,
986-
Callback,
987-
GetQueryArg());
1009+
AresQuery(env(), name, ns_c_in, ns_t_soa, Callback, GetQueryArg());
9881010
return 0;
9891011
}
9901012

@@ -1445,6 +1467,9 @@ void SetServers(const FunctionCallbackInfo<Value>& args) {
14451467

14461468
delete[] servers;
14471469

1470+
if (err == ARES_SUCCESS)
1471+
env->set_cares_is_servers_default(false);
1472+
14481473
args.GetReturnValue().Set(err);
14491474
}
14501475

@@ -1479,20 +1504,7 @@ void Initialize(Local<Object> target,
14791504
if (r != ARES_SUCCESS)
14801505
return env->ThrowError(ToErrorCodeString(r));
14811506

1482-
struct ares_options options;
1483-
memset(&options, 0, sizeof(options));
1484-
options.flags = ARES_FLAG_NOCHECKRESP;
1485-
options.sock_state_cb = ares_sockstate_cb;
1486-
options.sock_state_cb_data = env;
1487-
1488-
/* We do the call to ares_init_option for caller. */
1489-
r = ares_init_options(env->cares_channel_ptr(),
1490-
&options,
1491-
ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);
1492-
if (r != ARES_SUCCESS) {
1493-
ares_library_cleanup();
1494-
return env->ThrowError(ToErrorCodeString(r));
1495-
}
1507+
SetupCaresChannel(env);
14961508

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

src/env-inl.h

+18
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,8 @@ inline Environment::Environment(IsolateData* isolate_data,
292292
isolate_data_(isolate_data),
293293
async_hooks_(context->GetIsolate()),
294294
timer_base_(uv_now(isolate_data->event_loop())),
295+
cares_query_last_ok_(true),
296+
cares_is_servers_default_(true),
295297
using_domains_(false),
296298
printed_error_(false),
297299
trace_sync_io_(false),
@@ -505,6 +507,22 @@ inline ares_channel* Environment::cares_channel_ptr() {
505507
return &cares_channel_;
506508
}
507509

510+
inline bool Environment::cares_query_last_ok() {
511+
return cares_query_last_ok_;
512+
}
513+
514+
inline void Environment::set_cares_query_last_ok(bool ok) {
515+
cares_query_last_ok_ = ok;
516+
}
517+
518+
inline bool Environment::cares_is_servers_default() {
519+
return cares_is_servers_default_;
520+
}
521+
522+
inline void Environment::set_cares_is_servers_default(bool is_default) {
523+
cares_is_servers_default_ = is_default;
524+
}
525+
508526
inline node_ares_task_list* Environment::cares_task_list() {
509527
return &cares_task_list_;
510528
}

src/env.h

+6
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,10 @@ class Environment {
546546
inline uv_timer_t* cares_timer_handle();
547547
inline ares_channel cares_channel();
548548
inline ares_channel* cares_channel_ptr();
549+
inline bool cares_query_last_ok();
550+
inline void set_cares_query_last_ok(bool ok);
551+
inline bool cares_is_servers_default();
552+
inline void set_cares_is_servers_default(bool is_default);
549553
inline node_ares_task_list* cares_task_list();
550554
inline IsolateData* isolate_data() const;
551555

@@ -667,6 +671,8 @@ class Environment {
667671
const uint64_t timer_base_;
668672
uv_timer_t cares_timer_handle_;
669673
ares_channel cares_channel_;
674+
bool cares_query_last_ok_;
675+
bool cares_is_servers_default_;
670676
node_ares_task_list cares_task_list_;
671677
bool using_domains_;
672678
bool printed_error_;

0 commit comments

Comments
 (0)