net/dns: Introduce the qname_copy routine
When a CNAME is part of the DNS answer RR, sometimes a label with a pointer is found. The CNAME must be reused to create a new DNS query and that CNAME will become the new DNS Query QNAME. This new QNAME must not include pointers. This patch introduces the qname_copy routine that "linearizes" a given QNAME (perhaps with pointers). The dns_read routine is also updated to reflect these changes. Change-Id: I8e8f64e85e2cbf494fd589e2b7a67d470d34604b Signed-off-by: Flavio Santes <flavio.santes@intel.com>
This commit is contained in:
parent
e8eb62b87b
commit
e86b6c23af
3 changed files with 101 additions and 9 deletions
|
@ -73,8 +73,8 @@ int dns_write(struct dns_context *ctx, struct net_buf *dns_data,
|
|||
uint16_t dns_id, struct net_buf *dns_qname);
|
||||
|
||||
static
|
||||
int dns_read(struct dns_context *ctx, struct net_buf *dns_data,
|
||||
uint16_t dns_id, uint8_t *cname, uint16_t *cname_len);
|
||||
int dns_read(struct dns_context *ctx, struct net_buf *dns_data, uint16_t dns_id,
|
||||
struct net_buf *cname);
|
||||
|
||||
/* net_context_recv callback */
|
||||
static
|
||||
|
@ -128,8 +128,7 @@ int dns_resolve(struct dns_context *ctx)
|
|||
goto exit_resolve;
|
||||
}
|
||||
|
||||
rc = dns_read(ctx, dns_data, dns_id,
|
||||
dns_qname->data, &dns_qname->len);
|
||||
rc = dns_read(ctx, dns_data, dns_id, dns_qname);
|
||||
if (rc != 0) {
|
||||
goto exit_resolve;
|
||||
}
|
||||
|
@ -222,8 +221,8 @@ void cb_recv(struct net_context *net_ctx, struct net_buf *buf, int status,
|
|||
}
|
||||
|
||||
static
|
||||
int dns_read(struct dns_context *ctx, struct net_buf *dns_data,
|
||||
uint16_t dns_id, uint8_t *cname, uint16_t *cname_len)
|
||||
int dns_read(struct dns_context *ctx, struct net_buf *dns_data, uint16_t dns_id,
|
||||
struct net_buf *cname)
|
||||
{
|
||||
/* helper struct to track the dns msg received from the server */
|
||||
struct dns_msg_t dns_msg;
|
||||
|
@ -358,10 +357,14 @@ int dns_read(struct dns_context *ctx, struct net_buf *dns_data,
|
|||
*/
|
||||
if (ctx->items == 0) {
|
||||
if (dns_msg.response_type == DNS_RESPONSE_CNAME_NO_IP) {
|
||||
src = dns_msg.msg + dns_msg.response_position;
|
||||
*cname_len = dns_msg.response_length;
|
||||
uint16_t pos = dns_msg.response_position;
|
||||
|
||||
rc = dns_copy_qname(cname->data, &cname->len,
|
||||
cname->size, &dns_msg, pos);
|
||||
if (rc != 0) {
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
memcpy(cname, src, *cname_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,5 +373,6 @@ exit_ok:
|
|||
|
||||
exit_error:
|
||||
net_nbuf_unref(ctx->rx_buf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "dns_pack.h"
|
||||
#include <string.h>
|
||||
|
||||
/* This is the label's length octet, see 4.1.2. Question section format */
|
||||
#define DNS_LABEL_LEN_SIZE 1
|
||||
#define DNS_LABEL_MAX_SIZE 63
|
||||
#define DNS_ANSWER_MIN_SIZE 12
|
||||
#define DNS_COMMON_UINT_SIZE 2
|
||||
|
@ -350,3 +352,67 @@ int dns_unpack_response_query(struct dns_msg_t *dns_msg)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_copy_qname(uint8_t *buf, uint16_t *len, uint16_t size,
|
||||
struct dns_msg_t *dns_msg, uint16_t pos)
|
||||
{
|
||||
uint16_t msg_size = dns_msg->msg_size;
|
||||
uint8_t *msg = dns_msg->msg;
|
||||
uint16_t lb_size;
|
||||
int rc = -EINVAL;
|
||||
int i = 0;
|
||||
|
||||
*len = 0;
|
||||
|
||||
/* Iterate ANCOUNT + 1 to allow the Query's QNAME to be parsed.
|
||||
* This is required to avoid 'alias loops'
|
||||
*/
|
||||
while (i++ < dns_header_ancount(dns_msg->msg) + 1) {
|
||||
if (pos >= msg_size) {
|
||||
rc = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
lb_size = msg[pos];
|
||||
|
||||
/* pointer */
|
||||
if (lb_size > DNS_LABEL_MAX_SIZE) {
|
||||
uint8_t mask = DNS_LABEL_MAX_SIZE;
|
||||
|
||||
if (pos + 1 >= msg_size) {
|
||||
rc = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
/* See: RFC 1035, 4.1.4. Message compression */
|
||||
pos = ((msg[pos] & mask) << 8) + msg[pos + 1];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* validate that the label (i.e. size + elements),
|
||||
* fits the current msg buffer
|
||||
*/
|
||||
if (DNS_LABEL_LEN_SIZE + lb_size > size - *len) {
|
||||
rc = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
/* copy the lb_size value and label elements */
|
||||
memcpy(buf + *len, msg + pos, DNS_LABEL_LEN_SIZE + lb_size);
|
||||
/* update destination buffer len */
|
||||
*len += DNS_LABEL_LEN_SIZE + lb_size;
|
||||
/* update msg ptr position */
|
||||
pos += DNS_LABEL_LEN_SIZE + lb_size;
|
||||
|
||||
/* The domain name terminates with the zero length octet
|
||||
* for the null label of the root
|
||||
*/
|
||||
if (lb_size == 0) {
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -361,4 +361,26 @@ int dns_msg_pack_query(uint8_t *buf, uint16_t *len, uint16_t size,
|
|||
*/
|
||||
int dns_unpack_response_query(struct dns_msg_t *dns_msg);
|
||||
|
||||
/**
|
||||
* @brief dns_copy_qname Copies the qname from dns_msg to buf
|
||||
*
|
||||
* @details This routine applies the algorithm described in
|
||||
* RFC 1035, 4.1.4. Message compression to copy the
|
||||
* qname (perhaps containing pointers with offset)
|
||||
* to the linear buffer buf. Pointers are removed
|
||||
* and only the "true" labels are copied.
|
||||
*
|
||||
* @param [out] buf Output buffer
|
||||
* @param [out] len Output buffer's length
|
||||
* @param [in] size Output buffer's size
|
||||
* @param [in] dns_msg Structure containing the message
|
||||
* @param [in] pos QNAME's position in dns_msg->msg
|
||||
* @return 0 on success
|
||||
* @return -EINVAL if an invalid parameter was passed as
|
||||
* an argument
|
||||
* @return -ENOMEM if the label's size is corrupted
|
||||
*/
|
||||
int dns_copy_qname(uint8_t *buf, uint16_t *len, uint16_t size,
|
||||
struct dns_msg_t *dns_msg, uint16_t pos);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue