- Merge EDNS Client subnet implementation from feature branch into main branch,

using new EDNS processing framework.


git-svn-id: file:///svn/unbound/trunk@4074 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Ralph Dolmans
2017-03-21 12:08:17 +00:00
parent 80029d63f0
commit b0fd814975
51 changed files with 7517 additions and 3089 deletions
+6 -1
View File
@@ -1070,8 +1070,13 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
sldns_buffer_write_u16(pend->buffer, qinfo->qclass);
sldns_buffer_flip(pend->buffer);
if(1) {
/* add edns */
struct edns_data edns;
if(!inplace_cb_query_call(env, qinfo, flags, addr, addrlen,
zone, zonelen, qstate, qstate->region)) {
free(pend);
return NULL;
}
/* add edns */
edns.edns_present = 1;
edns.ext_rcode = 0;
edns.edns_version = EDNS_ADVERTISED_VERSION;
+10
View File
@@ -77,6 +77,7 @@ testbound_usage(void)
printf("-2 detect SHA256 support (exit code 0 or 1)\n");
printf("-g detect GOST support (exit code 0 or 1)\n");
printf("-e detect ECDSA support (exit code 0 or 1)\n");
printf("-c detect CLIENT_SUBNET support (exit code 0 or 1)\n");
printf("-s testbound self-test - unit test of testbound parts.\n");
printf("-o str unbound commandline options separated by spaces.\n");
printf("Version %s\n", PACKAGE_VERSION);
@@ -325,6 +326,15 @@ main(int argc, char* argv[])
#else
printf("GOST not supported\n");
exit(1);
#endif
break;
case 'c':
#ifdef CLIENT_SUBNET
printf("CLIENT_SUBNET supported\n");
exit(0);
#else
printf("CLIENT_SUBNET not supported\n");
exit(1);
#endif
break;
case 'p':
+109 -16
View File
@@ -98,6 +98,7 @@ entry_add_reply(struct entry* entry)
pkt->packet_sleep = 0;
pkt->reply_pkt = NULL;
pkt->reply_from_hex = NULL;
pkt->raw_ednsdata = NULL;
/* link at end */
while(*p)
p = &((*p)->next);
@@ -134,6 +135,8 @@ static void matchline(char* line, struct entry* e)
e->match_do = 1;
} else if(str_keyword(&parse, "noedns")) {
e->match_noedns = 1;
} else if(str_keyword(&parse, "ednsdata")) {
e->match_ednsdata_raw = 1;
} else if(str_keyword(&parse, "UDP")) {
e->match_transport = transport_udp;
} else if(str_keyword(&parse, "TCP")) {
@@ -230,6 +233,8 @@ static void adjustline(char* line, struct entry* e,
e->copy_id = 1;
} else if(str_keyword(&parse, "copy_query")) {
e->copy_query = 1;
} else if(str_keyword(&parse, "copy_ednsdata_assume_clientsubnet")) {
e->copy_ednsdata_assume_clientsubnet = 1;
} else if(str_keyword(&parse, "sleep=")) {
e->sleeptime = (unsigned int) strtol(parse, (char**)&parse, 10);
while(isspace((unsigned char)*parse))
@@ -267,6 +272,7 @@ static struct entry* new_entry(void)
e->reply_list = NULL;
e->copy_id = 0;
e->copy_query = 0;
e->copy_ednsdata_assume_clientsubnet = 0;
e->sleeptime = 0;
e->next = NULL;
return e;
@@ -484,25 +490,28 @@ static void add_rr(char* rrstr, uint8_t* pktbuf, size_t pktsize,
else error("internal error bad section %d", (int)add_section);
}
/* add EDNS 4096 DO opt record */
/* add EDNS 4096 opt record */
static void
add_do_flag(uint8_t* pktbuf, size_t pktsize, size_t* pktlen)
add_edns(uint8_t* pktbuf, size_t pktsize, int do_flag, uint8_t *ednsdata,
uint16_t ednslen, size_t* pktlen)
{
uint8_t edns[] = {0x00, /* root label */
0x00, LDNS_RR_TYPE_OPT, /* type */
0x10, 0x00, /* class is UDPSIZE 4096 */
0x00, /* TTL[0] is ext rcode */
0x00, /* TTL[1] is edns version */
0x80, 0x00, /* TTL[2-3] is edns flags, DO */
0x00, 0x00 /* rdatalength (0 options) */
(uint8_t)(do_flag?0x80:0x00), 0x00, /* TTL[2-3] is edns flags, DO */
(uint8_t)((ednslen >> 8) & 0xff),
(uint8_t)(ednslen & 0xff), /* rdatalength */
};
if(*pktlen < LDNS_HEADER_SIZE)
return;
if(*pktlen + sizeof(edns) > pktsize)
if(*pktlen + sizeof(edns) + ednslen > pktsize)
error("not enough space for EDNS OPT record");
memmove(pktbuf+*pktlen, edns, sizeof(edns));
memmove(pktbuf+*pktlen+sizeof(edns), ednsdata, ednslen);
sldns_write_uint16(pktbuf+10, LDNS_ARCOUNT(pktbuf)+1);
*pktlen += sizeof(edns);
*pktlen += (sizeof(edns) + ednslen);
}
/* Reads one entry from file. Returns entry or NULL on error. */
@@ -516,7 +525,9 @@ read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate,
sldns_pkt_section add_section = LDNS_SECTION_QUESTION;
struct reply_packet *cur_reply = NULL;
int reading_hex = 0;
int reading_hex_ednsdata = 0;
sldns_buffer* hex_data_buffer = NULL;
sldns_buffer* hex_ednsdata_buffer = NULL;
uint8_t pktbuf[MAX_PACKETLEN];
size_t pktlen = LDNS_HEADER_SIZE;
int do_flag = 0; /* DO flag in EDNS */
@@ -583,21 +594,45 @@ read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate,
cur_reply->reply_from_hex = hex_buffer2wire(hex_data_buffer);
sldns_buffer_free(hex_data_buffer);
hex_data_buffer = NULL;
} else if(reading_hex) {
sldns_buffer_printf(hex_data_buffer, "%s", line);
} else if(str_keyword(&parse, "HEX_EDNSDATA_BEGIN")) {
hex_ednsdata_buffer = sldns_buffer_new(MAX_PACKETLEN);
reading_hex_ednsdata = 1;
} else if(str_keyword(&parse, "HEX_EDNSDATA_END")) {
if (!reading_hex_ednsdata) {
error("%s line %d: HEX_EDNSDATA_END read but no"
"HEX_EDNSDATA_BEGIN keyword seen", name, pstate->lineno);
}
reading_hex_ednsdata = 0;
cur_reply->raw_ednsdata = hex_buffer2wire(hex_ednsdata_buffer);
sldns_buffer_free(hex_ednsdata_buffer);
hex_ednsdata_buffer = NULL;
} else if(reading_hex_ednsdata) {
sldns_buffer_printf(hex_ednsdata_buffer, "%s", line);
} else if(str_keyword(&parse, "ENTRY_END")) {
if(hex_data_buffer)
sldns_buffer_free(hex_data_buffer);
if(hex_ednsdata_buffer)
sldns_buffer_free(hex_ednsdata_buffer);
if(pktlen != 0) {
if(do_flag)
add_do_flag(pktbuf, sizeof(pktbuf),
&pktlen);
if(do_flag || cur_reply->raw_ednsdata) {
if(cur_reply->raw_ednsdata &&
sldns_buffer_limit(cur_reply->raw_ednsdata))
add_edns(pktbuf, sizeof(pktbuf), do_flag,
sldns_buffer_begin(cur_reply->raw_ednsdata),
(uint16_t)sldns_buffer_limit(cur_reply->raw_ednsdata),
&pktlen);
else
add_edns(pktbuf, sizeof(pktbuf), do_flag,
NULL, 0, &pktlen);
}
cur_reply->reply_pkt = memdup(pktbuf, pktlen);
cur_reply->reply_len = pktlen;
if(!cur_reply->reply_pkt)
error("out of memory");
}
return current;
} else if(reading_hex) {
sldns_buffer_printf(hex_data_buffer, "%s", line);
} else {
add_rr(skip_whitespace?parse:line, pktbuf,
sizeof(pktbuf), &pktlen, pstate, add_section,
@@ -605,10 +640,14 @@ read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate,
}
}
if (reading_hex) {
if(reading_hex) {
error("%s: End of file reached while still reading hex, "
"missing HEX_ANSWER_END\n", name);
}
if(reading_hex_ednsdata) {
error("%s: End of file reached while still reading edns data, "
"missing HEX_EDNSDATA_END\n", name);
}
if(current) {
error("%s: End of file reached while reading entry. "
"missing ENTRY_END\n", name);
@@ -778,16 +817,16 @@ pkt_find_edns_opt(uint8_t** p, size_t* plen)
wlen -= LDNS_HEADER_SIZE;
/* skip other records with wire2str_scan */
for(i=0; i < LDNS_QDCOUNT(p); i++)
for(i=0; i < LDNS_QDCOUNT(*p); i++)
(void)sldns_wire2str_rrquestion_scan(&w, &wlen, &snull, &sl,
*p, *plen);
for(i=0; i < LDNS_ANCOUNT(p); i++)
for(i=0; i < LDNS_ANCOUNT(*p); i++)
(void)sldns_wire2str_rr_scan(&w, &wlen, &snull, &sl, *p, *plen);
for(i=0; i < LDNS_NSCOUNT(p); i++)
for(i=0; i < LDNS_NSCOUNT(*p); i++)
(void)sldns_wire2str_rr_scan(&w, &wlen, &snull, &sl, *p, *plen);
/* walk through additional section */
for(i=0; i < LDNS_ARCOUNT(p); i++) {
for(i=0; i < LDNS_ARCOUNT(*p); i++) {
/* if this is OPT then done */
uint8_t* dstart = w;
size_t dlen = wlen;
@@ -1338,6 +1377,31 @@ static int subdomain_dname(uint8_t* q, size_t qlen, uint8_t* p, size_t plen)
return 0;
}
/** Match OPT RDATA (not the EDNS payload size or flags) */
static int
match_ednsdata(uint8_t* q, size_t qlen, uint8_t* p, size_t plen)
{
uint8_t* walk_q = q;
size_t walk_qlen = qlen;
uint8_t* walk_p = p;
size_t walk_plen = plen;
if(!pkt_find_edns_opt(&walk_q, &walk_qlen))
walk_qlen = 0;
if(!pkt_find_edns_opt(&walk_p, &walk_plen))
walk_plen = 0;
/* class + ttl + rdlen = 8 */
if(walk_qlen <= 8 && walk_plen <= 8) {
verbose(3, "NO edns opt, move on");
return 1;
}
if(walk_qlen != walk_plen)
return 0;
return (memcmp(walk_p+8, walk_q+8, walk_qlen-8) == 0);
}
/* finds entry in list, or returns NULL */
struct entry*
find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
@@ -1409,6 +1473,11 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
verbose(3, "bad; EDNS OPT present\n");
continue;
}
if(p->match_ednsdata_raw &&
!match_ednsdata(query_pkt, len, reply, rlen)) {
verbose(3, "bad EDNS data match.\n");
continue;
}
if(p->match_transport != transport_any && p->match_transport != transport) {
verbose(3, "bad transport\n");
continue;
@@ -1494,6 +1563,29 @@ adjust_packet(struct entry* match, uint8_t** answer_pkt, size_t *answer_len,
if(match->copy_id && reslen >= 1)
res[0] = orig[0];
if(match->copy_ednsdata_assume_clientsubnet) {
/** Assume there is only one EDNS option, which is ECS.
* Copy source mask from query to scope mask in reply. Assume
* rest of ECS data in response (eg address) matches the query.
*/
uint8_t* walk_q = orig;
size_t walk_qlen = origlen;
uint8_t* walk_p = res;
size_t walk_plen = reslen;
if(!pkt_find_edns_opt(&walk_q, &walk_qlen)) {
walk_qlen = 0;
}
if(!pkt_find_edns_opt(&walk_p, &walk_plen)) {
walk_plen = 0;
}
/* class + ttl + rdlen + optcode + optlen + ecs fam + ecs source
* + ecs scope = index 15 */
if(walk_qlen >= 15 && walk_plen >= 15) {
walk_p[15] = walk_q[14];
}
}
if(match->sleeptime > 0) {
verbose(3, "sleeping for %d seconds\n", match->sleeptime);
#ifdef HAVE_SLEEP
@@ -1587,6 +1679,7 @@ void delete_replylist(struct reply_packet* replist)
np = p->next;
free(p->reply_pkt);
sldns_buffer_free(p->reply_from_hex);
sldns_buffer_free(p->raw_ednsdata);
free(p);
p=np;
}
+13
View File
@@ -53,6 +53,7 @@ struct sldns_file_parse_state;
; 'rcode' makes the query match the rcode from the reply
; 'question' makes the query match the question section
; 'answer' makes the query match the answer section
; 'ednsdata' matches queries to HEX_EDNS section.
MATCH [opcode] [qtype] [qname] [serial=<value>] [all] [ttl]
MATCH [UDP|TCP] DO
MATCH ...
@@ -87,6 +88,11 @@ struct sldns_file_parse_state;
; be parsed, ADJUST rules for the answer packet
; are ignored. Only copy_id is done.
HEX_ANSWER_END
HEX_EDNS_BEGIN ; follow with hex data.
; Raw EDNS data to match against. It must be an
; exact match (all options are matched) and will be
; evaluated only when 'MATCH ednsdata' given.
HEX_EDNS_END
ENTRY_END
@@ -147,6 +153,8 @@ struct reply_packet {
uint8_t* reply_pkt;
/** length of reply pkt */
size_t reply_len;
/** Additional EDNS data for matching queries. */
struct sldns_buffer* raw_ednsdata;
/** or reply pkt in hex if not parsable */
struct sldns_buffer* reply_from_hex;
/** seconds to sleep before giving packet */
@@ -182,6 +190,8 @@ struct entry {
uint8_t match_do;
/** match absence of EDNS OPT record in query */
uint8_t match_noedns;
/** match edns data field given in hex */
uint8_t match_ednsdata_raw;
/** match query serial with this value. */
uint32_t ixfr_soa_serial;
/** match on UDP/TCP */
@@ -195,6 +205,9 @@ struct entry {
uint8_t copy_id;
/** copy the query nametypeclass from query into the answer */
uint8_t copy_query;
/** copy ednsdata to reply, assume it is clientsubnet and
* adjust scopemask to match sourcemask */
uint8_t copy_ednsdata_assume_clientsubnet;
/** in seconds */
unsigned int sleeptime;
+284
View File
@@ -0,0 +1,284 @@
/*
* testcode/unitecs.c - unit test for ecs routines.
*
* Copyright (c) 2013, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* \file
* Calls ecs related unit tests. Exits with code 1 on a failure.
*/
#include "config.h"
#ifdef CLIENT_SUBNET
#include "util/log.h"
#include "util/module.h"
#include "testcode/unitmain.h"
#include "edns-subnet/addrtree.h"
#include "edns-subnet/subnetmod.h"
/*
void printkey(addrkey_t *k, addrlen_t bits)
{
int byte;
int bytes = bits/8 + ((bits%8)>0);
char msk = 0xFF;
for (byte = 0; byte < bytes; byte++) {
//~ if (byte+1 == bytes)
//~ msk = 0xFF<<(8-bits%8);
printf("%02x ", k[byte]&msk);
}
}
void print_tree(struct addrnode* node, int indent, int maxdepth)
{
struct addredge* edge;
int i, s, byte;
if (indent == 0) printf("-----Tree-----\n");
if (indent > maxdepth) {
printf("\n");
return;
}
printf("[node elem:%d] (%d)\n", node->elem != NULL, node);
for (i = 0; i<2; i++) {
if (node->edge[i]) {
for (s = 0; s < indent; s++) printf(" ");
printkey(node->edge[i]->str, node->edge[i]->len);
printf("(len %d bits, %d bytes) ", node->edge[i]->len,
node->edge[i]->len/8 + ((node->edge[i]->len%8)>0));
print_tree(node->edge[i]->node, indent+1, maxdepth);
}
}
if (indent == 0) printf("-----Tree-----");
}
*/
/* what should we check?
* X - is it balanced? (a node with 1 child shoudl not have
* a node with 1 child MUST have elem
* child must be sub of parent
* edge must be longer than parent edge
* */
static int addrtree_inconsistent_subtree(struct addrtree* tree,
struct addredge* parent_edge, addrlen_t depth)
{
struct addredge* edge;
struct addrnode* node = parent_edge->node;
int childcount, i, r;
if (depth > tree->max_depth) return 15;
childcount = (node->edge[0] != NULL) + (node->edge[1] != NULL);
/* Only nodes with 2 children should possibly have no element. */
if (childcount < 2 && !node->elem) return 10;
for (i = 0; i<2; i++) {
edge = node->edge[i];
if (!edge) continue;
if (!edge->node) return 11;
if (!edge->str) return 12;
if (edge->len <= parent_edge->len) return 13;
if (!unittest_wrapper_addrtree_issub(parent_edge->str,
parent_edge->len, edge->str, edge->len, 0))
return 14;
if ((r = addrtree_inconsistent_subtree(tree, edge, depth+1)) != 0)
return 100+r;
}
return 0;
}
static int addrtree_inconsistent(struct addrtree* tree)
{
struct addredge* edge;
int i, r;
if (!tree) return 0;
if (!tree->root) return 1;
for (i = 0; i<2; i++) {
edge = tree->root->edge[i];
if (!edge) continue;
if (!edge->node) return 3;
if (!edge->str) return 4;
if ((r = addrtree_inconsistent_subtree(tree, edge, 1)) != 0)
return r;
}
return 0;
}
static addrlen_t randomkey(addrkey_t **k, int maxlen)
{
int byte;
int bits = rand() % maxlen;
int bytes = bits/8 + (bits%8>0); /*ceil*/
*k = (addrkey_t *) malloc(bytes * sizeof(addrkey_t));
for (byte = 0; byte < bytes; byte++) {
(*k)[byte] = (addrkey_t)(rand() & 0xFF);
}
return (addrlen_t)bits;
}
static void elemfree(void *envptr, void *elemptr)
{
struct reply_info *elem = (struct reply_info *)elemptr;
(void)envptr;
free(elem);
}
static void consistency_test(void)
{
addrlen_t l;
time_t i;
unsigned int count;
addrkey_t *k;
struct addrtree* t;
struct module_env env;
struct reply_info *elem;
time_t timenow = 0;
unit_show_func("edns-subnet/addrtree.h", "Tree consistency check");
srand(9195); /* just some value for reproducibility */
t = addrtree_create(100, &elemfree, &unittest_wrapper_subnetmod_sizefunc, &env, 0);
count = t->node_count;
unit_assert(count == 0);
for (i = 0; i < 1000; i++) {
l = randomkey(&k, 128);
elem = (struct reply_info *) calloc(1, sizeof(struct reply_info));
addrtree_insert(t, k, l, 64, elem, timenow + 10, timenow);
/* This should always hold because no items ever expire. They
* could be overwritten, though. */
unit_assert( count <= t->node_count );
count = t->node_count;
free(k);
unit_assert( !addrtree_inconsistent(t) );
}
addrtree_delete(t);
unit_show_func("edns-subnet/addrtree.h", "Tree consistency with purge");
t = addrtree_create(8, &elemfree, &unittest_wrapper_subnetmod_sizefunc, &env, 0);
unit_assert(t->node_count == 0);
for (i = 0; i < 1000; i++) {
l = randomkey(&k, 128);
elem = (struct reply_info *) calloc(1, sizeof(struct reply_info));
addrtree_insert(t, k, l, 64, elem, i + 10, i);
free(k);
unit_assert( !addrtree_inconsistent(t) );
}
addrtree_delete(t);
unit_show_func("edns-subnet/addrtree.h", "Tree consistency with limit");
t = addrtree_create(8, &elemfree, &unittest_wrapper_subnetmod_sizefunc, &env, 27);
unit_assert(t->node_count == 0);
for (i = 0; i < 1000; i++) {
l = randomkey(&k, 128);
elem = (struct reply_info *) calloc(1, sizeof(struct reply_info));
addrtree_insert(t, k, l, 64, elem, i + 10, i);
unit_assert( t->node_count <= 27);
free(k);
unit_assert( !addrtree_inconsistent(t) );
}
addrtree_delete(t);
}
static void issub_test(void)
{
addrkey_t k1[] = {0x55, 0x55, 0x5A};
addrkey_t k2[] = {0x55, 0x5D, 0x5A};
unit_show_func("edns-subnet/addrtree.h", "issub");
unit_assert( !unittest_wrapper_addrtree_issub(k1, 24, k2, 24, 0) );
unit_assert( unittest_wrapper_addrtree_issub(k1, 8, k2, 16, 0) );
unit_assert( unittest_wrapper_addrtree_issub(k2, 12, k1, 13, 0) );
unit_assert( !unittest_wrapper_addrtree_issub(k1, 16, k2, 12, 0) );
unit_assert( unittest_wrapper_addrtree_issub(k1, 12, k2, 12, 0) );
unit_assert( !unittest_wrapper_addrtree_issub(k1, 13, k2, 13, 0) );
unit_assert( unittest_wrapper_addrtree_issub(k1, 24, k2, 24, 13) );
unit_assert( !unittest_wrapper_addrtree_issub(k1, 24, k2, 20, 13) );
unit_assert( unittest_wrapper_addrtree_issub(k1, 20, k2, 24, 13) );
}
static void getbit_test(void)
{
addrkey_t k1[] = {0x55, 0x55, 0x5A};
int i;
unit_show_func("edns-subnet/addrtree.h", "getbit");
for(i = 0; i<20; i++) {
unit_assert( unittest_wrapper_addrtree_getbit(k1, 20, (addrlen_t)i) == (i&1) );
}
}
static void bits_common_test(void)
{
addrkey_t k1[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};
addrkey_t k2[] = {0,0,0,0,0,0,0,0};
addrlen_t i;
unit_show_func("edns-subnet/addrtree.h", "bits_common");
for(i = 0; i<64; i++) {
unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k1, 64, i) == 64 );
}
for(i = 0; i<8; i++) {
k2[i] = k1[i]^(1<<i);
}
unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 0) == 0*8+7 );
unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 8) == 1*8+6 );
unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 16) == 2*8+5 );
unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 24) == 3*8+4 );
unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 32) == 4*8+3 );
unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 40) == 5*8+2 );
unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 48) == 6*8+1 );
unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 56) == 7*8+0 );
}
static void cmpbit_test(void)
{
addrkey_t k1[] = {0xA5, 0x0F};
addrkey_t k2[] = {0x5A, 0xF0};
addrlen_t i;
unit_show_func("edns-subnet/addrtree.h", "cmpbit");
for(i = 0; i<16; i++) {
unit_assert( !unittest_wrapper_addrtree_cmpbit(k1,k1,i) );
unit_assert( unittest_wrapper_addrtree_cmpbit(k1,k2,i) );
}
}
void ecs_test(void)
{
unit_show_feature("ecs");
cmpbit_test();
bits_common_test();
getbit_test();
issub_test();
consistency_test();
}
#endif /* CLIENT_SUBNET */
+3
View File
@@ -880,6 +880,9 @@ main(int argc, char* argv[])
infra_test();
ldns_test();
msgparse_test();
#ifdef CLIENT_SUBNET
ecs_test();
#endif /* CLIENT_SUBNET */
checklock_stop();
printf("%d checks ok.\n", testcount);
#ifdef HAVE_SSL
+4
View File
@@ -72,6 +72,10 @@ void verify_test(void);
void neg_test(void);
/** unit test for regional allocator functions */
void regional_test(void);
#ifdef CLIENT_SUBNET
/** Unit test for ECS functions */
void ecs_test(void);
#endif /* CLIENT_SUBNET */
/** unit test for ldns functions */
void ldns_test(void);