Commit e0202814 authored by Jan Včelák's avatar Jan Včelák 🚀

Merge branch master into libdnssec

parents 6072b7c1 a636c6de
FROM debian:jessie
MAINTAINER Marek Vavrusa <marek.vavrusa@nic.cz>
# Select entrypoint
WORKDIR /root
CMD ["/usr/local/sbin/knotd"]
# Expose port
EXPOSE 53
# Environment
ENV THREADS 4
ENV BUILD_PKGS git-core make gcc libtool autoconf pkg-config flex bison libssl-dev liburcu-dev liblmdb-dev
ENV RUNTIME_PKGS libssl1.0.0 liburcu2 liblmdb0
# Install dependencies and sources
RUN apt-get -q -y update && \
apt-get install -q -y ${BUILD_PKGS} ${RUNTIME_PKGS} && \
# Compile sources
git clone -b master https://gitlab.labs.nic.cz/labs/knot.git /knot-src && \
cd /knot-src && \
autoreconf -if && \
./configure --disable-static && \
make -j${THREADS} && \
make install && \
ldconfig && \
# Trim down the image
cd && \
rm -rf /knot-src && \
apt-get purge -q -y ${BUILD_PKGS} && \
apt-get autoremove -q -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
......@@ -165,7 +165,7 @@ static int cmd_remote_reply(int c)
switch(ret) {
case KNOT_RCODE_NOERROR:
if (authority->count > 0) {
ret = cmd_remote_print_reply(&authority->rr[0]);
ret = cmd_remote_print_reply(knot_pkt_rr(authority, 0));
}
break;
case KNOT_RCODE_REFUSED:
......
......@@ -702,7 +702,7 @@ int remote_answer(int sock, server_t *s, knot_pkt_t *pkt)
}
const knot_pktsection_t *authority = knot_pkt_section(pkt, KNOT_AUTHORITY);
args.arg = authority->rr;
args.arg = knot_pkt_rr(authority, 0);
args.argc = authority->count;
args.rc = KNOT_RCODE_NOERROR;
......
......@@ -355,13 +355,13 @@ static int axfr_answer_packet(knot_pkt_t *pkt, struct xfr_proc *proc)
zcreator_t zc = {.z = proc->contents, .master = false, .ret = KNOT_EOK };
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
const knot_rrset_t *answer_rr = knot_pkt_rr(answer, 0);
for (uint16_t i = 0; i < answer->count; ++i) {
const knot_rrset_t *rr = &answer->rr[i];
if (rr->type == KNOT_RRTYPE_SOA &&
if (answer_rr[i].type == KNOT_RRTYPE_SOA &&
node_rrtype_exists(zc.z->apex, KNOT_RRTYPE_SOA)) {
return KNOT_NS_PROC_DONE;
} else {
int ret = zcreator_step(&zc, rr);
int ret = zcreator_step(&zc, &answer_rr[i]);
if (ret != KNOT_EOK) {
return KNOT_NS_PROC_FAIL;
}
......
......@@ -867,7 +867,8 @@ static int process_soa_answer(knot_pkt_t *pkt, struct answer_data *data)
/* Expect SOA in answer section. */
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
if (answer->count < 1 || answer->rr[0].type != KNOT_RRTYPE_SOA) {
const knot_rrset_t *first_rr = knot_pkt_rr(answer, 0);
if (answer->count < 1 || first_rr->type != KNOT_RRTYPE_SOA) {
return KNOT_NS_PROC_FAIL;
}
......@@ -880,7 +881,7 @@ static int process_soa_answer(knot_pkt_t *pkt, struct answer_data *data)
/* Check if master has newer zone and schedule transfer. */
knot_rdataset_t *soa = node_rdataset(zone->contents->apex, KNOT_RRTYPE_SOA);
uint32_t our_serial = knot_soa_serial(soa);
uint32_t their_serial = knot_soa_serial(&answer->rr[0].rrs);
uint32_t their_serial = knot_soa_serial(&first_rr->rrs);
if (serial_compare(our_serial, their_serial) >= 0) {
ANSWER_LOG(LOG_INFO, data, "refresh, outgoing", "zone is up-to-date");
zone_events_cancel(zone, ZONE_EVENT_EXPIRE);
......
......@@ -198,7 +198,7 @@ static int ixfr_query_check(struct query_data *qdata)
NS_NEED_QTYPE(qdata, KNOT_RRTYPE_IXFR, KNOT_RCODE_FORMERR);
/* Need SOA authority record. */
const knot_pktsection_t *authority = knot_pkt_section(qdata->query, KNOT_AUTHORITY);
const knot_rrset_t *their_soa = &authority->rr[0];
const knot_rrset_t *their_soa = knot_pkt_rr(authority, 0);
if (authority->count < 1 || their_soa->type != KNOT_RRTYPE_SOA) {
qdata->rcode = KNOT_RCODE_FORMERR;
return KNOT_NS_PROC_FAIL;
......@@ -242,7 +242,8 @@ static int ixfr_answer_init(struct query_data *qdata)
}
/* Compare serials. */
const knot_rrset_t *their_soa = &knot_pkt_section(qdata->query, KNOT_AUTHORITY)->rr[0];
const knot_pktsection_t *authority = knot_pkt_section(qdata->query, KNOT_AUTHORITY);
const knot_rrset_t *their_soa = knot_pkt_rr(authority, 0);
list_t chgsets;
init_list(&chgsets);
int ret = ixfr_load_chsets(&chgsets, (zone_t *)qdata->zone, their_soa);
......@@ -333,8 +334,8 @@ static bool ixfr_is_axfr(const knot_pkt_t *pkt)
{
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
return answer->count >= 2 &&
answer->rr[0].type == KNOT_RRTYPE_SOA &&
answer->rr[1].type != KNOT_RRTYPE_SOA;
knot_pkt_rr(answer, 0)->type == KNOT_RRTYPE_SOA &&
knot_pkt_rr(answer, 1)->type != KNOT_RRTYPE_SOA;
}
/*! \brief Cleans up data allocated by IXFR-in processing. */
......@@ -585,7 +586,7 @@ static int process_ixfrin_packet(knot_pkt_t *pkt, struct answer_data *adata)
return KNOT_NS_PROC_FAIL;
}
const knot_rrset_t *rr = &answer->rr[i];
const knot_rrset_t *rr = knot_pkt_rr(answer, i);
if (out_of_zone(rr, ixfr)) {
continue;
}
......@@ -675,7 +676,7 @@ static int check_format(knot_pkt_t *pkt)
{
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
if (answer->count >= 1 && answer->rr[0].type == KNOT_RRTYPE_SOA) {
if (answer->count >= 1 && knot_pkt_rr(answer, 0)->type == KNOT_RRTYPE_SOA) {
return KNOT_EOK;
} else {
return KNOT_EMALF;
......
......@@ -85,7 +85,7 @@ int notify_process_query(knot_pkt_t *pkt, struct query_data *qdata)
/* SOA RR in answer may be included, recover serial. */
const knot_pktsection_t *answer = knot_pkt_section(qdata->query, KNOT_ANSWER);
if (answer->count > 0) {
const knot_rrset_t *soa = &answer->rr[0];
const knot_rrset_t *soa = knot_pkt_rr(answer, 0);
if (soa->type == KNOT_RRTYPE_SOA) {
uint32_t serial = knot_soa_serial(&soa->rrs);
NOTIFY_QLOG(LOG_INFO, "received serial %u", serial);
......
......@@ -314,7 +314,7 @@ int tcp_master(dthread_t *thread)
/* Create big enough memory cushion. */
mm_ctx_t mm;
mm_ctx_mempool(&mm, 4 * sizeof(knot_pkt_t));
mm_ctx_mempool(&mm, 16 * MM_DEFAULT_BLKSIZE);
/* Create TCP answering context. */
tcp.server = handler->server;
......
......@@ -499,7 +499,7 @@ int udp_master(dthread_t *thread)
/* Create big enough memory cushion. */
mm_ctx_t mm;
mm_ctx_mempool(&mm, 4 * sizeof(knot_pkt_t));
mm_ctx_mempool(&mm, 16 * MM_DEFAULT_BLKSIZE);
udp.overlay.mm = &mm;
/* Chose select as epoll/kqueue has larger overhead for a
......
......@@ -892,9 +892,10 @@ int ddns_process_prereqs(const knot_pkt_t *query, zone_update_t *update,
init_list(&rrset_list);
const knot_pktsection_t *answer = knot_pkt_section(query, KNOT_ANSWER);
const knot_rrset_t *answer_rr = knot_pkt_rr(answer, 0);
for (int i = 0; i < answer->count; ++i) {
// Check what can be checked, store full RRs into list
ret = process_prereq(&answer->rr[i], knot_pkt_qclass(query),
ret = process_prereq(&answer_rr[i], knot_pkt_qclass(query),
update, rcode, &rrset_list);
if (ret != KNOT_EOK) {
rrset_list_clear(&rrset_list);
......@@ -934,10 +935,10 @@ int ddns_process_update(const zone_t *zone, const knot_pkt_t *query,
// Process all RRs in the authority section.
int apex_ns_rem = 0;
const knot_pktsection_t *authority =
knot_pkt_section(query, KNOT_AUTHORITY);
const knot_pktsection_t *authority = knot_pkt_section(query, KNOT_AUTHORITY);
const knot_rrset_t *authority_rr = knot_pkt_rr(authority, 0);
for (uint16_t i = 0; i < authority->count; ++i) {
const knot_rrset_t *rr = &authority->rr[i];
const knot_rrset_t *rr = &authority_rr[i];
// Check if RR is correct.
int ret = check_update(rr, query, rcode);
if (ret != KNOT_EOK) {
......
......@@ -119,7 +119,7 @@ void zone_update_init(zone_update_t *update, const zone_contents_t *zone, change
{
update->zone = zone;
update->change = change;
mm_ctx_mempool(&update->mm, 4096);
mm_ctx_mempool(&update->mm, MM_DEFAULT_BLKSIZE);
}
const zone_node_t *zone_update_get_node(zone_update_t *update, const knot_dname_t *dname)
......
......@@ -315,12 +315,16 @@ bool zone_transfer_needed(const zone_t *zone, const knot_pkt_t *pkt)
}
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
const knot_rrset_t soa = answer->rr[0];
if (soa.type != KNOT_RRTYPE_SOA) {
if (answer->count < 1) {
return false;
}
const knot_rrset_t *soa = knot_pkt_rr(answer, 0);
if (soa->type != KNOT_RRTYPE_SOA) {
return false;
}
return serial_compare(zone_contents_serial(zone->contents),
knot_soa_serial(&soa.rrs)) < 0;
knot_soa_serial(&soa->rrs)) < 0;
}
......@@ -114,6 +114,9 @@ static const error_table_t error_messages[] = {
{ KNOT_DNSSEC_ENOKEY, "no keys for signing" },
{ KNOT_DNSSEC_EMISSINGKEYTYPE, "missing active KSK or ZSK" },
/* Processing errors. */
{ KNOT_LAYER_ERROR, "processing layer error" },
{ KNOT_ERROR, NULL } /* Terminator */
};
......
......@@ -120,6 +120,9 @@ enum knot_error {
KNOT_DNSSEC_EMISSINGKEYTYPE,
KNOT_DNSSEC_ENOKEY,
/* Processing error. */
KNOT_LAYER_ERROR,
KNOT_ERROR_MAX = -501
};
......
......@@ -396,11 +396,21 @@ static int insert(namedb_txn_t *txn, namedb_val_t *key, namedb_val_t *val, unsig
MDB_val db_key = { key->len, key->data };
MDB_val data = { val->len, val->data };
int ret = mdb_put(txn->txn, env->dbi, &db_key, &data, 0);
/* Reserve if only size is declared. */
unsigned mdb_flags = 0;
if (val->len > 0 && val->data == NULL) {
mdb_flags |= MDB_RESERVE;
}
int ret = mdb_put(txn->txn, env->dbi, &db_key, &data, mdb_flags);
if (ret != MDB_SUCCESS) {
return lmdb_error_to_knot(ret);
}
/* Update the result. */
val->data = data.mv_data;
val->len = data.mv_size;
return KNOT_EOK;
}
......
......@@ -92,6 +92,11 @@ static int find(namedb_txn_t *txn, namedb_val_t *key, namedb_val_t *val, unsigne
static int insert(namedb_txn_t *txn, namedb_val_t *key, namedb_val_t *val, unsigned flags)
{
/* No flags supported. */
if (flags != 0) {
return KNOT_ENOTSUP;
}
value_t *ret = hattrie_get((hattrie_t *)txn->db, key->data, key->len);
if (ret == NULL) {
return KNOT_ENOMEM;
......
......@@ -15,6 +15,7 @@
*/
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
......@@ -169,7 +170,7 @@ int net_is_connected(int fd)
}
/*! \brief Wait for data and return true if data arrived. */
static int tcp_wait_for_data(int fd, struct timeval *timeout)
static int wait_for_data(int fd, struct timeval *timeout)
{
fd_set set;
FD_ZERO(&set);
......@@ -178,11 +179,11 @@ static int tcp_wait_for_data(int fd, struct timeval *timeout)
}
/* \brief Receive a block of data from TCP socket with wait. */
static int tcp_recv_data(int fd, uint8_t *buf, int len, struct timeval *timeout)
static int recv_data(int fd, uint8_t *buf, int len, bool oneshot, struct timeval *timeout)
{
int ret = 0;
int rcvd = 0;
int flags = 0;
int flags = MSG_DONTWAIT;
#ifdef MSG_NOSIGNAL
flags |= MSG_NOSIGNAL;
......@@ -193,7 +194,12 @@ static int tcp_recv_data(int fd, uint8_t *buf, int len, struct timeval *timeout)
ret = recv(fd, buf + rcvd, len - rcvd, flags);
if (ret > 0) {
rcvd += ret;
continue;
/* One-shot recv() */
if (oneshot) {
return ret;
} else {
continue;
}
}
/* Check for disconnected socket. */
if (ret == 0) {
......@@ -203,7 +209,7 @@ static int tcp_recv_data(int fd, uint8_t *buf, int len, struct timeval *timeout)
/* Check for no data available. */
if (errno == EAGAIN || errno == EINTR) {
/* Continue only if timeout didn't expire. */
ret = tcp_wait_for_data(fd, timeout);
ret = wait_for_data(fd, timeout);
if (ret) {
continue;
} else {
......@@ -217,8 +223,7 @@ static int tcp_recv_data(int fd, uint8_t *buf, int len, struct timeval *timeout)
return rcvd;
}
int udp_send_msg(int fd, const uint8_t *msg, size_t msglen,
const struct sockaddr *addr)
int udp_send_msg(int fd, const uint8_t *msg, size_t msglen, const struct sockaddr *addr)
{
socklen_t addr_len = sockaddr_len(addr);
int ret = sendto(fd, msg, msglen, 0, addr, addr_len);
......@@ -229,15 +234,9 @@ int udp_send_msg(int fd, const uint8_t *msg, size_t msglen,
return ret;
}
int udp_recv_msg(int fd, uint8_t *buf, size_t len, struct sockaddr *addr)
int udp_recv_msg(int fd, uint8_t *buf, size_t len, struct timeval *timeout)
{
socklen_t addr_len = sizeof(struct sockaddr_storage);
int ret = recvfrom(fd, buf, len, 0, addr, &addr_len);
if (ret < 0) {
return KNOT_ECONN;
}
return ret;
return recv_data(fd, buf, len, true, timeout);
}
int tcp_send_msg(int fd, const uint8_t *msg, size_t msglen)
......@@ -268,7 +267,7 @@ int tcp_recv_msg(int fd, uint8_t *buf, size_t len, struct timeval *timeout)
/* Receive size. */
unsigned short pktsize = 0;
int ret = tcp_recv_data(fd, (uint8_t *)&pktsize, sizeof(pktsize), timeout);
int ret = recv_data(fd, (uint8_t *)&pktsize, sizeof(pktsize), false, timeout);
if (ret != sizeof(pktsize)) {
return ret;
}
......@@ -281,10 +280,5 @@ int tcp_recv_msg(int fd, uint8_t *buf, size_t len, struct timeval *timeout)
}
/* Receive payload. */
ret = tcp_recv_data(fd, buf, pktsize, timeout);
if (ret != pktsize) {
return ret;
}
return ret;
return recv_data(fd, buf, pktsize, false, timeout);
}
......@@ -78,32 +78,31 @@ int net_connected_socket(int type, const struct sockaddr_storage *dst_addr,
int net_is_connected(int fd);
/*!
* \brief Send a UDP message.
* \brief Send a UDP message over connected socket.
*
* \param fd Associated socket.
* \param msg Buffer for a query wireformat.
* \param msglen Buffer maximum size.
* \param addr Destination address.
* \param addr Destination address (or NULL if connected).
*
* \retval Number of sent data on success.
* \retval KNOT_ERROR on error.
*/
int udp_send_msg(int fd, const uint8_t *msg, size_t msglen,
const struct sockaddr *addr);
int udp_send_msg(int fd, const uint8_t *msg, size_t msglen, const struct sockaddr *addr);
/*!
* \brief Receive a UDP message.
* \brief Receive a UDP message from connected socket.
*
* \param fd Associated socket.
* \param buf Buffer for incoming bytestream.
* \param len Buffer maximum size.
* \param addr Source address.
* \param timeout Message receive timeout.
*
* \retval Number of read bytes on success.
* \retval KNOT_ERROR on error.
* \retval KNOT_ENOMEM on potential buffer overflow.
*/
int udp_recv_msg(int fd, uint8_t *buf, size_t len, struct sockaddr *addr);
int udp_recv_msg(int fd, uint8_t *buf, size_t len, struct timeval *timeout);
/*!
* \brief Send a TCP message.
......
......@@ -25,6 +25,10 @@
int sockaddr_len(const struct sockaddr *ss)
{
if (ss == NULL) {
return 0;
}
const struct sockaddr_storage *sa = (const struct sockaddr_storage *)ss;
switch(sa->ss_family) {
case AF_INET:
......
......@@ -27,6 +27,10 @@
#include "libknot/packet/rrset-wire.h"
#include "libknot/internal/macros.h"
/*! \brief Packet RR array growth step. */
#define NEXT_RR_ALIGN 16
#define NEXT_RR_COUNT(count) (((count) / NEXT_RR_ALIGN + 1) * NEXT_RR_ALIGN)
/*! \brief Scan packet for RRSet existence. */
static bool pkt_contains(const knot_pkt_t *packet,
const knot_rrset_t *rrset)
......@@ -124,6 +128,41 @@ static void pkt_rr_wirecount_add(knot_pkt_t *pkt, knot_section_t section_id,
}
}
/*! \brief Reserve enough space in the RR arrays. */
static int pkt_rr_array_alloc(knot_pkt_t *pkt, uint16_t count)
{
/* Enough space. */
if (pkt->rrset_allocd >= count) {
return KNOT_EOK;
}
/* Allocate rr_info and rr fields to next size. */
size_t next_size = NEXT_RR_COUNT(count);
knot_rrinfo_t *rr_info = mm_alloc(&pkt->mm, sizeof(knot_rrinfo_t) * next_size);
if (rr_info == NULL) {
return KNOT_ENOMEM;
}
knot_rrset_t *rr = mm_alloc(&pkt->mm, sizeof(knot_rrset_t) * next_size);
if (rr == NULL) {
mm_free(&pkt->mm, rr_info);
return KNOT_ENOMEM;
}
/* Copy the old data. */
memcpy(rr_info, pkt->rr_info, pkt->rrset_allocd * sizeof(knot_rrinfo_t));
memcpy(rr, pkt->rr, pkt->rrset_allocd * sizeof(knot_rrset_t));
/* Reassign and free old data. */
mm_free(&pkt->mm, pkt->rr);
mm_free(&pkt->mm, pkt->rr_info);
pkt->rr = rr;
pkt->rr_info = rr_info;
pkt->rrset_allocd = next_size;
return KNOT_EOK;
}
/*! \brief Clear the packet and switch wireformat pointers (possibly allocate new). */
static int pkt_reset(knot_pkt_t *pkt, void *wire, uint16_t len)
{
......@@ -131,14 +170,12 @@ static int pkt_reset(knot_pkt_t *pkt, void *wire, uint16_t len)
/* Free allocated data. */
pkt_free_data(pkt);
/* NULL everything up to 'sections' (not the large data fields). */
int ret = KNOT_EOK;
mm_ctx_t mm = pkt->mm;
memset(pkt, 0, offsetof(knot_pkt_t, rr_info));
memset(pkt, 0, sizeof(knot_pkt_t));
pkt->mm = mm;
/* Initialize wire. */
int ret = KNOT_EOK;
if (wire == NULL) {
ret = pkt_wire_alloc(pkt, len);
} else {
......@@ -185,9 +222,9 @@ static knot_pkt_t *pkt_new_mm(void *wire, uint16_t len, mm_ctx_t *mm)
if (pkt == NULL) {
return NULL;
}
memset(pkt, 0, sizeof(knot_pkt_t));
/* No data to free, set memory context. */
pkt->rrset_count = 0;
memcpy(&pkt->mm, mm, sizeof(mm_ctx_t));
if (pkt_reset(pkt, wire, len) != KNOT_EOK) {
mm_free(mm, pkt);
......@@ -233,6 +270,12 @@ int knot_pkt_copy(knot_pkt_t *dst, const knot_pkt_t *src)
}
}
/* Invalidate arrays . */
dst->rr = NULL;
dst->rr_info = NULL;
dst->rrset_count = 0;
dst->rrset_allocd = 0;
/* @note This could be done more effectively if needed. */
return knot_pkt_parse(dst, 0);
}
......@@ -291,6 +334,10 @@ void knot_pkt_free(knot_pkt_t **pkt)
/* Free temporary RRSets. */
pkt_free_data(*pkt);
/* Free RR/RR info arrays. */
mm_free(&(*pkt)->mm, (*pkt)->rr);
mm_free(&(*pkt)->mm, (*pkt)->rr_info);
// free the space for wireformat
if ((*pkt)->flags & KNOT_PF_FREE) {
(*pkt)->mm.free((*pkt)->wire);
......@@ -423,8 +470,9 @@ int knot_pkt_begin(knot_pkt_t *pkt, knot_section_t section_id)
pkt->current = section_id;
/* Remember watermark. */
pkt->sections[section_id].rr = pkt->rr + pkt->rrset_count;
pkt->sections[section_id].rrinfo = pkt->rr_info + pkt->rrset_count;
pkt->sections[section_id].pkt = pkt;
pkt->sections[section_id].pos = pkt->rrset_count;
return KNOT_EOK;
}
......@@ -474,12 +522,18 @@ int knot_pkt_put(knot_pkt_t *pkt, uint16_t compr_hint, const knot_rrset_t *rr,
return KNOT_EINVAL;
}
/* Reserve memory for RR descriptors. */
int ret = pkt_rr_array_alloc(pkt, pkt->rrset_count + 1);
if (ret != KNOT_EOK) {
return ret;
}
knot_rrinfo_t *rrinfo = &pkt->rr_info[pkt->rrset_count];
memset(rrinfo, 0, sizeof(knot_rrinfo_t));
rrinfo->pos = pkt->size;
rrinfo->flags = flags;
rrinfo->compress_ptr[0] = compr_hint;
pkt->rr[pkt->rrset_count] = *rr;
memcpy(pkt->rr + pkt->rrset_count, rr, sizeof(knot_rrset_t));
/* Check for double insertion. */
if ((flags & KNOT_PF_CHECKDUP) &&
......@@ -499,7 +553,7 @@ int knot_pkt_put(knot_pkt_t *pkt, uint16_t compr_hint, const knot_rrset_t *rr,
compr.wire);
/* Write RRSet to wireformat. */
int ret = knot_rrset_to_wire(rr, pos, maxlen, &compr);
ret = knot_rrset_to_wire(rr, pos, maxlen, &compr);
if (ret < 0) {
/* Truncate packet if required. */
if (ret == KNOT_ESPACE && !(flags & KNOT_PF_NOTRUNC)) {
......@@ -537,6 +591,16 @@ const knot_pktsection_t *knot_pkt_section(const knot_pkt_t *pkt,
return &pkt->sections[section_id];
}
_public_
const knot_rrset_t *knot_pkt_rr(const knot_pktsection_t *section, uint16_t i)
{
if (section == NULL) {
return NULL;
}
return section->pkt->rr + section->pos + i;
}
_public_
int knot_pkt_parse(knot_pkt_t *pkt, unsigned flags)
{
......@@ -656,8 +720,13 @@ int knot_pkt_parse_rr(knot_pkt_t *pkt, unsigned flags)
return KNOT_EFEWDATA;
}
/* Reserve memory for RR descriptors. */
int ret = pkt_rr_array_alloc(pkt, pkt->rrset_count + 1);
if (ret != KNOT_EOK) {
return ret;
}
/* Initialize RR info. */
int ret = KNOT_EOK;
memset(&pkt->rr_info[pkt->rrset_count], 0, sizeof(knot_rrinfo_t));
pkt->rr_info[pkt->rrset_count].pos = pkt->parsed;
pkt->rr_info[pkt->rrset_count].flags = KNOT_PF_FREE;
......@@ -714,7 +783,14 @@ int knot_pkt_parse_payload(knot_pkt_t *pkt, unsigned flags)
assert(pkt->wire != NULL);
assert(pkt->size > 0);
int ret = KNOT_ERROR;
/* Reserve memory in advance to avoid resizing. */
size_t rr_count = knot_wire_get_ancount(pkt->wire) +
knot_wire_get_nscount(pkt->wire) +
knot_wire_get_arcount(pkt->wire);
int ret = pkt_rr_array_alloc(pkt, rr_count);
if (ret != KNOT_EOK) {
return ret;
}
for (knot_section_t i = KNOT_ANSWER; i <= KNOT_ADDITIONAL; ++i) {
ret = knot_pkt_begin(pkt, i);
......@@ -730,7 +806,8 @@ int knot_pkt_parse_payload(knot_pkt_t *pkt, unsigned flags)
/* TSIG must be last record of AR if present. */
const knot_pktsection_t *ar = knot_pkt_section(pkt, KNOT_ADDITIONAL);
if (pkt->tsig_rr != NULL) {
if (ar->count > 0 && pkt->tsig_rr->rrs.data != ar->rr[ar->count - 1].rrs.data) {
const knot_rrset_t *last_rr = knot_pkt_rr(ar, ar->count - 1);
if (ar->count > 0 && pkt->tsig_rr->rrs.data != last_rr->rrs.data) {
return KNOT_EMALF;
}
}
......
......@@ -39,8 +39,8 @@
/* Number of packet sections (ANSWER, AUTHORITY, ADDITIONAL). */
#define KNOT_PKT_SECTIONS 3
/* Number of maximum RRs in packet. */
#define KNOT_PKT_MAX_RRS (KNOT_WIRE_MAX_PAYLOAD / KNOT_WIRE_RR_MIN_SIZE)
/* Forward decls */
struct knot_pkt;
/*!
* \brief DNS query types (internal use only).
......@@ -80,9 +80,9 @@ enum {
* This structure is required for random access to packet sections.
*/
typedef struct {
const knot_rrset_t *rr; /*!< Array of RRSets for this section. */
knot_rrinfo_t *rrinfo; /*!< Compression info for each RRSet. */
uint16_t count; /*!< Number of RRSets in this section. */
struct knot_pkt *pkt; /*!< Owner. */
uint16_t pos; /*!< Position in the rr/rrinfo fields in packet. */
uint16_t count; /*!< Number of RRSets in this section. */
} knot_pktsection_t;
/*!
......@@ -106,11 +106,10 @@ typedef struct knot_pkt {
knot_section_t current;
knot_pktsection_t sections[KNOT_PKT_SECTIONS];
/*! \note <== Memory below this point is not cleared on init for performance reasons. */
/* Packet RRSet (meta)data. */
knot_rrinfo_t rr_info[KNOT_PKT_MAX_RRS];
knot_rrset_t rr[KNOT_PKT_MAX_RRS];
size_t rrset_allocd;
knot_rrinfo_t *rr_info;
knot_rrset_t *rr;
mm_ctx_t mm; /*!< Memory allocation context. */
} knot_pkt_t;
......@@ -244,6 +243,8 @@ int knot_pkt_put(knot_pkt_t *pkt, uint16_t compr_hint, const knot_rrset_t *rr,
const knot_pktsection_t *knot_pkt_section(const knot_pkt_t *pkt,
knot_section_t section_id);
/*! \brief Get RRSet from the packet section. */
const knot_rrset_t *knot_pkt_rr(const knot_pktsection_t *section, uint16_t i);
/*
* Packet parsing API.
*/
......
......@@ -40,41 +40,28 @@ static struct knot_request *request_make(mm_ctx_t *mm)
return request;
}
/*! \brief Wait for socket readiness. */
static int request_wait(int fd, int state, struct timeval *timeout)
/*! \brief Ensure a socket is connected. */
static int request_ensure_connected(struct knot_request *request)
{
fd_set set;
FD_ZERO(&set);
FD_SET(fd, &set);
switch(state) {
case KNOT_NS_PROC_FULL: /* Wait for writeability. */
return select(fd + 1, NULL, &set, NULL, timeout);
case KNOT_NS_PROC_MORE: /* Wait for data. */
return select(fd + 1, &set, NULL, NULL, timeout);
default:
return -1;
/* Connect the socket if not already connected. */
if (request->fd < 0) {
int sock_type = use_tcp(request) ? SOCK_STREAM : SOCK_DGRAM;
request->fd = net_connected_socket(sock_type, &request->remote, &request->origin, 0);
if (request->fd < 0) {
return KNOT_ECONN;
}
}
return KNOT_EOK;
}
static int request_send(struct knot_request *request,
const struct timeval *timeout)
{
/* Each request has unique timeout. */
struct timeval tv = { timeout->tv_sec, timeout->tv_usec };
/* Wait for writeability or error. */
int ret = request_wait(request->fd, KNOT_NS_PROC_FULL, &tv);