Skip to content
Snippets Groups Projects
Commit 1e1d76d8 authored by Jan Kadlec's avatar Jan Kadlec
Browse files

Merge remote branch 'origin/dnslib-new' into zoneparser

parents c9b0c61f fba41080
No related branches found
No related tags found
No related merge requests found
......@@ -82,3 +82,6 @@ src/tests/dnslib/dnslib_zone_tests.c
src/dnslib/rrsig.h
src/dnslib/rrsig.c
src/other/tree.h
src/dnslib/response.h
src/dnslib/packet.h
src/dnslib/response.c
......@@ -43,6 +43,21 @@ typedef unsigned int uint;
#define ERR_ALLOC_FAILED log_error("Allocation failed at %s:%d (%s ver.%x)\n", \
__FILE__, __LINE__, PROJECT_NAME, PROJECT_VER)
#define CHECK_ALLOC_LOG(var) \
do { \
if ((var) == NULL) { \
ERR_ALLOC_FAILED; \
return NULL; \
} \
} while (0)
#define CHECK_ALLOC(var) \
do { \
if ((var) == NULL) { \
return NULL; \
} \
} while (0)
/* Eliminate compiler warning with unused parameters. */
#define UNUSED(param) (param) = (param)
......
......@@ -192,7 +192,7 @@ dnslib_dname_t *dnslib_dname_new_from_str(char *name, uint size,
/*----------------------------------------------------------------------------*/
dnslib_dname_t *dnslib_dname_new_from_wire(uint8_t *name, uint size,
dnslib_dname_t *dnslib_dname_new_from_wire(const uint8_t *name, uint size,
struct dnslib_node *node)
{
if (name == NULL && size != 0) {
......
......@@ -86,7 +86,7 @@ dnslib_dname_t *dnslib_dname_new_from_str(char *name, uint size,
* is OK to retain this and check the data in other functions before
* calling this one, or if it should verify the given data.
*/
dnslib_dname_t *dnslib_dname_new_from_wire(uint8_t *name, uint size,
dnslib_dname_t *dnslib_dname_new_from_wire(const uint8_t *name, uint size,
struct dnslib_node *node);
/*!
......
/*!
* \file packet.h
*
* \author Lubos Slovak <lubos.slovak@nic.cz>
*
* \brief Functions for manipulating and parsing raw data in DNS packets.
*
* \addtogroup dnslib
* @{
*/
#ifndef _CUTEDNS_DNSLIB_PACKET_H_
#define _CUTEDNS_DNSLIB_PACKET_H_
#include <stdint.h>
enum dnslib_packet_offsets {
DNSLIB_PACKET_OFFSET_ID = 0,
DNSLIB_PACKET_OFFSET_FLAGS1 = 2,
DNSLIB_PACKET_OFFSET_FLAGS2 = 3,
DNSLIB_PACKET_OFFSET_QDCOUNT = 4,
DNSLIB_PACKET_OFFSET_ANCOUNT = 6,
DNSLIB_PACKET_OFFSET_NSCOUNT = 8,
DNSLIB_PACKET_OFFSET_ARCOUNT = 10
};
enum dnslib_packet_sizes {
DNSLIB_PACKET_HEADER_SIZE = 12,
DNSLIB_PACKET_QUESTION_MIN_SIZE = 5,
DNSLIB_PACKET_RR_MIN_SIZE = 11
};
/*
* Writing / reading arbitrary data to / from wireformat.
*/
static inline uint16_t dnslib_packet_read_u16(const uint8_t *pos)
{
return (pos[0] << 8) | pos[1];
}
static inline uint16_t dnslib_packet_read_u32(const uint8_t *pos)
{
return (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) | pos[3];
}
static inline void dnslib_packet_write_u16(uint8_t *pos, uint16_t data)
{
pos[0] = (uint8_t)((data >> 8) & 0xff);
pos[1] = (uint8_t)(data & 0xff);
}
static inline void dnslib_packet_write_u32(uint8_t *pos, uint32_t data)
{
pos[0] = (uint8_t)((data >> 24) & 0xff);
pos[0] = (uint8_t)((data >> 16) & 0xff);
pos[2] = (uint8_t)((data >> 8) & 0xff);
pos[3] = (uint8_t)(data & 0xff);
}
/*
* Packet header manipulation functions.
*/
static inline uint16_t dnslib_packet_get_id(const uint8_t *packet)
{
return dnslib_packet_read_u16(packet + DNSLIB_PACKET_OFFSET_ID);
}
static inline void dnslib_packet_set_id(uint8_t *packet, uint16_t id)
{
dnslib_packet_write_u16(packet + DNSLIB_PACKET_OFFSET_ID, id);
}
static inline uint8_t dnslib_packet_get_flags1(const uint8_t *packet)
{
return *(packet + DNSLIB_PACKET_OFFSET_FLAGS1);
}
static inline uint8_t dnslib_packet_set_flags1(uint8_t *packet, uint8_t flags1)
{
return *(packet + DNSLIB_PACKET_OFFSET_FLAGS1) = flags1;
}
static inline uint8_t dnslib_packet_get_flags2(const uint8_t *packet)
{
return *(packet + DNSLIB_PACKET_OFFSET_FLAGS2);
}
static inline uint8_t dnslib_packet_set_flags2(uint8_t *packet, uint8_t flags2)
{
return *(packet + DNSLIB_PACKET_OFFSET_FLAGS2) = flags2;
}
static inline uint16_t dnslib_packet_get_qdcount(const uint8_t *packet)
{
return dnslib_packet_read_u16(packet + DNSLIB_PACKET_OFFSET_QDCOUNT);
}
static inline void dnslib_packet_set_qdcount(uint8_t *packet, uint16_t qdcount)
{
dnslib_packet_write_u16(packet + DNSLIB_PACKET_OFFSET_QDCOUNT, qdcount);
}
static inline uint16_t dnslib_packet_get_ancount(const uint8_t *packet)
{
return dnslib_packet_read_u16(packet + DNSLIB_PACKET_OFFSET_ANCOUNT);
}
static inline void dnslib_packet_set_ancount(uint8_t *packet, uint16_t ancount)
{
dnslib_packet_write_u16(packet + DNSLIB_PACKET_OFFSET_ANCOUNT, ancount);
}
static inline uint16_t dnslib_packet_get_nscount(const uint8_t *packet)
{
return dnslib_packet_read_u16(packet + DNSLIB_PACKET_OFFSET_NSCOUNT);
}
static inline void dnslib_packet_set_nscount(uint8_t *packet, uint16_t nscount)
{
dnslib_packet_write_u16(packet + DNSLIB_PACKET_OFFSET_NSCOUNT, nscount);
}
static inline uint16_t dnslib_packet_get_arcount(const uint8_t *packet)
{
return dnslib_packet_read_u16(packet + DNSLIB_PACKET_OFFSET_ARCOUNT);
}
static inline void dnslib_packet_set_arcount(uint8_t *packet, uint16_t arcount)
{
dnslib_packet_write_u16(packet + DNSLIB_PACKET_OFFSET_ARCOUNT, arcount);
}
/*
* Packet header flags manipulation functions.
*/
enum dnslib_packet_flags1_consts {
RD_MASK = (uint8_t)0x01U,
RD_SHIFT = 0,
TC_MASK = (uint8_t)0x02U,
TC_SHIFT = 1,
AA_MASK = (uint8_t)0x04U,
AA_SHIFT = 2,
OPCODE_MASK = (uint8_t)0x78U,
OPCODE_SHIFT = 3,
QR_MASK = (uint8_t)0x80U,
QR_SHIFT = 7
};
enum dnslib_packet_flags2_consts {
RCODE_MASK = (uint8_t)0x0fU,
RCODE_SHIFT = 0,
CD_MASK = (uint8_t)0x10U,
CD_SHIFT = 4,
AD_MASK = (uint8_t)0x20U,
AD_SHIFT = 5,
Z_MASK = (uint8_t)0x40U,
Z_SHIFT = 6,
RA_MASK = (uint8_t)0x80U,
RA_SHIFT = 7
};
/*
* Functions for getting / setting / clearing flags and codes directly in packet
*/
static inline uint8_t dnslib_packet_get_rd(const uint8_t *packet)
{
return *(packet + DNSLIB_PACKET_OFFSET_FLAGS1) & RD_MASK;
}
static inline void dnslib_packet_set_rd(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS1) |= RD_MASK;
}
static inline void dnslib_packet_flags_clear_rd(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS1) &= ~RD_MASK;
}
static inline uint8_t dnslib_packet_get_tc(const uint8_t *packet)
{
return *(packet + DNSLIB_PACKET_OFFSET_FLAGS1) & TC_MASK;
}
static inline void dnslib_packet_set_tc(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS1) |= TC_MASK;
}
static inline void dnslib_packet_clear_tc(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS1) &= ~TC_MASK;
}
static inline uint8_t dnslib_packet_get_aa(const uint8_t *packet)
{
return *(packet + DNSLIB_PACKET_OFFSET_FLAGS1) & AA_MASK;
}
static inline void dnslib_packet_set_aa(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS1) |= AA_MASK;
}
static inline void dnslib_packet_clear_aa(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS1) &= ~AA_MASK;
}
static inline uint8_t dnslib_packet_get_opcode(const uint8_t *packet)
{
return (*(packet + DNSLIB_PACKET_OFFSET_FLAGS1) & OPCODE_MASK)
>> OPCODE_SHIFT;
}
static inline void dnslib_packet_set_opcode(uint8_t *packet, short opcode)
{
uint8_t *flags1 = packet + DNSLIB_PACKET_OFFSET_FLAGS1;
*flags1 = (*flags1 & ~OPCODE_MASK) | ((opcode) << OPCODE_SHIFT);
}
static inline uint8_t dnslib_packet_get_qr(const uint8_t *packet)
{
return *(packet + DNSLIB_PACKET_OFFSET_FLAGS1) & QR_MASK;
}
static inline void dnslib_packet_set_qr(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS1) |= QR_MASK;
}
static inline void dnslib_packet_clear_qr(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS1) &= ~QR_MASK;
}
static inline uint8_t dnslib_packet_get_rcode(const uint8_t *packet)
{
return *(packet + DNSLIB_PACKET_OFFSET_FLAGS2) & RCODE_MASK;
}
static inline void dnslib_packet_set_rcode(uint8_t *packet, short rcode)
{
uint8_t *flags2 = packet + DNSLIB_PACKET_OFFSET_FLAGS2;
*flags2 = (*flags2 & ~RCODE_MASK) | (rcode);
}
static inline uint8_t dnslib_packet_get_cd(const uint8_t *packet)
{
return *(packet + DNSLIB_PACKET_OFFSET_FLAGS2) & CD_MASK;
}
static inline void dnslib_packet_set_cd(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS2) |= CD_MASK;
}
static inline void dnslib_packet_clear_cd(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS2) &= ~CD_MASK;
}
static inline uint8_t dnslib_packet_get_ad(const uint8_t *packet)
{
return *(packet + DNSLIB_PACKET_OFFSET_FLAGS2) & AD_MASK;
}
static inline void dnslib_packet_set_ad(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS2) |= AD_MASK;
}
static inline void dnslib_packet_clear_ad(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS2) &= ~AD_MASK;
}
static inline uint8_t dnslib_packet_get_z(const uint8_t *packet)
{
return *(packet + DNSLIB_PACKET_OFFSET_FLAGS2) & Z_MASK;
}
static inline void dnslib_packet_set_z(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS2) |= Z_MASK;
}
static inline void dnslib_packet_clear_z(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS2) &= ~Z_MASK;
}
static inline uint8_t dnslib_packet_get_ra(const uint8_t *packet)
{
return *(packet + DNSLIB_PACKET_OFFSET_FLAGS2) & RA_MASK;
}
static inline void dnslib_packet_set_ra(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS2) |= RA_MASK;
}
static inline void dnslib_packet_clear_ra(uint8_t *packet)
{
*(packet + DNSLIB_PACKET_OFFSET_FLAGS2) &= ~RA_MASK;
}
/*
* Functions for getting / setting / clearing flags in flags variable
*/
static inline uint8_t dnslib_packet_flags_get_rd(uint8_t flags1)
{
return flags1 & RD_MASK;
}
static inline void dnslib_packet_flags_set_rd(uint8_t *flags1)
{
*flags1 |= RD_MASK;
}
static inline void dnslib_packet_flags_flags_clear_rd(uint8_t *flags1)
{
*flags1 &= ~RD_MASK;
}
static inline uint8_t dnslib_packet_flags_get_tc(uint8_t flags1)
{
return flags1 & TC_MASK;
}
static inline void dnslib_packet_flags_set_tc(uint8_t *flags1)
{
*flags1 |= TC_MASK;
}
static inline void dnslib_packet_flags_clear_tc(uint8_t *flags1)
{
*flags1 &= ~TC_MASK;
}
static inline uint8_t dnslib_packet_flags_get_aa(uint8_t flags1)
{
return flags1 & AA_MASK;
}
static inline void dnslib_packet_flags_set_aa(uint8_t *flags1)
{
*flags1 |= AA_MASK;
}
static inline void dnslib_packet_flags_clear_aa(uint8_t *flags1)
{
*flags1 &= ~AA_MASK;
}
static inline uint8_t dnslib_packet_flags_get_opcode(uint8_t flags1)
{
return (flags1 & OPCODE_MASK) >> OPCODE_SHIFT;
}
static inline void dnslib_packet_flags_set_opcode(uint8_t *flags1, short opcode)
{
*flags1 = (*flags1 & ~OPCODE_MASK) | ((opcode) << OPCODE_SHIFT);
}
static inline uint8_t dnslib_packet_flags_get_qr(uint8_t flags1)
{
return flags1 & QR_MASK;
}
static inline void dnslib_packet_flags_set_qr(uint8_t *flags1)
{
*flags1 |= QR_MASK;
}
static inline void dnslib_packet_flags_clear_qr(uint8_t *flags1)
{
*flags1 &= ~QR_MASK;
}
static inline uint8_t dnslib_packet_flags_get_rcode(uint8_t flags2)
{
return flags2 & RCODE_MASK;
}
static inline void dnslib_packet_flags_set_rcode(uint8_t *flags2, short rcode)
{
*flags2 = (*flags2 & ~RCODE_MASK) | (rcode);
}
static inline uint8_t dnslib_packet_flags_get_cd(uint8_t flags2)
{
return flags2 & CD_MASK;
}
static inline void dnslib_packet_flags_set_cd(uint8_t *flags2)
{
*flags2 |= CD_MASK;
}
static inline void dnslib_packet_flags_clear_cd(uint8_t *flags2)
{
*flags2 &= ~CD_MASK;
}
static inline uint8_t dnslib_packet_flags_get_ad(uint8_t flags2)
{
return flags2 & AD_MASK;
}
static inline void dnslib_packet_flags_set_ad(uint8_t *flags2)
{
*flags2 |= AD_MASK;
}
static inline void dnslib_packet_flags_clear_ad(uint8_t *flags2)
{
*flags2 &= ~AD_MASK;
}
static inline uint8_t dnslib_packet_flags_get_z(uint8_t flags2)
{
return flags2 & Z_MASK;
}
static inline void dnslib_packet_flags_set_z(uint8_t *flags2)
{
*flags2 |= Z_MASK;
}
static inline void dnslib_packet_flags_clear_z(uint8_t *flags2)
{
*flags2 &= ~Z_MASK;
}
static inline uint8_t dnslib_packet_flags_get_ra(uint8_t flags2)
{
return flags2 & RA_MASK;
}
static inline void dnslib_packet_flags_set_ra(uint8_t *flags2)
{
*flags2 |= RA_MASK;
}
static inline void dnslib_packet_flags_clear_ra(uint8_t *flags2)
{
*flags2 &= ~RA_MASK;
}
#endif /* _CUTEDNS_DNSLIB_PACKET_H_ */
/*! @} */
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include "response.h"
#include "rrset.h"
#include "common.h"
#include "packet.h"
#include "descriptor.h"
enum {
DEFAULT_ANCOUNT = 6,
DEFAULT_NSCOUNT = 8,
DEFAULT_ARCOUNT = 28,
DEFAULT_DOMAINS_IN_RESPONSE = 22,
DEFAULT_TMP_DOMAINS = 5
};
enum {
PREALLOC_RESPONSE = sizeof(dnslib_response_t),
PREALLOC_QNAME = 256,
PREALLOC_ANSWER = DEFAULT_ANCOUNT * sizeof(dnslib_dname_t *),
PREALLOC_AUTHORITY = DEFAULT_NSCOUNT * sizeof(dnslib_dname_t *),
PREALLOC_ADDITIONAL = DEFAULT_ARCOUNT * sizeof(dnslib_dname_t *),
PREALLOC_RRSETS = PREALLOC_ANSWER
+ PREALLOC_AUTHORITY
+ PREALLOC_ADDITIONAL,
PREALLOC_DOMAINS =
DEFAULT_DOMAINS_IN_RESPONSE * sizeof(dnslib_dname_t *),
PREALLOC_OFFSETS =
DEFAULT_DOMAINS_IN_RESPONSE * sizeof(size_t *),
PREALLOC_TMP_DOMAINS =
DEFAULT_TMP_DOMAINS * sizeof(dnslib_dname_t *),
PREALLOC_TOTAL = PREALLOC_RESPONSE
+ PREALLOC_QNAME
+ PREALLOC_RRSETS
+ PREALLOC_DOMAINS
+ PREALLOC_OFFSETS
+ PREALLOC_TMP_DOMAINS
};
static const uint16_t EDNS_NOT_SUPPORTED = 65535;
/*----------------------------------------------------------------------------*/
/* Non-API functions */
/*----------------------------------------------------------------------------*/
static void dnslib_response_parse_host_edns(dnslib_response_t *response,
const uint8_t *edns_wire, short edns_size)
{
}
/*----------------------------------------------------------------------------*/
static void dnslib_response_init_pointers(dnslib_response_t *resp)
{
debug_dnslib_response("Response pointer: %p\n", resp);
// put QNAME directly after the structure
resp->question.qname =
(dnslib_dname_t *)((char *)resp + PREALLOC_RESPONSE);
debug_dnslib_response("QNAME: %p (%d after start of response)\n",
resp->question.qname,
(void *)resp->question.qname - (void *)resp);
// then answer, authority and additional sections
resp->answer = (dnslib_rrset_t **)
((char *)resp->question.qname + PREALLOC_QNAME);
resp->authority = resp->answer + DEFAULT_ANCOUNT;
resp->additional = resp->authority + DEFAULT_NSCOUNT;
debug_dnslib_response("Answer section: %p (%d after QNAME)\n",
resp->answer,
(void *)resp->answer - (void *)resp->question.qname);
debug_dnslib_response("Authority section: %p (%d after Answer)\n",
resp->authority,
(void *)resp->authority - (void *)resp->answer);
debug_dnslib_response("Additional section: %p (%d after Authority)\n",
resp->additional,
(void *)resp->additional - (void *)resp->authority);
resp->max_ancount = DEFAULT_ANCOUNT;
resp->max_nscount = DEFAULT_NSCOUNT;
resp->max_arcount = DEFAULT_ARCOUNT;
// then domain names for compression and offsets
resp->compression.dnames = (dnslib_dname_t **)
(resp->additional + DEFAULT_ARCOUNT);
resp->compression.offsets = (size_t *)
(resp->compression.dnames + DEFAULT_DOMAINS_IN_RESPONSE);
debug_dnslib_response("Compression dnames: %p (%d after Additional)\n",
resp->compression.dnames,
(void *)resp->compression.dnames - (void *)resp->additional);
debug_dnslib_response("Compression offsets: %p (%d after c. dnames)\n",
resp->compression.offsets,
(void *)resp->compression.offsets
- (void *)resp->compression.dnames);
resp->compression.max = DEFAULT_DOMAINS_IN_RESPONSE;
resp->tmp_dnames = (dnslib_dname_t **)
(resp->compression.offsets + DEFAULT_DOMAINS_IN_RESPONSE);
debug_dnslib_response("Tmp dnames: %p (%d after compression offsets)\n",
resp->tmp_dnames,
(void *)resp->tmp_dnames - (void *)resp->compression.offsets);
resp->tmp_dname_max = DEFAULT_TMP_DOMAINS;
debug_dnslib_response("End of data: %p (%d after start of response)\n",
resp->tmp_dnames + DEFAULT_TMP_DOMAINS,
(void *)(resp->tmp_dnames + DEFAULT_TMP_DOMAINS)
- (void *)resp);
debug_dnslib_response("Allocated total: %u\n", PREALLOC_TOTAL);
assert((char *)(resp->tmp_dnames + DEFAULT_TMP_DOMAINS)
== (char *)resp + PREALLOC_TOTAL);
}
/*----------------------------------------------------------------------------*/
static void dnslib_response_init(dnslib_response_t *resp,
const uint8_t *edns_wire, short edns_size)
{
memset(resp, 0, PREALLOC_TOTAL);
resp->edns_wire = edns_wire;
resp->edns_size = edns_size;
if (edns_wire != NULL && edns_size > 0) {
// parse given EDNS record and save max size
dnslib_response_parse_host_edns(resp, edns_wire, edns_size);
}
// save default pointers to the space after the structure
dnslib_response_init_pointers(resp);
}
/*----------------------------------------------------------------------------*/
static int dnslib_response_parse_header(const uint8_t **pos, size_t *remaining,
dnslib_header_t *header)
{
if (pos == NULL || *pos == NULL || remaining == NULL
|| header == NULL) {
debug_dnslib_response("Missing inputs to header parsing.\n");
return -1;
}
if (*remaining < DNSLIB_PACKET_HEADER_SIZE) {
debug_dnslib_response("Not enough data to parse header.\n");
return -2;
}
header->id = dnslib_packet_get_id(*pos);
header->flags1 = dnslib_packet_get_flags1(*pos);
header->flags2 = dnslib_packet_get_flags2(*pos);
header->qdcount = dnslib_packet_get_qdcount(*pos);
header->ancount = dnslib_packet_get_ancount(*pos);
header->nscount = dnslib_packet_get_nscount(*pos);
header->arcount = dnslib_packet_get_arcount(*pos);
*pos += DNSLIB_PACKET_HEADER_SIZE;
*remaining -= DNSLIB_PACKET_HEADER_SIZE;
return 0;
}
/*----------------------------------------------------------------------------*/
static int dnslib_response_parse_question(const uint8_t **pos,
size_t *remaining,
dnslib_question_t *question)
{
if (pos == NULL || *pos == NULL || remaining == NULL
|| question == NULL) {
debug_dnslib_response("Missing inputs to question parsing\n");
return -1;
}
if (*remaining < DNSLIB_PACKET_QUESTION_MIN_SIZE) {
debug_dnslib_response("Not enough data to parse question.\n");
return -2; // malformed
}
// domain name must end with 0, so just search for 0
int i = 0;
while (i < *remaining && (*pos)[i] != 0) {
++i;
}
if (i == *remaining || *remaining - i - 1 < 4) {
debug_dnslib_response("Not enough data to parse question.\n");
return -2; // no 0 found or not enough data left
}
question->qname = dnslib_dname_new_from_wire(*pos, i + 1, NULL);
*pos += i + 1;
question->qtype = dnslib_packet_read_u16(*pos);
*pos += 2;
question->qclass = dnslib_packet_read_u16(*pos);
*pos += 2;
*remaining -= (i + 5);
return 0;
}
/*----------------------------------------------------------------------------*/
static int dnslib_response_parse_client_edns(const uint8_t **pos,
size_t *remaining,
dnslib_edns_data_t *edns)
{
if (pos == NULL || *pos == NULL || remaining == NULL
|| edns == NULL) {
return -1;
}
if (*remaining < DNSLIB_PACKET_RR_MIN_SIZE) {
debug_dnslib_response("Not enough data to parse ENDS.\n");
return -2;
}
// owner of EDNS OPT RR must be root (0)
if (**pos != 0) {
debug_dnslib_response("EDNS packet malformed (expected root "
"domain as owner).\n");
return -3;
}
*pos += 1;
// check the type of the record (must be OPT)
if (dnslib_packet_read_u16(*pos) != DNSLIB_RRTYPE_OPT) {
debug_dnslib_response("EDNS packet malformed (expected OPT type"
".\n");
return -2;
}
*pos += 2;
edns->payload = dnslib_packet_read_u16(*pos);
*pos += 2;
edns->ext_rcode = *(*pos)++;
edns->version = *(*pos)++;
// skip Z
*pos += 2;
// ignore RDATA, but move pos behind them
uint16_t rdlength = dnslib_packet_read_u16(*pos);
*remaining -= 11;
if (*remaining < rdlength) {
debug_dnslib_response("Not enough data to parse ENDS.\n");
return -3;
}
*pos += 2 + rdlength;
*remaining -= rdlength;
return 0;
}
/*----------------------------------------------------------------------------*/
static void dnslib_response_free_tmp_domains(dnslib_response_t *resp)
{
for (int i = 0; i < resp->tmp_dname_count; ++i) {
dnslib_dname_free(&resp->tmp_dnames[i]);
}
}
/*----------------------------------------------------------------------------*/
static void dnslib_response_free_allocated_space(dnslib_response_t *resp)
{
if (resp->max_ancount > DEFAULT_ANCOUNT) {
free(resp->answer);
}
if (resp->max_nscount > DEFAULT_NSCOUNT) {
free(resp->authority);
}
if (resp->max_arcount > DEFAULT_ARCOUNT) {
free(resp->additional);
}
if (resp->compression.max > DEFAULT_DOMAINS_IN_RESPONSE) {
free(resp->compression.dnames);
free(resp->compression.offsets);
}
if (resp->tmp_dname_max > DEFAULT_TMP_DOMAINS) {
free(resp->tmp_dnames);
}
}
/*----------------------------------------------------------------------------*/
static void dnslib_response_dump(const dnslib_response_t *resp)
{
debug_dnslib_response("DNS response:\n-----------------------------\n");
debug_dnslib_response("\nHeader:\n");
debug_dnslib_response(" ID: %u", resp->header.id);
debug_dnslib_response(" FLAGS: %s %s %s %s %s %s %s\n",
dnslib_packet_flags_get_qr(resp->header.flags1) ? "qr" : "",
dnslib_packet_flags_get_aa(resp->header.flags1) ? "aa" : "",
dnslib_packet_flags_get_tc(resp->header.flags1) ? "tc" : "",
dnslib_packet_flags_get_rd(resp->header.flags1) ? "rd" : "",
dnslib_packet_flags_get_ra(resp->header.flags2) ? "ra" : "",
dnslib_packet_flags_get_ad(resp->header.flags2) ? "ad" : "",
dnslib_packet_flags_get_cd(resp->header.flags2) ? "cd" : "");
debug_dnslib_response(" QDCOUNT: %u\n", resp->header.qdcount);
debug_dnslib_response(" ANCOUNT: %u\n", resp->header.ancount);
debug_dnslib_response(" NSCOUNT: %u\n", resp->header.nscount);
debug_dnslib_response(" ARCOUNT: %u\n", resp->header.arcount);
debug_dnslib_response("\nQuestion:\n");
char *qname = dnslib_dname_to_str(resp->question.qname);
debug_dnslib_response(" QNAME: %s\n", qname);
free(qname);
debug_dnslib_response(" QTYPE: %u (%s)\n", resp->question.qtype,
dnslib_rrtype_to_string(resp->question.qtype));
debug_dnslib_response(" QCLASS: %u (%s)\n", resp->question.qclass,
dnslib_rrclass_to_string(resp->question.qclass));
/*! \todo Dumping of Answer, Authority and Additional sections. */
debug_dnslib_response("\nEDNS - client:\n");
debug_dnslib_response(" Version: %u\n", resp->edns_query.version);
debug_dnslib_response(" Payload: %u\n", resp->edns_query.payload);
debug_dnslib_response(" Extended RCODE: %u\n",
resp->edns_query.ext_rcode);
debug_dnslib_response("\n-----------------------------\n");
}
/*----------------------------------------------------------------------------*/
/* API functions */
/*----------------------------------------------------------------------------*/
dnslib_response_t *dnslib_response_new_empty(const uint8_t *edns_wire,
short edns_size)
{
dnslib_response_t *resp = (dnslib_response_t *)malloc(PREALLOC_TOTAL);
CHECK_ALLOC_LOG(resp);
dnslib_response_init(resp, edns_wire, edns_size);
return resp;
}
/*----------------------------------------------------------------------------*/
int dnslib_response_parse_query(dnslib_response_t *resp,
const uint8_t *query_wire, size_t query_size)
{
int err = 0;
const uint8_t *pos = query_wire;
size_t remaining = query_size;
if ((err = dnslib_response_parse_header(
&pos, &remaining, &resp->header))) {
return err;
}
if ((err = dnslib_response_parse_question(
&pos, &remaining, &resp->question))) {
return err;
}
if (resp->header.arcount > 0) { // expecting EDNS OPT RR
if ((err = dnslib_response_parse_client_edns(
&pos, &remaining, &resp->edns_query))) {
return err;
}
} else {
// set client EDNS version to EDNS_NOT_SUPPORTED
resp->edns_query.version = EDNS_NOT_SUPPORTED;
}
if (remaining > 0) {
// some trailing garbage; ignore, but log
log_info("%d bytes of trailing garbage in query.\n", remaining);
}
dnslib_response_dump(resp);
return 0;
}
/*----------------------------------------------------------------------------*/
int dnslib_response_add_rrset_answer(dnslib_response_t *response,
const dnslib_rrset_t *rrset, int tc)
{
return -1;
}
/*----------------------------------------------------------------------------*/
int dnslib_response_add_rrset_authority(dnslib_response_t *response,
const dnslib_rrset_t *rrset, int tc)
{
return -1;
}
/*----------------------------------------------------------------------------*/
int dnslib_response_add_rrset_aditional(dnslib_response_t *response,
const dnslib_rrset_t *rrset, int tc)
{
return -1;
}
/*----------------------------------------------------------------------------*/
int dnslib_response_to_wire(dnslib_response_t *response,
uint8_t **resp_wire, size_t *resp_size)
{
return -1;
}
/*----------------------------------------------------------------------------*/
void dnslib_response_free(dnslib_response_t **response)
{
if (response == NULL || *response == NULL) {
return;
}
// free temporary domain names
dnslib_response_free_tmp_domains(*response);
// check if some additional space was allocated for the response
dnslib_response_free_allocated_space(*response);
free(*response);
*response = NULL;
}
/*!
* \file response.h
*
* \author Lubos Slovak <lubos.slovak@nic.cz>
*
* \brief Structure for holding response data and metadata.
*
* This structure can be used to pass all data needed for response creation
* inside and between various processing functions of the application.
*
* \addtogroup dnslib
* @{
*/
#ifndef _CUTEDNS_DNSLIB_RESPONSE_H_
#define _CUTEDNS_DNSLIB_RESPONSE_H_
#include <stdint.h>
#include <string.h>
#include "dname.h"
#include "rrset.h"
/*----------------------------------------------------------------------------*/
/*!
* MTU <= 4500B
* IP header has 24 B
* DNS header has 12 B
* DNS question is at least 5 B long (2 bytes TYPE, 2 bytes CLASS, 1 byte QNAME)
* Each DNS RR is at least 11 B long:
* TYPE: 2 B
* CLASS: 2 B
* TTL: 4 B
* RDLENGTH: 2 B
* OWNER: at least 1 B (root label)
* RDATA: may be 0 B (theoretically)
*
* (4500 - 24 - 12 - 5) / 11 = 405
*/
static const size_t MAX_RRS_IN_RESPONSE = 405;
/*----------------------------------------------------------------------------*/
/*!
* \todo NSID
*/
struct dnslib_edns_data {
uint16_t payload;
uint16_t ext_rcode;
uint16_t version;
};
typedef struct dnslib_edns_data dnslib_edns_data_t;
/*----------------------------------------------------------------------------*/
/*!
*
*/
struct dnslib_compressed_dnames {
dnslib_dname_t **dnames;
size_t *offsets;
short count;
short max;
};
typedef struct dnslib_compressed_dnames dnslib_compressed_dnames_t;
/*----------------------------------------------------------------------------*/
/*!
*
*/
struct dnslib_header {
uint16_t id; /*!< ID stored in host byte order. */
uint8_t flags1; /*!< First octet of header flags. */
uint8_t flags2; /*!< Second octet of header flags. */
uint16_t qdcount; /*!< Number of Question RRs, in host byte order. */
uint16_t ancount; /*!< Number of Answer RRs, in host byte order. */
uint16_t nscount; /*!< Number of Authority RRs, in host byte order. */
uint16_t arcount; /*!< Number of Additional RRs, in host byte order. */
};
typedef struct dnslib_header dnslib_header_t;
struct dnslib_question {
dnslib_dname_t *qname;
uint16_t qtype;
uint16_t qclass;
};
typedef struct dnslib_question dnslib_question_t;
/*----------------------------------------------------------------------------*/
/*!
* \note QNAME, Answer, Authority and Additonal sections are by default put to
* preallocated space after the structure with default sizes. If the
* space is not enough, more space is allocated dynamically.
*/
struct dnslib_response {
/*!
* \note Only one Question is supported!
*/
dnslib_question_t question;
short max_size; /*!< Maximum allowed size of the response. */
dnslib_rrset_t **answer;
dnslib_rrset_t **authority;
dnslib_rrset_t **additional;
short max_ancount; /*!< Allocated space for Answer RRsets. */
short max_nscount; /*!< Allocated space for Authority RRsets. */
short max_arcount; /*!< Allocated space for Additional RRsets. */
dnslib_header_t header;
/*!
* \brief EDNS data parsed from query.
*
* \todo Do we need this actually??
*/
dnslib_edns_data_t edns_query;
const uint8_t *edns_wire;
short edns_size;
dnslib_compressed_dnames_t compression;
dnslib_dname_t **tmp_dnames; /*!< Synthetized domain names. */
short tmp_dname_count; /*!< Count of synthetized domain names. */
short tmp_dname_max; /*!< Allocated space for synthetized dnames. */
};
typedef struct dnslib_response dnslib_response_t;
/*----------------------------------------------------------------------------*/
dnslib_response_t *dnslib_response_new_empty(const uint8_t *edns_wire,
short edns_size);
int dnslib_response_parse_query(dnslib_response_t *response,
const uint8_t *query_wire, size_t query_size);
/*!
* \param tc Set to <> 0 if omitting this RRSet should result in the TC bit set.
* Otherwise set to 0.
*/
int dnslib_response_add_rrset_answer(dnslib_response_t *response,
const dnslib_rrset_t *rrset, int tc);
int dnslib_response_add_rrset_authority(dnslib_response_t *response,
const dnslib_rrset_t *rrset, int tc);
int dnslib_response_add_rrset_aditional(dnslib_response_t *response,
const dnslib_rrset_t *rrset, int tc);
/*
* TODO: some functions for setting RCODE and flags!
*/
int dnslib_response_to_wire(dnslib_response_t *response,
uint8_t **resp_wire, size_t *resp_size);
void dnslib_response_free(dnslib_response_t **response);
#endif /* _CUTEDNS_DNSLIB_RESPONSE_H_ */
/*! @} */
......@@ -31,6 +31,7 @@
//#define DNSLIB_DNAME_DEBUG
#define DNSLIB_ZONE_DEBUG
#define DNSLIB_RESPONSE_DEBUG
#ifdef SERVER_DEBUG
#define debug_server(msg...) log_msg(LOG_DEBUG, msg)
......@@ -60,6 +61,12 @@
#define debug_dnslib_zone(msg...)
#endif
#ifdef DNSLIB_RESPONSE_DEBUG
#define debug_dnslib_response(msg...) log_msg(LOG_DEBUG, msg)
#else
#define debug_dnslib_response(msg...)
#endif
#ifdef CUCKOO_DEBUG
#define debug_ck(msg...) log_msg(LOG_DEBUG, msg)
#define debug_ck_hex(data, len) hex_print((data), (len))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment