Skip to content

Commit 1897896

Browse files
jukkarnashif
authored andcommitted
net: sockets: Make sure that getaddrinfo() cannot hang forever
If for some reason the DNS resolver callback is not called properly then make sure that semaphore will not block forever. Fixes #15197 Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 22c9646 commit 1897896

File tree

2 files changed

+43
-32
lines changed

2 files changed

+43
-32
lines changed

subsys/net/lib/sockets/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ config NET_SOCKETS_POLL_MAX
2929
help
3030
Maximum number of entries supported for poll() call.
3131

32+
config NET_SOCKETS_DNS_TIMEOUT
33+
int "Timeout value in milliseconds for DNS queries"
34+
default 2000
35+
range 1000 300000
36+
depends on DNS_RESOLVER
37+
help
38+
This variable specifies time in milliseconds after which DNS
39+
query is considered timeout. Minimum timeout is 1 second and
40+
maximum timeout is 5 min.
41+
3242
config NET_SOCKETS_SOCKOPT_TLS
3343
bool "Enable TCP TLS socket option support [EXPERIMENTAL]"
3444
select TLS_CREDENTIALS

subsys/net/lib/sockets/getaddrinfo.c

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,19 @@ static void dns_resolve_cb(enum dns_resolve_status status,
7979
state->idx++;
8080
}
8181

82+
static int exec_query(const char *host, int family,
83+
struct getaddrinfo_state *ai_state)
84+
{
85+
enum dns_query_type qtype = DNS_QUERY_TYPE_A;
86+
87+
if (IS_ENABLED(CONFIG_NET_IPV6) && family != AF_INET) {
88+
qtype = DNS_QUERY_TYPE_AAAA;
89+
}
90+
91+
return dns_get_addr_info(host, qtype, NULL,
92+
dns_resolve_cb, ai_state,
93+
CONFIG_NET_SOCKETS_DNS_TIMEOUT);
94+
}
8295

8396
int z_impl_z_zsock_getaddrinfo_internal(const char *host, const char *service,
8497
const struct zsock_addrinfo *hints,
@@ -111,43 +124,31 @@ int z_impl_z_zsock_getaddrinfo_internal(const char *host, const char *service,
111124
/* Link entries in advance */
112125
ai_state.ai_arr[0].ai_next = &ai_state.ai_arr[1];
113126

114-
/* Execute if AF_UNSPEC or AF_INET4 */
115-
if (family != AF_INET6) {
116-
ret = dns_get_addr_info(host, DNS_QUERY_TYPE_A, NULL,
117-
dns_resolve_cb, &ai_state, 1000);
118-
if (ret == 0) {
119-
k_sem_take(&ai_state.sem, K_FOREVER);
120-
st1 = ai_state.status;
121-
} else {
122-
errno = -ret;
123-
st1 = DNS_EAI_SYSTEM;
127+
ret = exec_query(host, family, &ai_state);
128+
if (ret == 0) {
129+
/* If the DNS query for reason fails so that the
130+
* dns_resolve_cb() would not be called, then we want the
131+
* semaphore to timeout so that we will not hang forever.
132+
* So make the sem timeout longer than the DNS timeout so that
133+
* we do not need to start to cancel any pending DNS queries.
134+
*/
135+
int ret = k_sem_take(&ai_state.sem,
136+
CONFIG_NET_SOCKETS_DNS_TIMEOUT +
137+
K_MSEC(100));
138+
if (ret == -EAGAIN) {
139+
return DNS_EAI_AGAIN;
124140
}
125141

126-
if (ai_state.idx > 0) {
127-
ai_addr = &ai_state.ai_arr[ai_state.idx - 1]._ai_addr;
128-
net_sin(ai_addr)->sin_port = htons(port);
129-
}
142+
st1 = ai_state.status;
143+
} else {
144+
errno = -ret;
145+
st1 = DNS_EAI_SYSTEM;
130146
}
131147

132-
#if defined(CONFIG_NET_IPV6)
133-
/* Execute if AF_UNSPEC or AF_INET6 */
134-
if (family != AF_INET) {
135-
ret = dns_get_addr_info(host, DNS_QUERY_TYPE_AAAA, NULL,
136-
dns_resolve_cb, &ai_state, 1000);
137-
if (ret == 0) {
138-
k_sem_take(&ai_state.sem, K_FOREVER);
139-
st2 = ai_state.status;
140-
} else {
141-
errno = -ret;
142-
st2 = DNS_EAI_SYSTEM;
143-
}
144-
145-
if (ai_state.idx > 0) {
146-
ai_addr = &ai_state.ai_arr[ai_state.idx - 1]._ai_addr;
147-
net_sin6(ai_addr)->sin6_port = htons(port);
148-
}
148+
if (ai_state.idx > 0) {
149+
ai_addr = &ai_state.ai_arr[ai_state.idx - 1]._ai_addr;
150+
net_sin(ai_addr)->sin_port = htons(port);
149151
}
150-
#endif
151152

152153
/* If both attempts failed, it's error */
153154
if (st1 && st2) {

0 commit comments

Comments
 (0)