Skip to content
Snippets Groups Projects
Commit f752ba56 authored by Lubos Slovak's avatar Lubos Slovak
Browse files

Packet structure and API, query + response API.

- General packet structure and API separated into packet.h/.c.
- Query API separated to query.h/.c.
- Response API separated to response2.h/.c

These structures are not yet used, nor they are added to the
makefile. A lot of functions not yet implemented, just a skeleton.

refs #816 @2:00
parent 27b8ede2
No related branches found
No related tags found
No related merge requests found
......@@ -49,6 +49,12 @@ src/dnslib/descriptor.h
src/dnslib/descriptor.c
src/dnslib/zone.h
src/dnslib/zone.c
src/dnslib/packet.h
src/dnslib/packet.c
src/dnslib/query.h
src/dnslib/query.c
src/dnslib/response2.h
src/dnslib/response2.c
src/dnslib/response.h
src/dnslib/wire.h
src/dnslib/response.c
......
......@@ -78,6 +78,7 @@ void dnslib_zone_dump(dnslib_zone_t *zone, char loaded_zone);
//#define DNSLIB_ZONEDB_DEBUG
//#define DNSLIB_DNAME_DEBUG
//#define DNSLIB_RESPONSE_DEBUG
//#define DNSLIB_PACKET_DEBUG
//#define DNSLIB_EDNS_DEBUG
//#define DNSLIB_RRSET_DEBUG
//#define DNSLIB_NSEC3_DEBUG
......@@ -124,6 +125,16 @@ void dnslib_zone_dump(dnslib_zone_t *zone, char loaded_zone);
#define DEBUG_DNSLIB_RESPONSE(cmds)
#endif
#ifdef DNSLIB_PACKET_DEBUG
#define debug_dnslib_packet(msg...) fprintf(stderr, msg)
#define debug_dnslib_packet_hex(data, len) hex_print((data), (len))
#define DEBUG_DNSLIB_PACKET(cmds) do { cmds } while (0)
#else
#define debug_dnslib_packet(msg...)
#define debug_dnslib_packet_hex(data, len)
#define DEBUG_DNSLIB_PACKET(cmds)
#endif
#ifdef DNSLIB_EDNS_DEBUG
#define debug_dnslib_edns(msg...) fprintf(stderr, msg)
#else
......
#include "dnslib/packet.h"
/*----------------------------------------------------------------------------*/
/*!
* \brief Default sizes for response structure parts and steps for increasing
* them.
*/
enum {
DEFAULT_ANCOUNT = 6, /*!< Default count of Answer RRSets. */
DEFAULT_NSCOUNT = 8, /*!< Default count of Authority RRSets. */
DEFAULT_ARCOUNT = 28, /*!< Default count of Additional RRSets. */
DEFAULT_ANCOUNT_QUERY = 1, /*!< Default count of Answer RRSets. */
DEFAULT_NSCOUNT_QUERY = 0, /*!< Default count of Authority RRSets. */
DEFAULT_ARCOUNT_QUERY = 1, /*!< Default count of Additional RRSets. */
/*!
* \brief Default count of all domain names in response.
*
* Used for compression table.
*/
DEFAULT_DOMAINS_IN_RESPONSE = 22,
/*! \brief Default count of temporary RRSets stored in response. */
DEFAULT_TMP_RRSETS = 5,
/*! \brief Default count of temporary RRSets stored in query. */
DEFAULT_TMP_RRSETS_QUERY = 2,
STEP_ANCOUNT = 6, /*!< Step for increasing space for Answer RRSets. */
STEP_NSCOUNT = 8, /*!< Step for increasing space for Authority RRSets.*/
STEP_ARCOUNT = 8,/*!< Step for increasing space for Additional RRSets.*/
STEP_DOMAINS = 10, /*!< Step for resizing compression table. */
STEP_TMP_RRSETS = 5 /*!< Step for increasing temorary RRSets count. */
};
/*----------------------------------------------------------------------------*/
#define PREALLOC_RRSETS(count) (count * sizeof(dnslib_rrset_t *))
/*! \brief Sizes for preallocated space in the response structure. */
enum {
/*! \brief Size of the response structure itself. */
PREALLOC_PACKET = sizeof(dnslib_packet_t),
/*! \brief Space for QNAME dname structure. */
PREALLOC_QNAME_DNAME = sizeof(dnslib_dname_t),
/*! \brief Space for QNAME name (maximum domain name size). */
PREALLOC_QNAME_NAME = 256,
/*! \brief Space for QNAME labels (maximum label count). */
PREALLOC_QNAME_LABELS = 127,
/*! \brief Total space for QNAME. */
PREALLOC_QNAME = PREALLOC_QNAME_DNAME
+ PREALLOC_QNAME_NAME
+ PREALLOC_QNAME_LABELS,
/*!
* \brief Space for RR owner wire format.
*
* Temporary buffer, used when putting RRSets to the response.
*/
PREALLOC_RR_OWNER = 256,
// /*! \brief Space for Answer RRSets. */
// PREALLOC_ANSWER = DEFAULT_ANCOUNT * sizeof(dnslib_dname_t *),
// /*! \brief Space for Authority RRSets. */
// PREALLOC_AUTHORITY = DEFAULT_NSCOUNT * sizeof(dnslib_dname_t *),
// /*! \brief Space for Additional RRSets. */
// PREALLOC_ADDITIONAL = DEFAULT_ARCOUNT * sizeof(dnslib_dname_t *),
// /*! \brief Total size for Answer, Authority and Additional RRSets. */
// PREALLOC_RRSETS = PREALLOC_ANSWER
// + PREALLOC_AUTHORITY
// + PREALLOC_ADDITIONAL,
/*! \brief Space for one part of the compression table (domain names).*/
PREALLOC_DOMAINS =
DEFAULT_DOMAINS_IN_RESPONSE * sizeof(dnslib_dname_t *),
/*! \brief Space for other part of the compression table (offsets). */
PREALLOC_OFFSETS =
DEFAULT_DOMAINS_IN_RESPONSE * sizeof(size_t),
PREALLOC_COMPRESSION = PREALLOC_DOMAINS + PREALLOC_OFFSETS,
// /*! \brief Space for temporary RRSets. */
// PREALLOC_TMP_RRSETS =
// DEFAULT_TMP_RRSETS * sizeof(dnslib_rrset_t *),
PREALLOC_QUERY = PREALLOC_PACKET
+ PREALLOC_QNAME
+ PREALLOC_RRSETS(DEFAULT_ANCOUNT_QUERY)
+ PREALLOC_RRSETS(DEFAULT_NSCOUNT_QUERY)
+ PREALLOC_RRSETS(DEFAULT_ARCOUNT_QUERY)
+ PREALLOC_RRSETS(DEFAULT_TMP_RRSETS_QUERY),
/*! \brief Total preallocated size for the response. */
PREALLOC_TOTAL = PREALLOC_PACKET
+ PREALLOC_QNAME
+ PREALLOC_RR_OWNER
+ PREALLOC_RRSETS
+ PREALLOC_COMPRESSION
+ PREALLOC_RRSETS(DEFAULT_TMP_RRSETS),
};
/*----------------------------------------------------------------------------*/
/* Non-API functions */
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/* API functions */
/*----------------------------------------------------------------------------*/
dnslib_packet_t *dnslib_packet_new(dnslib_packet_prealloc_type_t prealloc)
{
/*! \todo Implement! */
return NULL;
}
/*----------------------------------------------------------------------------*/
int dnslib_packet_parse_from_wire(dnslib_packet_t *packet, uint8_t *wireformat,
size_t size, int question_only)
{
/*! \todo Implement! */
return DNSLIB_ERROR;
}
/*----------------------------------------------------------------------------*/
uint8_t dnslib_packet_opcode(const dnslib_packet_t *packet)
{
return dnslib_wire_flags_get_opcode(packet->header.flags1);
}
/*----------------------------------------------------------------------------*/
const dnslib_dname_t *dnslib_packet_qname(const dnslib_packet_t *packet)
{
return packet->question.qname;
}
/*----------------------------------------------------------------------------*/
uint16_t dnslib_packet_qtype(const dnslib_packet_t *packet)
{
return packet->question.qtype;
}
/*----------------------------------------------------------------------------*/
uint16_t dnslib_packet_qclass(const dnslib_packet_t *packet)
{
return packet->question.qclass;
}
/*----------------------------------------------------------------------------*/
short dnslib_packet_answer_rrset_count(const dnslib_packet_t *packet)
{
return packet->an_rrsets;
}
/*----------------------------------------------------------------------------*/
short dnslib_packet_authority_rrset_count(const dnslib_packet_t *packet)
{
return packet->ns_rrsets;
}
/*----------------------------------------------------------------------------*/
short dnslib_packet_additional_rrset_count(const dnslib_packet_t *packet)
{
return packet->ar_rrsets;
}
/*----------------------------------------------------------------------------*/
const dnslib_rrset_t *dnslib_packet_answer_rrset(
const dnslib_packet_t *packet, short pos)
{
if (pos > packet->an_rrsets) {
return NULL;
}
return packet->answer[pos];
}
/*----------------------------------------------------------------------------*/
const dnslib_rrset_t *dnslib_packet_authority_rrset(
dnslib_packet_t *packet, short pos)
{
if (pos > packet->ns_rrsets) {
return NULL;
}
return packet->authority[pos];
}
/*----------------------------------------------------------------------------*/
const dnslib_rrset_t *dnslib_packet_additional_rrset(
dnslib_packet_t *packet, short pos)
{
if (pos > packet->ar_rrsets) {
return NULL;
}
return packet->additional[pos];
}
/*----------------------------------------------------------------------------*/
void dnslib_packet_free(dnslib_packet_t **packet)
{
if (packet == NULL || *packet == NULL) {
return;
}
// free temporary domain names
debug_dnslib_packet("Freeing tmp domains...\n");
dnslib_packet_free_tmp_rrsets(*packet);
// check if some additional space was allocated for the packet
debug_dnslib_packet("Freeing additional allocated space...\n");
dnslib_packet_free_allocated_space(*packet);
// free the space for wireformat
assert((*packet)->wireformat != NULL);
free((*packet)->wireformat);
debug_dnslib_packet("Freeing packet structure\n");
free(*packet);
*packet = NULL;
}
/*----------------------------------------------------------------------------*/
#ifdef DNSLIB_PACKET_DEBUG
static void dnslib_packet_dump_rrsets(const dnslib_rrset_t **rrsets,
int count)
{
for (int i = 0; i < count; ++i) {
debug_dnslib_packet(" RRSet %d:\n", i + 1);
char *name = dnslib_dname_to_str(rrsets[i]->owner);
debug_dnslib_packet(" Owner: %s\n", name);
free(name);
debug_dnslib_packet(" Type: %s\n",
dnslib_rrtype_to_string(rrsets[i]->type));
debug_dnslib_packet(" Class: %s\n",
dnslib_rrclass_to_string(rrsets[i]->rclass));
debug_dnslib_packet(" TTL: %d\n", rrsets[i]->ttl);
debug_dnslib_packet(" RDATA: ");
dnslib_rrtype_descriptor_t *desc =
dnslib_rrtype_descriptor_by_type(rrsets[i]->type);
const dnslib_rdata_t *rdata = dnslib_rrset_rdata(rrsets[i]);
while (rdata != NULL) {
for (int j = 0; j < rdata->count; ++j) {
switch (desc->wireformat[j]) {
case DNSLIB_RDATA_WF_COMPRESSED_DNAME:
case DNSLIB_RDATA_WF_LITERAL_DNAME:
case DNSLIB_RDATA_WF_UNCOMPRESSED_DNAME:
name = dnslib_dname_to_str(
rdata->items[j].dname);
debug_dnslib_packet("%s \n",name);
free(name);
break;
case DNSLIB_RDATA_WF_BINARYWITHLENGTH:
debug_dnslib_packet_hex(
(char *)rdata->items[j].raw_data,
rdata->items[j].raw_data[0]);
break;
default:
debug_dnslib_packet_hex(
(char *)&rdata->items[j].raw_data[1],
rdata->items[j].raw_data[0]);
break;
}
}
rdata = dnslib_rrset_rdata_next(rrsets[i], rdata);
}
}
}
#endif
/*----------------------------------------------------------------------------*/
void dnslib_packet_dump(const dnslib_packet_t *packet)
{
#ifdef DNSLIB_PACKET_DEBUG
debug_dnslib_packet("DNS packet:\n-----------------------------\n");
debug_dnslib_packet("\nHeader:\n");
debug_dnslib_packet(" ID: %u", packet->header.id);
debug_dnslib_packet(" FLAGS: %s %s %s %s %s %s %s\n",
dnslib_wire_flags_get_qr(packet->header.flags1) ? "qr" : "",
dnslib_wire_flags_get_aa(packet->header.flags1) ? "aa" : "",
dnslib_wire_flags_get_tc(packet->header.flags1) ? "tc" : "",
dnslib_wire_flags_get_rd(packet->header.flags1) ? "rd" : "",
dnslib_wire_flags_get_ra(packet->header.flags2) ? "ra" : "",
dnslib_wire_flags_get_ad(packet->header.flags2) ? "ad" : "",
dnslib_wire_flags_get_cd(packet->header.flags2) ? "cd" : "");
debug_dnslib_packet(" QDCOUNT: %u\n", packet->header.qdcount);
debug_dnslib_packet(" ANCOUNT: %u\n", packet->header.ancount);
debug_dnslib_packet(" NSCOUNT: %u\n", packet->header.nscount);
debug_dnslib_packet(" ARCOUNT: %u\n", packet->header.arcount);
debug_dnslib_packet("\nQuestion:\n");
char *qname = dnslib_dname_to_str(packet->question.qname);
debug_dnslib_packet(" QNAME: %s\n", qname);
free(qname);
debug_dnslib_packet(" QTYPE: %u (%s)\n", packet->question.qtype,
dnslib_rrtype_to_string(packet->question.qtype));
debug_dnslib_packet(" QCLASS: %u (%s)\n", packet->question.qclass,
dnslib_rrclass_to_string(packet->question.qclass));
debug_dnslib_packet("\nAnswer RRSets:\n");
dnslib_packet_dump_rrsets(packet->answer, packet->an_rrsets);
debug_dnslib_packet("\nAuthority RRSets:\n");
dnslib_packet_dump_rrsets(packet->authority, packet->ns_rrsets);
debug_dnslib_packet("\nAdditional RRSets:\n");
dnslib_packet_dump_rrsets(packet->additional, packet->ar_rrsets);
/*! \todo Dumping of Answer, Authority and Additional sections. */
debug_dnslib_packet("\nEDNS:\n");
debug_dnslib_packet(" Version: %u\n", packet->opt_rr.version);
debug_dnslib_packet(" Payload: %u\n", packet->opt_rr.payload);
debug_dnslib_packet(" Extended RCODE: %u\n",
packet->opt_rr.ext_rcode);
debug_dnslib_packet("\nPacket size: %d\n", packet->size);
debug_dnslib_packet("\n-----------------------------\n");
#endif
}
/*!
* \file packet.h
*
* \author Lubos Slovak <lubos.slovak@nic.cz>
*
* \brief Structure for holding DNS packet data and metadata.
*
* \addtogroup dnslib
* @{
*/
#ifndef _KNOT_DNSLIB_PACKET_H_
#define _KNOT_DNSLIB_PACKET_H_
#include <stdint.h>
#include <string.h>
#include "dnslib/dname.h"
#include "dnslib/rrset.h"
#include "dnslib/edns.h"
/*----------------------------------------------------------------------------*/
/*!
* \brief Structure for holding information needed for compressing domain names.
*
* It's a simple table of domain names and their offsets in wire format of the
* packet.
*
* \todo Consider using some better lookup structure, such as skip-list.
*/
struct dnslib_compressed_dnames {
const dnslib_dname_t **dnames; /*!< Domain names present in packet. */
size_t *offsets; /*!< Offsets of domain names in the packet. */
short count; /*!< Count of items in the previous arrays. */
short max; /*!< Capacity of the structure (allocated). */
};
typedef struct dnslib_compressed_dnames dnslib_compressed_dnames_t;
/*----------------------------------------------------------------------------*/
/*!
* \brief Structure representing the DNS packet header.
*/
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;
/*!
* \brief Structure representing one Question entry in the DNS packet.
*/
struct dnslib_question {
dnslib_dname_t *qname; /*!< Question domain name. */
uint16_t qtype; /*!< Question TYPE. */
uint16_t qclass; /*!< Question CLASS. */
};
typedef struct dnslib_question dnslib_question_t;
enum dnslib_packet_prealloc_type {
DNSLIB_PACKET_PREALLOC_NONE,
DNSLIB_PACKET_PREALLOC_QUERY,
DNSLIB_PACKET_PREALLOC_RESPONSE
};
typedef enum dnslib_packet_prealloc_type dnslib_packet_prealloc_type_t;
/*----------------------------------------------------------------------------*/
/*!
* \brief Structure representing a DNS packet.
*
* \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_packet {
/*! \brief DNS header. */
dnslib_header_t header;
/*!
* \brief Question section.
*
* \note Only one Question is supported!
*/
dnslib_question_t question;
uint8_t *owner_tmp; /*!< Allocated space for RRSet owner wire format.*/
const dnslib_rrset_t **answer; /*!< Answer RRSets. */
const dnslib_rrset_t **authority; /*!< Authority RRSets. */
const dnslib_rrset_t **additional; /*!< Additional RRSets. */
short an_rrsets; /*!< Count of Answer RRSets in the response. */
short ns_rrsets; /*!< Count of Authority RRSets in the response. */
short ar_rrsets; /*!< Count of Additional RRSets in the response. */
short max_an_rrsets; /*!< Allocated space for Answer RRsets. */
short max_ns_rrsets; /*!< Allocated space for Authority RRsets. */
short max_ar_rrsets; /*!< Allocated space for Additional RRsets. */
dnslib_opt_rr_t opt_rr; /*!< OPT RR included in the packet. */
uint8_t *wireformat; /*!< Wire format of the packet. */
size_t size; /*!< Current wire size of the packet. */
size_t max_size; /*!< Maximum allowed size of the packet. */
/*! \brief Information needed for compressing domain names in packet. */
dnslib_compressed_dnames_t compression;
/*! \brief RRSets to be destroyed with the packet structure. */
const dnslib_rrset_t **tmp_rrsets;
short tmp_rrsets_count; /*!< Count of temporary RRSets. */
short tmp_rrsets_max; /*!< Allocated space for temporary RRSets. */
struct dnslib_packet *query; /*!< Associated query. */
};
typedef struct dnslib_packet dnslib_packet_t;
/*----------------------------------------------------------------------------*/
/*!
* \brief Creates new empty packet structure.
*
* \param prealloc What space should be preallocated in the structure.
*
* \return New packet structure or NULL if an error occured.
*/
dnslib_packet_t *dnslib_packet_new(dnslib_packet_prealloc_type_t prealloc);
/*!
* \brief Parses the DNS packet from wire format.
*
* \param packet Packet structure to parse into.
* \param wireformat Wire format of the DNS packet.
* \param size Size of the wire format in bytes.
* \param question_only Set to <> 0 if you do not want to parse the whole
* packet. In such case the parsing will end after the
* Question section. Set to 0 to parse the whole packet.
*
* \retval DNSLIB_EOK
*/
int dnslib_packet_parse_from_wire(dnslib_packet_t *packet, uint8_t *wireformat,
size_t size, int question_only);
/*!
* \brief Returns the OPCODE of the packet.
*
* \param packet Packet (with parsed query) to get the OPCODE from.
*
* \return OPCODE stored in the packet.
*/
uint8_t dnslib_packet_opcode(const dnslib_packet_t *packet);
/*!
* \brief Returns the QNAME from the packet.
*
* \param packet Packet (with parsed query) to get the QNAME from.
*
* \return QNAME stored in the packet.
*/
const dnslib_dname_t *dnslib_packet_qname(const dnslib_packet_t *packet);
/*!
* \brief Returns the QTYPE from the packet.
*
* \param packet Packet (with parsed query) to get the QTYPE from.
*
* \return QTYPE stored in the packet.
*/
uint16_t dnslib_packet_qtype(const dnslib_packet_t *packet);
/*!
* \brief Returns the QCLASS from the packet.
*
* \param response Packet (with parsed query) to get the QCLASS from.
*
* \return QCLASS stored in the packet.
*/
uint16_t dnslib_packet_qclass(const dnslib_packet_t *packet);
/*!
* \brief Returns number of RRSets in Answer section of the packet.
*
* \param response Packet to get the Answer RRSet count from.
*/
short dnslib_packet_answer_rrset_count(const dnslib_packet_t *packet);
/*!
* \brief Returns number of RRSets in Authority section of the packet.
*
* \param response Packet to get the Authority RRSet count from.
*/
short dnslib_packet_authority_rrset_count(const dnslib_packet_t *packet);
/*!
* \brief Returns number of RRSets in Additional section of the packet.
*
* \param response Packet to get the Additional RRSet count from.
*/
short dnslib_packet_additional_rrset_count(const dnslib_packet_t *packet);
/*!
* \brief Returns the requested Answer RRset.
*
* \param packet Packet to get the RRSet from.
* \param pos Position of the RRSet in the Answer section (RRSets are stored
* in the order they were added to the response or parsed from the
* query).
*
* \return The RRSet on position \a pos in the Answer section of \a packet
* or NULL if there is no such RRSet.
*/
const dnslib_rrset_t *dnslib_packet_answer_rrset(
const dnslib_packet_t *packet, short pos);
/*!
* \brief Returns the requested Authority RRset.
*
* \param packet Packet to get the RRSet from.
* \param pos Position of the RRSet in the Authority section (RRSets are stored
* in the order they were added to the response or parsed from the
* query).
*
* \return The RRSet on position \a pos in the Authority section of \a packet
* or NULL if there is no such RRSet.
*/
const dnslib_rrset_t *dnslib_packet_authority_rrset(
dnslib_packet_t *packet, short pos);
/*!
* \brief Returns the requested Additional RRset.
*
* \param packet Packet to get the RRSet from.
* \param pos Position of the RRSet in the Additional section (RRSets are stored
* in the order they were added to the response or parsed from the
* query).
*
* \return The RRSet on position \a pos in the Additional section of \a packet
* or NULL if there is no such RRSet.
*/
const dnslib_rrset_t *dnslib_packet_additional_rrset(
dnslib_packet_t *packet, short pos);
/*!
* \brief Properly destroys the packet structure.
*
* \param response Packet to be destroyed.
*/
void dnslib_packet_free(dnslib_packet_t **packet);
/*!
* \brief Dumps the whole packet in human-readable form.
*
* \note This function is empty unless DNSLIB_PACKET_DEBUG is defined.
*
* \param resp Packet to dump.
*/
void dnslib_packet_dump(const dnslib_packet_t *packet);
#endif /* _KNOT_DNSLIB_PACKET_H_ */
/*! @} */
#include "dnslib/query.h"
/*----------------------------------------------------------------------------*/
int dnslib_response_dnssec_requested(const dnslib_packet_t *query)
{
return dnslib_edns_do(&query->opt_rr);
}
/*----------------------------------------------------------------------------*/
int dnslib_response_nsid_requested(const dnslib_packet_t *query)
{
return dnslib_edns_has_option(&query->opt_rr, EDNS_OPTION_NSID);
}
/*!
* \file query.h
*
* \author Lubos Slovak <lubos.slovak@nic.cz>
*
* \brief API for manipulating queries.
*
* \addtogroup dnslib
* @{
*/
#ifndef _KNOT_DNSLIB_QUERY_H_
#define _KNOT_DNSLIB_QUERY_H_
#include <stdint.h>
#include <string.h>
#include "dnslib/packet.h"
#include "dnslib/dname.h"
#include "dnslib/rrset.h"
#include "dnslib/edns.h"
/*----------------------------------------------------------------------------*/
/*!
* \brief Checks if DNSSEC was requested in the query (i.e. the DO bit was set).
*
* \param query Packet where the parsed query is stored.
*
* \retval 0 if the DO bit was not set in the query, or the query is not yet
* parsed.
* \retval > 0 if DO bit was set in the query.
*/
int dnslib_query_dnssec_requested(const dnslib_packet_t *query);
/*!
* \brief Checks if NSID was requested in the query (i.e. the NSID option was
* present in the query OPT RR).
*
* \param query Packet where the parsed query is stored.
*
* \retval 0 if the NSID option was not present in the query, or the query is
* not yet parsed.
* \retval > 0 if the NSID option was present in the query.
*/
int dnslib_query_nsid_requested(const dnslib_packet_t *query);
#endif /* _KNOT_DNSLIB_QUERY_H_ */
/*! @} */
#include "dnslib/response2.h"
/*----------------------------------------------------------------------------*/
int dnslib_packet_response_from_query(dnslib_packet_t *response,
dnslib_packet_t *query)
{
/*! \todo Implement! */
return DNSLIB_ERROR;
}
/*----------------------------------------------------------------------------*/
int dnslib_response_add_opt(dnslib_packet_t *resp,
const dnslib_opt_rr_t *opt_rr,
int override_max_size)
{
if (resp == NULL || opt_rr == NULL) {
return DNSLIB_EBADARG;
}
// copy the OPT RR
resp->edns_response.version = opt_rr->version;
resp->edns_response.ext_rcode = opt_rr->ext_rcode;
resp->edns_response.payload = opt_rr->payload;
resp->edns_response.size = opt_rr->size;
// if max size is set, it means there is some reason to be that way,
// so we can't just set it to higher value
if (override_max_size && resp->max_size > 0
&& resp->max_size < opt_rr->payload) {
return DNSLIB_EPAYLOAD;
}
// set max size (less is OK)
if (override_max_size) {
resp->max_size = resp->edns_response.payload;
}
return DNSLIB_EOK;
}
/*----------------------------------------------------------------------------*/
int dnslib_response_set_max_size(dnslib_packet_t *resp, int max_size)
{
if (resp == NULL || max_size <= 0) {
return DNSLIB_EBADARG;
}
if (resp->max_size < max_size) {
// reallocate space for the wire format (and copy anything
// that might have been there before
uint8_t *wire_new = (uint8_t *)malloc(max_size);
if (wire_new == NULL) {
return DNSLIB_ENOMEM;
}
memcpy(wire_new, resp->wireformat, resp->max_size);
resp->wireformat = wire_new;
}
// set max size
resp->max_size = max_size;
return DNSLIB_EOK;
}
/*----------------------------------------------------------------------------*/
int dnslib_response_add_rrset_answer(dnslib_packet_t *response,
const dnslib_rrset_t *rrset, int tc,
int check_duplicates, int compr_cs)
{
if (response == NULL || rrset == NULL) {
return DNSLIB_EBADARG;
}
debug_dnslib_response("add_rrset_answer()\n");
assert(response->header.arcount == 0);
assert(response->header.nscount == 0);
if (response->an_rrsets == response->max_an_rrsets
&& dnslib_response_realloc_rrsets(&response->answer,
&response->max_an_rrsets, DEFAULT_ANCOUNT, STEP_ANCOUNT)
!= DNSLIB_EOK) {
return DNSLIB_ENOMEM;
}
if (check_duplicates && dnslib_response_contains(response, rrset)) {
return DNSLIB_EOK;
}
debug_dnslib_response("Trying to add RRSet to Answer section.\n");
debug_dnslib_response("RRset: %p\n", rrset);
debug_dnslib_response("Owner: %p\n", rrset->owner);
int rrs = dnslib_response_try_add_rrset(response->answer,
&response->an_rrsets, response,
response->max_size
- response->size
- response->edns_response.size,
rrset, tc, compr_cs);
if (rrs >= 0) {
response->header.ancount += rrs;
return DNSLIB_EOK;
}
return DNSLIB_ESPACE;
}
/*----------------------------------------------------------------------------*/
int dnslib_response_add_rrset_authority(dnslib_packet_t *response,
const dnslib_rrset_t *rrset, int tc,
int check_duplicates, int compr_cs)
{
if (response == NULL || rrset == NULL) {
return DNSLIB_EBADARG;
}
assert(response->header.arcount == 0);
if (response->ns_rrsets == response->max_ns_rrsets
&& dnslib_response_realloc_rrsets(&response->authority,
&response->max_ns_rrsets, DEFAULT_NSCOUNT, STEP_NSCOUNT)
!= 0) {
return DNSLIB_ENOMEM;
}
if (check_duplicates && dnslib_response_contains(response, rrset)) {
return DNSLIB_EOK;
}
debug_dnslib_response("Trying to add RRSet to Authority section.\n");
int rrs = dnslib_response_try_add_rrset(response->authority,
&response->ns_rrsets, response,
response->max_size
- response->size
- response->edns_response.size,
rrset, tc, compr_cs);
if (rrs >= 0) {
response->header.nscount += rrs;
return DNSLIB_EOK;
}
return DNSLIB_ESPACE;
}
/*----------------------------------------------------------------------------*/
int dnslib_response_add_rrset_additional(dnslib_packet_t *response,
const dnslib_rrset_t *rrset, int tc,
int check_duplicates, int compr_cs)
{
if (response == NULL || rrset == NULL) {
return DNSLIB_EBADARG;
}
// if this is the first additional RRSet, add EDNS OPT RR first
if (response->header.arcount == 0
&& response->edns_response.version != EDNS_NOT_SUPPORTED) {
dnslib_response_edns_to_wire(response);
}
if (response->ar_rrsets == response->max_ar_rrsets
&& dnslib_response_realloc_rrsets(&response->additional,
&response->max_ar_rrsets, DEFAULT_ARCOUNT, STEP_ARCOUNT)
!= 0) {
return DNSLIB_ENOMEM;
}
if (check_duplicates && dnslib_response_contains(response, rrset)) {
return DNSLIB_EOK;
}
debug_dnslib_response("Trying to add RRSet to Additional section.\n");
int rrs = dnslib_response_try_add_rrset(response->additional,
&response->ar_rrsets, response,
response->max_size
- response->size, rrset, tc,
compr_cs);
if (rrs >= 0) {
response->header.arcount += rrs;
return DNSLIB_EOK;
}
return DNSLIB_ESPACE;
}
/*----------------------------------------------------------------------------*/
void dnslib_response_set_rcode(dnslib_packet_t *response, short rcode)
{
dnslib_wire_flags_set_rcode(&response->header.flags2, rcode);
dnslib_wire_set_rcode(response->wireformat, rcode);
}
/*----------------------------------------------------------------------------*/
void dnslib_response_set_aa(dnslib_packet_t *response)
{
dnslib_wire_flags_set_aa(&response->header.flags1);
dnslib_wire_set_aa(response->wireformat);
}
/*----------------------------------------------------------------------------*/
void dnslib_response_set_tc(dnslib_packet_t *response)
{
dnslib_wire_flags_set_tc(&response->header.flags1);
dnslib_wire_set_tc(response->wireformat);
}
/*----------------------------------------------------------------------------*/
int dnslib_response_add_tmp_rrset(dnslib_packet_t *response,
dnslib_rrset_t *tmp_rrset)
{
if (response->tmp_rrsets_count == response->tmp_rrsets_max
&& dnslib_response_realloc_rrsets(&response->tmp_rrsets,
&response->tmp_rrsets_max, DEFAULT_TMP_RRSETS,
STEP_TMP_RRSETS) != DNSLIB_EOK) {
return DNSLIB_ENOMEM;
}
response->tmp_rrsets[response->tmp_rrsets_count++] = tmp_rrset;
return DNSLIB_EOK;
}
/*----------------------------------------------------------------------------*/
int dnslib_response_add_nsid(dnslib_packet_t *response, const uint8_t *data,
uint16_t length)
{
return dnslib_edns_add_option(&response->edns_response,
EDNS_OPTION_NSID, length, data);
}
/*----------------------------------------------------------------------------*/
int dnslib_response_to_wire(dnslib_packet_t *resp,
uint8_t **resp_wire, size_t *resp_size)
{
if (resp == NULL || resp_wire == NULL || resp_size == NULL
|| *resp_wire != NULL) {
return DNSLIB_EBADARG;
}
assert(resp->size <= resp->max_size);
// if there are no additional RRSets, add EDNS OPT RR
if (resp->header.arcount == 0
&& resp->edns_response.version != EDNS_NOT_SUPPORTED) {
dnslib_response_edns_to_wire(resp);
}
// set ANCOUNT to the packet
dnslib_wire_set_ancount(resp->wireformat, resp->header.ancount);
// set NSCOUNT to the packet
dnslib_wire_set_nscount(resp->wireformat, resp->header.nscount);
// set ARCOUNT to the packet
dnslib_wire_set_arcount(resp->wireformat, resp->header.arcount);
//assert(response->size == size);
*resp_wire = resp->wireformat;
*resp_size = resp->size;
return DNSLIB_EOK;
}
/*!
* \file response2.h
*
* \author Lubos Slovak <lubos.slovak@nic.cz>
*
* \brief API for response manipulation.
*
* \addtogroup dnslib
* @{
*/
#ifndef _KNOT_DNSLIB_RESPONSE2_H_
#define _KNOT_DNSLIB_RESPONSE2_H_
#include <stdint.h>
#include <string.h>
#include "dnslib/packet.h"
#include "dnslib/dname.h"
#include "dnslib/rrset.h"
#include "dnslib/edns.h"
/*!
* \brief Default maximum DNS response size
*
* This size must be supported by all servers and clients.
*/
static const short DNSLIB_MAX_RESPONSE_SIZE = 512;
/*----------------------------------------------------------------------------*/
/*!
* \brief Initializes response from the given query.
*
* Copies the header, Changes QR bit to 1, copies the Question section and
* stores pointer to the query packet structure in the response packet
* structure.
*
* \param response Packet structure representing the response.
* \param query Packet structure representing the query.
*
* \retval DNSLIB_EOK
*/
int dnslib_packet_response_from_query(dnslib_packet_t *response,
dnslib_packet_t *query);
/*!
* \brief Sets the OPT RR of the response.
*
* This function also allocates space for the wireformat of the response, if
* the payload in the OPT RR is larger than the current maximum size of the
* response and copies the current wireformat over to the new space.
*
* \note The contents of the OPT RR are copied.
*
* \param resp Response to set the OPT RR to.
* \param opt_rr OPT RR to set.
*
* \retval DNSLIB_EOK
* \retval DNSLIB_EBADARG
* \retval DNSLIB_ENOMEM
*
* \todo Needs test.
*/
int dnslib_response_add_opt(dnslib_packet_t *resp,
const dnslib_opt_rr_t *opt_rr,
int override_max_size);
/*!
* \brief Sets the maximum size of the response and allocates space for wire
* format (if needed).
*
* This function also allocates space for the wireformat of the response, if
* the given max size is larger than the current maximum size of the response
* and copies the current wireformat over to the new space.
*
* \warning Do not call this function if you are not completely sure that the
* current wire format of the response fits into the new space.
* It does not update the current size of the wire format, so the
* produced response may be larger than the given max size.
*
* \param resp Response to set the maximum size of.
* \param max_size Maximum size of the response.
*
* \retval DNSLIB_EOK
* \retval DNSLIB_EBADARG
* \retval DNSLIB_ENOMEM
*
* \todo Needs test.
*/
int dnslib_response_set_max_size(dnslib_packet_t *resp, int max_size);
/*!
* \brief Adds a RRSet to the Answer section of the response.
*
* \param response Response to add the RRSet into.
* \param rrset RRSet to be added.
* \param tc Set to <> 0 if omitting this RRSet should result in the TC bit set.
* Otherwise set to 0.
* \param check_duplicates Set to <> 0 if the RRSet should not be added to the
* response in case it is already there.
* \param compr_cs Set to <> 0 if dname compression should use case sensitive
* comparation. Set to 0 otherwise.
*
* \retval DNSLIB_EOK if successful, or the RRSet was already in the answer.
* \retval DNSLIB_ENOMEM
* \retval DNSLIB_ESPACE
*/
int dnslib_response_add_rrset_answer(dnslib_packet_t *response,
const dnslib_rrset_t *rrset, int tc,
int check_duplicates, int compr_cs);
/*!
* \brief Adds a RRSet to the Authority section of the response.
*
* \param response Response to add the RRSet into.
* \param rrset RRSet to be added.
* \param tc Set to <> 0 if omitting this RRSet should result in the TC bit set.
* Otherwise set to 0.
* \param check_duplicates Set to <> 0 if the RRSet should not be added to the
* response in case it is already there.
* \param compr_cs Set to <> 0 if dname compression should use case sensitive
* comparation. Set to 0 otherwise.
*
* \retval DNSLIB_EOK if successful, or the RRSet was already in the answer.
* \retval DNSLIB_ENOMEM
* \retval DNSLIB_ESPACE
*/
int dnslib_response_add_rrset_authority(dnslib_packet_t *response,
const dnslib_rrset_t *rrset, int tc,
int check_duplicates, int compr_cs);
/*!
* \brief Adds a RRSet to the Additional section of the response.
*
* \param response Response to add the RRSet into.
* \param rrset RRSet to be added.
* \param tc Set to <> 0 if omitting this RRSet should result in the TC bit set.
* Otherwise set to 0.
* \param check_duplicates Set to <> 0 if the RRSet should not be added to the
* response in case it is already there.
* \param compr_cs Set to <> 0 if dname compression should use case sensitive
* comparation. Set to 0 otherwise.
*
* \retval DNSLIB_EOK if successful, or the RRSet was already in the answer.
* \retval DNSLIB_ENOMEM
* \retval DNSLIB_ESPACE
*/
int dnslib_response_add_rrset_additional(dnslib_packet_t *response,
const dnslib_rrset_t *rrset, int tc,
int check_duplicates, int compr_cs);
/*!
* \brief Sets the RCODE of the response.
*
* \param response Response to set the RCODE in.
* \param rcode RCODE to set.
*/
void dnslib_response_set_rcode(dnslib_packet_t *response, short rcode);
/*!
* \brief Sets the AA bit of the response to 1.
*
* \param response Response in which the AA bit should be set.
*/
void dnslib_response_set_aa(dnslib_packet_t *response);
/*!
* \brief Sets the TC bit of the response to 1.
*
* \param response Response in which the TC bit should be set.
*/
void dnslib_response_set_tc(dnslib_packet_t *response);
/*!
* \brief Adds RRSet to the list of temporary RRSets.
*
* Temporary RRSets are fully freed when the response structure is destroyed.
*
* \param response Response to which the temporary RRSet should be added.
* \param tmp_rrset Temporary RRSet to be stored in the response.
*
* \retval DNSLIB_EOK
* \retval DNSLIB_ENOMEM
*/
int dnslib_response_add_tmp_rrset(dnslib_packet_t *response,
dnslib_rrset_t *tmp_rrset);
/*!
* \brief Adds NSID option to the response.
*
* \param response Response to add the NSID option into.
* \param data NSID data.
* \param length Size of NSID data in bytes.
*
* \retval DNSLIB_EOK
* \retval DNSLIB_ENOMEM
*/
int dnslib_response_add_nsid(dnslib_packet_t *response, const uint8_t *data,
uint16_t length);
/*!
* \brief Converts the response to wire format.
*
* \param response Response to be converted to wire format.
* \param resp_wire Here the wire format of the response will be stored.
* Space for the response will be allocated. *resp_wire must
* be set to NULL (to avoid leaks).
* \param resp_size The size of the response in wire format will be stored here.
*
* \retval DNSLIB_EOK
* \retval DNSLIB_EBADARG
*/
int dnslib_response_to_wire(dnslib_packet_t *response,
uint8_t **resp_wire, size_t *resp_size);
#endif /* _KNOT_DNSLIB_RESPONSE2_H_ */
/*! @} */
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