Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dns: fix resolve failed starts without network #13076

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 86 additions & 74 deletions src/cares_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,69 @@ struct CaresAsyncData {
uv_async_t async_handle;
};

void SetupCaresChannel(Environment* env) {
struct ares_options options;
memset(&options, 0, sizeof(options));
options.flags = ARES_FLAG_NOCHECKRESP;
options.sock_state_cb = ares_sockstate_cb;
options.sock_state_cb_data = env;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we somehow share this code with Initialize, to make it more obviously correct? It looks like there’s quite a bit that could be shared

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'v extracted these code to SetupCaresChannel().


/* We do the call to ares_init_option for caller. */
int r = ares_init_options(env->cares_channel_ptr(),
&options,
ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);

if (r != ARES_SUCCESS) {
ares_library_cleanup();
return env->ThrowError(ToErrorCodeString(r));
}
}


/**
* This function is to check whether current servers are fallback servers
* when cares initialized.
*
* The fallback servers of cares is [ "127.0.0.1" ] with no user additional
* setting.
*/
void AresEnsureServers(Environment* env) {
/* if last query is OK or servers are set by user self, do not check */
if (env->cares_query_last_ok() || !env->cares_is_servers_default()) {
return;
}

ares_channel channel = env->cares_channel();
ares_addr_node* servers = nullptr;

ares_get_servers(channel, &servers);

/* if no server or multi-servers, ignore */
if (servers == nullptr) return;
if (servers->next != nullptr) {
ares_free_data(servers);
env->set_cares_is_servers_default(false);
return;
}

/* if the only server is not 127.0.0.1, ignore */
if (servers[0].family != AF_INET ||
servers[0].addr.addr4.s_addr != htonl(INADDR_LOOPBACK)) {
ares_free_data(servers);
env->set_cares_is_servers_default(false);
return;
}

ares_free_data(servers);
servers = nullptr;

/* destroy channel and reset channel */
ares_destroy(channel);

SetupCaresChannel(env);
}


class QueryWrap : public AsyncWrap {
public:
QueryWrap(Environment* env, Local<Object> req_wrap_obj)
Expand Down Expand Up @@ -417,6 +480,13 @@ class QueryWrap : public AsyncWrap {
return static_cast<void*>(this);
}

static void AresQuery(Environment* env, const char* name,
int dnsclass, int type, ares_callback callback,
void* arg) {
AresEnsureServers(env);
ares_query(env->cares_channel(), name, dnsclass, type, callback, arg);
}

static void CaresAsyncClose(uv_handle_t* handle) {
uv_async_t* async = reinterpret_cast<uv_async_t*>(handle);
auto data = static_cast<struct CaresAsyncData*>(async->data);
Expand Down Expand Up @@ -466,6 +536,7 @@ class QueryWrap : public AsyncWrap {
uv_async_t* async_handle = &data->async_handle;
uv_async_init(wrap->env()->event_loop(), async_handle, CaresAsyncCb);

wrap->env()->set_cares_query_last_ok(status != ARES_ECONNREFUSED);
async_handle->data = data;
uv_async_send(async_handle);
}
Expand All @@ -489,6 +560,7 @@ class QueryWrap : public AsyncWrap {
uv_async_t* async_handle = &data->async_handle;
uv_async_init(wrap->env()->event_loop(), async_handle, CaresAsyncCb);

wrap->env()->set_cares_query_last_ok(status != ARES_ECONNREFUSED);
async_handle->data = data;
uv_async_send(async_handle);
}
Expand Down Expand Up @@ -533,12 +605,7 @@ class QueryAWrap: public QueryWrap {
}

int Send(const char* name) override {
ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_a,
Callback,
GetQueryArg());
AresQuery(env(), name, ns_c_in, ns_t_a, Callback, GetQueryArg());
return 0;
}

Expand Down Expand Up @@ -581,12 +648,7 @@ class QueryAaaaWrap: public QueryWrap {
}

int Send(const char* name) override {
ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_aaaa,
Callback,
GetQueryArg());
AresQuery(env(), name, ns_c_in, ns_t_aaaa, Callback, GetQueryArg());
return 0;
}

Expand Down Expand Up @@ -629,12 +691,7 @@ class QueryCnameWrap: public QueryWrap {
}

int Send(const char* name) override {
ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_cname,
Callback,
GetQueryArg());
AresQuery(env(), name, ns_c_in, ns_t_cname, Callback, GetQueryArg());
return 0;
}

Expand Down Expand Up @@ -670,12 +727,7 @@ class QueryMxWrap: public QueryWrap {
}

int Send(const char* name) override {
ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_mx,
Callback,
GetQueryArg());
AresQuery(env(), name, ns_c_in, ns_t_mx, Callback, GetQueryArg());
return 0;
}

Expand Down Expand Up @@ -721,12 +773,7 @@ class QueryNsWrap: public QueryWrap {
}

int Send(const char* name) override {
ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_ns,
Callback,
GetQueryArg());
AresQuery(env(), name, ns_c_in, ns_t_ns, Callback, GetQueryArg());
return 0;
}

Expand Down Expand Up @@ -759,12 +806,7 @@ class QueryTxtWrap: public QueryWrap {
}

int Send(const char* name) override {
ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_txt,
Callback,
GetQueryArg());
AresQuery(env(), name, ns_c_in, ns_t_txt, Callback, GetQueryArg());
return 0;
}

Expand Down Expand Up @@ -816,12 +858,7 @@ class QuerySrvWrap: public QueryWrap {
}

int Send(const char* name) override {
ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_srv,
Callback,
GetQueryArg());
AresQuery(env(), name, ns_c_in, ns_t_srv, Callback, GetQueryArg());
return 0;
}

Expand Down Expand Up @@ -872,12 +909,7 @@ class QueryPtrWrap: public QueryWrap {
}

int Send(const char* name) override {
ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_ptr,
Callback,
GetQueryArg());
AresQuery(env(), name, ns_c_in, ns_t_ptr, Callback, GetQueryArg());
return 0;
}

Expand Down Expand Up @@ -915,12 +947,7 @@ class QueryNaptrWrap: public QueryWrap {
}

int Send(const char* name) override {
ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_naptr,
Callback,
GetQueryArg());
AresQuery(env(), name, ns_c_in, ns_t_naptr, Callback, GetQueryArg());
return 0;
}

Expand Down Expand Up @@ -979,12 +1006,7 @@ class QuerySoaWrap: public QueryWrap {
}

int Send(const char* name) override {
ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_soa,
Callback,
GetQueryArg());
AresQuery(env(), name, ns_c_in, ns_t_soa, Callback, GetQueryArg());
return 0;
}

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

delete[] servers;

if (err == ARES_SUCCESS)
env->set_cares_is_servers_default(false);

args.GetReturnValue().Set(err);
}

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

struct ares_options options;
memset(&options, 0, sizeof(options));
options.flags = ARES_FLAG_NOCHECKRESP;
options.sock_state_cb = ares_sockstate_cb;
options.sock_state_cb_data = env;

/* We do the call to ares_init_option for caller. */
r = ares_init_options(env->cares_channel_ptr(),
&options,
ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);
if (r != ARES_SUCCESS) {
ares_library_cleanup();
return env->ThrowError(ToErrorCodeString(r));
}
SetupCaresChannel(env);

/* Initialize the timeout timer. The timer won't be started until the */
/* first socket is opened. */
Expand Down
18 changes: 18 additions & 0 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,8 @@ inline Environment::Environment(IsolateData* isolate_data,
isolate_data_(isolate_data),
async_hooks_(context->GetIsolate()),
timer_base_(uv_now(isolate_data->event_loop())),
cares_query_last_ok_(true),
cares_is_servers_default_(true),
using_domains_(false),
printed_error_(false),
trace_sync_io_(false),
Expand Down Expand Up @@ -505,6 +507,22 @@ inline ares_channel* Environment::cares_channel_ptr() {
return &cares_channel_;
}

inline bool Environment::cares_query_last_ok() {
return cares_query_last_ok_;
}

inline void Environment::set_cares_query_last_ok(bool ok) {
cares_query_last_ok_ = ok;
}

inline bool Environment::cares_is_servers_default() {
return cares_is_servers_default_;
}

inline void Environment::set_cares_is_servers_default(bool is_default) {
cares_is_servers_default_ = is_default;
}

inline node_ares_task_list* Environment::cares_task_list() {
return &cares_task_list_;
}
Expand Down
6 changes: 6 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,10 @@ class Environment {
inline uv_timer_t* cares_timer_handle();
inline ares_channel cares_channel();
inline ares_channel* cares_channel_ptr();
inline bool cares_query_last_ok();
inline void set_cares_query_last_ok(bool ok);
inline bool cares_is_servers_default();
inline void set_cares_is_servers_default(bool is_default);
inline node_ares_task_list* cares_task_list();
inline IsolateData* isolate_data() const;

Expand Down Expand Up @@ -667,6 +671,8 @@ class Environment {
const uint64_t timer_base_;
uv_timer_t cares_timer_handle_;
ares_channel cares_channel_;
bool cares_query_last_ok_;
bool cares_is_servers_default_;
node_ares_task_list cares_task_list_;
bool using_domains_;
bool printed_error_;
Expand Down