1
0
Fork 0
knot/tests/libknot/test_pkt.c
Daniel Baumann 70063ca008
Adding upstream version 3.4.6.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-21 13:47:52 +02:00

199 lines
5.9 KiB
C

/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <tap/basic.h>
#include "libknot/libknot.h"
#include "libknot/packet/pkt.c"
#include "contrib/ucw/mempool.h"
#define TTL 7200
#define NAMECOUNT 3
#define DATACOUNT 3
const char *g_names[NAMECOUNT] = {
"example.com",
"ns1.example.com",
"ns2.example.com"
};
const char *g_rdata[DATACOUNT] = {
"\x04" "\xc2\x0c\x00\x01", /* 4B, 194.0.12.1" */
"\x11" "\x03""ns1""\x07""example""\x03""com""\x00", /* domain name */
"\x11" "\x03""ns2""\x07""example""\x03""com""\x00", /* domain name */
};
#define RDVAL(i) ((const uint8_t*)(g_rdata[(i)] + 1))
#define RDLEN(i) ((uint16_t)(g_rdata[(i)][0]))
/* @note Packet equivalence test, 5 checks. */
static void packet_match(knot_pkt_t *in, knot_pkt_t *out)
{
assert(in);
assert(out);
/* Check counts */
is_int(knot_wire_get_qdcount(out->wire),
knot_wire_get_qdcount(in->wire), "pkt: QD match");
is_int(knot_wire_get_ancount(out->wire),
knot_wire_get_ancount(in->wire), "pkt: AN match");
is_int(knot_wire_get_nscount(out->wire),
knot_wire_get_nscount(in->wire), "pkt: NS match");
is_int(knot_wire_get_arcount(out->wire),
knot_wire_get_arcount(in->wire), "pkt: AR match");
/* Check RRs */
int rr_matched = 0;
for (unsigned i = 0; i < NAMECOUNT; ++i) {
if (knot_rrset_equal(&out->rr[i], &in->rr[i], true) > 0) {
++rr_matched;
}
}
is_int(NAMECOUNT, rr_matched, "pkt: RR content match");
}
int main(int argc, char *argv[])
{
plan_lazy();
/* Create memory pool context. */
int ret = 0;
knot_mm_t mm;
mm_ctx_mempool(&mm, MM_DEFAULT_BLKSIZE);
/* Create names and data. */
knot_dname_t* dnames[NAMECOUNT] = {0};
knot_rrset_t* rrsets[NAMECOUNT] = {0};
for (unsigned i = 0; i < NAMECOUNT; ++i) {
dnames[i] = knot_dname_from_str_alloc(g_names[i]);
}
uint8_t *edns_str = (uint8_t *)"ab";
/* Create OPT RR. */
knot_rrset_t opt_rr = { 0 };
ret = knot_edns_init(&opt_rr, 1024, 0, 0, &mm);
is_int(KNOT_EOK, ret, "initialize OPT RR");
/* Add NSID */
ret = knot_edns_add_option(&opt_rr, KNOT_EDNS_OPTION_NSID,
strlen((char *)edns_str), edns_str, &mm);
is_int(KNOT_EOK, ret, "initialize NSID in OPT RR");
/*
* Packet writer tests.
*/
/* Create packet. */
knot_pkt_t *out = knot_pkt_new(NULL, MM_DEFAULT_BLKSIZE, &mm);
ok(out != NULL, "pkt: new");
assert(out);
/* Mark as response (not part of the test). */
knot_wire_set_qr(out->wire);
/* Secure packet. */
const char *tsig_secret = "abcd";
knot_tsig_key_t tsig_key;
tsig_key.algorithm = DNSSEC_TSIG_HMAC_MD5;
tsig_key.name = dnames[0];
tsig_key.secret.data = (uint8_t *)strdup(tsig_secret);
tsig_key.secret.size = strlen(tsig_secret);
ret = knot_pkt_reserve(out, knot_tsig_wire_size(&tsig_key));
is_int(KNOT_EOK, ret, "pkt: set TSIG key");
/* Write question. */
ret = knot_pkt_put_question(out, dnames[0], KNOT_CLASS_IN, KNOT_RRTYPE_A);
is_int(KNOT_EOK, ret, "pkt: put question");
/* Add OPT to packet (empty NSID). */
ret = knot_pkt_reserve(out, knot_edns_wire_size(&opt_rr));
is_int(KNOT_EOK, ret, "pkt: reserve OPT RR");
/* Begin ANSWER section. */
ret = knot_pkt_begin(out, KNOT_ANSWER);
is_int(KNOT_EOK, ret, "pkt: begin ANSWER");
/* Write ANSWER section. */
rrsets[0] = knot_rrset_new(dnames[0], KNOT_RRTYPE_A, KNOT_CLASS_IN, TTL, NULL);
knot_dname_free(dnames[0], NULL);
knot_rrset_add_rdata(rrsets[0], RDVAL(0), RDLEN(0), NULL);
ret = knot_pkt_put(out, KNOT_COMPR_HINT_QNAME, rrsets[0], 0);
is_int(KNOT_EOK, ret, "pkt: write ANSWER");
/* Begin AUTHORITY. */
ret = knot_pkt_begin(out, KNOT_AUTHORITY);
is_int(KNOT_EOK, ret, "pkt: begin AUTHORITY");
/* Write rest to AUTHORITY. */
ret = KNOT_EOK;
for (unsigned i = 1; i < NAMECOUNT; ++i) {
rrsets[i] = knot_rrset_new(dnames[i], KNOT_RRTYPE_NS, KNOT_CLASS_IN, TTL, NULL);
knot_dname_free(dnames[i], NULL);
knot_rrset_add_rdata(rrsets[i], RDVAL(i), RDLEN(i), NULL);
ret |= knot_pkt_put(out, KNOT_COMPR_HINT_NONE, rrsets[i], 0);
}
is_int(KNOT_EOK, ret, "pkt: write AUTHORITY(%u)", NAMECOUNT - 1);
/* Begin ADDITIONALS */
ret = knot_pkt_begin(out, KNOT_ADDITIONAL);
is_int(KNOT_EOK, ret, "pkt: begin ADDITIONALS");
/* Encode OPT RR. */
ret = knot_pkt_put(out, KNOT_COMPR_HINT_NONE, &opt_rr, 0);
is_int(KNOT_EOK, ret, "pkt: write OPT RR");
/*
* Packet reader tests.
*/
/* Create new packet from query packet. */
knot_pkt_t *in = knot_pkt_new(out->wire, out->size, &out->mm);
ok(in != NULL, "pkt: create packet for parsing");
/* Read packet header. */
ret = knot_pkt_parse_question(in);
is_int(KNOT_EOK, ret, "pkt: read header");
/* Read packet payload. */
ret = parse_payload(in, 0);
is_int(KNOT_EOK, ret, "pkt: read payload");
/* Compare parsed packet to written packet. */
packet_match(in, out);
/*
* Copied packet tests.
*/
knot_pkt_t *copy = knot_pkt_new(NULL, in->max_size, &in->mm);
ret = knot_pkt_copy(copy, in);
is_int(KNOT_EOK, ret, "pkt: create packet copy");
/* Compare copied packet to original. */
packet_match(in, copy);
/* Free packets. */
knot_pkt_free(copy);
knot_pkt_free(out);
knot_pkt_free(in);
/* Free extra data. */
for (unsigned i = 0; i < NAMECOUNT; ++i) {
knot_rrset_free(rrsets[i], NULL);
}
free(tsig_key.secret.data);
mp_delete((struct mempool *)mm.ctx);
return 0;
}