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

netdb:Add macro to control DNS using TCP transmission #15069

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions libs/libc/netdb/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,13 @@ config NETDB_DNSSERVER_IPv4ADDR
Default DNS server IPv4 address in host byte order. Default value
10.0.0.1. This may be changed via dns_add_nameserver().

config NETDB_DNS_STREAM
Copy link
Contributor

Choose a reason for hiding this comment

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

the original code already support both TCP/UDP, why do you make this patch?

Copy link
Author

Choose a reason for hiding this comment

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

When DNS resolution returns the truncate response, this function will establish TCP connection and return the complete response. However, the complete response can easily exceed the RECV_BUFFER_SIZE, causing the resolution to fail, so I wrote a simple solution to solve this problem. There are two better solutions. One is to recycle the buffer and finally splice the buffer. The second is to use molloc to create a length that matches the response. I would like to ask if there is a better solution. @yamt
ping failed
ping failed.log

Copy link
Contributor

Choose a reason for hiding this comment

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

the simplest solution, if it's acceptable for your configuration, would be to bump your CONFIG_NETDB_DNSCLIENT_MAXRESPONSE.

i agree it makes sense to try to use malloc when it doesn't fit RECV_BUFFER_SIZE.
it shouldn't be too difficult to make our client decide after receiving the record size (the first two bytes of the response) with tcp.

i'm not sure how difficult buffer recycling is.

depending on your configurations and environment, you might also want to implement EDNS buffer size.
some servers "tweak" their responses to fit the specified size.

Copy link
Author

Choose a reason for hiding this comment

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

thank you for your suggestion!

bool "DNS supports TCP transmission"
depends on LIBC_NETDB
default n
Copy link
Contributor

Choose a reason for hiding this comment

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

Please include a --help-- to explain exactly what is this feature, when it should be used, etc

Copy link
Author

Choose a reason for hiding this comment

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

Done

---help---
Enable support for DNS Name resolution over TCP.

if NETDB_DNSSERVER_IPv6

config NETDB_DNSSERVER_IPv6ADDR_1
Expand Down
4 changes: 4 additions & 0 deletions libs/libc/netdb/lib_dns.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,11 @@ void dns_restorelock(unsigned int count);
*
****************************************************************************/

#ifndef CONFIG_NETDB_DNS_STREAM
int dns_bind(sa_family_t family);
#else
int dns_bind(sa_family_t family, bool stream);
#endif

/****************************************************************************
* Name: dns_query
Expand Down
12 changes: 12 additions & 0 deletions libs/libc/netdb/lib_dnsbind.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,28 @@
*
****************************************************************************/

#ifndef CONFIG_NETDB_DNS_STREAM
int dns_bind(sa_family_t family)
#else
int dns_bind(sa_family_t family, bool stream)
#endif
{
#ifdef CONFIG_NETDB_DNS_STREAM
int stype = stream ? SOCK_STREAM : SOCK_DGRAM;
#endif

struct timeval tv;
int sd;
int ret;

/* Create a new socket */

#ifndef CONFIG_NETDB_DNS_STREAM
sd = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
#else
sd = socket(family, stype | SOCK_CLOEXEC, 0);
#endif

if (sd < 0)
{
ret = -get_errno();
Expand Down
67 changes: 65 additions & 2 deletions libs/libc/netdb/lib_dnsquery.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ struct dns_query_data_s
*
****************************************************************************/

#ifdef CONFIG_NETDB_DNS_STREAM
static ssize_t stream_send(int fd, FAR const void *buf, size_t len)
{
ssize_t total = 0;
Expand Down Expand Up @@ -292,6 +293,7 @@ static ssize_t stream_recv_record(int fd, FAR void *buf, size_t len)

return ret;
}
#endif

/****************************************************************************
* Name: dns_parse_name
Expand Down Expand Up @@ -380,11 +382,18 @@ static inline uint16_t dns_alloc_id(void)
*
****************************************************************************/

#ifndef CONFIG_NETDB_DNS_STREAM
static int dns_send_query(int sd, FAR const char *name,
FAR union dns_addr_u *uaddr, uint16_t rectype,
FAR struct dns_query_info_s *qinfo,
FAR uint8_t *buffer)
#else
static int dns_send_query(int sd, FAR const char *name,
FAR union dns_addr_u *uaddr, uint16_t rectype,
FAR struct dns_query_info_s *qinfo,
FAR uint8_t *buffer,
bool stream)
#endif
{
FAR struct dns_header_s *hdr;
FAR uint8_t *dest;
Expand Down Expand Up @@ -488,11 +497,13 @@ static int dns_send_query(int sd, FAR const char *name,
return ret;
}

#ifdef CONFIG_NETDB_DNS_STREAM
if (stream)
{
ret = stream_send_record(sd, buffer, dest - buffer);
}
else
#endif
{
ret = send(sd, buffer, dest - buffer, 0);
}
Expand All @@ -519,10 +530,16 @@ static int dns_send_query(int sd, FAR const char *name,
*
****************************************************************************/

#ifndef CONFIG_NETDB_DNS_STREAM
static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int naddr,
FAR struct dns_query_info_s *qinfo,
FAR uint32_t *ttl, FAR uint8_t *buffer)
#else
static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int naddr,
FAR struct dns_query_info_s *qinfo,
FAR uint32_t *ttl, FAR uint8_t *buffer,
bool stream, bool *should_try_stream)
#endif
{
FAR uint8_t *nameptr;
FAR uint8_t *namestart;
Expand All @@ -543,11 +560,13 @@ static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int naddr,

/* Receive the response */

#ifdef CONFIG_NETDB_DNS_STREAM
if (stream)
{
ret = stream_recv_record(sd, buffer, RECV_BUFFER_SIZE);
}
else
#endif
{
ret = recv(sd, buffer, RECV_BUFFER_SIZE, 0);
}
Expand Down Expand Up @@ -579,6 +598,7 @@ static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int naddr,

/* Check for error */

#ifdef CONFIG_NETDB_DNS_STREAM
if ((hdr->flags1 & DNS_FLAG1_TRUNC) != 0)
{
/* RFC 2181
Expand All @@ -601,6 +621,7 @@ static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int naddr,
*should_try_stream = true;
return -EAGAIN;
}
#endif

if ((hdr->flags2 & DNS_FLAG2_ERR_MASK) != 0)
{
Expand Down Expand Up @@ -851,33 +872,47 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
int retries;
int ret;
int sd;
#ifdef CONFIG_NETDB_DNS_STREAM
bool stream = false;
#endif

/* Loop while receive timeout errors occur and there are remaining
* retries.
*/

for (retries = 0; retries < CONFIG_NETDB_DNSCLIENT_RETRIES; retries++)
{
#ifdef CONFIG_NETDB_DNS_STREAM
bool should_try_stream;

try_stream:
#endif
#ifdef CONFIG_NET_IPv6
if (dns_is_queryfamily(AF_INET6))
{
/* Send the IPv6 query */

#ifndef CONFIG_NETDB_DNS_STREAM
sd = dns_bind(addr->sa_family);
#else
sd = dns_bind(addr->sa_family, stream);
#endif
if (sd < 0)
{
query->result = sd;
return 0;
}

#ifndef CONFIG_NETDB_DNS_STREAM
ret = dns_send_query(sd, query->hostname,
(FAR union dns_addr_u *)addr,
DNS_RECTYPE_AAAA, &qdata->qinfo,
qdata->buffer);
#else
ret = dns_send_query(sd, query->hostname,
(FAR union dns_addr_u *)addr,
DNS_RECTYPE_AAAA, &qdata->qinfo,
qdata->buffer, stream);
#endif
if (ret < 0)
{
dns_query_error("ERROR: IPv6 dns_send_query failed",
Expand All @@ -887,25 +922,33 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
else
{
/* Obtain the IPv6 response */

#ifndef CONFIG_NETDB_DNS_STREAM
ret = dns_recv_response(sd, &query->addr[next],
CONFIG_NETDB_MAX_IPv6ADDR,
&qdata->qinfo,
&query->ttl, qdata->buffer);
#else
should_try_stream = false;
ret = dns_recv_response(sd, &query->addr[next],
CONFIG_NETDB_MAX_IPv6ADDR,
&qdata->qinfo,
&query->ttl, qdata->buffer,
stream, &should_try_stream);
#endif
if (ret >= 0)
{
next += ret;
}
else
{
#ifdef CONFIG_NETDB_DNS_STREAM
if (!stream && should_try_stream)
{
stream = true;
goto try_stream; /* Don't consume retry count */
}

#endif
dns_query_error("ERROR: IPv6 dns_recv_response failed",
ret, (FAR union dns_addr_u *)addr);
query->result = ret;
Expand All @@ -914,24 +957,35 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,

close(sd);
}

#endif

#ifdef CONFIG_NET_IPv4
if (dns_is_queryfamily(AF_INET))
{
/* Send the IPv4 query */

#ifndef CONFIG_NETDB_DNS_STREAM
sd = dns_bind(addr->sa_family);
#else
sd = dns_bind(addr->sa_family, stream);
#endif
if (sd < 0)
{
query->result = sd;
return 0;
}

#ifndef CONFIG_NETDB_DNS_STREAM
ret = dns_send_query(sd, query->hostname,
(FAR union dns_addr_u *)addr,
DNS_RECTYPE_A, &qdata->qinfo, qdata->buffer);
#else
ret = dns_send_query(sd, query->hostname,
(FAR union dns_addr_u *)addr,
DNS_RECTYPE_A, &qdata->qinfo, qdata->buffer,
stream);
#endif
if (ret < 0)
{
dns_query_error("ERROR: IPv4 dns_send_query failed",
Expand All @@ -947,24 +1001,33 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
next = *query->naddr / 2;
}

#ifndef CONFIG_NETDB_DNS_STREAM
ret = dns_recv_response(sd, &query->addr[next],
CONFIG_NETDB_MAX_IPv4ADDR,
&qdata->qinfo,
&query->ttl, qdata->buffer);
#else
should_try_stream = false;
ret = dns_recv_response(sd, &query->addr[next],
CONFIG_NETDB_MAX_IPv4ADDR,
&qdata->qinfo,
&query->ttl, qdata->buffer,
stream, &should_try_stream);
#endif
if (ret >= 0)
{
next += ret;
}
else
{
#ifdef CONFIG_NETDB_DNS_STREAM
if (!stream && should_try_stream)
{
stream = true;
goto try_stream; /* Don't consume retry count */
}

#endif
dns_query_error("ERROR: IPv4 dns_recv_response failed",
ret, (FAR union dns_addr_u *)addr);
query->result = ret;
Expand Down
Loading